2020-11-17 11:16:16 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 2001-2006, William Joseph.
|
|
|
|
All Rights Reserved.
|
|
|
|
|
|
|
|
This file is part of GtkRadiant.
|
|
|
|
|
|
|
|
GtkRadiant 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 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
GtkRadiant 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 GtkRadiant; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if !defined( INCLUDED_UNIQUENAMES_H )
|
|
|
|
#define INCLUDED_UNIQUENAMES_H
|
|
|
|
|
|
|
|
#include "debugging/debugging.h"
|
|
|
|
#include <map>
|
|
|
|
#include "string/string.h"
|
|
|
|
#include "generic/static.h"
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
class Postfix
|
|
|
|
{
|
|
|
|
unsigned int m_value;
|
|
|
|
public:
|
|
|
|
Postfix( const char* postfix ) : m_value( atoi( postfix ) ){
|
|
|
|
}
|
|
|
|
unsigned int number() const {
|
|
|
|
return m_value;
|
|
|
|
}
|
|
|
|
void write( char* buffer ) const {
|
|
|
|
sprintf( buffer, "%u", m_value );
|
|
|
|
}
|
|
|
|
Postfix& operator++(){
|
|
|
|
++m_value;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
bool operator<( const Postfix& other ) const {
|
|
|
|
return m_value < other.m_value;
|
|
|
|
}
|
|
|
|
bool operator==( const Postfix& other ) const {
|
|
|
|
return m_value == other.m_value;
|
|
|
|
}
|
|
|
|
bool operator!=( const Postfix& other ) const {
|
|
|
|
return !operator==( other );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#else
|
|
|
|
class Postfix
|
|
|
|
{
|
|
|
|
std::pair<unsigned int, unsigned int> m_value;
|
|
|
|
public:
|
|
|
|
Postfix( unsigned int number, unsigned int leading_zeros )
|
|
|
|
: m_value( leading_zeros, number ){
|
|
|
|
}
|
|
|
|
Postfix( const char* postfix )
|
|
|
|
: m_value( number_count_leading_zeros( postfix ), atoi( postfix ) ){
|
|
|
|
}
|
|
|
|
unsigned int number() const {
|
|
|
|
return m_value.second;
|
|
|
|
}
|
|
|
|
unsigned int leading_zeros() const {
|
|
|
|
return m_value.first;
|
|
|
|
}
|
|
|
|
void write( char* buffer ){
|
|
|
|
for ( unsigned int count = 0; count < m_value.first; ++count, ++buffer )
|
|
|
|
*buffer = '0';
|
|
|
|
sprintf( buffer, "%u", m_value.second );
|
|
|
|
}
|
|
|
|
Postfix& operator++(){
|
|
|
|
++m_value.second;
|
|
|
|
if ( m_value.first != 0 && m_value.second % 10 == 0 ) {
|
|
|
|
--m_value.first;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
bool operator<( const Postfix& other ) const {
|
|
|
|
return m_value < other.m_value;
|
|
|
|
}
|
|
|
|
bool operator==( const Postfix& other ) const {
|
|
|
|
return m_value == other.m_value;
|
|
|
|
}
|
|
|
|
bool operator!=( const Postfix& other ) const {
|
|
|
|
return !operator==( other );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef std::pair<CopiedString, Postfix> name_t;
|
|
|
|
|
|
|
|
inline void name_write( char* buffer, name_t name ){
|
|
|
|
strcpy( buffer, name.first.c_str() );
|
|
|
|
name.second.write( buffer + strlen( name.first.c_str() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
inline name_t name_read( const char* name ){
|
|
|
|
const char* end = name + strlen( name );
|
|
|
|
for ( const char* p = end; end != name; --p )
|
|
|
|
{
|
|
|
|
if ( strrchr( "1234567890", *p ) == NULL ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
end = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
return name_t( CopiedString( StringRange( name, end ) ), Postfix( end ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class PostFixes
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef std::map<Postfix, unsigned int> postfixes_t;
|
|
|
|
postfixes_t m_postfixes;
|
|
|
|
|
|
|
|
private:
|
|
|
|
Postfix find_first_empty() const {
|
|
|
|
Postfix postfix( "1" );
|
|
|
|
for ( postfixes_t::const_iterator i = m_postfixes.find( postfix ); i != m_postfixes.end(); ++i, ++postfix )
|
|
|
|
{
|
|
|
|
if ( ( *i ).first != postfix ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return postfix;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
Postfix make_unique( Postfix postfix ) const {
|
|
|
|
postfixes_t::const_iterator i = m_postfixes.find( postfix );
|
|
|
|
if ( i == m_postfixes.end() ) {
|
|
|
|
return postfix;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return find_first_empty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void insert( Postfix postfix ){
|
|
|
|
postfixes_t::iterator i = m_postfixes.find( postfix );
|
|
|
|
if ( i == m_postfixes.end() ) {
|
|
|
|
m_postfixes.insert( postfixes_t::value_type( postfix, 1 ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++( *i ).second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void erase( Postfix postfix ){
|
|
|
|
postfixes_t::iterator i = m_postfixes.find( postfix );
|
|
|
|
if ( i == m_postfixes.end() ) {
|
|
|
|
// error
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( --( *i ).second == 0 ) {
|
|
|
|
m_postfixes.erase( i );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool empty() const {
|
|
|
|
return m_postfixes.empty();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class UniqueNames
|
|
|
|
{
|
|
|
|
typedef std::map<CopiedString, PostFixes> names_t;
|
|
|
|
names_t m_names;
|
|
|
|
public:
|
|
|
|
name_t make_unique( const name_t& name ) const {
|
|
|
|
char buf[80];
|
|
|
|
name_t r( "","" );
|
|
|
|
name_write( buf, name );
|
|
|
|
globalErrorStream() << "find unique name for " << buf << "\n";
|
|
|
|
globalErrorStream() << "> currently registered names:\n";
|
|
|
|
for ( names_t::const_iterator i = m_names.begin(); i != m_names.end(); ++i )
|
|
|
|
{
|
|
|
|
globalErrorStream() << ">> " << i->first.c_str() << ": ";
|
|
|
|
for ( PostFixes::postfixes_t::const_iterator j = i->second.m_postfixes.begin(); j != i->second.m_postfixes.end(); ++j )
|
|
|
|
{
|
|
|
|
j->first.write( buf );
|
|
|
|
globalErrorStream() << " '" << buf << "'";
|
|
|
|
}
|
|
|
|
globalErrorStream() << "\n";
|
|
|
|
}
|
|
|
|
names_t::const_iterator i = m_names.find( name.first );
|
|
|
|
if ( i == m_names.end() ) {
|
|
|
|
r = name;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
r = name_t( name.first, ( *i ).second.make_unique( name.second ) );
|
|
|
|
}
|
|
|
|
name_write( buf, r );
|
|
|
|
globalErrorStream() << "> unique name is " << buf << "\n";
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void insert( const name_t& name ){
|
|
|
|
m_names[name.first].insert( name.second );
|
|
|
|
}
|
|
|
|
|
|
|
|
void erase( const name_t& name ){
|
|
|
|
names_t::iterator i = m_names.find( name.first );
|
|
|
|
if ( i == m_names.end() ) {
|
|
|
|
ASSERT_MESSAGE( true, "erase: name not found" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
( *i ).second.erase( name.second );
|
|
|
|
if ( ( *i ).second.empty() ) {
|
|
|
|
m_names.erase( i );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool empty() const {
|
|
|
|
return m_names.empty();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
#undef ERROR_MESSAGE
|
|
|
|
#define ERROR_MESSAGE( message )
|
|
|
|
|
|
|
|
class TestUniqueName
|
|
|
|
{
|
|
|
|
void name_check_equal( const name_t& name, const char* string, unsigned int postfix ){
|
|
|
|
ASSERT_MESSAGE( strcmp( name.first.c_str(), string ) == 0
|
2021-08-04 20:23:18 +00:00
|
|
|
&& name.second.number() == postfix,
|
|
|
|
"test failed!" );
|
2020-11-17 11:16:16 +00:00
|
|
|
}
|
|
|
|
void test_refcount(){
|
|
|
|
Names names;
|
|
|
|
|
|
|
|
names.insert( name_t( "func_bleh_", "100" ) );
|
|
|
|
names.insert( name_t( "func_bleh_", "100" ) );
|
|
|
|
names.insert( name_t( "func_bleh_", "100" ) );
|
|
|
|
|
|
|
|
|
|
|
|
names.erase( name_t( "func_bleh_", "100" ) );
|
|
|
|
names.erase( name_t( "func_bleh_", "100" ) );
|
|
|
|
names.erase( name_t( "func_bleh_", "100" ) );
|
|
|
|
|
|
|
|
ASSERT_MESSAGE( names.empty(), "test failed!" );
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_make_unique(){
|
|
|
|
Names names;
|
|
|
|
|
|
|
|
{
|
|
|
|
name_t name( names.make_unique( name_t( "func_bleh_", "01" ) ) );
|
|
|
|
name_check_equal( name, "func_bleh_", 1 );
|
|
|
|
names.insert( name );
|
|
|
|
}
|
|
|
|
{
|
|
|
|
name_t name( names.make_unique( name_t( "func_bleh_", "04" ) ) );
|
|
|
|
name_check_equal( name, "func_bleh_", 4 );
|
|
|
|
names.insert( name );
|
|
|
|
}
|
|
|
|
{
|
|
|
|
name_t name( names.make_unique( name_t( "func_bleh_", "04" ) ) );
|
|
|
|
name_check_equal( name, "func_bleh_", 2 );
|
|
|
|
names.insert( name );
|
|
|
|
}
|
|
|
|
{
|
|
|
|
name_t name( names.make_unique( name_t( "func_bleh_", "1" ) ) );
|
|
|
|
name_check_equal( name, "func_bleh_", 3 );
|
|
|
|
names.insert( name );
|
|
|
|
}
|
|
|
|
{
|
|
|
|
name_t name( names.make_unique( name_t( "func_bleh_", "2" ) ) );
|
|
|
|
name_check_equal( name, "func_bleh_", 5 );
|
|
|
|
names.insert( name );
|
|
|
|
}
|
|
|
|
{
|
|
|
|
name_t name( names.make_unique( name_t( "func_bleh_", "3" ) ) );
|
|
|
|
name_check_equal( name, "func_bleh_", 6 );
|
|
|
|
names.insert( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
names.erase( name_t( "func_bleh_", "1" ) );
|
|
|
|
names.erase( name_t( "func_bleh_", "2" ) );
|
|
|
|
names.erase( name_t( "func_bleh_", "3" ) );
|
|
|
|
names.erase( name_t( "func_bleh_", "4" ) );
|
|
|
|
names.erase( name_t( "func_bleh_", "5" ) );
|
|
|
|
names.erase( name_t( "func_bleh_", "6" ) );
|
|
|
|
|
|
|
|
ASSERT_MESSAGE( names.empty(), "test failed!" );
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
TestUniqueName(){
|
|
|
|
test_refcount();
|
|
|
|
test_make_unique();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const TestUniqueName g_testuniquename;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|