1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef TrenchBroom_StringMap
21 #define TrenchBroom_StringMap
22 
23 #include "CollectionUtils.h"
24 #include "Exceptions.h"
25 #include "StringUtils.h"
26 
27 #include <cassert>
28 #include <map>
29 #include <set>
30 #include <vector>
31 
32 namespace TrenchBroom {
33     template <typename V>
34     class StringMapValueContainer {
35     public:
36         typedef std::vector<V> ValueContainer;
37         typedef std::vector<V> QueryResult;
38 
insertValue(ValueContainer & values,const V & value)39         static void insertValue(ValueContainer& values, const V& value) {
40             values.push_back(value);
41         }
42 
removeValue(ValueContainer & values,const V & value)43         static void removeValue(ValueContainer& values, const V& value) {
44             typename ValueContainer::iterator it = std::find(values.begin(), values.end(), value);
45             if (it == values.end())
46                 throw Exception("Cannot remove value (does not belong to this node)");
47             values.erase(it);
48         }
49 
getValues(const ValueContainer & values,QueryResult & result)50         static void getValues(const ValueContainer& values, QueryResult& result) {
51             VectorUtils::append(result, values);
52         }
53     };
54 
55     template <typename V>
56     class StringMultiMapValueContainer {
57     public:
58         typedef std::map<V, size_t> ValueContainer;
59         typedef std::set<V> QueryResult;
60 
insertValue(ValueContainer & values,const V & value)61         static void insertValue(ValueContainer& values, const V& value) {
62             typename ValueContainer::iterator it = MapUtils::findOrInsert(values, value, 0u);
63             ++it->second;
64         }
65 
removeValue(ValueContainer & values,const V & value)66         static void removeValue(ValueContainer& values, const V& value) {
67             typename ValueContainer::iterator it = values.find(value);
68             if (it == values.end())
69                 throw Exception("Cannot remove value from string map.");
70             if (it->second == 1)
71                 values.erase(it);
72             else
73                 --it->second;
74         }
75 
getValues(const ValueContainer & values,QueryResult & result)76         static void getValues(const ValueContainer& values, QueryResult& result) {
77             typename ValueContainer::const_iterator it, end;
78             for (it = values.begin(), end = values.end(); it != end; ++it)
79                 result.insert(it->first);
80         }
81     };
82 
83     template <typename V, typename P>
84     class StringMap {
85     public:
86         typedef typename P::QueryResult QueryResult;
87     private:
88         class Node {
89         private:
90             typedef std::set<Node> NodeSet;
91             typedef typename P::ValueContainer ValueContainer;
92 
93             // The key is declared mutable because we must change it in splitNode and mergeNode, but the resulting new key
94             // will still compare equal to the old key.
95             mutable String m_key;
96             mutable ValueContainer m_values;
97             mutable NodeSet m_children;
98         public:
Node(const String & key)99             explicit Node(const String& key) :
100             m_key(key) {}
101 
102             bool operator<(const Node& rhs) const {
103                 const size_t firstDiff = StringUtils::findFirstDifference(m_key, rhs.m_key);
104                 if (firstDiff == 0)
105                     return m_key[0] < rhs.m_key[0];
106                 // both keys share a common prefix and are thus treated as the same
107                 return false;
108             }
109 
110             /*
111              Possible cases for insertion:
112               index: 01234567 |   | #m_key: 6
113               m_key: target   | ^ | #key | conditions              | todo
114              =================|===|======|=========================|======
115               case:  key:     |   |      |                         |
116                  1:  targetli | 6 | 8    | ^ < #key AND ^ = #m_key | try insert in all children, if none match, create child 'li' and insert there;
117                            ^  |   |      |                         |
118                  2:  target   | 6 | 6    | ^ = #key AND ^ = #m_key | insert here; return true;
119                            ^  |   |      |                         |
120                  3:  tarus    | 3 | 5    | ^ < #key AND ^ < #m_key | split this node in 'tar' and 'get'; create child 'us' and insert there;
121                         ^     |   |      |                         |
122                  4:  tar      | 3 | 3    | ^ = #key AND ^ < #m_key | split this node in 'tar' and 'get'; insert here; return true;
123                         ^     |   |      |                         |
124                  5:  blah     | 0 | 4    | ^ = 0                   | return false;
125                      ^        |   |      |                         |
126              ==================================================================================
127               ^ indicates where key and m_key first differ
128              */
insert(const String & key,const V & value)129             void insert(const String& key, const V& value) const {
130                 const size_t firstDiff = StringUtils::findFirstDifference(key, m_key);
131                 if (firstDiff == 0 && !m_key.empty())
132                     // no common prefix
133                     return;
134                 if (firstDiff < key.size()) {
135                     if (firstDiff < m_key.size()) {
136                         // key and m_key share a common prefix, split this node and insert again
137                         splitNode(firstDiff);
138                         insert(key, value);
139                     } else if (firstDiff == m_key.size()) {
140                         // m_key is a prefix of key, find or create a child that shares a common prefix with remainder, and insert there, and insert here
141                         const String remainder = key.substr(firstDiff);
142                         const Node& child = findOrCreateChild(remainder);
143                         child.insert(remainder, value);
144                     }
145                 } else if (firstDiff == key.size()) {
146                     if (firstDiff < m_key.size()) {
147                         // key is prefix of m_key, split this node and insert here
148                         splitNode(firstDiff);
149                         insertValue(value);
150                     } else if (firstDiff == m_key.size()) {
151                         // keys are equal, insert here
152                         insertValue(value);
153                     }
154                 }
155             }
156 
remove(const String & key,const V & value)157             bool remove(const String& key, const V& value) const {
158                 const size_t firstDiff = StringUtils::findFirstDifference(key, m_key);
159                 if (m_key.size() <= key.size() && firstDiff == m_key.size()) {
160                     // this node's key is a prefix of the given key
161                     if (firstDiff < key.size()) {
162                         // the given key is longer than this node's key, so we must continue at the appropriate child node
163                         const String remainder(key.substr(firstDiff));
164                         const Node query(remainder);
165                         typename NodeSet::iterator it = m_children.find(query);
166                         assert(it != m_children.end());
167                         const Node& child = *it;
168                         if (child.remove(remainder, value))
169                             m_children.erase(it);
170                     } else {
171                         removeValue(value);
172                     }
173 
174                     if (!m_key.empty() && m_values.empty() && m_children.size() == 1)
175                         mergeNode();
176                 }
177                 return !m_key.empty() && m_values.empty() && m_children.empty();
178             }
179 
queryExact(const String & key,QueryResult & result)180             void queryExact(const String& key, QueryResult& result) const {
181                 const size_t firstDiff = StringUtils::findFirstDifference(key, m_key);
182                 if (firstDiff == 0 && !m_key.empty())
183                     // no common prefix
184                     return;
185                 if (firstDiff == key.size() && firstDiff <= m_key.size()) {
186                     // this node represents the given (remaining) prefix
187                     if (firstDiff == m_key.size())
188                         getValues(result);
189                 } else if (firstDiff < key.size() && firstDiff == m_key.size()) {
190                     // this node is only a partial match, try to find a child to continue searching
191                     const String remainder(key.substr(firstDiff));
192                     const Node query(remainder);
193                     typename NodeSet::iterator it = m_children.find(query);
194                     if (it != m_children.end()) {
195                         const Node& child = *it;
196                         child.queryExact(remainder, result);
197                     }
198                 }
199             }
200 
queryPrefix(const String & prefix,QueryResult & result)201             void queryPrefix(const String& prefix, QueryResult& result) const {
202                 const size_t firstDiff = StringUtils::findFirstDifference(prefix, m_key);
203                 if (firstDiff == 0 && !m_key.empty())
204                     // no common prefix
205                     return;
206                 if (firstDiff == prefix.size() && firstDiff <= m_key.size()) {
207                     // the given prefix is a prefix of this node's key, collect all values in the subtree starting at
208                     // this node
209                     collectValues(result);
210                 } else if (firstDiff < prefix.size() && firstDiff == m_key.size()) {
211                     // this node is only a partial match, try to find a child to continue searching
212                     const String remainder(prefix.substr(firstDiff));
213                     const Node query(remainder);
214                     typename NodeSet::iterator it = m_children.find(query);
215                     if (it != m_children.end()) {
216                         const Node& child = *it;
217                         child.queryPrefix(remainder, result);
218                     }
219                 }
220             }
221 
collectValues(QueryResult & result)222             void collectValues(QueryResult& result) const {
223                 getValues(result);
224                 typename NodeSet::const_iterator it, end;
225                 for (it = m_children.begin(), end = m_children.end(); it != end; ++it) {
226                     const Node& child = *it;
227                     child.collectValues(result);
228                 }
229             }
230 
queryNumbered(const String & prefix,QueryResult & result)231             void queryNumbered(const String& prefix, QueryResult& result) const {
232                 const size_t firstDiff = StringUtils::findFirstDifference(prefix, m_key);
233                 if (firstDiff == 0 && !m_key.empty())
234                     // no common prefix
235                     return;
236                 if (firstDiff == prefix.size() && firstDiff <= m_key.size()) {
237                     // the given prefix is a prefix of this node's key
238                     // if the remainder of this node's key is a number, add this node's values and continue searching
239                     // the entire subtree starting at this node
240                     const String remainder(m_key.substr(firstDiff));
241                     if (StringUtils::isNumber(remainder)) {
242                         getValues(result);
243                         typename NodeSet::const_iterator it, end;
244                         for (it = m_children.begin(), end = m_children.end(); it != end; ++it) {
245                             const Node& child = *it;
246                             child.collectIfNumbered(result);
247                         }
248                     }
249                 } else if (firstDiff < prefix.size() && firstDiff == m_key.size()) {
250                     // this node is only a partial match, try to find a child to continue searching
251                     const String remainder(prefix.substr(firstDiff));
252                     const Node query(remainder);
253                     typename NodeSet::iterator it = m_children.find(query);
254                     if (it != m_children.end()) {
255                         const Node& child = *it;
256                         child.queryNumbered(remainder, result);
257                     }
258                 }
259             }
260 
collectIfNumbered(QueryResult & result)261             void collectIfNumbered(QueryResult& result) const {
262                 if (StringUtils::isNumber(m_key)) {
263                     getValues(result);
264                     typename NodeSet::const_iterator it, end;
265                     for (it = m_children.begin(), end = m_children.end(); it != end; ++it) {
266                         const Node& child = *it;
267                         child.collectIfNumbered(result);
268                     }
269                 }
270             }
271         private:
insertValue(const V & value)272             void insertValue(const V& value) const {
273                 P::insertValue(m_values, value);
274             }
275 
removeValue(const V & value)276             void removeValue(const V& value) const {
277                 P::removeValue(m_values, value);
278             }
279 
findOrCreateChild(const String & key)280             const Node& findOrCreateChild(const String& key) const {
281                 std::pair<typename NodeSet::iterator, bool> result = m_children.insert(Node(key));
282                 typename NodeSet::iterator it = result.first;
283                 return *it;
284             }
285 
splitNode(const size_t index)286             void splitNode(const size_t index) const {
287                 using std::swap;
288 
289                 assert(m_key.size() > 1);
290                 assert(index < m_key.size());
291 
292                 const String newKey = m_key.substr(0, index);
293                 const String remainder = m_key.substr(index);
294 
295                 // We want to avoid copying the children of this node to the new child, therefore we swap with an empty
296                 // node set. Afterwards this node's children are empty.
297                 NodeSet newChildren;
298                 swap(newChildren, m_children);
299 
300                 const Node& newChild = findOrCreateChild(remainder);
301                 swap(newChild.m_children, newChildren);
302                 swap(newChild.m_values, m_values);
303 
304                 m_key = newKey;
305             }
306 
mergeNode()307             void mergeNode() const {
308                 using std::swap;
309 
310                 assert(m_children.size() == 1);
311                 assert(m_values.empty());
312 
313                 NodeSet oldChildren;
314                 swap(oldChildren, m_children);
315 
316                 const Node& child = *oldChildren.begin();
317                 swap(m_children, child.m_children);
318                 swap(m_values, child.m_values);
319 
320                 m_key += child.m_key;
321             }
322 
getValues(QueryResult & result)323             void getValues(QueryResult& result) const {
324                 P::getValues(m_values, result);
325             }
326         };
327 
328         Node* m_root;
329     public:
StringMap()330         StringMap() :
331         m_root(new Node("")) {}
332 
~StringMap()333         ~StringMap() {
334             delete m_root;
335             m_root = NULL;
336         }
337 
insert(const String & key,const V & value)338         void insert(const String& key, const V& value) {
339             assert(m_root != NULL);
340             m_root->insert(key, value);
341         }
342 
remove(const String & key,const V & value)343         void remove(const String& key, const V& value) {
344             assert(m_root != NULL);
345             m_root->remove(key, value);
346         }
347 
clear()348         void clear() {
349             delete m_root;
350             m_root = new Node("");
351         }
352 
queryPrefixMatches(const String & prefix)353         QueryResult queryPrefixMatches(const String& prefix) const {
354             assert(m_root != NULL);
355             QueryResult result;
356             m_root->queryPrefix(prefix, result);
357             return result;
358         }
359 
queryNumberedMatches(const String & prefix)360         QueryResult queryNumberedMatches(const String& prefix) const {
361             assert(m_root != NULL);
362             QueryResult result;
363             m_root->queryNumbered(prefix, result);
364             return result;
365         }
366 
queryExactMatches(const String & prefix)367         QueryResult queryExactMatches(const String& prefix) const {
368             assert(m_root != NULL);
369             QueryResult result;
370             m_root->queryExact(prefix, result);
371             return result;
372         }
373     private:
374         StringMap(const StringMap& other);
375         StringMap& operator=(const StringMap& other);
376     };
377 }
378 
379 #endif /* defined(TrenchBroom_StringMap) */
380