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::transform(str.begin(), str.end(), 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::transform(upper.begin(), upper.end(), upper.begin(),
53 toUpper);
54
55 if(upper.find(str) != std::string::npos || str.find(upper) != std::string::npos)
56 {
57 alternatives.insert(entry.first);
58 }
59 }
60
61 if (alternatives.empty())
62 {
63 return {};
64 }
65
66 std::string concatedStr;
67 for (const auto& alt : alternatives) {
68 concatedStr += alt;
69 concatedStr += ", ";
70 }
71 return concatedStr.substr(0, concatedStr.size()-2);
72}
73
74template<std::string_view::size_type MAX_CHARS>
76{
77public:
78 std::size_t operator()(std::string_view key) const
79 {
80 return hasher(key.substr(0, MAX_CHARS));
81 }
82private:
83 std::hash<std::string_view> hasher;
84};
85
86
87template<>
88class TruncatedStringHash<std::string_view::npos> : public std::hash<std::string_view>
89{};
90
91template<std::string_view::size_type MAX_CHARS>
93{
94 bool operator()(std::string_view str1, std::string_view str2) const
95 {
96 return str1.substr(0, MAX_CHARS) == str2.substr(0, MAX_CHARS);
97 }
98};
99
100template<>
101struct TruncatedStringEquals<std::string::npos> : public std::equal_to<std::string>
102{};
103
104} // end namespace OrderedMapDetail
105
118template <typename T, std::string_view::size_type MAX_CHARS = std::string_view::npos>
119class OrderedMap {
120public:
121 using storage_type = std::vector<std::pair<std::string, T>>;
122 using index_type = std::unordered_map<std::string, typename storage_type::size_type,
125 using iter_type = typename storage_type::iterator;
126 using const_iter_type = typename storage_type::const_iterator;
127
128private:
129 index_type m_map;
130 storage_type m_vector;
131
132public:
133
134 OrderedMap() = default;
135
136 OrderedMap(const index_type& index, const storage_type& storage)
137 : m_map(index)
138 , m_vector(storage)
139 {
140 }
141
142 const index_type& getIndex() const { return m_map; }
143
144 const storage_type& getStorage() const { return m_vector; }
145
146 std::size_t count(const std::string& key) const {
147 return this->m_map.count(key);
148 }
149
150
151
152 T& operator[](const std::string& key) {
153 if (this->count(key) == 0)
154 this->insert( std::make_pair(key, T()));
155
156 return this->at(key);
157 }
158
159
160 std::size_t erase(const std::string& key) {
161 if (this->count(key) == 0)
162 return 0;
163
164 const std::size_t idx = this->m_map.at(key);
165 this->m_map.erase(key);
166 this->m_vector.erase(this->m_vector.begin() + idx);
167
168 for (const auto& index_pair : this->m_map) {
169 auto target_index = index_pair.second;
170 if (target_index > idx) {
171 --target_index;
172 }
173
174 this->m_map[index_pair.first] = target_index;
175 }
176 return 1;
177 }
178
179
180 void insert(std::pair<std::string,T> key_value_pair) {
181 if (this->count(key_value_pair.first) > 0) {
182 auto iter = m_map.find( key_value_pair.first );
183 const std::size_t idx = iter->second;
184 m_vector[idx] = key_value_pair;
185 } else {
186 const std::size_t idx = m_vector.size();
187 this->m_map.emplace(key_value_pair.first, idx);
188 this->m_vector.push_back(std::move(key_value_pair));
189 }
190 }
191
192
193 T& get(const std::string& key) {
194 auto iter = m_map.find( key );
195 if (iter == m_map.end())
196 {
197 using namespace std::string_literals;
198 auto startsWithSame = OrderedMapDetail::findSimilarStrings(key, m_vector);
199 if (!startsWithSame.empty())
200 {
201 startsWithSame = " Similar entries are "s +
202 startsWithSame + "."s;
203 }
204 throw std::invalid_argument("Key "s + key + " not found."s
205 + startsWithSame);
206 }
207 else {
208 const std::size_t idx = iter->second;
209 return iget(idx);
210 }
211 }
212
213
214 T& iget(std::size_t index) {
215 if (index >= m_vector.size())
216 throw std::invalid_argument("Invalid index");
217 return m_vector[index].second;
218 }
219
220 const T& get(const std::string& key) const {
221 const auto& iter = this->m_map.find( key );
222 if (iter == m_map.end())
223 {
224 auto startsWithSame = OrderedMapDetail::findSimilarStrings(key, m_vector);
225 if (!startsWithSame.empty())
226 {
227 startsWithSame = std::string(" Similar entries are ") +
228 startsWithSame + std::string(".");
229 }
230 using namespace std::string_literals;
231 throw std::invalid_argument("Key "s + key + " not found."s
232 + startsWithSame);
233 }
234 else {
235 const std::size_t idx = iter->second;
236 return iget(idx);
237 }
238 }
239
240
241 const T& iget(std::size_t index) const {
242 if (index >= m_vector.size())
243 {
244 using namespace std::string_literals;
245 throw std::invalid_argument("Invalid index "s +
246 std::to_string(index) +
247 " is larger than container size"s);
248 }
249 return m_vector[index].second;
250 }
251
252 const T& at(std::size_t index) const {
253 return this->iget(index);
254 }
255
256 const T& at(const std::string& key) const {
257 return this->get(key);
258 }
259
260 T& at(std::size_t index) {
261 return this->iget(index);
262 }
263
264 T& at(const std::string& key) {
265 return this->get(key);
266 }
267
268 std::size_t size() const {
269 return m_vector.size();
270 }
271
272
273 const_iter_type begin() const {
274 return m_vector.begin();
275 }
276
277
278 const_iter_type end() const {
279 return m_vector.end();
280 }
281
282 iter_type begin() {
283 return m_vector.begin();
284 }
285
286 iter_type end() {
287 return m_vector.end();
288 }
289
290 iter_type find(const std::string& key) {
291 const auto map_iter = this->m_map.find(key);
292 if (map_iter == this->m_map.end())
293 return this->m_vector.end();
294
295 return std::next(this->m_vector.begin(), map_iter->second);
296 }
297
298 const_iter_type find(const std::string& key) const {
299 const auto map_iter = this->m_map.find(key);
300 if (map_iter == this->m_map.end())
301 return this->m_vector.end();
302
303 return std::next(this->m_vector.begin(), map_iter->second);
304 }
305
306 template<std::size_t n>
307 bool operator==(const OrderedMap<T,n>& data) const {
308 return this->getIndex() == data.getIndex() &&
309 this->getStorage() == data.getStorage();
310 }
311
312 template<class Serializer>
313 void serializeOp(Serializer& serializer)
314 {
315 serializer(m_map);
316 serializer(m_vector);
317 }
318};
319
320}
321
322#endif
Definition OrderedMap.hpp:76
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