KiCad PCB EDA Suite
Loading...
Searching...
No Matches
component_class_manager.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <utility>
21
23
24
26{
27 m_constituentClasses.push_back( componentClass );
28}
29
30
31bool COMPONENT_CLASS::ContainsClassName( const wxString& className ) const
32{
33 if( m_constituentClasses.size() == 0 )
34 return false;
35
36 if( m_constituentClasses.size() == 1 )
37 return m_name == className;
38
39 return std::any_of( m_constituentClasses.begin(), m_constituentClasses.end(),
40 [&className]( const COMPONENT_CLASS* testClass )
41 {
42 return testClass->GetFullName() == className;
43 } );
44}
45
46
48{
49 if( m_constituentClasses.size() == 0 )
50 return wxT( "<None>" );
51
52 if( m_constituentClasses.size() == 1 )
53 return m_name;
54
55 wxASSERT( m_constituentClasses.size() >= 2 );
56
57 wxString name;
58
59 if( m_constituentClasses.size() == 2 )
60 {
61 name.Printf( _( "%s and %s" ), m_constituentClasses[0]->GetName(),
63 }
64 else if( m_constituentClasses.size() == 3 )
65 {
66 name.Printf( _( "%s, %s and %s" ), m_constituentClasses[0]->GetName(),
68 }
69 else if( m_constituentClasses.size() > 3 )
70 {
71 name.Printf( _( "%s, %s and %d more" ), m_constituentClasses[0]->GetName(),
73 static_cast<int>( m_constituentClasses.size() - 2 ) );
74 }
75
76 return name;
77}
78
79
81{
82 return m_constituentClasses.size() == 0;
83}
84
85
87{
88 m_noneClass = std::make_unique<COMPONENT_CLASS>( wxEmptyString );
89}
90
91
93COMPONENT_CLASS_MANAGER::GetEffectiveComponentClass( std::unordered_set<wxString>& classNames )
94{
95 if( classNames.size() == 0 )
96 return m_noneClass.get();
97
98 // Lambda to handle finding constituent component classes. This first checks the cache,
99 // and if found moves the class to the primary classes map. If not found, it either returns
100 // an existing class in the primary list or creates a new class.
101 auto getOrCreateClass = [this]( const wxString& className )
102 {
103 if( m_classesCache.count( className ) )
104 {
105 auto existingClass = m_classesCache.extract( className );
106 m_classes.insert( std::move( existingClass ) );
107 }
108 else if( !m_classes.count( className ) )
109 {
110 std::unique_ptr<COMPONENT_CLASS> newClass =
111 std::make_unique<COMPONENT_CLASS>( className );
112 newClass->AddConstituentClass( newClass.get() );
113 m_classes[className] = std::move( newClass );
114 }
115
116 return m_classes[className].get();
117 };
118
119 // Handle single-assignment component classes
120 if( classNames.size() == 1 )
121 return getOrCreateClass( *classNames.begin() );
122
123 // Handle composite component classes
124 std::vector<wxString> sortedClassNames( classNames.begin(), classNames.end() );
125
126 std::sort( sortedClassNames.begin(), sortedClassNames.end(),
127 []( const wxString& str1, const wxString& str2 )
128 {
129 return str1.Cmp( str2 ) < 0;
130 } );
131
132 wxString fullName = GetFullClassNameForConstituents( sortedClassNames );
133
134 if( m_effectiveClassesCache.count( fullName ) )
135 {
136 // The effective class was previously constructed - copy it across to the new live map
137 auto existingClass = m_effectiveClassesCache.extract( fullName );
138 COMPONENT_CLASS* effClass = existingClass.mapped().get();
139 m_effectiveClasses.insert( std::move( existingClass ) );
140
141 // Ensure that all constituent component classes are copied to the live map
142 for( COMPONENT_CLASS* constClass : effClass->GetConstituentClasses() )
143 {
144 if( m_classesCache.count( constClass->GetFullName() ) )
145 {
146 auto constClassNode = m_classesCache.extract( constClass->GetFullName() );
147 m_classes.insert( std::move( constClassNode ) );
148 }
149 }
150 }
151 else if( !m_effectiveClasses.count( fullName ) )
152 {
153 // The effective class was not previously constructed
154 std::unique_ptr<COMPONENT_CLASS> effClass = std::make_unique<COMPONENT_CLASS>( fullName );
155
156 for( const wxString& className : sortedClassNames )
157 effClass->AddConstituentClass( getOrCreateClass( className ) );
158
159 m_effectiveClasses[fullName] = std::move( effClass );
160 }
161
162 return m_effectiveClasses[fullName].get();
163}
164
165
167{
168 m_classesCache = std::move( m_classes );
170}
171
172
174{
175 m_classesCache.clear();
177}
178
179
180wxString
181COMPONENT_CLASS_MANAGER::GetFullClassNameForConstituents( std::unordered_set<wxString>& classNames )
182{
183 std::vector<wxString> sortedClassNames( classNames.begin(), classNames.end() );
184
185 std::sort( sortedClassNames.begin(), sortedClassNames.end(),
186 []( const wxString& str1, const wxString& str2 )
187 {
188 return str1.Cmp( str2 ) < 0;
189 } );
190
191 return GetFullClassNameForConstituents( sortedClassNames );
192}
193
194
195wxString
197{
198 if( classNames.size() == 0 )
199 return wxEmptyString;
200
201 wxString fullName = classNames[0];
202
203 for( std::size_t i = 1; i < classNames.size(); ++i )
204 {
205 fullName += ",";
206 fullName += classNames[i];
207 }
208
209 return fullName;
210}
const char * name
Definition: DXF_plotter.cpp:57
std::unique_ptr< COMPONENT_CLASS > m_noneClass
The class to represent an unassigned component class.
std::unordered_map< wxString, std::unique_ptr< COMPONENT_CLASS > > m_classes
All individual component classes.
std::unordered_map< wxString, std::unique_ptr< COMPONENT_CLASS > > m_classesCache
Cache of all individual component classes (for netlist updating)
void FinishNetlistUpdate()
Cleans up the manager after a board update Must be called after updating the PCB from the netlist.
static wxString GetFullClassNameForConstituents(std::unordered_set< wxString > &classNames)
Gets the full effective class name for the given set of constituent classes.
std::unordered_map< wxString, std::unique_ptr< COMPONENT_CLASS > > m_effectiveClassesCache
Cache of all generated effective component classes (for netlist updating)
std::unordered_map< wxString, std::unique_ptr< COMPONENT_CLASS > > m_effectiveClasses
Generated effective component classes.
void InitNetlistUpdate()
Prepare the manager for a board update Must be called prior to updating the PCB from the netlist.
COMPONENT_CLASS * GetEffectiveComponentClass(std::unordered_set< wxString > &classNames)
Gets an effective component class for the given constituent class names.
void AddConstituentClass(COMPONENT_CLASS *componentClass)
Adds a constituent component class to an effective component class.
bool ContainsClassName(const wxString &className) const
Determines if this (effective) component class contains a specific sub-class.
std::vector< COMPONENT_CLASS * > m_constituentClasses
The COMPONENT_CLASS objects contributing to this complete component class.
const std::vector< COMPONENT_CLASS * > & GetConstituentClasses() const
Fetches a vector of the constituent classes for this (effective) class.
wxString m_name
The full name of the component class.
wxString GetName() const
Fetches the display name of this component class.
bool IsEmpty() const
Determines if this (effective) component class is empty (i.e. no classes defined)
#define _(s)