opm-common
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 
36 namespace Opm {
37 
38 namespace OrderedMapDetail {
39 
40 template<class T, class A>
41 std::string
42 findSimilarStrings(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 
73 template<std::string_view::size_type MAX_CHARS>
75 {
76 public:
77  std::size_t operator()(std::string_view key) const
78  {
79  return hasher(key.substr(0, MAX_CHARS));
80  }
81 private:
82  std::hash<std::string_view> hasher;
83 };
84 
85 
86 template<>
87 class TruncatedStringHash<std::string_view::npos> : public std::hash<std::string_view>
88 {};
89 
90 template<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 
99 template<>
100 struct TruncatedStringEquals<std::string::npos> : public std::equal_to<std::string>
101 {};
102 
103 } // end namespace OrderedMapDetail
104 
117 template <typename T, std::string_view::size_type MAX_CHARS = std::string_view::npos>
118 class OrderedMap {
119 public:
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 
127 private:
128  index_type m_map;
129  storage_type m_vector;
130 
131 public:
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:74
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
A map with iteration in the order of insertion.
Definition: OrderedMap.hpp:118
Class for (de-)serializing.
Definition: Serializer.hpp:94