/* 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 #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 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 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 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 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 && name.second.number() == postfix, "test failed!" ); } 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