]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/uniquenames.h
Partial OSX support
[xonotic/netradiant.git] / libs / uniquenames.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #if !defined( INCLUDED_UNIQUENAMES_H )
23 #define INCLUDED_UNIQUENAMES_H
24
25 #include <cstdlib>
26 #include "debugging/debugging.h"
27 #include <map>
28 #include "string/string.h"
29 #include "generic/static.h"
30
31 #if 1
32 class Postfix
33 {
34 unsigned int m_value;
35 public:
36 Postfix( const char* postfix ) : m_value( atoi( postfix ) ){
37 }
38 unsigned int number() const {
39         return m_value;
40 }
41 void write( char* buffer ) const {
42         sprintf( buffer, "%u", m_value );
43 }
44 Postfix& operator++(){
45         ++m_value;
46         return *this;
47 }
48 bool operator<( const Postfix& other ) const {
49         return m_value < other.m_value;
50 }
51 bool operator==( const Postfix& other ) const {
52         return m_value == other.m_value;
53 }
54 bool operator!=( const Postfix& other ) const {
55         return !operator==( other );
56 }
57 };
58
59 #else
60 class Postfix
61 {
62 std::pair<unsigned int, unsigned int> m_value;
63 public:
64 Postfix( unsigned int number, unsigned int leading_zeros )
65         : m_value( leading_zeros, number ){
66 }
67 Postfix( const char* postfix )
68         : m_value( number_count_leading_zeros( postfix ), atoi( postfix ) ){
69 }
70 unsigned int number() const {
71         return m_value.second;
72 }
73 unsigned int leading_zeros() const {
74         return m_value.first;
75 }
76 void write( char* buffer ){
77         for ( unsigned int count = 0; count < m_value.first; ++count, ++buffer )
78                 *buffer = '0';
79         sprintf( buffer, "%u", m_value.second );
80 }
81 Postfix& operator++(){
82         ++m_value.second;
83         if ( m_value.first != 0 && m_value.second % 10 == 0 ) {
84                 --m_value.first;
85         }
86         return *this;
87 }
88 bool operator<( const Postfix& other ) const {
89         return m_value < other.m_value;
90 }
91 bool operator==( const Postfix& other ) const {
92         return m_value == other.m_value;
93 }
94 bool operator!=( const Postfix& other ) const {
95         return !operator==( other );
96 }
97 };
98
99 #endif
100
101 typedef std::pair<std::string, Postfix> name_t;
102
103 inline void name_write( char* buffer, name_t name ){
104         strcpy( buffer, name.first.c_str() );
105         name.second.write( buffer + strlen( name.first.c_str() ) );
106 }
107
108 inline name_t name_read( const char* name ){
109         const char* end = name + strlen( name );
110         for ( const char* p = end; end != name; --p )
111         {
112                 if ( strrchr( "1234567890", *p ) == NULL ) {
113                         break;
114                 }
115                 end = p;
116         }
117
118         return name_t( std::string( StringRange( name, end ) ), Postfix( end ) );
119 }
120
121
122 class PostFixes
123 {
124 public:
125 typedef std::map<Postfix, unsigned int> postfixes_t;
126 postfixes_t m_postfixes;
127
128 private:
129 Postfix find_first_empty() const {
130         Postfix postfix( "1" );
131         for ( postfixes_t::const_iterator i = m_postfixes.find( postfix ); i != m_postfixes.end(); ++i, ++postfix )
132         {
133                 if ( ( *i ).first != postfix ) {
134                         break;
135                 }
136         }
137         return postfix;
138 }
139
140 public:
141 Postfix make_unique( Postfix postfix ) const {
142         postfixes_t::const_iterator i = m_postfixes.find( postfix );
143         if ( i == m_postfixes.end() ) {
144                 return postfix;
145         }
146         else
147         {
148                 return find_first_empty();
149         }
150 }
151
152 void insert( Postfix postfix ){
153         postfixes_t::iterator i = m_postfixes.find( postfix );
154         if ( i == m_postfixes.end() ) {
155                 m_postfixes.insert( postfixes_t::value_type( postfix, 1 ) );
156         }
157         else
158         {
159                 ++( *i ).second;
160         }
161 }
162
163 void erase( Postfix postfix ){
164         postfixes_t::iterator i = m_postfixes.find( postfix );
165         if ( i == m_postfixes.end() ) {
166                 // error
167         }
168         else
169         {
170                 if ( --( *i ).second == 0 ) {
171                         m_postfixes.erase( i );
172                 }
173         }
174 }
175
176 bool empty() const {
177         return m_postfixes.empty();
178 }
179 };
180
181
182 class UniqueNames
183 {
184 typedef std::map<std::string, PostFixes> names_t;
185 names_t m_names;
186 public:
187 name_t make_unique( const name_t& name ) const {
188         char buf[80];
189         name_t r( "","" );
190         name_write( buf, name );
191         globalErrorStream() << "find unique name for " << buf << "\n";
192         globalErrorStream() << "> currently registered names:\n";
193         for ( names_t::const_iterator i = m_names.begin(); i != m_names.end(); ++i )
194         {
195                 globalErrorStream() << ">> " << i->first.c_str() << ": ";
196                 for ( PostFixes::postfixes_t::const_iterator j = i->second.m_postfixes.begin(); j != i->second.m_postfixes.end(); ++j )
197                 {
198                         j->first.write( buf );
199                         globalErrorStream() << " '" << buf << "'";
200                 }
201                 globalErrorStream() << "\n";
202         }
203         names_t::const_iterator i = m_names.find( name.first );
204         if ( i == m_names.end() ) {
205                 r = name;
206         }
207         else
208         {
209                 r = name_t( name.first, ( *i ).second.make_unique( name.second ) );
210         }
211         name_write( buf, r );
212         globalErrorStream() << "> unique name is " << buf << "\n";
213         return r;
214 }
215
216 void insert( const name_t& name ){
217         m_names[name.first].insert( name.second );
218 }
219
220 void erase( const name_t& name ){
221         names_t::iterator i = m_names.find( name.first );
222         if ( i == m_names.end() ) {
223                 ASSERT_MESSAGE( true, "erase: name not found" );
224         }
225         else
226         {
227                 ( *i ).second.erase( name.second );
228                 if ( ( *i ).second.empty() ) {
229                         m_names.erase( i );
230                 }
231         }
232 }
233
234 bool empty() const {
235         return m_names.empty();
236 }
237 };
238
239
240
241 #if 0
242
243 #undef ERROR_MESSAGE
244 #define ERROR_MESSAGE( message )
245
246 class TestUniqueName
247 {
248 void name_check_equal( const name_t& name, const char* string, unsigned int postfix ){
249         ASSERT_MESSAGE( strcmp( name.first.c_str(), string ) == 0
250                                         && name.second.number() == postfix,
251                                         "test failed!" );
252 }
253 void test_refcount(){
254         Names names;
255
256         names.insert( name_t( "func_bleh_", "100" ) );
257         names.insert( name_t( "func_bleh_", "100" ) );
258         names.insert( name_t( "func_bleh_", "100" ) );
259
260
261         names.erase( name_t( "func_bleh_", "100" ) );
262         names.erase( name_t( "func_bleh_", "100" ) );
263         names.erase( name_t( "func_bleh_", "100" ) );
264
265         ASSERT_MESSAGE( names.empty(), "test failed!" );
266 }
267
268 void test_make_unique(){
269         Names names;
270
271         {
272                 name_t name( names.make_unique( name_t( "func_bleh_", "01" ) ) );
273                 name_check_equal( name, "func_bleh_", 1 );
274                 names.insert( name );
275         }
276         {
277                 name_t name( names.make_unique( name_t( "func_bleh_", "04" ) ) );
278                 name_check_equal( name, "func_bleh_", 4 );
279                 names.insert( name );
280         }
281         {
282                 name_t name( names.make_unique( name_t( "func_bleh_", "04" ) ) );
283                 name_check_equal( name, "func_bleh_", 2 );
284                 names.insert( name );
285         }
286         {
287                 name_t name( names.make_unique( name_t( "func_bleh_", "1" ) ) );
288                 name_check_equal( name, "func_bleh_", 3 );
289                 names.insert( name );
290         }
291         {
292                 name_t name( names.make_unique( name_t( "func_bleh_", "2" ) ) );
293                 name_check_equal( name, "func_bleh_", 5 );
294                 names.insert( name );
295         }
296         {
297                 name_t name( names.make_unique( name_t( "func_bleh_", "3" ) ) );
298                 name_check_equal( name, "func_bleh_", 6 );
299                 names.insert( name );
300         }
301
302         names.erase( name_t( "func_bleh_", "1" ) );
303         names.erase( name_t( "func_bleh_", "2" ) );
304         names.erase( name_t( "func_bleh_", "3" ) );
305         names.erase( name_t( "func_bleh_", "4" ) );
306         names.erase( name_t( "func_bleh_", "5" ) );
307         names.erase( name_t( "func_bleh_", "6" ) );
308
309         ASSERT_MESSAGE( names.empty(), "test failed!" );
310 }
311 public:
312 TestUniqueName(){
313         test_refcount();
314         test_make_unique();
315 }
316 };
317
318 const TestUniqueName g_testuniquename;
319
320 #endif
321
322
323 #endif