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_MutGuard_HeaderFile
0015 #define _BRepGraph_MutGuard_HeaderFile
0016 
0017 #include <BRepGraph.hxx>
0018 #include <BRepGraphInc_Definition.hxx>
0019 #include <BRepGraphInc_Reference.hxx>
0020 #include <BRepGraphInc_Storage.hxx>
0021 #include <Standard_ProgramError.hxx>
0022 
0023 #include <type_traits>
0024 
0025 //! @brief RAII scope token batching mutation notifications for a single entity.
0026 //!
0027 //! Obtained via BRepGraph::Editor().<Ops>().Mut() / MutRef() / MutSurface() etc.
0028 //! Reads via `operator->()` / `operator*()`; writes via Editor's typed setters
0029 //! (or `Internal()` for in-tree structural remaps). Any call to `Internal()`
0030 //! flags the guard dirty and the destructor fires `markModified` /
0031 //! `markRefModified` once on scope exit.
0032 //!
0033 //! The guard registers itself as active on the guarded item at construction
0034 //! and deregisters on destruction. This prevents double-mutation: attempting
0035 //! to acquire a second guard on the same item while the first is still alive
0036 //! will throw. Move-only; after a move, the source guard becomes inert and
0037 //! does not deregister.
0038 //!
0039 //! Compile-time dispatch selects the ID type and notification method:
0040 //! - For types derived from BRepGraphInc::BaseDef: BRepGraph_NodeId + markModified()
0041 //! - For types derived from BRepGraphInc::BaseRef: BRepGraph_RefId + markRefModified()
0042 //!
0043 //! @code
0044 //!   {
0045 //!     BRepGraph_MutGuard<BRepGraphInc::EdgeDef> anEdge =
0046 //!       theGraph.Editor().Edges().Mut(BRepGraph_EdgeId(42));
0047 //!     theGraph.Editor().Edges().SetTolerance(anEdge, 0.5);
0048 //!   } // markModified called once here, guard deregistered
0049 //! @endcode
0050 template <typename T>
0051 class BRepGraph_MutGuard
0052 {
0053   static_assert(std::is_base_of_v<BRepGraphInc::BaseDef, T>
0054                   || std::is_base_of_v<BRepGraphInc::BaseRef, T>,
0055                 "BRepGraph_MutGuard<T>: T must derive from BaseDef or BaseRef");
0056 
0057   using TypeId = typename T::TypeId;
0058 
0059   //! Call the appropriate notification method on the graph.
0060   void notify() noexcept
0061   {
0062     try
0063     {
0064       if constexpr (std::is_base_of_v<BRepGraphInc::BaseDef, T>)
0065       {
0066         myGraph->markModified(myId, *myEntity);
0067       }
0068       else if constexpr (std::is_base_of_v<BRepGraphInc::BaseRef, T>)
0069       {
0070         myGraph->markRefModified(myId);
0071       }
0072     }
0073     catch (...)
0074     {
0075     }
0076   }
0077 
0078 public:
0079   //! Construct a guard over a mutable entity.
0080   //! Registers the item via the storage bit-plane. The Mut() factory pre-validates
0081   //! that no guard is active, so this assertion should never fire in normal use.
0082   //! @param[in] theGraph   owning graph (used for notification)
0083   //! @param[in] theStorage storage instance (for bit-plane guard tracking)
0084   //! @param[in] theEntity  pointer to the mutable entity
0085   //! @param[in] theId      identity for notification and guard registration
0086   BRepGraph_MutGuard(BRepGraph&            theGraph,
0087                      BRepGraphInc_Storage& theStorage,
0088                      T*                    theEntity,
0089                      const TypeId          theId)
0090       : myGraph(&theGraph),
0091         myStorage(&theStorage),
0092         myEntity(theEntity),
0093         myId(theId),
0094         myDirty(false)
0095   {
0096     Standard_ProgramError_Raise_if(myStorage->IsGuarded(BRepGraph_ItemId(myId)),
0097                                    "BRepGraph_MutGuard: guard already active on this item");
0098     myStorage->SetGuarded(BRepGraph_ItemId(myId));
0099   }
0100 
0101   //! Destructor: clears the guard bit-plane and notifies the graph if the
0102   //! guard owns an entity AND at least one setter (or `MarkDirty`) flagged it modified.
0103   //! Guard clearance happens BEFORE notification so that markModified() propagation
0104   //! does not see a stale guard registration on the same item.
0105   ~BRepGraph_MutGuard()
0106   {
0107     if (myEntity != nullptr)
0108     {
0109       myStorage->ClearGuarded(BRepGraph_ItemId(myId));
0110       if (myDirty)
0111       {
0112         notify();
0113       }
0114     }
0115   }
0116 
0117   //! Move constructor: transfers guard ownership. The source becomes inert
0118   //! and will not deregister on its destruction.
0119   BRepGraph_MutGuard(BRepGraph_MutGuard&& theOther) noexcept
0120       : myGraph(theOther.myGraph),
0121         myStorage(theOther.myStorage),
0122         myEntity(theOther.myEntity),
0123         myId(theOther.myId),
0124         myDirty(theOther.myDirty)
0125   {
0126     theOther.myEntity  = nullptr;
0127     theOther.myDirty   = false;
0128     theOther.myGraph   = nullptr;
0129     theOther.myStorage = nullptr;
0130   }
0131 
0132   //! Move assignment: deregisters current guard (if active), then transfers
0133   //! ownership from the source. The source becomes inert.
0134   BRepGraph_MutGuard& operator=(BRepGraph_MutGuard&& theOther) noexcept
0135   {
0136     if (this != &theOther)
0137     {
0138       if (myEntity != nullptr)
0139       {
0140         myStorage->ClearGuarded(BRepGraph_ItemId(myId));
0141         if (myDirty)
0142         {
0143           notify();
0144         }
0145       }
0146       myGraph            = theOther.myGraph;
0147       myStorage          = theOther.myStorage;
0148       myEntity           = theOther.myEntity;
0149       myId               = theOther.myId;
0150       myDirty            = theOther.myDirty;
0151       theOther.myEntity  = nullptr;
0152       theOther.myDirty   = false;
0153       theOther.myGraph   = nullptr;
0154       theOther.myStorage = nullptr;
0155     }
0156     return *this;
0157   }
0158 
0159   BRepGraph_MutGuard(const BRepGraph_MutGuard&)            = delete;
0160   BRepGraph_MutGuard& operator=(const BRepGraph_MutGuard&) = delete;
0161 
0162   //! True when the guard still owns an entity; false after a move or when
0163   //! constructed in an inert state.
0164   [[nodiscard]] explicit operator bool() const noexcept { return myEntity != nullptr; }
0165 
0166   //! Read-only access via pointer syntax. Field writes go through the
0167   //! Editor's typed setters.
0168   [[nodiscard]] const T* operator->() const
0169   {
0170     Standard_ProgramError_Raise_if(
0171       myEntity == nullptr,
0172       "BRepGraph_MutGuard::operator->(): guard is empty or moved-from");
0173     return myEntity;
0174   }
0175 
0176   //! Read-only dereference.
0177   [[nodiscard]] const T& operator*() const
0178   {
0179     Standard_ProgramError_Raise_if(myEntity == nullptr,
0180                                    "BRepGraph_MutGuard::operator*(): guard is empty or moved-from");
0181     return *myEntity;
0182   }
0183 
0184   //! Identity for notification.
0185   [[nodiscard]] TypeId Id() const noexcept { return myId; }
0186 
0187   //! Owning graph handle.
0188   [[nodiscard]] BRepGraph& Graph() const { return *myGraph; }
0189 
0190   //! Flag the guarded entity as modified without writing through `Internal()`.
0191   //! Use when an external mutation (e.g. in-place geometry transform on a shared
0192   //! Geom handle) is not visible to the guard.
0193   void MarkDirty() noexcept { myDirty = true; }
0194 
0195   //! True if `Internal()` or `MarkDirty()` flagged the entity modified.
0196   [[nodiscard]] bool IsDirty() const noexcept { return myDirty; }
0197 
0198   //! INTERNAL USE ONLY. Mutable accessor; auto-flags dirty. External code MUST go
0199   //! through Editor's typed setters. Use `operator->()` / `operator*()` for reads.
0200   [[nodiscard]] T& Internal() noexcept
0201   {
0202     myDirty = true;
0203     return *myEntity;
0204   }
0205 
0206 private:
0207   BRepGraph*            myGraph;   //!< Owning graph, non-owning.
0208   BRepGraphInc_Storage* myStorage; //!< Storage instance for bit-plane guard tracking, non-owning.
0209   T*                    myEntity;  //!< Mutable entity pointer; access via Editor setters.
0210   TypeId                myId;      //!< Identity for notification and guard registration.
0211   bool                  myDirty;   //!< True once a setter has modified the entity in this scope.
0212 };
0213 
0214 #endif // _BRepGraph_MutGuard_HeaderFile