package layoutgraph

import 

// LookupEdgeLengthCost reads one entry from the graph-owned placement cache
// while holding the graph's cost read lock.
func ( *Graph) ( uint64) (float64, bool) {
	.costMu.RLock()
	defer .costMu.RUnlock()
	,  := .edgeLengthCache[]
	return , 
}

// StoreEdgeLengthCost writes one entry while holding the graph's cost lock. It
// is a no-op when this graph has disabled placement caching.
func ( *Graph) ( uint64,  float64) {
	.costMu.Lock()
	defer .costMu.Unlock()
	if .edgeLengthCache != nil {
		.edgeLengthCache[] = 
	}
}

// EdgeLengthCacheEntries reports the size of the graph-owned placement cache.
func ( *Graph) () int {
	.costMu.RLock()
	defer .costMu.RUnlock()
	return len(.edgeLengthCache)
}

// ResetPlacementCosts clears route-derived scoring state without replacing
// the graph's cache map or changing whether caching is enabled.
func ( *Graph) () {
	.costMu.Lock()
	defer .costMu.Unlock()
	clear(.edgeLengthCache)
	.crossingCost = 0
	.turnCost = 0
	.nonCenterPortCost = 0
}

// PlacementCostSnapshot is an opaque copy of graph-owned placement scoring
// state used to roll back a rejected optimizer candidate.
type PlacementCostSnapshot struct {
	graph             *Graph
	cacheRef          map[uint64]float64
	cache             map[uint64]float64
	crossingCost      float64
	turnCost          float64
	nonCenterPortCost float64
}

// SnapshotPlacementCosts copies graph-owned scoring state. The placement
// domain charges its own work budget before requesting this bounded copy.
func ( *Graph) () *PlacementCostSnapshot {
	.costMu.RLock()
	defer .costMu.RUnlock()
	 := &PlacementCostSnapshot{
		graph:             ,
		cacheRef:          .edgeLengthCache,
		crossingCost:      .crossingCost,
		turnCost:          .turnCost,
		nonCenterPortCost: .nonCenterPortCost,
	}
	if .edgeLengthCache != nil {
		.cache = maps.Clone(.edgeLengthCache)
	}
	return 
}

// Restore reinstates the captured costs and the exact cache map owned by the
// graph when the state was captured.
func ( *PlacementCostSnapshot) () {
	if  == nil || .graph == nil {
		return
	}
	.graph.costMu.Lock()
	defer .graph.costMu.Unlock()
	if .cacheRef == nil {
		.graph.edgeLengthCache = nil
	} else {
		clear(.cacheRef)
		maps.Copy(.cacheRef, .cache)
		.graph.edgeLengthCache = .cacheRef
	}
	.graph.crossingCost = .crossingCost
	.graph.turnCost = .turnCost
	.graph.nonCenterPortCost = .nonCenterPortCost
}