34 wxASSERT( wxThread::IsMain() );
38 for(
const auto& [node, version] : aPartition.
identity )
42 if( std::holds_alternative<NAME_KEY>( nodeKey ) && version == 0 )
45 const auto* key = std::get_if<RECORD_NODE>( &nodeKey );
46 const auto* entry = key ? aRecords.
Find( key->record ) :
nullptr;
49 throw std::invalid_argument(
"Bundle partition does not match current records" );
54 result.items.push_back( { item, key->record.inst } );
61 result.claims.push_back( { key->record, claim, {}, &claim == &record.
claims.front() } );
67 result.netclasses.erase( std::ranges::unique(
result.netclasses ).begin(),
result.netclasses.end() );
69 if(
result.claims.empty() )
72 std::swap(
result.claims.front(),
80 if( !leaves.empty() && !std::in_range<uint32_t>( leaves.size() - 1 ) )
81 throw std::length_error(
"Bus schema exceeds slot ordinal range" );
83 source.
leaves.reserve( leaves.size() );
89 for(
const wxString&
group : leaf.groupPath )
92 local += leaf.localName;
107 if( aInput.
claims.empty() )
113 throw std::invalid_argument(
"Bundle binding requires a parent and canonical schema" );
133 for(
size_t i = 0; i < canonical.
leaves.size(); ++i )
136 result.members.push_back( key );
137 result.slots.push_back( makeSlot( key, canonical, i ) );
141 std::map<std::pair<INST_ID, NAME_ID>,
const BUNDLE_CLAIM*> answers;
148 const auto [found, inserted] = answers.try_emplace( { source.
record.
inst, source.
claim.
name }, &source );
150 if( !inserted && claimLess( found->second->claim, source.
claim ) )
151 found->second = &source;
157 throw std::invalid_argument(
"Prepared bundle leaves do not match their schema" );
164 if(
auto found = answers.find( { *source.claim.portInstance, source.claim.name } ); found != answers.end() )
165 answer = found->second;
172 if( !named && !answer )
176 const auto parentEdges = [&](
SLOT_INPUT& aSlot ) -> std::vector<NAME_KEY>&
178 return sheetPin ? aSlot.parentEdges : aSlot.edges;
183 for(
const auto& [from, to] : alignment.
matched )
185 parentEdges(
result.slots[to] )
186 .push_back( { SCOPE::SHEET, source.
record.
inst, source.
leaves[from].name } );
193 const auto ordinal =
static_cast<uint32_t
>( from );
197 parentEdges( slot ).push_back( { SCOPE::SHEET, source.
record.
inst, source.
leaves[from].name } );
202 result.slots.push_back( std::move( slot ) );
212 std::ranges::sort( *edges, keyLess );
213 edges->erase( std::ranges::unique( *edges ).begin(), edges->end() );
228 wxASSERT( wxThread::IsMain() );
231 std::set<SLOT_KEY, KEY_LESS> live(
m_slots.Entries().key_comp() );
232 std::set<NODE_ID> parents;
234 for(
const auto& bundle : aBundles.
Entries() )
236 const NODE_ID parent = bundle->input.anchor;
238 if( !parents.insert( parent ).second )
239 throw std::invalid_argument(
"Duplicate bundle component" );
241 const auto [previous, inserted] =
m_bundleInputs.try_emplace( parent, bundle->version );
242 const bool changed = inserted || std::exchange( previous->second, bundle->version ) != bundle->version;
244 for(
const SLOT_INPUT& slot : bundle->value.slots )
247 throw std::invalid_argument(
"Slot has a duplicate key or inconsistent parent" );
254 for(
auto it =
m_slots.Entries().begin(); it !=
m_slots.Entries().end(); )
257 const SLOT_KEY key = ( it++ )->first;
259 if( !live.contains( key ) )
264 [&](
const auto& entry )
266 return !parents.contains( entry.first );
287 std::set<NODE_ID> claimedNames;
290 claimedNames.insert( record.edges.begin(), record.edges.end() );
292 for(
const auto& [key, entry] : aSlots.
Entries() )
295 input.
edges.reserve( entry->value.edges.size() );
297 for(
const NAME_KEY& edge : entry->value.edges )
298 input.edges.push_back( aKeys.
InternNode( edge ) );
301 for(
const NAME_KEY& edge : entry->value.parentEdges )
303 if(
const NODE_ID node = aKeys.
InternNode( edge ); claimedNames.contains( node ) )
304 input.edges.push_back( node );
307 result.push_back( std::move( input ) );
const auto & Entries() const
const ENTRY * Find(const KEY &aKey) const
Entry references survive unchanged writes, but not replacement or erasure of their key.
One sequence for all cache tables for the lifetime of an engine session.
Cache current component evaluations by exact node/version identity, within one stratum and key sessio...
const auto & Entries() const
CACHE_TABLE< RECORD_KEY, ISLAND_RECORD, KEY_LESS > RECORD_CACHE
Session IDs are dense handles, never a canonical ordering.
const NODE_KEY & Node(NODE_ID aId) const
const wxString & Name(NAME_ID aId) const
NAME_ID InternName(const wxString &aText)
NODE_ID InternNode(NODE_KEY aKey)
CACHE_TABLE< SLOT_KEY, SLOT_INPUT, KEY_LESS > SLOT_CACHE
std::map< NODE_ID, uint64_t > m_bundleInputs
void Update(const COMPONENT_CACHE< BUNDLE_BINDING > &aBundles)
SLOT_STORE(CACHE_VERSIONS &aVersions, SESSION_KEYS &aKeys)
Value keys and the key session of the schematic connectivity engine.
std::variant< RECORD_NODE, NAME_KEY, SLOT_KEY > NODE_KEY
Any node of the union-find graph.
BUNDLE_INPUT PrepareBundle(const PARTITION &aPartition, const RECORD_STORE::RECORD_CACHE &aRecords, SESSION_KEYS &aKeys)
Collect the bus claims of a bundle partition and intern their leaf names on the main thread.
uint32_t NODE_ID
Session handle of a NODE_KEY graph node.
BUS_ALIGNMENT Align(const BUS_SCHEMA &aLeft, const BUS_SCHEMA &aRight)
Match the leaves of aLeft to the leaves of aRight.
constexpr uint32_t INVALID_ID
Marks an unset handle.
BUNDLE_BINDING BindBundle(const BUNDLE_INPUT &aInput, const SESSION_KEYS &aKeys)
Align the prepared claims to the canonical claim and make the member slots.
std::vector< NODE_INPUT > SignalNodes(const RECORD_STORE::RECORD_CACHE &aRecords, const SLOT_STORE::SLOT_CACHE &aSlots, SESSION_KEYS &aKeys)
Main-thread interning of current signal records and slots for the signal fold.
@ SHEET_PIN
Sheet pin. The name belongs to the child instance.
@ BUS_MEMBER
Synthetic claim of a bus member slot, set by BindBundle().
@ HIER_LABEL
Hierarchical label. The first strong priority.
std::vector< NODE_INPUT > RecordNodes(const RECORD_STORE::RECORD_CACHE &aRecords, KIND aKind, SESSION_KEYS &aKeys)
Main-thread node interning for one record stratum.
Bound result of one bus component.
NAME_ID fullName
Leaf name after the sheet path of this claim.
NAME_ID localName
Group path and leaf local name joined with dots.
NAME_ID name
Leaf name with all group prefixes.
One bus claim of a bundle partition, with its leaf names interned.
bool drivesRecord
The claim drives its own island, which lets a sheet pin name members in the parent sheet.
std::vector< LEAF_NAME > leaves
One entry for each leaf of the claim schema, in the same order.
RECORD_KEY record
Record of the island that holds the claim.
Member correspondence between two bus schemas.
std::vector< size_t > unmappedLeft
Left leaf ordinals without a right partner.
std::vector< std::pair< size_t, size_t > > matched
Pairs of left and right leaf ordinals.
Strict weak order on claims by value.
The claim of one item for the name of its island.
ITEM_KEY source
The claiming item, the last tie-break.
uint16_t depth
Sheet path size, or zero if unscoped.
std::optional< INST_ID > portInstance
Sheet pin child. Members bind there, not in the parent.
NAME_ID ncName
Name of an unconnected pin net.
NAME_ID name
Item text without the sheet prefix.
std::shared_ptr< const BUS_SCHEMA > schema
Parsed bus, or null for a signal.
NAME_ID path
Sheet prefix, or the empty name if unscoped.
NAME_ID fullName
path followed by name.
std::vector< NAME_ID > netclasses
std::vector< KIID > items
std::vector< CLAIM > claims
Descending by CLAIM_LESS, so front() is the island driver.
Orders keys by value through SESSION_KEYS::Less().
The graph node of one name in one scope.
Orders name handles by UTF-8 value.
Exact identity of one connected component.
std::vector< std::pair< NODE_ID, uint64_t > > identity
INST_ID inst
The sheet instance of the record.
One member position of a bus.
wxString result
Test unit parsing edge cases and error handling.