mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
Provide an option to track ever reference designator ever used in the project to prevent its reuse even if the component has been removed Fixes https://gitlab.com/kicad/code/kicad/-/issues/13052
234 lines
8.1 KiB
C++
234 lines
8.1 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* KiCad is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* KiCad is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with KiCad. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <string>
|
|
#include <mutex>
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
// Forward declaration
|
|
class SCH_REFERENCE;
|
|
|
|
/**
|
|
* Class to efficiently track reference designators and provide next available designators.
|
|
*
|
|
* Maintains internal data structures for O(1) lookup of existing designators and efficient
|
|
* retrieval of next available numerical suffixes for any given prefix.
|
|
*/
|
|
class REFDES_TRACKER
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param aThreadSafe if true, enables mutex locking for thread-safe operation
|
|
*/
|
|
explicit REFDES_TRACKER( bool aThreadSafe = false );
|
|
|
|
/**
|
|
* Insert a reference designator into the tracker.
|
|
*
|
|
* @param aRefDes the reference designator to insert
|
|
* @return true if inserted successfully, false if already exists
|
|
*/
|
|
bool Insert( const std::string& aRefDes );
|
|
|
|
/**
|
|
* Check if a reference designator exists in the tracker.
|
|
*
|
|
* @param aRefDes the reference designator to check
|
|
* @return true if the reference designator exists
|
|
*/
|
|
bool Contains( const std::string& aRefDes ) const;
|
|
|
|
/**
|
|
* Get the next available reference designator for a given prefix and reserve it.
|
|
*
|
|
* The returned designator is automatically inserted into the tracker.
|
|
*
|
|
* @param aPrefix the alphabetic prefix (e.g., "R", "C", "IC")
|
|
* @param aMinValue the minimum numerical value to use (default 1)
|
|
* @return the next available number for the given prefix (now reserved)
|
|
*/
|
|
int GetNextRefDes( const std::string& aPrefix, int aMinValue = 1 );
|
|
|
|
/**
|
|
* Get the next available reference designator number for multi-unit symbols.
|
|
*
|
|
* Finds the smallest unused reference number for the given prefix, or the smallest
|
|
* number where all required units are available. The returned number is automatically
|
|
* inserted into the tracker as a base reference designator.
|
|
*
|
|
* @param aRef the schematic reference to use for prefix and unit filtering
|
|
* @param aRefNumberMap map from reference numbers to vectors of SCH_REFERENCE for currently used references
|
|
* @param aRequiredUnits vector of unit numbers needed (negative values are ignored)
|
|
* @param aMinValue the minimum value to start searching from
|
|
* @return the next available reference number
|
|
*/
|
|
int GetNextRefDesForUnits( const SCH_REFERENCE& aRef,
|
|
const std::map<int, std::vector<SCH_REFERENCE>>& aRefNumberMap,
|
|
const std::vector<int>& aRequiredUnits,
|
|
int aMinValue );
|
|
|
|
/**
|
|
* Serialize the tracker data to a compact string representation.
|
|
*
|
|
* Uses range notation for consecutive numbers (e.g., "R1-3,R5-7,R10").
|
|
*
|
|
* @return serialized string representation
|
|
*/
|
|
std::string Serialize() const;
|
|
|
|
/**
|
|
* Deserialize tracker data from string representation.
|
|
*
|
|
* @param aData the serialized data string
|
|
* @return true if deserialization was successful
|
|
*/
|
|
bool Deserialize( const std::string& aData );
|
|
|
|
/**
|
|
* Clear all stored reference designators.
|
|
*/
|
|
void Clear();
|
|
|
|
/**
|
|
* Get the total count of stored reference designators.
|
|
*
|
|
* @return number of reference designators stored
|
|
*/
|
|
size_t Size() const;
|
|
|
|
private:
|
|
/**
|
|
* Data structure for tracking used numbers and caching next available values.
|
|
*/
|
|
struct PREFIX_DATA
|
|
{
|
|
std::set<int> m_usedNumbers; ///< Sorted set of used numbers for this prefix
|
|
mutable std::map<int, int> m_nextCache; ///< Cache of next available number for given min values
|
|
mutable int m_baseNext; ///< Next available from 1 (cached)
|
|
mutable bool m_cacheValid; ///< True if m_baseNext cache is valid
|
|
|
|
PREFIX_DATA() : m_baseNext( 1 ), m_cacheValid( false ) {}
|
|
};
|
|
|
|
mutable std::mutex m_mutex; ///< Mutex for thread safety
|
|
bool m_threadSafe; ///< True if thread safety is enabled
|
|
|
|
/// Map from prefix to its tracking data
|
|
std::unordered_map<std::string, PREFIX_DATA> m_prefixData;
|
|
|
|
/// Set of all reference designators for O(1) lookup
|
|
std::unordered_set<std::string> m_allRefDes;
|
|
|
|
/**
|
|
* Internal implementation of Insert without locking.
|
|
*
|
|
* @param aRefDes reference designator to insert
|
|
* @return true if inserted, false if already exists
|
|
*/
|
|
bool insertImpl( const std::string& aRefDes );
|
|
|
|
/**
|
|
* Clear all internal data structures without locking.
|
|
*
|
|
* This is used internally to reset the tracker state.
|
|
*/
|
|
void clearImpl();
|
|
|
|
/**
|
|
* Parse a reference designator into prefix and numerical suffix.
|
|
*
|
|
* @param aRefDes the reference designator to parse
|
|
* @return pair of (prefix, number) where number is 0 if no numerical suffix
|
|
*/
|
|
std::pair<std::string, int> parseRefDes( const std::string& aRefDes ) const;
|
|
|
|
/**
|
|
* Update cached next available values when a number is inserted.
|
|
*
|
|
* @param aData the prefix data to update
|
|
* @param aInsertedNumber the number that was just inserted
|
|
*/
|
|
void updateCacheOnInsert( PREFIX_DATA& aData, int aInsertedNumber ) const;
|
|
|
|
/**
|
|
* Find next available number for a prefix starting from a minimum value.
|
|
*
|
|
* @param aData the prefix data
|
|
* @param aMinValue minimum value to start search from
|
|
* @return next available number >= aMinValue
|
|
*/
|
|
int findNextAvailable( const PREFIX_DATA& aData, int aMinValue ) const;
|
|
|
|
/**
|
|
* Check if all required units are available for a given reference number.
|
|
*
|
|
* @param aRef the SCH_REFERENCE object to check against
|
|
* @param aRefVector vector of SCH_REFERENCE objects for a specific reference number
|
|
* @param aRequiredUnits vector of unit numbers needed (negative values ignored)
|
|
* @return true if all required units are available (not conflicting)
|
|
*/
|
|
bool areUnitsAvailable( const SCH_REFERENCE& aRef,
|
|
const std::vector<SCH_REFERENCE>& aRefVector,
|
|
const std::vector<int>& aRequiredUnits ) const;
|
|
|
|
/**
|
|
* Insert a number for a specific prefix, updating internal structures.
|
|
*
|
|
* @param aPrefix the prefix
|
|
* @param aNumber the number to insert (0 for prefix-only)
|
|
* @return true if inserted, false if already exists
|
|
*/
|
|
bool insertNumber( const std::string& aPrefix, int aNumber );
|
|
|
|
/**
|
|
* Escape special characters for serialization.
|
|
*
|
|
* @param aStr string to escape
|
|
* @return escaped string
|
|
*/
|
|
std::string escapeForSerialization( const std::string& aStr ) const;
|
|
|
|
/**
|
|
* Unescape special characters from serialization.
|
|
*
|
|
* @param aStr escaped string
|
|
* @return unescaped string
|
|
*/
|
|
std::string unescapeFromSerialization( const std::string& aStr ) const;
|
|
|
|
/**
|
|
* Split string by delimiter, handling escaped characters.
|
|
*
|
|
* @param aStr string to split
|
|
* @param aDelimiter delimiter character
|
|
* @return vector of split parts
|
|
*/
|
|
std::vector<std::string> splitString( const std::string& aStr, char aDelimiter ) const;
|
|
|
|
void updateBaseNext( PREFIX_DATA& aData ) const;
|
|
}; |