mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-08-29 22:38:28 +08:00
Modeling, BRepGraph - Identity copy path, lock-free cache reads, per-CoEdge queries (#1306)
Identity copy path: - copyFullGraphIdentity with PrepareForLoad() + direct slot assignment - CopyDerivedRelationsFrom for O(K) relation vector copy - CopyRemovedFlagsFrom for bulk removed-flag copy - CopyShapeBindingsFrom for TShape/Original shape binding copy - PrepareForLoad skips Clear() when storage already empty (IsEmpty fast path) - appendRelationIdDirect for O(1) append in rebuild loop (duplicates structurally impossible) - ChangeCompoundRefsOfNodeInternal uses TryBound for single lookup - Counts() and ActiveCounts() accessors for Counts struct construction Lock-free cache reads: - EdgeEntry: packed atomic<uint8_t> (GeomStatus+IsClosed+IsComputed) - CoEdgeSameRangeEntry: packed atomic<uint8_t> (SameRange+SameParameter+Computed) - WireEntry: packed atomic<uint8_t> (IsClosed+IsComputed) - ShellEntry: atomic<ClosureStatus> with Invalid sentinel - All entries use memory_order_acquire/release pairs - ensureSize handles lazy array growth (no myPreSized) - Enums (GeomStatus, ClosureStatus) moved inside entry structs Per-CoEdge queries: - SameRange/SameParameter are per-CoEdge properties, bound to CoEdge OwnGen - Edge class no longer has SameParameter/SameRange/IsClosed coedge overloads - CoEdge class owns SameParameter/SameRange queries - Test files use local edgeSameParameter/edgeSameRange helpers Lock-free storage and registry: - BRepGraphInc_Storage: atomic dirty flags for UID reverse indexes - BRepGraph_LayerRegistry: atomic subscription masks for lock-free dispatch - Ensure/EnsureCache/EnsureLayer: double-checked locking with shared fast path Other optimizations: - Iterator Next() fast-path: check next element validity inline - NbFaces O(K) inline dedup with NCollection_LocalArray - GeomAdaptor_Curve/Surface/Geom2dAdaptor_Curve for cached geometry eval - Value() calls replaced with EvalD0() for clearer naming - TargetItem returns value instead of pointer (no null-pointer risk) - copyTopologyDefinitionsIdentity clears Curve3DRepId on GeomPolicy::Drop - ensureEdgeEntry concurrency: fast-path validation + selective field merge
This commit is contained in:
@@ -30,14 +30,16 @@ BRepGraph_LayerRegistry::BRepGraph_LayerRegistry() = default;
|
||||
BRepGraph_LayerRegistry::BRepGraph_LayerRegistry(BRepGraph_LayerRegistry&& theOther) noexcept
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> aLock(theOther.myMutex);
|
||||
myLayers = std::move(theOther.myLayers);
|
||||
myGuidToSlot = std::move(theOther.myGuidToSlot);
|
||||
mySubscribedKindsMask = theOther.mySubscribedKindsMask;
|
||||
mySubscribedRefKindsMask = theOther.mySubscribedRefKindsMask;
|
||||
myGraph = theOther.myGraph;
|
||||
theOther.mySubscribedKindsMask = 0;
|
||||
theOther.mySubscribedRefKindsMask = 0;
|
||||
theOther.myGraph = nullptr;
|
||||
myLayers = std::move(theOther.myLayers);
|
||||
myGuidToSlot = std::move(theOther.myGuidToSlot);
|
||||
mySubscribedKindsMask.store(theOther.mySubscribedKindsMask.load(std::memory_order_relaxed),
|
||||
std::memory_order_relaxed);
|
||||
mySubscribedRefKindsMask.store(theOther.mySubscribedRefKindsMask.load(std::memory_order_relaxed),
|
||||
std::memory_order_relaxed);
|
||||
myGraph = theOther.myGraph;
|
||||
theOther.mySubscribedKindsMask.store(0, std::memory_order_relaxed);
|
||||
theOther.mySubscribedRefKindsMask.store(0, std::memory_order_relaxed);
|
||||
theOther.myGraph = nullptr;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
@@ -52,14 +54,17 @@ BRepGraph_LayerRegistry& BRepGraph_LayerRegistry::operator=(
|
||||
std::lock(aThisLock, anOtherLock);
|
||||
|
||||
detachAllLocked();
|
||||
myLayers = std::move(theOther.myLayers);
|
||||
myGuidToSlot = std::move(theOther.myGuidToSlot);
|
||||
mySubscribedKindsMask = theOther.mySubscribedKindsMask;
|
||||
mySubscribedRefKindsMask = theOther.mySubscribedRefKindsMask;
|
||||
myGraph = theOther.myGraph;
|
||||
theOther.mySubscribedKindsMask = 0;
|
||||
theOther.mySubscribedRefKindsMask = 0;
|
||||
theOther.myGraph = nullptr;
|
||||
myLayers = std::move(theOther.myLayers);
|
||||
myGuidToSlot = std::move(theOther.myGuidToSlot);
|
||||
mySubscribedKindsMask.store(theOther.mySubscribedKindsMask.load(std::memory_order_relaxed),
|
||||
std::memory_order_relaxed);
|
||||
mySubscribedRefKindsMask.store(
|
||||
theOther.mySubscribedRefKindsMask.load(std::memory_order_relaxed),
|
||||
std::memory_order_relaxed);
|
||||
myGraph = theOther.myGraph;
|
||||
theOther.mySubscribedKindsMask.store(0, std::memory_order_relaxed);
|
||||
theOther.mySubscribedRefKindsMask.store(0, std::memory_order_relaxed);
|
||||
theOther.myGraph = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -100,8 +105,12 @@ uint32_t BRepGraph_LayerRegistry::registerLayerLocked(const occ::handle<BRepGrap
|
||||
theLayer->attachGraph(myGraph);
|
||||
myLayers.Append(theLayer);
|
||||
myGuidToSlot.Bind(aGUID, aNewSlot);
|
||||
mySubscribedKindsMask |= theLayer->SubscribedKinds();
|
||||
mySubscribedRefKindsMask |= theLayer->SubscribedRefKinds();
|
||||
mySubscribedKindsMask.store(mySubscribedKindsMask.load(std::memory_order_relaxed)
|
||||
| theLayer->SubscribedKinds(),
|
||||
std::memory_order_relaxed);
|
||||
mySubscribedRefKindsMask.store(mySubscribedRefKindsMask.load(std::memory_order_relaxed)
|
||||
| theLayer->SubscribedRefKinds(),
|
||||
std::memory_order_relaxed);
|
||||
return aNewSlot;
|
||||
}
|
||||
|
||||
@@ -179,6 +188,35 @@ occ::handle<BRepGraph_Layer> BRepGraph_LayerRegistry::findLayerLocked(
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
occ::handle<BRepGraph_Layer> BRepGraph_LayerRegistry::ensureLayer(
|
||||
const Standard_GUID& theGUID,
|
||||
const std::function<occ::handle<BRepGraph_Layer>()>& theFactory)
|
||||
{
|
||||
// Fast path: shared lock for read-only lookup.
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> aLock(myMutex);
|
||||
occ::handle<BRepGraph_Layer> aLayer = findLayerLocked(theGUID);
|
||||
if (!aLayer.IsNull())
|
||||
{
|
||||
return aLayer;
|
||||
}
|
||||
}
|
||||
|
||||
// Slow path: exclusive lock for creation.
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> aLock(myMutex);
|
||||
occ::handle<BRepGraph_Layer> aLayer = findLayerLocked(theGUID);
|
||||
if (aLayer.IsNull())
|
||||
{
|
||||
aLayer = theFactory();
|
||||
registerLayerLocked(aLayer);
|
||||
}
|
||||
return aLayer;
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
bool BRepGraph_LayerRegistry::FindSlot(const Standard_GUID& theGUID, uint32_t& theSlot) const
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> aLock(myMutex);
|
||||
@@ -270,12 +308,10 @@ void BRepGraph_LayerRegistry::DispatchOnNodeReplaced(const BRepGraph_NodeId theO
|
||||
|
||||
void BRepGraph_LayerRegistry::DispatchNodeModified(const BRepGraph_NodeId theNode) noexcept
|
||||
{
|
||||
// Lock-free early exit: check subscription mask without mutex.
|
||||
if (mySubscribedKindsMask.load(std::memory_order_acquire) == 0)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> aLock(myMutex);
|
||||
if (mySubscribedKindsMask == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const int aKindBit = BRepGraph_Layer::KindBit(theNode.NodeKind);
|
||||
@@ -321,12 +357,10 @@ void BRepGraph_LayerRegistry::DispatchNodesModified(
|
||||
const NCollection_Array1<BRepGraph_NodeId>& theModifiedNodes,
|
||||
const int theModifiedKindsMask) noexcept
|
||||
{
|
||||
// Lock-free early exit: check subscription mask without mutex.
|
||||
if (mySubscribedKindsMask.load(std::memory_order_acquire) == 0 || theModifiedKindsMask == 0)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> aLock(myMutex);
|
||||
if (mySubscribedKindsMask == 0 || theModifiedKindsMask == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t aSlot = 0;; ++aSlot)
|
||||
@@ -369,8 +403,8 @@ void BRepGraph_LayerRegistry::CopyLayersTo(
|
||||
aSelf.detachAllLocked();
|
||||
aSelf.myLayers.Clear();
|
||||
aSelf.myGuidToSlot.Clear();
|
||||
aSelf.mySubscribedKindsMask = 0;
|
||||
aSelf.mySubscribedRefKindsMask = 0;
|
||||
aSelf.mySubscribedKindsMask.store(0, std::memory_order_relaxed);
|
||||
aSelf.mySubscribedRefKindsMask.store(0, std::memory_order_relaxed);
|
||||
aLock.unlock();
|
||||
|
||||
// Call CopyTo on each old (now detached) layer.
|
||||
@@ -404,6 +438,30 @@ void BRepGraph_LayerRegistry::CopyLayersTo(
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
void BRepGraph_LayerRegistry::CopyLayersTo(BRepGraph& theTargetGraph,
|
||||
BRepGraph_CopyRemap::MappingKind theMappingKind,
|
||||
BRepGraph_CopyRemap::Mode theMode) const
|
||||
{
|
||||
BRepGraph* aSourceGraph = nullptr;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> aLock(myMutex);
|
||||
aSourceGraph = myGraph;
|
||||
}
|
||||
|
||||
const BRepGraph_CopyRemap aCopy(*aSourceGraph, theTargetGraph, theMappingKind, theMode);
|
||||
for (uint32_t aSlot = 0;; ++aSlot)
|
||||
{
|
||||
occ::handle<BRepGraph_Layer> aLayer = layerAt(aSlot);
|
||||
if (aLayer.IsNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
aLayer->CopyTo(aCopy);
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
void BRepGraph_LayerRegistry::ClearAll() noexcept
|
||||
{
|
||||
for (uint32_t aSlot = 0;; ++aSlot)
|
||||
@@ -451,12 +509,10 @@ void BRepGraph_LayerRegistry::DispatchOnRefRemoved(const BRepGraph_RefId theRef)
|
||||
|
||||
void BRepGraph_LayerRegistry::DispatchRefModified(const BRepGraph_RefId theRef) noexcept
|
||||
{
|
||||
// Lock-free early exit: check subscription mask without mutex.
|
||||
if (mySubscribedRefKindsMask.load(std::memory_order_acquire) == 0)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> aLock(myMutex);
|
||||
if (mySubscribedRefKindsMask == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const int aRefKindBit = BRepGraph_Layer::RefKindBit(theRef.RefKind);
|
||||
@@ -480,12 +536,10 @@ void BRepGraph_LayerRegistry::DispatchRefsModified(
|
||||
const NCollection_Array1<BRepGraph_RefId>& theModifiedRefs,
|
||||
const int theModifiedRefKindsMask) noexcept
|
||||
{
|
||||
// Lock-free early exit: check subscription mask without mutex.
|
||||
if (mySubscribedRefKindsMask.load(std::memory_order_acquire) == 0 || theModifiedRefKindsMask == 0)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> aLock(myMutex);
|
||||
if (mySubscribedRefKindsMask == 0 || theModifiedRefKindsMask == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t aSlot = 0;; ++aSlot)
|
||||
@@ -519,11 +573,13 @@ void BRepGraph_LayerRegistry::detachAllLocked() noexcept
|
||||
|
||||
void BRepGraph_LayerRegistry::recomputeSubscribedKindsMask()
|
||||
{
|
||||
mySubscribedKindsMask = 0;
|
||||
mySubscribedRefKindsMask = 0;
|
||||
uint32_t aKindsMask = 0;
|
||||
uint32_t aRefKindsMask = 0;
|
||||
for (const occ::handle<BRepGraph_Layer>& aLayer : myLayers)
|
||||
{
|
||||
mySubscribedKindsMask |= aLayer->SubscribedKinds();
|
||||
mySubscribedRefKindsMask |= aLayer->SubscribedRefKinds();
|
||||
aKindsMask |= aLayer->SubscribedKinds();
|
||||
aRefKindsMask |= aLayer->SubscribedRefKinds();
|
||||
}
|
||||
mySubscribedKindsMask.store(aKindsMask, std::memory_order_relaxed);
|
||||
mySubscribedRefKindsMask.store(aRefKindsMask, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user