opm-common
Loading...
Searching...
No Matches
OrderedMap.hpp
1/*
2 Copyright 2014 Statoil ASA.
3
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM 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 OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef OPM_ORDERED_MAP_HPP
21#define OPM_ORDERED_MAP_HPP
22
23#include <algorithm>
24#include <cctype>
25#include <cstddef>
26#include <functional>
27#include <iterator>
28#include <set>
29#include <stdexcept>
30#include <string>
31#include <string_view>
32#include <unordered_map>
33#include <utility>
34#include <vector>
35
36namespace Opm {
37
38namespace OrderedMapDetail {
39
40template<class T, class A>
41std::string
42findSimilarStrings(std::string str,
43 const std::vector<std::pair<std::string, T>,A>& storage)
44{
45 auto toUpper = [](const char c){ return std::toupper(c);};
46 std::ranges::transform(str, str.begin(), toUpper);
47 std::set<std::string> alternatives;
48
49 for(const auto& entry: storage)
50 {
51 std::string upper = entry.first;
52 std::ranges::transform(upper, upper.begin(), toUpper);
53
54 if(upper.find(str) != std::string::npos || str.find(upper) != std::string::npos)
55 {
56 alternatives.insert(entry.first);
57 }
58 }
59
60 if (alternatives.empty())
61 {
62 return {};
63 }
64
65 std::string concatedStr;
66 for (const auto& alt : alternatives) {
67 concatedStr += alt;
68 concatedStr += ", ";
69 }
70 return concatedStr.substr(0, concatedStr.size()-2);
71}
72
73template<std::string_view::size_type MAX_CHARS>
75{
76public:
77 std::size_t operator()(std::string_view key) const
78 {
79 return hasher(key.substr(0, MAX_CHARS));
80 }
81private:
82 std::hash<std::string_view> hasher;
83};
84
85
86template<>
87class TruncatedStringHash<std::string_view::npos> : public std::hash<std::string_view>
88{};
89
90template<std::string_view::size_type MAX_CHARS>
92{
93 bool operator()(std::string_view str1, std::string_view str2) const
94 {
95 return str1.substr(0, MAX_CHARS) == str2.substr(0, MAX_CHARS);
96 }
97};
98
99template<>
100struct TruncatedStringEquals<std::string::npos> : public std::equal_to<std::string>
101{};
102
103} // end namespace OrderedMapDetail
104
117template <typename T, std::string_view::size_type MAX_CHARS = std::string_view::npos>
118class OrderedMap {
119public:
120 using storage_type = std::vector<std::pair<std::string, T>>;
121 using index_type = std::unordered_map<std::string, typename storage_type::size_type,
124 using iter_type = typename storage_type::iterator;
125 using const_iter_type = typename storage_type::const_iterator;
126
127private:
128 index_type m_map;
129 storage_type m_vector;
130
131public:
132
133 OrderedMap() = default;
134
135 OrderedMap(const index_type& index, const storage_type& storage)
136 : m_map(index)
137 , m_vector(storage)
138 {
139 }
140
141 const index_type& getIndex() const { return m_map; }
142
143 const storage_type& getStorage() const { return m_vector; }
144
145 std::size_t count(const std::string& key) const {
146 return this->m_map.count(key);
147 }
148
149
150
151 T& operator[](const std::string& key) {
152 if (this->count(key) == 0)
153 this->insert( std::make_pair(key, T()));
154
155 return this->at(key);
156 }
157
158
159 std::size_t erase(const std::string& key) {
160 if (this->count(key) == 0)
161 return 0;
162
163 const std::size_t idx = this->m_map.at(key);
164 this->m_map.erase(key);
165 this->m_vector.erase(this->m_vector.begin() + idx);
166
167 for (const auto& index_pair : this->m_map) {
168 auto target_index = index_pair.second;
169 if (target_index > idx) {
170 --target_index;
171 }
172
173 this->m_map[index_pair.first] = target_index;
174 }
175 return 1;
176 }
177
178
179 void insert(std::pair<std::string,T> key_value_pair) {
180 if (this->count(key_value_pair.first) > 0) {
181 auto iter = m_map.find( key_value_pair.first );
182 const std::size_t idx = iter->second;
183 m_vector[idx] = key_value_pair;
184 } else {
185 const std::size_t idx = m_vector.size();
186 this->m_map.emplace(key_value_pair.first, idx);
187 this->m_vector.push_back(std::move(key_value_pair));
188 }
189 }
190
191
192 T& get(const std::string& key) {
193 auto iter = m_map.find( key );
194 if (iter == m_map.end())
195 {
196 using namespace std::string_literals;
197 auto startsWithSame = OrderedMapDetail::findSimilarStrings(key, m_vector);
198 if (!startsWithSame.empty())
199 {
200 startsWithSame = " Similar entries are "s +
201 startsWithSame + "."s;
202 }
203 throw std::invalid_argument("Key "s + key + " not found."s
204 + startsWithSame);
205 }
206 else {
207 const std::size_t idx = iter->second;
208 return iget(idx);
209 }
210 }
211
212
213 T& iget(std::size_t index) {
214 if (index >= m_vector.size())
215 throw std::invalid_argument("Invalid index");
216 return m_vector[index].second;
217 }
218
219 const T& get(const std::string& key) const {
220 const auto& iter = this->m_map.find( key );
221 if (iter == m_map.end())
222 {
223 auto startsWithSame = OrderedMapDetail::findSimilarStrings(key, m_vector);
224 if (!startsWithSame.empty())
225 {
226 startsWithSame = std::string(" Similar entries are ") +
227 startsWithSame + std::string(".");
228 }
229 using namespace std::string_literals;
230 throw std::invalid_argument("Key "s + key + " not found."s
231 + startsWithSame);
232 }
233 else {
234 const std::size_t idx = iter->second;
235 return iget(idx);
236 }
237 }
238
239
240 const T& iget(std::size_t index) const {
241 if (index >= m_vector.size())
242 {
243 using namespace std::string_literals;
244 throw std::invalid_argument("Invalid index "s +
245 std::to_string(index) +
246 " is larger than container size"s);
247 }
248 return m_vector[index].second;
249 }
250
251 const T& at(std::size_t index) const {
252 return this->iget(index);
253 }
254
255 const T& at(const std::string& key) const {
256 return this->get(key);
257 }
258
259 T& at(std::size_t index) {
260 return this->iget(index);
261 }
262
263 T& at(const std::string& key) {
264 return this->get(key);
265 }
266
267 std::size_t size() const {
268 return m_vector.size();
269 }
270
271
272 const_iter_type begin() const {
273 return m_vector.begin();
274 }
275
276
277 const_iter_type end() const {
278 return m_vector.end();
279 }
280
281 iter_type begin() {
282 return m_vector.begin();
283 }
284
285 iter_type end() {
286 return m_vector.end();
287 }
288
289 iter_type find(const std::string& key) {
290 const auto map_iter = this->m_map.find(key);
291 if (map_iter == this->m_map.end())
292 return this->m_vector.end();
293
294 return std::next(this->m_vector.begin(), map_iter->second);
295 }
296
297 const_iter_type find(const std::string& key) const {
298 const auto map_iter = this->m_map.find(key);
299 if (map_iter == this->m_map.end())
300 return this->m_vector.end();
301
302 return std::next(this->m_vector.begin(), map_iter->second);
303 }
304
305 template<std::size_t n>
306 bool operator==(const OrderedMap<T,n>& data) const {
307 return this->getIndex() == data.getIndex() &&
308 this->getStorage() == data.getStorage();
309 }
310
311 template<class Serializer>
312 void serializeOp(Serializer& serializer)
313 {
314 serializer(m_map);
315 serializer(m_vector);
316 }
317};
318
319}
320
321#endif
Definition OrderedMap.hpp:75
Class for (de-)serializing.
Definition Serializer.hpp:94
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition Exceptions.hpp:30