]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/uniquenames.h
- Radiant is now Vista compatible (Aero must be disabled)
[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 "debugging/debugging.h"
26 #include <map>
27 #include "string/string.h"
28 #include "generic/static.h"
29
30 #if 1
31 class Postfix
32 {
33   unsigned int m_value;
34 public:
35   Postfix(const char* postfix) : m_value(atoi(postfix))
36   {
37   }
38   unsigned int number() const
39   {
40     return m_value;
41   }
42   void write(char* buffer)
43   {
44     sprintf(buffer, "%u", m_value);
45   }
46   Postfix& operator++()
47   { 
48     ++m_value;
49     return *this;
50   }
51   bool operator<(const Postfix& other) const
52   {
53     return m_value < other.m_value;
54   }
55   bool operator==(const Postfix& other) const
56   {
57     return m_value == other.m_value;
58   }
59   bool operator!=(const Postfix& other) const
60   {
61     return !operator==(other);
62   }
63 };
64
65 #else
66 class Postfix
67 {
68   std::pair<unsigned int, unsigned int> m_value;
69 public:
70   Postfix(unsigned int number, unsigned int leading_zeros)
71     : m_value(leading_zeros, number)
72   {
73   }
74   Postfix(const char* postfix)
75     : m_value(number_count_leading_zeros(postfix), atoi(postfix))
76   {
77   }
78   unsigned int number() const
79   {
80     return m_value.second;
81   }
82   unsigned int leading_zeros() const
83   {
84     return m_value.first;
85   }
86   void write(char* buffer)
87   {
88     for(unsigned int count = 0; count < m_value.first; ++count, ++buffer)
89       *buffer = '0';
90     sprintf(buffer, "%u", m_value.second);
91   }
92   Postfix& operator++()
93   { 
94     ++m_value.second;
95     if(m_value.first != 0 && m_value.second % 10 == 0)
96       --m_value.first;
97     return *this;
98   }
99   bool operator<(const Postfix& other) const
100   {
101     return m_value < other.m_value;
102   }
103   bool operator==(const Postfix& other) const
104   {
105     return m_value == other.m_value;
106   }
107   bool operator!=(const Postfix& other) const
108   {
109     return !operator==(other);
110   }
111 };
112
113 #endif
114
115 typedef std::pair<CopiedString, Postfix> name_t;
116
117 inline void name_write(char* buffer, name_t name)
118 {
119   strcpy(buffer, name.first.c_str());
120   name.second.write(buffer + strlen(name.first.c_str()));
121 }
122
123 inline name_t name_read(const char* name)
124 {
125   const char* end = name + strlen(name);
126   for(const char* p = end; end != name; --p)
127   {
128     if(strrchr("1234567890", *p) == NULL)
129       break;
130     end = p;
131   }
132
133   return name_t(CopiedString(StringRange(name, end)), Postfix(end));
134 }
135
136
137 class PostFixes
138 {
139   typedef std::map<Postfix, unsigned int> postfixes_t;
140   postfixes_t m_postfixes;
141
142   Postfix find_first_empty() const
143   {
144     Postfix postfix("1");
145     for(postfixes_t::const_iterator i = m_postfixes.find(postfix); i != m_postfixes.end(); ++i, ++postfix)
146     {
147       if((*i).first != postfix)
148       {
149         break;
150       }
151     }
152     return postfix;
153   }
154
155 public:
156   Postfix make_unique(Postfix postfix) const
157   {
158     postfixes_t::const_iterator i = m_postfixes.find(postfix);
159     if(i == m_postfixes.end())
160     {
161       return postfix;
162     }
163     else
164     {
165       return find_first_empty();
166     }
167   }
168
169   void insert(Postfix postfix)
170   {
171     postfixes_t::iterator i = m_postfixes.find(postfix);
172     if(i == m_postfixes.end())
173     {
174       m_postfixes.insert(postfixes_t::value_type(postfix, 1));
175     }
176     else
177     {
178       ++(*i).second;
179     }
180   }
181
182   void erase(Postfix postfix)
183   {
184     postfixes_t::iterator i = m_postfixes.find(postfix);
185     if(i == m_postfixes.end())
186     {
187       // error
188     }
189     else
190     {
191       if(--(*i).second == 0)
192         m_postfixes.erase(i);
193     }
194   }
195
196   bool empty() const
197   {
198     return m_postfixes.empty();
199   }
200 };
201
202
203 class UniqueNames
204 {
205   typedef std::map<CopiedString, PostFixes> names_t;
206   names_t m_names;
207 public:
208   name_t make_unique(const name_t& name) const
209   {
210     names_t::const_iterator i = m_names.find(name.first);
211     if(i == m_names.end())
212     {
213       return name;
214     }
215     else
216     {
217       return name_t(name.first, (*i).second.make_unique(name.second));
218     }
219   }
220
221   void insert(const name_t& name)
222   {
223     m_names[name.first].insert(name.second);
224   }
225
226   void erase(const name_t& name)
227   {
228     names_t::iterator i = m_names.find(name.first);
229     if(i == m_names.end())
230     {
231       ASSERT_MESSAGE(true, "erase: name not found");
232     }
233     else
234     {
235       (*i).second.erase(name.second);
236       if((*i).second.empty())
237         m_names.erase(i);
238     }
239   }
240
241   bool empty() const
242   {
243     return m_names.empty();
244   }
245 };
246
247
248
249 #if 0
250
251 #undef ERROR_MESSAGE
252 #define ERROR_MESSAGE(message)
253
254 class TestUniqueName
255 {
256   void name_check_equal(const name_t& name, const char* string, unsigned int postfix)
257   {
258     ASSERT_MESSAGE(strcmp(name.first.c_str(), string) == 0
259       && name.second.number() == postfix,
260       "test failed!");
261   }
262   void test_refcount()
263   {
264     Names names;
265
266     names.insert(name_t("func_bleh_", "100"));
267     names.insert(name_t("func_bleh_", "100"));
268     names.insert(name_t("func_bleh_", "100"));
269
270
271     names.erase(name_t("func_bleh_", "100"));
272     names.erase(name_t("func_bleh_", "100"));
273     names.erase(name_t("func_bleh_", "100"));
274
275     ASSERT_MESSAGE(names.empty(), "test failed!");
276   }
277
278   void test_make_unique()
279   {
280     Names names;
281
282     {
283       name_t name(names.make_unique(name_t("func_bleh_", "01")));
284       name_check_equal(name, "func_bleh_", 1);
285       names.insert(name);
286     }
287     {
288       name_t name(names.make_unique(name_t("func_bleh_", "04")));
289       name_check_equal(name, "func_bleh_", 4);
290       names.insert(name);
291     }
292     {
293       name_t name(names.make_unique(name_t("func_bleh_", "04")));
294       name_check_equal(name, "func_bleh_", 2);
295       names.insert(name);
296     }
297     {
298       name_t name(names.make_unique(name_t("func_bleh_", "1")));
299       name_check_equal(name, "func_bleh_", 3);
300       names.insert(name);
301     }
302     {
303       name_t name(names.make_unique(name_t("func_bleh_", "2")));
304       name_check_equal(name, "func_bleh_", 5);
305       names.insert(name);
306     }
307     {
308       name_t name(names.make_unique(name_t("func_bleh_", "3")));
309       name_check_equal(name, "func_bleh_", 6);
310       names.insert(name);
311     }
312
313     names.erase(name_t("func_bleh_", "1"));
314     names.erase(name_t("func_bleh_", "2"));
315     names.erase(name_t("func_bleh_", "3"));
316     names.erase(name_t("func_bleh_", "4"));
317     names.erase(name_t("func_bleh_", "5"));
318     names.erase(name_t("func_bleh_", "6"));
319
320     ASSERT_MESSAGE(names.empty(), "test failed!");
321   }
322 public:
323   TestUniqueName()
324   {
325     test_refcount();
326     test_make_unique();
327   }
328 };
329
330 const TestUniqueName g_testuniquename;
331
332 #endif
333
334
335 #endif