Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-28 09:19:36

0001 // Copyright (c) 2026 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef _BRepGraph_NodeId_HeaderFile
0015 #define _BRepGraph_NodeId_HeaderFile
0016 
0017 #include <Standard_Assert.hxx>
0018 #include <Standard_HashUtils.hxx>
0019 
0020 #include <cstddef>
0021 #include <cstdint>
0022 #include <functional>
0023 #include <limits>
0024 #include <utility>
0025 
0026 class BRepGraph;
0027 
0028 //! Lightweight typed index into a per-kind node vector inside BRepGraph.
0029 //!
0030 //! The pair (NodeKind, Index) forms a unique node identifier within one graph
0031 //! instance.  Default-constructed NodeId has Index = UINT32_MAX (invalid).
0032 //!
0033 //! NodeId is a value type: cheap to copy, compare, hash.  It carries no
0034 //! pointer back to the owning graph; the caller is responsible for using
0035 //! it with the correct BRepGraph instance.
0036 struct BRepGraph_NodeId
0037 {
0038   //! Enumeration of node kinds within a BRepGraph.
0039   //!
0040   //! Topology kinds 0-5 cover core hierarchy; Compound(6)/CompSolid(7)
0041   //! are container kinds.  Note: ordering does NOT match TopAbs_ShapeEnum.
0042   //! Geometry kinds start at 10, leaving room for future topology extensions.
0043   enum class Kind : int
0044   {
0045     Solid     = 0,
0046     Shell     = 1,
0047     Face      = 2,
0048     Wire      = 3,
0049     Edge      = 4,
0050     Vertex    = 5,
0051     Compound  = 6, //!< TopoDS_Compound container
0052     CompSolid = 7, //!< TopoDS_CompSolid container
0053     CoEdge    = 8, //!< Use of an edge on a face (owns PCurve data)
0054     // Value 9 reserved for future topology kind extension.
0055     Product    = 10, //!< Reusable shape definition (part or assembly)
0056     Occurrence = 11  //!< Placed instance of a product within a parent product
0057   };
0058 
0059   //! True if the kind value is one of the supported node kinds.
0060   static bool IsValidKind(const Kind theKind)
0061   {
0062     switch (theKind)
0063     {
0064       case Kind::Solid:
0065       case Kind::Shell:
0066       case Kind::Face:
0067       case Kind::Wire:
0068       case Kind::Edge:
0069       case Kind::Vertex:
0070       case Kind::Compound:
0071       case Kind::CompSolid:
0072       case Kind::CoEdge:
0073       case Kind::Product:
0074       case Kind::Occurrence:
0075         return true;
0076     }
0077     return false;
0078   }
0079 
0080   //! @brief Compile-time typed wrapper around BRepGraph_NodeId.
0081   //!
0082   //! Provides compile-time kind safety: a Typed<Kind::Face>
0083   //! cannot be accidentally used where a Typed<Kind::Edge> is expected.
0084   //! Implicitly converts to BRepGraph_NodeId for API continuity.
0085   //!
0086   //! @tparam TheKind the BRepGraph_NodeId::Kind this typed id represents
0087   template <Kind TheKind>
0088   struct Typed
0089   {
0090     static constexpr uint32_t THE_START_INDEX   = 0u;
0091     static constexpr uint32_t THE_INVALID_INDEX = std::numeric_limits<uint32_t>::max();
0092 
0093     uint32_t Index;
0094 
0095     //! Default: invalid (Index = UINT32_MAX).
0096     Typed()
0097         : Index(THE_INVALID_INDEX)
0098     {
0099     }
0100 
0101     //! Construct from index.
0102     explicit Typed(const uint32_t theIdx)
0103         : Index(theIdx)
0104     {
0105     }
0106 
0107     //! Construct from an untyped node id of the same kind.
0108     explicit Typed(const BRepGraph_NodeId theId)
0109         : Typed(FromNodeId(theId))
0110     {
0111     }
0112 
0113     template <Kind OtherKind, typename std::enable_if_t<OtherKind != TheKind, int> = 0>
0114     Typed(const Typed<OtherKind>&) = delete;
0115 
0116     //! First valid id in a dense per-kind sequence.
0117     [[nodiscard]] static Typed Start() { return Typed(THE_START_INDEX); }
0118 
0119     //! Invalid sentinel id.
0120     [[nodiscard]] static Typed Invalid() { return Typed(); }
0121 
0122     //! True if this id points to an allocated node slot.
0123     [[nodiscard]] bool IsValid() const
0124     {
0125       return BRepGraph_NodeId::IsValidKind(TheKind) && Index != THE_INVALID_INDEX;
0126     }
0127 
0128     //! True if this id points to an allocated slot within [0, theMaxCount).
0129     //! UINT32_MAX (invalid sentinel) always fails this check for any realistic count.
0130     [[nodiscard]] bool IsValid(const uint32_t theMaxCount) const
0131     {
0132       return IsValid() && Index < theMaxCount;
0133     }
0134 
0135     //! True if this id is within the dense range exposed by a provider with Nb().
0136     template <typename CountProviderT>
0137     [[nodiscard]] auto IsValidIn(const CountProviderT& theProvider) const
0138       -> decltype(theProvider.Nb(), bool())
0139     {
0140       return IsValid(theProvider.Nb());
0141     }
0142 
0143     //! True if this id is within the dense range exposed by a provider with Size().
0144     template <typename CountProviderT>
0145     [[nodiscard]] auto IsValidIn(const CountProviderT& theProvider) const
0146       -> decltype(theProvider.Size(), bool())
0147     {
0148       return IsValid(static_cast<uint32_t>(theProvider.Size()));
0149     }
0150 
0151     //! Implicit conversion to untyped NodeId.
0152     operator BRepGraph_NodeId() const { return BRepGraph_NodeId(TheKind, Index); }
0153 
0154     //! Explicit conversion from untyped NodeId.
0155     //! Asserts that the Kind matches in debug builds.
0156     //! @param[in] theId untyped NodeId to convert
0157     static Typed FromNodeId(const BRepGraph_NodeId theId)
0158     {
0159       Standard_ASSERT_RETURN(theId.NodeKind == TheKind, "NodeId kind mismatch", Typed());
0160       if (!theId.IsValid())
0161       {
0162         return Typed();
0163       }
0164       return Typed(theId.Index);
0165     }
0166 
0167     bool operator==(const Typed& theOther) const { return Index == theOther.Index; }
0168 
0169     bool operator!=(const Typed& theOther) const { return Index != theOther.Index; }
0170 
0171     bool operator<(const Typed& theOther) const { return Index < theOther.Index; }
0172 
0173     bool operator<=(const Typed& theOther) const { return Index <= theOther.Index; }
0174 
0175     bool operator>(const Typed& theOther) const { return Index > theOther.Index; }
0176 
0177     bool operator>=(const Typed& theOther) const { return Index >= theOther.Index; }
0178 
0179     //! Pre-increment (++id).
0180     Typed& operator++()
0181     {
0182       Standard_ASSERT_VOID(Index != THE_INVALID_INDEX, "pre-increment on invalid id");
0183       ++Index;
0184       return *this;
0185     }
0186 
0187     //! Post-increment (id++).
0188     Typed operator++(int)
0189     {
0190       Standard_ASSERT_VOID(Index != THE_INVALID_INDEX, "post-increment on invalid id");
0191       Typed aPrev = *this;
0192       ++Index;
0193       return aPrev;
0194     }
0195 
0196     //! Advance by offset.
0197     [[nodiscard]] Typed operator+(const uint32_t theOffset) const
0198     {
0199       return Typed(Index + theOffset);
0200     }
0201 
0202     //! Retreat by offset.
0203     [[nodiscard]] Typed operator-(const uint32_t theOffset) const
0204     {
0205       Standard_ASSERT_VOID(Index != THE_INVALID_INDEX && Index >= theOffset,
0206                            "retreat underflows index");
0207       return Typed(Index - theOffset);
0208     }
0209 
0210     //! Comparison with untyped NodeId (checks both Kind and Index).
0211     bool operator==(const BRepGraph_NodeId& theOther) const
0212     {
0213       return theOther.NodeKind == TheKind && theOther.Index == Index;
0214     }
0215 
0216     bool operator!=(const BRepGraph_NodeId& theOther) const { return !(*this == theOther); }
0217 
0218     //! Allow reversed comparison: NodeId == Typed.
0219     friend bool operator==(const BRepGraph_NodeId& theLhs, const Typed& theRhs)
0220     {
0221       return theRhs == theLhs;
0222     }
0223 
0224     friend bool operator!=(const BRepGraph_NodeId& theLhs, const Typed& theRhs)
0225     {
0226       return theRhs != theLhs;
0227     }
0228 
0229     //! Return true if this node has been soft-removed in the given graph.
0230     [[nodiscard]] bool IsRemoved(const BRepGraph& theGraph) const
0231     {
0232       return BRepGraph_NodeId(*this).IsRemoved(theGraph);
0233     }
0234 
0235     //! Return true if this node has an active owner in the given graph.
0236     [[nodiscard]] bool IsOwned(const BRepGraph& theGraph) const
0237     {
0238       return BRepGraph_NodeId(*this).IsOwned(theGraph);
0239     }
0240   };
0241 
0242   //! True if the kind is a core topology kind (Solid..CoEdge).
0243   static bool IsTopologyKind(const Kind theKind)
0244   {
0245     return IsValidKind(theKind) && theKind >= Kind::Solid && theKind <= Kind::CoEdge;
0246   }
0247 
0248   //! True if the kind is an assembly kind (Product or Occurrence).
0249   static bool IsAssemblyKind(const Kind theKind)
0250   {
0251     return IsValidKind(theKind) && (theKind == Kind::Product || theKind == Kind::Occurrence);
0252   }
0253 
0254   //! Total number of dense kind slots used by per-kind arrays.
0255   //! Includes the reserved gap at enum value 9.
0256   static constexpr int      THE_KIND_COUNT    = static_cast<int>(Kind::Occurrence) + 1;
0257   static constexpr uint32_t THE_START_INDEX   = 0u;
0258   static constexpr uint32_t THE_INVALID_INDEX = std::numeric_limits<uint32_t>::max();
0259 
0260   Kind     NodeKind;
0261   uint32_t Index;
0262 
0263   //! Default: invalid NodeId (Index = UINT32_MAX).
0264   //! NodeKind is set to Kind::Solid but is meaningless when !IsValid().
0265   BRepGraph_NodeId()
0266       : NodeKind(Kind::Solid),
0267         Index(THE_INVALID_INDEX)
0268   {
0269   }
0270 
0271   BRepGraph_NodeId(const Kind theKind, const uint32_t theIdx)
0272       : NodeKind(theKind),
0273         Index(theIdx)
0274   {
0275   }
0276 
0277   //! First valid id in a dense sequence for the specified kind.
0278   [[nodiscard]] static BRepGraph_NodeId Start(const Kind theKind)
0279   {
0280     return BRepGraph_NodeId(theKind, THE_START_INDEX);
0281   }
0282 
0283   //! Invalid sentinel id for the specified kind.
0284   [[nodiscard]] static BRepGraph_NodeId Invalid(const Kind theKind = Kind::Solid)
0285   {
0286     return BRepGraph_NodeId(theKind, THE_INVALID_INDEX);
0287   }
0288 
0289   //! True if this id points to an allocated node slot.
0290   [[nodiscard]] bool IsValid() const { return IsValidKind(NodeKind) && Index != THE_INVALID_INDEX; }
0291 
0292   //! True if this id points to an allocated slot within [0, theMaxCount).
0293   //! UINT32_MAX (invalid sentinel) always fails this check for any realistic count.
0294   [[nodiscard]] bool IsValid(const uint32_t theMaxCount) const
0295   {
0296     return IsValid() && Index < theMaxCount;
0297   }
0298 
0299   //! True if this id is within the dense range exposed by a provider with Nb().
0300   template <typename CountProviderT>
0301   [[nodiscard]] auto IsValidIn(const CountProviderT& theProvider) const
0302     -> decltype(theProvider.Nb(), bool())
0303   {
0304     return IsValid(theProvider.Nb());
0305   }
0306 
0307   //! True if this id is within the dense range exposed by a provider with Size().
0308   template <typename CountProviderT>
0309   [[nodiscard]] auto IsValidIn(const CountProviderT& theProvider) const
0310     -> decltype(theProvider.Size(), bool())
0311   {
0312     return IsValid(static_cast<uint32_t>(theProvider.Size()));
0313   }
0314 
0315   bool operator==(const BRepGraph_NodeId& theOther) const
0316   {
0317     return NodeKind == theOther.NodeKind && Index == theOther.Index;
0318   }
0319 
0320   bool operator!=(const BRepGraph_NodeId& theOther) const { return !(*this == theOther); }
0321 
0322   bool operator<(const BRepGraph_NodeId& theOther) const
0323   {
0324     if (NodeKind != theOther.NodeKind)
0325     {
0326       return static_cast<int>(NodeKind) < static_cast<int>(theOther.NodeKind);
0327     }
0328     return Index < theOther.Index;
0329   }
0330 
0331   //! Pre-increment (++id).
0332   BRepGraph_NodeId& operator++()
0333   {
0334     Standard_ASSERT_VOID(Index != THE_INVALID_INDEX, "pre-increment on invalid id");
0335     ++Index;
0336     return *this;
0337   }
0338 
0339   //! Post-increment (id++).
0340   BRepGraph_NodeId operator++(int)
0341   {
0342     Standard_ASSERT_VOID(Index != THE_INVALID_INDEX, "post-increment on invalid id");
0343     BRepGraph_NodeId aPrev = *this;
0344     ++Index;
0345     return aPrev;
0346   }
0347 
0348   //! Advance by offset.
0349   [[nodiscard]] BRepGraph_NodeId operator+(const uint32_t theOffset) const
0350   {
0351     return BRepGraph_NodeId(NodeKind, Index + theOffset);
0352   }
0353 
0354   //! Retreat by offset.
0355   [[nodiscard]] BRepGraph_NodeId operator-(const uint32_t theOffset) const
0356   {
0357     Standard_ASSERT_VOID(Index != THE_INVALID_INDEX && Index >= theOffset,
0358                          "retreat underflows index");
0359     return BRepGraph_NodeId(NodeKind, Index - theOffset);
0360   }
0361 
0362   //! Dispatch a generic node id to a callable taking the matching typed node id.
0363   template <typename FuncT>
0364   static auto Visit(const BRepGraph_NodeId theNodeId, FuncT&& theFunc)
0365     -> decltype(std::forward<FuncT>(theFunc)(Typed<Kind::Vertex>()))
0366   {
0367     switch (theNodeId.NodeKind)
0368     {
0369       case Kind::Vertex:
0370         return std::forward<FuncT>(theFunc)(Typed<Kind::Vertex>::FromNodeId(theNodeId));
0371       case Kind::Edge:
0372         return std::forward<FuncT>(theFunc)(Typed<Kind::Edge>::FromNodeId(theNodeId));
0373       case Kind::CoEdge:
0374         return std::forward<FuncT>(theFunc)(Typed<Kind::CoEdge>::FromNodeId(theNodeId));
0375       case Kind::Wire:
0376         return std::forward<FuncT>(theFunc)(Typed<Kind::Wire>::FromNodeId(theNodeId));
0377       case Kind::Face:
0378         return std::forward<FuncT>(theFunc)(Typed<Kind::Face>::FromNodeId(theNodeId));
0379       case Kind::Shell:
0380         return std::forward<FuncT>(theFunc)(Typed<Kind::Shell>::FromNodeId(theNodeId));
0381       case Kind::Solid:
0382         return std::forward<FuncT>(theFunc)(Typed<Kind::Solid>::FromNodeId(theNodeId));
0383       case Kind::Compound:
0384         return std::forward<FuncT>(theFunc)(Typed<Kind::Compound>::FromNodeId(theNodeId));
0385       case Kind::CompSolid:
0386         return std::forward<FuncT>(theFunc)(Typed<Kind::CompSolid>::FromNodeId(theNodeId));
0387       case Kind::Product:
0388         return std::forward<FuncT>(theFunc)(Typed<Kind::Product>::FromNodeId(theNodeId));
0389       case Kind::Occurrence:
0390         return std::forward<FuncT>(theFunc)(Typed<Kind::Occurrence>::FromNodeId(theNodeId));
0391     }
0392 
0393     Standard_ASSERT_VOID(false, "BRepGraph_NodeId::Visit: unhandled Kind");
0394     return std::forward<FuncT>(theFunc)(Typed<Kind::Vertex>());
0395   }
0396 
0397   //! Return true if this node has been soft-removed in the given graph.
0398   [[nodiscard]] Standard_EXPORT bool IsRemoved(const BRepGraph& theGraph) const;
0399 
0400   //! Return true if this node has an active owner in the given graph.
0401   [[nodiscard]] Standard_EXPORT bool IsOwned(const BRepGraph& theGraph) const;
0402 };
0403 
0404 // Convenience type aliases for typed NodeIds.
0405 using BRepGraph_SolidId      = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::Solid>;
0406 using BRepGraph_ShellId      = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::Shell>;
0407 using BRepGraph_FaceId       = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::Face>;
0408 using BRepGraph_WireId       = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::Wire>;
0409 using BRepGraph_EdgeId       = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::Edge>;
0410 using BRepGraph_VertexId     = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::Vertex>;
0411 using BRepGraph_CompoundId   = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::Compound>;
0412 using BRepGraph_CompSolidId  = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::CompSolid>;
0413 using BRepGraph_CoEdgeId     = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::CoEdge>;
0414 using BRepGraph_ProductId    = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::Product>;
0415 using BRepGraph_OccurrenceId = BRepGraph_NodeId::Typed<BRepGraph_NodeId::Kind::Occurrence>;
0416 
0417 //! std::hash specialization for BRepGraph_NodeId.
0418 template <>
0419 struct std::hash<BRepGraph_NodeId>
0420 {
0421   size_t operator()(const BRepGraph_NodeId& theId) const noexcept
0422   {
0423     size_t aCombination[2];
0424     aCombination[0] = opencascade::hash(static_cast<int>(theId.NodeKind));
0425     aCombination[1] = opencascade::hash(theId.Index);
0426     return opencascade::hashBytes(aCombination, sizeof(aCombination));
0427   }
0428 };
0429 
0430 //! std::hash specialization for BRepGraph_NodeId::Typed.
0431 template <BRepGraph_NodeId::Kind TheKind>
0432 struct std::hash<BRepGraph_NodeId::Typed<TheKind>>
0433 {
0434   size_t operator()(const BRepGraph_NodeId::Typed<TheKind>& theId) const noexcept
0435   {
0436     return std::hash<BRepGraph_NodeId>{}(static_cast<BRepGraph_NodeId>(theId));
0437   }
0438 };
0439 
0440 #endif // _BRepGraph_NodeId_HeaderFile