/
UniqueNameSet.h
190 lines (158 loc) · 5.7 KB
/
UniqueNameSet.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#pragma once
#include <set>
#include <map>
#include "ComplexName.h"
/**
* \brief
* A set which maps name prefixes (e.g. "func_static_") to the set of
* postfixes which are used in the current map.
*/
class UniqueNameSet
{
// This maps name prefixes to a set of used postfixes
// e.g. "func_static_" => ["1","3","4","5","05","10"]
// Allows fairly quick lookup of used names and postfixes
typedef std::map<std::string, PostfixSet> Names;
Names _names;
public:
/// Test if this set is empty
bool empty() const
{
// Cycle through all prefixes and see if the postfixset is non-empty, break on first hit
for (const auto& i : _names)
{
if (!i.second.empty())
{
return false;
}
}
return true;
}
/**
* \brief
* Inserts the given full name into this set.
*
* Returns TRUE if the insertion was successful (i.e. the name didn't exist
* yet).
*/
bool insert(const ComplexName& name)
{
// Lookup the name in the map to see if we know this prefix already
Names::iterator found = _names.find(name.getNameWithoutPostfix());
if (found == _names.end())
{
// The name is not yet in the list, insert it afresh
auto result = _names.insert(std::make_pair(name.getNameWithoutPostfix(), PostfixSet()));
assert(result.second); // insert must succeed, we didn't find this just before
// Overwrite the iterator
found = result.first;
}
// The prefix is inserted at this point, add the postfix to the set
auto result = found->second.insert(name.getPostfix());
// Return the boolean of the insertion result, it is true on successful insertion
return result.second;
}
/**
* \brief
* Removes the given full name from the set.
*
* Returns TRUE if the name was there in the first place.
*/
bool erase(const ComplexName& name)
{
// Lookup the name in the map to see if we know this prefix already
Names::iterator found = _names.find(name.getNameWithoutPostfix());
if (found == _names.end())
{
return false; // Not found!
}
// The prefix has been found, remove the postfix from the set
// Return true if the erase method removed any elements
return found->second.erase(name.getPostfix()) > 0;
}
/**
* \brief
* Insert the given ComplexName into this set, changing its postfix if
* necessary to ensure that is is unique.
*
* \return
* The actual unique name that was used, which may be different from the
* original ComplexName if there was a conflict.
*/
std::string insertUnique(const ComplexName& name)
{
// Lookup the name in the map to see if we know this prefix
Names::iterator found = _names.find(name.getNameWithoutPostfix());
if (found == _names.end())
{
// The name is not yet in the list, we can add it with the given postfix
auto result = _names.insert(std::make_pair(name.getNameWithoutPostfix(), PostfixSet()));
assert(result.second); // insert must succeed, we didn't find this just before
// Overwrite the iterator
found = result.first;
}
// At this point, the "trunk" of the complex name is already in the list
// The found iterator points to a valid prefix => PostFixSet mapping
// Acquire a new unique postfix (if necessary) for this name to make it
// unique
PostfixSet& postfixSet = found->second;
ComplexName uniqueName(name);
std::string postfix = uniqueName.makePostfixUnique(postfixSet);
postfixSet.insert(postfix);
return uniqueName.getFullname();
}
/**
* greebo: Returns true if the full name already exists in this set.
*/
bool nameExists(const std::string& fullname) const
{
// Empty names never exist
if (fullname.empty())
{
return false;
}
// Analyse the name (split it into parts) and pass the call to the specialised method
return nameExists(ComplexName(fullname));
}
/**
* greebo: Returns true if the complex name already exists in this set.
*/
bool nameExists(const ComplexName& name) const
{
// Lookup the name in the map to see if we know this prefix
Names::const_iterator found = _names.find(name.getNameWithoutPostfix());
if (found != _names.end())
{
// We know the name "trunk", does the number exist?
const PostfixSet& postfixSet = found->second;
// If we know the number too, the full name exists
return postfixSet.find(name.getPostfix()) != postfixSet.end();
}
// Prefix is not known, hence full name is not known
return false;
}
/**
* Copies all names from the <other> UniqueNameSet into this one.
* This class will contain the union of both sets afterwards.
* Duplicate names will be ignored.
*/
void merge(const UniqueNameSet& other)
{
// cycle through all foreign names and import them
for (const auto& i : other._names)
{
// Check if the prefix exists already in this set
Names::iterator local = _names.find(i.first);
if (local != _names.end())
{
// Prefix exists, merge the postfixes
local->second.insert(i.second.begin(), i.second.end());
}
else
{
// Prefix doesn't exist yet, insert the whole string => PostfixSet pair
_names.insert(i);
}
}
}
};