83 const auto current = aCurrent.find( it->first );
85 if( current != aCurrent.end() && current->second.content ==
m_components.at( it->first ).content )
91 const auto group = it->second;
92 group->second.erase( it->first );
94 if(
group->second.empty() )
100 for(
const auto& [node, component] : aCurrent )
105 const auto& best = component.content->best;
108 || !best->schema->prefix.IsEmpty() )
112 signature.second.reserve( component.content->members.size() );
114 for(
const SLOT_KEY& slot : component.content->members )
115 signature.second.push_back( aSlots.at( slot )->claim.name );
118 std::sort( signature.second.begin(), signature.second.end() );
120 group->second.insert( node );
131 const auto setParents = [&](
NODE_ID node, std::vector<NODE_ID> parents )
135 if( std::ranges::equal( before, parents ) )
140 if( !std::binary_search( parents.begin(), parents.end(), parent, nodeLess ) )
145 throw std::invalid_argument(
"Published bundle membership is missing its reverse entry" );
147 std::erase( found->second, node );
149 if( found->second.empty() )
154 for(
NODE_ID parent : parents )
156 if( !std::binary_search( before.begin(), before.end(), parent, nodeLess ) )
159 members.insert( std::lower_bound( members.begin(), members.end(), node, nodeLess ), node );
163 if( parents.empty() )
166 m_busParents.insert_or_assign( node, std::move( parents ) );
172 const auto current = aCurrent.find( node );
174 if( component.name !=
INVALID_ID && ( current == aCurrent.end() || current->second.name != component.name ) )
180 if( current == aCurrent.end()
181 || ( component.content != current->second.content
182 && component.content->slots != current->second.content->slots ) )
184 for(
const SLOT_KEY& slot : component.content->slots )
188 if( current == aCurrent.end() )
189 setParents( node, {} );
192 for(
const auto& [node, component] : aCurrent )
198 const auto [found, inserted] =
m_byName.emplace( component.name, node );
200 if( !inserted && found->second != node )
201 throw std::invalid_argument(
"Published name belongs to multiple components: "
202 +
m_keys.Name( component.name ).utf8_string() );
206 || ( old !=
m_components.end() && old->second.content == component.content ) )
209 const bool slotsChanged = old ==
m_components.end() || old->second.content->slots != component.content->slots;
210 std::vector<NODE_ID> parents;
211 parents.reserve( component.content->slots.size() );
213 for(
const SLOT_KEY& slot : component.content->slots )
219 if( !inserted && found->second != node )
220 throw std::invalid_argument(
"Published slot belongs to multiple signal components" );
223 const NODE_ID parent = aSlots.at( slot )->parentBundle;
224 const auto bundle = aCurrent.find( parent );
226 if( bundle == aCurrent.end() || bundle->second.content->kind !=
KIND::BUNDLE )
227 throw std::invalid_argument(
"Published slot has no current bundle parent" );
229 parents.push_back( parent );
232 std::sort( parents.begin(), parents.end(), nodeLess );
233 parents.erase( std::unique( parents.begin(), parents.end() ), parents.end() );
234 setParents( node, std::move( parents ) );
wxString result
Test unit parsing edge cases and error handling.