// Copyright (c) 2026 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #ifndef _BRepGraph_LayerRegistry_HeaderFile #define _BRepGraph_LayerRegistry_HeaderFile #include "BRepGraph.hxx" #include "BRepGraph_Layer.hxx" #include "BRepGraph_RefId.hxx" #include "NCollection_DataMap.hxx" #include "NCollection_FlatDataMap.hxx" #include "NCollection_LinearVector.hxx" #include "Standard_DefineAlloc.hxx" #include "Standard_GUID.hxx" #include #include #include #include //! @brief Dense GUID-keyed runtime registry of graph layers. //! //! Stores registered layers in a compact vector for O(1) slot access and a //! GUID-to-slot map for O(1) lookup by stable public identity. class BRepGraph_LayerRegistry { public: DEFINE_STANDARD_ALLOC Standard_EXPORT BRepGraph_LayerRegistry(); BRepGraph_LayerRegistry(const BRepGraph_LayerRegistry&) = delete; BRepGraph_LayerRegistry& operator=(const BRepGraph_LayerRegistry&) = delete; Standard_EXPORT BRepGraph_LayerRegistry(BRepGraph_LayerRegistry&& theOther) noexcept; Standard_EXPORT BRepGraph_LayerRegistry& operator=(BRepGraph_LayerRegistry&& theOther) noexcept; //! Register a layer. Replaces an existing layer with the same GUID. //! @return slot index in the internal dense vector. Standard_EXPORT uint32_t RegisterLayer(const occ::handle& theLayer); //! Remove a layer by GUID. Standard_EXPORT void UnregisterLayer(const Standard_GUID& theGUID); //! Find a layer by GUID. Returns null handle if not found. [[nodiscard]] Standard_EXPORT occ::handle FindLayer( const Standard_GUID& theGUID) const; //! Typed convenience lookup by layer GUID. template [[nodiscard]] occ::handle FindLayer() const { return Find(); } //! Typed lookup by layer GUID. template [[nodiscard]] occ::handle Find() const { return occ::down_cast(FindLayer(T::GetID())); } //! Return an existing layer or create and register a default one. //! Template convenience wrapper: extracts GUID and calls ensureLayer. template [[nodiscard]] occ::handle Ensure() { return occ::down_cast( ensureLayer(T::GetID(), []() -> occ::handle { return new T(); })); } //! Return current slot for a GUID. [[nodiscard]] Standard_EXPORT bool FindSlot(const Standard_GUID& theGUID, uint32_t& theSlot) const; //! Return layer by slot index, or null handle if the slot is out of range. [[nodiscard]] Standard_EXPORT occ::handle Layer(uint32_t theSlot) const; //! Number of registered layers. [[nodiscard]] uint32_t NbLayers() const { std::shared_lock aLock(myMutex); return static_cast(myLayers.Size()); } //! True if any registered layer subscribes to node modification events. [[nodiscard]] bool HasModificationSubscribers() const { return mySubscribedKindsMask.load(std::memory_order_acquire) != 0; } //! Bitwise OR of all registered layer node subscription masks. [[nodiscard]] int SubscribedKindsMask() const { return static_cast(mySubscribedKindsMask.load(std::memory_order_acquire)); } //! Dispatch OnNodeRemoved to all registered layers. Standard_EXPORT void DispatchOnNodeRemoved(const BRepGraph_NodeId theNode) noexcept; //! Dispatch generic item removal to all registered layers. Standard_EXPORT void DispatchOnItemRemoved(const BRepGraph_ItemId theItem) noexcept; //! Dispatch OnNodeReplaced to all registered layers. Standard_EXPORT void DispatchOnNodeReplaced(const BRepGraph_NodeId theOldNode, const BRepGraph_NodeId theNewNode) noexcept; //! Dispatch OnNodeModified to subscribed layers. Standard_EXPORT void DispatchNodeModified(const BRepGraph_NodeId theNode) noexcept; //! Dispatch generic item modification through the matching typed subscription path. Standard_EXPORT void DispatchItemModified(const BRepGraph_ItemId theItem) noexcept; //! Dispatch OnNodesModified to subscribed layers. Standard_EXPORT void DispatchNodesModified( const NCollection_Array1& theModifiedNodes, const int theModifiedKindsMask) noexcept; //! Ask every registered source layer to copy itself into the target graph. //! For Mode::Compact, layers are unregistered first and CopyTo creates fresh instances. //! @param[in] theTargetGraph target graph to receive layer data //! @param[in] theItemRemap source -> target item id mapping //! @param[in] theMode Copy or Compact semantics Standard_EXPORT void CopyLayersTo( BRepGraph& theTargetGraph, const NCollection_FlatDataMap& theItemRemap, const BRepGraph_CopyRemap::Mode theMode) const; //! Ask every registered source layer to copy itself using identity mapping. //! Source item ids are the same as target item ids (full identity copy). //! @param[in] theTargetGraph target graph to receive layer data //! @param[in] theMappingKind identity or explicit mapping //! @param[in] theMode Copy or Compact semantics Standard_EXPORT void CopyLayersTo(BRepGraph& theTargetGraph, BRepGraph_CopyRemap::MappingKind theMappingKind, BRepGraph_CopyRemap::Mode theMode) const; //! True if any registered layer subscribes to reference modification events. [[nodiscard]] bool HasRefModificationSubscribers() const { return mySubscribedRefKindsMask.load(std::memory_order_acquire) != 0; } //! Bitwise OR of all registered layer reference subscription masks. [[nodiscard]] int SubscribedRefKindsMask() const { return static_cast(mySubscribedRefKindsMask.load(std::memory_order_acquire)); } //! Dispatch OnRefRemoved to all registered layers (unconditional - not filtered). Standard_EXPORT void DispatchOnRefRemoved(const BRepGraph_RefId theRef) noexcept; //! Dispatch OnRefModified to subscribed layers (immediate mode). Standard_EXPORT void DispatchRefModified(const BRepGraph_RefId theRef) noexcept; //! Dispatch OnRefsModified to subscribed layers (deferred/batch mode). Standard_EXPORT void DispatchRefsModified( const NCollection_Array1& theModifiedRefs, const int theModifiedRefKindsMask) noexcept; //! Clear all registered layer data without unregistering services. Standard_EXPORT void ClearAll() noexcept; //! Invalidate all registered layer data. Standard_EXPORT void InvalidateAll() noexcept; private: friend class ::BRepGraph; friend struct ::BRepGraph_Data; //! Attach this registry to graph owner. Propagates context to registered layers. Standard_EXPORT void Attach(BRepGraph* theGraph) noexcept; //! Clear the graph data binding. Standard_EXPORT void Detach() noexcept; [[nodiscard]] Standard_EXPORT occ::handle findLayerLocked( const Standard_GUID& theGUID) const; //! Return an existing layer or create and register a default one. //! Uses double-checked locking: shared lock for fast path (layer exists), //! exclusive lock only for creation (rare, first-call only). [[nodiscard]] Standard_EXPORT occ::handle ensureLayer( const Standard_GUID& theGUID, const std::function()>& theFactory); [[nodiscard]] Standard_EXPORT occ::handle layerAt(uint32_t theSlot) const; Standard_EXPORT uint32_t registerLayerLocked(const occ::handle& theLayer); Standard_EXPORT void recomputeSubscribedKindsMask(); Standard_EXPORT void detachAllLocked() noexcept; private: NCollection_LinearVector> myLayers; NCollection_DataMap myGuidToSlot; std::atomic mySubscribedKindsMask{0}; std::atomic mySubscribedRefKindsMask{0}; BRepGraph* myGraph = nullptr; mutable std::shared_mutex myMutex; }; #endif // _BRepGraph_LayerRegistry_HeaderFile