/* 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) { 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(name, end), Postfix(end)); } class PostFixes { typedef std::map postfixes_t; postfixes_t m_postfixes; 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 { names_t::const_iterator i = m_names.find(name.first); if(i == m_names.end()) { return name; } else { return name_t(name.first, (*i).second.make_unique(name.second)); } } 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