29 m_threadSafe( aThreadSafe ), m_reuseRefDes( true )
35 std::unique_lock<std::mutex> lock;
38 lock = std::unique_lock<std::mutex>(
m_mutex );
79 std::unique_lock<std::mutex> lock;
82 lock = std::unique_lock<std::mutex>(
m_mutex );
89 const std::map<
int, std::vector<SCH_REFERENCE>>& aRefNumberMap,
90 const std::vector<int>& aRequiredUnits,
93 std::unique_lock<std::mutex> lock;
96 lock = std::unique_lock<std::mutex>(
m_mutex );
99 std::vector<int> validUnits;
100 std::copy_if( aRequiredUnits.begin(), aRequiredUnits.end(),
101 std::back_inserter( validUnits ),
102 [](
int unit ) { return unit >= 0; } );
104 int candidate = aMinValue;
109 auto mapIt = aRefNumberMap.find( candidate );
111 if( mapIt == aRefNumberMap.end() )
114 std::string candidateRefDes = aRef.
GetRef().ToStdString() + std::to_string( candidate );
133 if( validUnits.empty() )
171 const std::vector<SCH_REFERENCE>& aRefVector,
172 const std::vector<int>& aRequiredUnits )
const
174 for(
const int& unit : aRequiredUnits )
181 if( ref.CompareLibName( aRef ) != 0
182 || ref.CompareValue( aRef ) != 0
183 || ref.GetUnit() == unit )
196 if( aRefDes.empty() )
200 std::regex pattern( R
"(^([A-Za-z]+)(\d+)?$)" );
203 if( std::regex_match( aRefDes, match, pattern ) )
205 std::string prefix = match[1].str();
206 if( match[2].matched )
208 int number = std::stoi( match[2].str() );
209 return { prefix, number };
213 return { prefix, 0 };
218 return { aRefDes, 0 };
232 if( used == candidate )
236 else if( used > candidate )
267 int cachedNext = cacheIt->second;
269 if( aInsertedNumber == cachedNext )
272 int candidate = cachedNext + 1;
277 cacheIt->second = candidate;
285 return cacheIt->second;
298 candidate = aMinValue;
312 std::unique_lock<std::mutex> lock;
314 lock = std::unique_lock<std::mutex>(
m_mutex );
316 std::ostringstream result;
328 std::vector<int> numbers;
329 bool hasPrefix =
false;
331 for(
int num : data.m_usedNumbers )
334 numbers.push_back( num );
339 if( numbers.empty() && !hasPrefix )
343 std::vector<std::pair<int, int>> ranges;
345 if( !numbers.empty() )
347 int start = numbers[0];
348 int end = numbers[0];
350 for(
size_t i = 1; i < numbers.size(); ++i )
352 if( numbers[i] ==
end + 1 )
358 ranges.push_back( { start,
end } );
359 start =
end = numbers[i];
362 ranges.push_back( { start,
end } );
365 bool firstRange =
true;
366 for(
const auto& [start,
end] : ranges )
372 result << escapedPrefix;
379 result << start <<
"-" <<
end;
388 result << escapedPrefix;
397 std::unique_lock<std::mutex> lock;
400 lock = std::unique_lock<std::mutex>(
m_mutex );
409 for(
const std::string& part : parts )
414 std::regex rangePattern( R
"(^([A-Za-z]+)(\d+)(?:-(\d+))?$)" );
415 std::regex prefixOnlyPattern( R"(^([A-Za-z]+)$)" );
418 if( std::regex_match( unescaped, match, rangePattern ) )
420 std::string prefix = match[1].str();
421 int start = std::stoi( match[2].str() );
422 int end = match[3].matched ? std::stoi( match[3].str() ) : start;
424 for(
int i = start; i <=
end; ++i )
426 if( !
insertImpl( prefix + std::to_string( i ) ) )
433 else if( std::regex_match( unescaped, match, prefixOnlyPattern ) )
435 std::string prefix = match[1].str();
455 std::unique_lock<std::mutex> lock;
458 lock = std::unique_lock<std::mutex>(
m_mutex );
472 std::unique_lock<std::mutex> lock;
475 lock = std::unique_lock<std::mutex>(
m_mutex );
483 result.reserve( aStr.length() * 2 );
487 if( c ==
'\\' || c ==
',' || c ==
'-' )
497 result.reserve( aStr.length() );
499 bool escaped =
false;
521 std::vector<std::string> result;
523 bool escaped =
false;
537 else if( c == aDelimiter )
539 result.push_back( current );
548 if( !current.empty() )
549 result.push_back( current );
557 std::unique_lock<std::mutex> lock;
560 lock = std::unique_lock<std::mutex>(
m_mutex );
568 std::unique_lock<std::mutex> lock;
571 lock = std::unique_lock<std::mutex>(
m_mutex );
void updateBaseNext(PREFIX_DATA &aData) const
std::string escapeForSerialization(const std::string &aStr) const
Escape special characters for serialization.
bool insertNumber(const std::string &aPrefix, int aNumber)
Insert a number for a specific prefix, updating internal structures.
void ClearUnitsChecker()
Clear the external units checker, reverting to default behavior.
bool Deserialize(const std::string &aData)
Deserialize tracker data from string representation.
std::vector< std::string > splitString(const std::string &aStr, char aDelimiter) const
Split string by delimiter, handling escaped characters.
bool m_reuseRefDes
If true, allows reusing existing reference designators.
std::mutex m_mutex
Mutex for thread safety.
int GetNextRefDesForUnits(const SCH_REFERENCE &aRef, const std::map< int, std::vector< SCH_REFERENCE > > &aRefNumberMap, const std::vector< int > &aRequiredUnits, int aMinValue)
Get the next available reference designator number for multi-unit symbols.
std::unordered_set< std::string > m_allRefDes
bool Insert(const std::string &aRefDes)
Insert a reference designator into the tracker.
void clearImpl()
Clear all internal data structures without locking.
size_t Size() const
Get the total count of stored reference designators.
std::string unescapeFromSerialization(const std::string &aStr) const
Unescape special characters from serialization.
bool insertImpl(const std::string &aRefDes)
Internal implementation of Insert without locking.
int findNextAvailable(const PREFIX_DATA &aData, int aMinValue) const
Find next available number for a prefix starting from a minimum value.
REFDES_TRACKER(bool aThreadSafe=false)
Constructor.
bool areUnitsAvailable(const SCH_REFERENCE &aRef, const std::vector< SCH_REFERENCE > &aRefVector, const std::vector< int > &aRequiredUnits) const
Check if all required units are available for a given reference number.
void SetUnitsChecker(const UNITS_CHECKER_FUNC< SCH_REFERENCE > &aChecker)
Set an external units checker function for SCH_REFERENCE objects.
void updateCacheOnInsert(PREFIX_DATA &aData, int aInsertedNumber) const
Update cached next available values when a number is inserted.
std::string Serialize() const
Serialize the tracker data to a compact string representation.
std::unordered_map< std::string, PREFIX_DATA > m_prefixData
Map from prefix to its tracking data.
bool m_threadSafe
True if thread safety is enabled.
bool Contains(const std::string &aRefDes) const
Check if a reference designator exists in the tracker.
std::pair< std::string, int > parseRefDes(const std::string &aRefDes) const
Parse a reference designator into prefix and numerical suffix.
bool containsImpl(const std::string &aRefDes) const
Check if a reference designator exists in the tracker without locking.
UNITS_CHECKER_FUNC< SCH_REFERENCE > m_externalUnitsChecker
External units checker function (optional)
void Clear()
Clear all stored reference designators.
A helper to define a symbol's reference designator in a schematic.
const char * GetRefStr() const
std::function< bool(const T &aTestRef, const std::vector< T > &aExistingRefs, const std::vector< int > &aRequiredUnits)> UNITS_CHECKER_FUNC
Function type for external units availability checking.
Data structure for tracking used numbers and caching next available values.
std::set< int > m_usedNumbers
Sorted set of used numbers for this prefix.
bool m_cacheValid
True if m_baseNext cache is valid.
int m_baseNext
Next available from 1 (cached)
std::map< int, int > m_nextCache
Cache of next available number for given min values.