Coverage Report

Created: 2026-07-25 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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