]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/uniquenames.h
Merge commit '515673c08f8718a237e90c2130a1f5294f966d6a'
[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) const
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 public:
140   typedef std::map<Postfix, unsigned int> postfixes_t;
141   postfixes_t m_postfixes;
142
143 private:
144   Postfix find_first_empty() const
145   {
146     Postfix postfix("1");
147     for(postfixes_t::const_iterator i = m_postfixes.find(postfix); i != m_postfixes.end(); ++i, ++postfix)
148     {
149       if((*i).first != postfix)
150       {
151         break;
152       }
153     }
154     return postfix;
155   }
156
157 public:
158   Postfix make_unique(Postfix postfix) const
159   {
160     postfixes_t::const_iterator i = m_postfixes.find(postfix);
161     if(i == m_postfixes.end())
162     {
163       return postfix;
164     }
165     else
166     {
167       return find_first_empty();
168     }
169   }
170
171   void insert(Postfix postfix)
172   {
173     postfixes_t::iterator i = m_postfixes.find(postfix);
174     if(i == m_postfixes.end())
175     {
176       m_postfixes.insert(postfixes_t::value_type(postfix, 1));
177     }
178     else
179     {
180       ++(*i).second;
181     }
182   }
183
184   void erase(Postfix postfix)
185   {
186     postfixes_t::iterator i = m_postfixes.find(postfix);
187     if(i == m_postfixes.end())
188     {
189       // error
190     }
191     else
192     {
193       if(--(*i).second == 0)
194         m_postfixes.erase(i);
195     }
196   }
197
198   bool empty() const
199   {
200     return m_postfixes.empty();
201   }
202 };
203
204
205 class UniqueNames
206 {
207   typedef std::map<CopiedString, PostFixes> names_t;
208   names_t m_names;
209 public:
210   name_t make_unique(const name_t& name) const
211   {
212     char buf[80];
213     name_t r("","");
214         name_write(buf, name);
215     globalErrorStream() << "find unique name for " << buf << "\n";
216         globalErrorStream() << "> currently registered names:\n";
217         for(names_t::const_iterator i = m_names.begin(); i != m_names.end(); ++i)
218         {
219                 globalErrorStream() << ">> " << i->first.c_str() << ": ";
220                 for(PostFixes::postfixes_t::const_iterator j = i->second.m_postfixes.begin(); j != i->second.m_postfixes.end(); ++j)
221                 {
222                         j->first.write(buf);
223                         globalErrorStream() << " '" << buf << "'";
224                 }
225                 globalErrorStream() << "\n";
226         }
227     names_t::const_iterator i = m_names.find(name.first);
228     if(i == m_names.end())
229     {
230       r = name;
231     }
232     else
233     {
234       r = name_t(name.first, (*i).second.make_unique(name.second));
235     }
236         name_write(buf, r);
237     globalErrorStream() << "> unique name is " << buf << "\n";
238         return r;
239   }
240
241   void insert(const name_t& name)
242   {
243     m_names[name.first].insert(name.second);
244   }
245
246   void erase(const name_t& name)
247   {
248     names_t::iterator i = m_names.find(name.first);
249     if(i == m_names.end())
250     {
251       ASSERT_MESSAGE(true, "erase: name not found");
252     }
253     else
254     {
255       (*i).second.erase(name.second);
256       if((*i).second.empty())
257         m_names.erase(i);
258     }
259   }
260
261   bool empty() const
262   {
263     return m_names.empty();
264   }
265 };
266
267
268
269 #if 0
270
271 #undef ERROR_MESSAGE
272 #define ERROR_MESSAGE(message)
273
274 class TestUniqueName
275 {
276   void name_check_equal(const name_t& name, const char* string, unsigned int postfix)
277   {
278     ASSERT_MESSAGE(strcmp(name.first.c_str(), string) == 0
279       && name.second.number() == postfix,
280       "test failed!");
281   }
282   void test_refcount()
283   {
284     Names names;
285
286     names.insert(name_t("func_bleh_", "100"));
287     names.insert(name_t("func_bleh_", "100"));
288     names.insert(name_t("func_bleh_", "100"));
289
290
291     names.erase(name_t("func_bleh_", "100"));
292     names.erase(name_t("func_bleh_", "100"));
293     names.erase(name_t("func_bleh_", "100"));
294
295     ASSERT_MESSAGE(names.empty(), "test failed!");
296   }
297
298   void test_make_unique()
299   {
300     Names names;
301
302     {
303       name_t name(names.make_unique(name_t("func_bleh_", "01")));
304       name_check_equal(name, "func_bleh_", 1);
305       names.insert(name);
306     }
307     {
308       name_t name(names.make_unique(name_t("func_bleh_", "04")));
309       name_check_equal(name, "func_bleh_", 4);
310       names.insert(name);
311     }
312     {
313       name_t name(names.make_unique(name_t("func_bleh_", "04")));
314       name_check_equal(name, "func_bleh_", 2);
315       names.insert(name);
316     }
317     {
318       name_t name(names.make_unique(name_t("func_bleh_", "1")));
319       name_check_equal(name, "func_bleh_", 3);
320       names.insert(name);
321     }
322     {
323       name_t name(names.make_unique(name_t("func_bleh_", "2")));
324       name_check_equal(name, "func_bleh_", 5);
325       names.insert(name);
326     }
327     {
328       name_t name(names.make_unique(name_t("func_bleh_", "3")));
329       name_check_equal(name, "func_bleh_", 6);
330       names.insert(name);
331     }
332
333     names.erase(name_t("func_bleh_", "1"));
334     names.erase(name_t("func_bleh_", "2"));
335     names.erase(name_t("func_bleh_", "3"));
336     names.erase(name_t("func_bleh_", "4"));
337     names.erase(name_t("func_bleh_", "5"));
338     names.erase(name_t("func_bleh_", "6"));
339
340     ASSERT_MESSAGE(names.empty(), "test failed!");
341   }
342 public:
343   TestUniqueName()
344   {
345     test_refcount();
346     test_make_unique();
347   }
348 };
349
350 const TestUniqueName g_testuniquename;
351
352 #endif
353
354
355 #endif