/src/poco/Foundation/include/Poco/ListMap.h
Line | Count | Source |
1 | | // |
2 | | // ListMap.h |
3 | | // |
4 | | // Library: Foundation |
5 | | // Package: Core |
6 | | // Module: ListMap |
7 | | // |
8 | | // Definition of the ListMap class. |
9 | | // |
10 | | // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. |
11 | | // and Contributors. |
12 | | // |
13 | | // SPDX-License-Identifier: BSL-1.0 |
14 | | // |
15 | | |
16 | | |
17 | | #ifndef Foundation_ListMap_INCLUDED |
18 | | #define Foundation_ListMap_INCLUDED |
19 | | |
20 | | |
21 | | #include "Poco/Foundation.h" |
22 | | #include "Poco/String.h" |
23 | | #include "Poco/Exception.h" |
24 | | #include <vector> |
25 | | #include <utility> |
26 | | |
27 | | |
28 | | namespace Poco { |
29 | | |
30 | | |
31 | | template <class Key, class Mapped, class Container = std::vector<std::pair<Key, Mapped>>, bool CaseSensitive = false> |
32 | | class ListMap |
33 | | /// This class implements a multimap in terms of a sequential container. |
34 | | /// The use for this type of associative container is wherever automatic |
35 | | /// ordering of elements is not desirable. Naturally, this container will |
36 | | /// have inferior data retrieval performance and it is not recommended for |
37 | | /// use with large datasets. The main purpose within POCO is for Internet |
38 | | /// messages (email message, http headers etc), to prevent automatic |
39 | | /// header entry reordering. |
40 | | { |
41 | | public: |
42 | | using KeyType = Key; |
43 | | using MappedType = Mapped; |
44 | | using Reference = Mapped&; |
45 | | using ConstReference = const Mapped&; |
46 | | using Pointer = Mapped*; |
47 | | using ConstPointer = const Mapped*; |
48 | | |
49 | | using ValueType = typename Container::value_type; |
50 | | using SizeType = typename Container::size_type; |
51 | | using Iterator = typename Container::iterator; |
52 | | using ConstIterator = typename Container::const_iterator; |
53 | | |
54 | 1.09M | ListMap() = default; |
55 | | /// Creates an empty ListMap. |
56 | | |
57 | | explicit ListMap(std::size_t initialReserve): |
58 | | _container(initialReserve) |
59 | | /// Creates the ListMap with room for initialReserve entries. |
60 | | { |
61 | | } |
62 | | |
63 | | ListMap(const ListMap& other): |
64 | 251k | _container(other._container) |
65 | 251k | { |
66 | 251k | } |
67 | | |
68 | | ListMap(ListMap&& other) noexcept: |
69 | 0 | _container(std::move(other._container)) |
70 | 0 | { |
71 | 0 | } |
72 | | |
73 | | ListMap& operator = (const ListMap& map) |
74 | | /// Assigns another ListMap. |
75 | | { |
76 | | ListMap tmp(map); |
77 | | swap(tmp); |
78 | | return *this; |
79 | | } |
80 | | |
81 | | ListMap& operator = (ListMap&& map) noexcept |
82 | | /// Assigns another ListMap. |
83 | 0 | { |
84 | 0 | _container = std::move(map._container); |
85 | 0 | return *this; |
86 | 0 | } |
87 | | |
88 | | void swap(ListMap& map) noexcept |
89 | | /// Swaps the ListMap with another one. |
90 | | { |
91 | | _container.swap(map._container); |
92 | | } |
93 | | |
94 | | ConstIterator begin() const |
95 | | /// Returns the beginning of the map. |
96 | 883k | { |
97 | 883k | return _container.begin(); |
98 | 883k | } |
99 | | |
100 | | ConstIterator end() const |
101 | | /// Returns the end of the map. |
102 | 3.73M | { |
103 | 3.73M | return _container.end(); |
104 | 3.73M | } |
105 | | |
106 | | Iterator begin() |
107 | | /// Returns the beginning of the map. |
108 | 18.7k | { |
109 | 18.7k | return _container.begin(); |
110 | 18.7k | } |
111 | | |
112 | | Iterator end() |
113 | | /// Returns the end of the map. |
114 | 979k | { |
115 | 979k | return _container.end(); |
116 | 979k | } |
117 | | |
118 | | ConstIterator find(const KeyType& key) const |
119 | | /// Finds the first occurrence of the key and |
120 | | /// returns iterator pointing to the found entry |
121 | | /// or iterator pointing to the end if entry is |
122 | | /// not found. |
123 | 1.98M | { |
124 | 1.98M | typename Container::const_iterator it = _container.begin(); |
125 | 1.98M | typename Container::const_iterator itEnd = _container.end(); |
126 | 2.38M | for(; it != itEnd; ++it) |
127 | 599k | { |
128 | 599k | if (isEqual(it->first, key)) return it; |
129 | 599k | } |
130 | 1.78M | return itEnd; |
131 | 1.98M | } |
132 | | |
133 | | Iterator find(const KeyType& key) |
134 | | /// Finds the first occurrence of the key and |
135 | | /// returns iterator pointing to the found entry |
136 | | /// or iterator pointing to the end if entry is |
137 | | /// not found. |
138 | 2.08M | { |
139 | 2.08M | typename Container::iterator it = _container.begin(); |
140 | 2.08M | typename Container::iterator itEnd = _container.end(); |
141 | 30.3M | for(; it != itEnd; ++it) |
142 | 28.5M | { |
143 | 28.5M | if (isEqual(it->first, key)) return it; |
144 | 28.5M | } |
145 | 1.86M | return itEnd; |
146 | 2.08M | } |
147 | | |
148 | | Iterator insert(const ValueType& val) |
149 | | /// Inserts the value into the map. If one or more values |
150 | | /// already exist, new value is inserted at the end of the |
151 | | /// block. Thus, all the equal value entries are located |
152 | | /// sequentially at all times. |
153 | | /// Returns iterator pointing to the newly inserted value |
154 | 1.14M | { |
155 | 1.14M | Iterator it = find(val.first); |
156 | 44.3M | while (it != _container.end() && isEqual(it->first, val.first)) ++it; |
157 | 1.14M | return _container.insert(it, val); |
158 | 1.14M | } |
159 | | |
160 | | void erase(Iterator it) |
161 | 10.5k | { |
162 | 10.5k | _container.erase(it); |
163 | 10.5k | } |
164 | | |
165 | | SizeType erase(const KeyType& key) |
166 | 275 | { |
167 | 275 | SizeType count = 0; |
168 | 275 | Iterator it = find(key); |
169 | 275 | bool removed = false; |
170 | 829 | while (it != _container.end()) |
171 | 628 | { |
172 | 628 | if (isEqual(it->first, key)) |
173 | 554 | { |
174 | 554 | ++count; |
175 | 554 | it = _container.erase(it); |
176 | 554 | removed = true; |
177 | 554 | } |
178 | 74 | else |
179 | 74 | { |
180 | 74 | if (removed) return count; |
181 | 0 | ++it; |
182 | 0 | } |
183 | 628 | } |
184 | 201 | return count; |
185 | 275 | } |
186 | | |
187 | | void clear() |
188 | 668k | { |
189 | 668k | _container.clear(); |
190 | 668k | } |
191 | | |
192 | | std::size_t size() const |
193 | 699 | { |
194 | 699 | return _container.size(); |
195 | 699 | } |
196 | | |
197 | | bool empty() const |
198 | 0 | { |
199 | 0 | return _container.empty(); |
200 | 0 | } |
201 | | |
202 | | ConstReference operator [] (const KeyType& key) const |
203 | | { |
204 | | ConstIterator it = find(key); |
205 | | if (it != _container.end()) |
206 | | return it->second; |
207 | | else |
208 | | throw NotFoundException(); |
209 | | } |
210 | | |
211 | | Reference operator [] (const KeyType& key) |
212 | | { |
213 | | Iterator it = find(key); |
214 | | if (it != _container.end()) |
215 | | { |
216 | | return it->second; |
217 | | } |
218 | | else |
219 | | { |
220 | | ValueType value(key, Mapped()); |
221 | | Iterator itInsert = insert(value); |
222 | | return itInsert->second; |
223 | | } |
224 | | } |
225 | | |
226 | | private: |
227 | | template <typename T1, typename T2> |
228 | | bool isEqual(T1 val1, T2 val2) const |
229 | | { |
230 | | return val1 == val2; |
231 | | } |
232 | | |
233 | | bool isEqual(const std::string& s1, const std::string& s2) const |
234 | 72.4M | { |
235 | 72.4M | if (!CaseSensitive) |
236 | 72.4M | return Poco::icompare(s1, s2) == 0; |
237 | 0 | else |
238 | 0 | return s1 == s2; |
239 | 72.4M | } |
240 | | |
241 | | bool isEqual(const std::string& s1, const char* s2) const |
242 | | { |
243 | | return isEqual(s1, std::string(s2)); |
244 | | } |
245 | | |
246 | | bool isEqual(const char* s1, const std::string& s2) const |
247 | | { |
248 | | return isEqual(std::string(s1), s2); |
249 | | } |
250 | | |
251 | | bool isEqual(const char* s1, const char* s2) const |
252 | | { |
253 | | return isEqual(std::string(s1), std::string(s2)); |
254 | | } |
255 | | |
256 | | Container _container; |
257 | | }; |
258 | | |
259 | | |
260 | | } // namespace Poco |
261 | | |
262 | | |
263 | | #endif // Foundation_ListMap_INCLUDED |