7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 00:21:25 +00:00

Clean up redundant component classes on netlist update

This commit is contained in:
JamesJCode 2024-10-07 22:24:03 +01:00
parent 045c1f347f
commit f4e5ae0514
3 changed files with 130 additions and 17 deletions

View File

@ -95,9 +95,17 @@ COMPONENT_CLASS_MANAGER::GetEffectiveComponentClass( std::unordered_set<wxString
if( classNames.size() == 0 )
return m_noneClass.get();
// Lambda to handle finding constituent component classes. This first checks the cache,
// and if found moves the class to the primary classes map. If not found, it either returns
// an existing class in the primary list or creates a new class.
auto getOrCreateClass = [this]( const wxString& className )
{
if( !m_classes.count( className ) )
if( m_classesCache.count( className ) )
{
auto existingClass = m_classesCache.extract( className );
m_classes.insert( std::move( existingClass ) );
}
else if( !m_classes.count( className ) )
{
std::unique_ptr<COMPONENT_CLASS> newClass =
std::make_unique<COMPONENT_CLASS>( className );
@ -108,11 +116,11 @@ COMPONENT_CLASS_MANAGER::GetEffectiveComponentClass( std::unordered_set<wxString
return m_classes[className].get();
};
// Handle single-assignment component classes
if( classNames.size() == 1 )
{
return getOrCreateClass( *classNames.begin() );
}
// Handle composite component classes
std::vector<wxString> sortedClassNames( classNames.begin(), classNames.end() );
std::sort( sortedClassNames.begin(), sortedClassNames.end(),
@ -121,25 +129,82 @@ COMPONENT_CLASS_MANAGER::GetEffectiveComponentClass( std::unordered_set<wxString
return str1.Cmp( str2 ) < 0;
} );
wxString fullName = sortedClassNames[0];
wxString fullName = GetFullClassNameForConstituents( sortedClassNames );
for( std::size_t i = 1; i < sortedClassNames.size(); ++i )
if( m_effectiveClassesCache.count( fullName ) )
{
fullName += ",";
fullName += sortedClassNames[i];
// The effective class was previously constructed - copy it across to the new live map
auto existingClass = m_effectiveClassesCache.extract( fullName );
COMPONENT_CLASS* effClass = existingClass.mapped().get();
m_effectiveClasses.insert( std::move( existingClass ) );
// Ensure that all constituent component classes are copied to the live map
for( COMPONENT_CLASS* constClass : effClass->GetConstituentClasses() )
{
if( m_classesCache.count( constClass->GetFullName() ) )
{
auto constClassNode = m_classesCache.extract( constClass->GetFullName() );
m_classes.insert( std::move( constClassNode ) );
}
}
}
if( !m_effectiveClasses.count( fullName ) )
else if( !m_effectiveClasses.count( fullName ) )
{
// The effective class was not previously constructed
std::unique_ptr<COMPONENT_CLASS> effClass = std::make_unique<COMPONENT_CLASS>( fullName );
for( const wxString& className : sortedClassNames )
{
effClass->AddConstituentClass( getOrCreateClass( className ) );
}
m_effectiveClasses[fullName] = std::move( effClass );
}
return m_effectiveClasses[fullName].get();
}
void COMPONENT_CLASS_MANAGER::InitNetlistUpdate()
{
m_classesCache = std::move( m_classes );
m_effectiveClassesCache = std::move( m_effectiveClasses );
}
void COMPONENT_CLASS_MANAGER::FinishNetlistUpdate()
{
m_classesCache.clear();
m_effectiveClassesCache.clear();
}
wxString
COMPONENT_CLASS_MANAGER::GetFullClassNameForConstituents( std::unordered_set<wxString>& classNames )
{
std::vector<wxString> sortedClassNames( classNames.begin(), classNames.end() );
std::sort( sortedClassNames.begin(), sortedClassNames.end(),
[]( const wxString& str1, const wxString& str2 )
{
return str1.Cmp( str2 ) < 0;
} );
return GetFullClassNameForConstituents( sortedClassNames );
}
wxString
COMPONENT_CLASS_MANAGER::GetFullClassNameForConstituents( std::vector<wxString>& classNames )
{
if( classNames.size() == 0 )
return wxEmptyString;
wxString fullName = classNames[0];
for( std::size_t i = 1; i < classNames.size(); ++i )
{
fullName += ",";
fullName += classNames[i];
}
return fullName;
}

View File

@ -73,11 +73,26 @@ private:
std::vector<COMPONENT_CLASS*> m_constituentClasses;
};
/*
* A class to manage Component Classes in a board context
*
* This manager owns generated COMPONENT_CLASS objects, and guarantees that pointers to managed
* objects are valid for the duration of the board lifetime. Note that, in order to maintain this
* guarantee, there are two methods that must be called when updating the board from the netlist
* (InitNetlistUpdate and FinishNetlistUpdate).
*/
class COMPONENT_CLASS_MANAGER
{
public:
COMPONENT_CLASS_MANAGER();
/// @brief Gets the full effective class name for the given set of constituent classes
static wxString GetFullClassNameForConstituents( std::unordered_set<wxString>& classNames );
/// @brief Gets the full effective class name for the given set of constituent classes
/// @param classNames a sorted vector of consituent class names
static wxString GetFullClassNameForConstituents( std::vector<wxString>& classNames );
/// @brief Gets an effective component class for the given constituent class names
/// @param classes The names of the constituent component classes
/// @return Effective COMPONENT_CLASS object
@ -86,6 +101,18 @@ public:
/// Returns the unassigned component class
const COMPONENT_CLASS* GetNoneComponentClass() const { return m_noneClass.get(); }
/// Prepare the manager for a board update
/// Must be called prior to updating the PCB from the netlist
void InitNetlistUpdate();
/// Cleans up the manager after a board update
/// Must be called after updating the PCB from the netlist
void FinishNetlistUpdate();
/// Resets the contents of the manager
// All pointers to COMPONENT_CLASS objects will being invalid
void Reset();
protected:
/// All individual component classes
std::unordered_map<wxString, std::unique_ptr<COMPONENT_CLASS>> m_classes;
@ -93,6 +120,12 @@ protected:
/// Generated effective component classes
std::unordered_map<wxString, std::unique_ptr<COMPONENT_CLASS>> m_effectiveClasses;
/// Cache of all individual component classes (for netlist updating)
std::unordered_map<wxString, std::unique_ptr<COMPONENT_CLASS>> m_classesCache;
/// Cache of all generated effective component classes (for netlist updating)
std::unordered_map<wxString, std::unique_ptr<COMPONENT_CLASS>> m_effectiveClassesCache;
/// The class to represent an unassigned component class
std::unique_ptr<COMPONENT_CLASS> m_noneClass;
};

View File

@ -205,16 +205,24 @@ FOOTPRINT* BOARD_NETLIST_UPDATER::addNewFootprint( COMPONENT* aComponent )
void BOARD_NETLIST_UPDATER::updateComponentClass( FOOTPRINT* aFootprint, COMPONENT* aNewComponent )
{
// Get the existing component class
wxString curClassName;
wxString curClassName, newClassName;
COMPONENT_CLASS* newClass = nullptr;
if( const COMPONENT_CLASS* curClass = aFootprint->GetComponentClass() )
curClassName = curClass->GetFullName();
// Calculate the new component class
COMPONENT_CLASS* newClass = m_board->GetComponentClassManager().GetEffectiveComponentClass(
aNewComponent->GetComponentClassNames() );
wxString newClassName = newClass->GetFullName();
if( m_isDryRun )
{
newClassName = COMPONENT_CLASS_MANAGER::GetFullClassNameForConstituents(
aNewComponent->GetComponentClassNames() );
}
else
{
newClass = m_board->GetComponentClassManager().GetEffectiveComponentClass(
aNewComponent->GetComponentClassNames() );
newClassName = newClass->GetFullName();
}
if( curClassName == newClassName )
return;
@ -228,6 +236,8 @@ void BOARD_NETLIST_UPDATER::updateComponentClass( FOOTPRINT* aFootprint, COMPONE
}
else
{
wxASSERT_MSG( newClass != nullptr, "Component class should not be nullptr" );
aFootprint->SetComponentClass( newClass );
msg.Printf( _( "Changed %s component class from %s to %s." ), aFootprint->GetReference(),
curClassName, newClassName );
@ -1195,12 +1205,14 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
cacheCopperZoneConnections();
// First mark all nets (except <no net>) as stale; we'll update those which are current
// in the following two loops.
// in the following two loops. Also prepare the component class manager for updates.
//
if( !m_isDryRun )
{
for( NETINFO_ITEM* net : m_board->GetNetInfo() )
net->SetIsCurrent( net->GetNetCode() == 0 );
m_board->GetComponentClassManager().InitNetlistUpdate();
}
// Next go through the netlist updating all board footprints which have matching component
@ -1361,6 +1373,9 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
if( !m_isDryRun )
{
// Finalise the component class manager
m_board->GetComponentClassManager().FinishNetlistUpdate();
m_board->BuildConnectivity();
testConnectivity( aNetlist, footprintMap );