0.3.0
Loading...
Searching...
No Matches
KeyedMap.hpp
Go to the documentation of this file.
1// This file is part of INSTINCT, the INS Toolkit for Integrated
2// Navigation Concepts and Training by the Institute of Navigation of
3// the University of Stuttgart, Germany.
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
13
14#pragma once
15
16#include <algorithm>
17#include <map>
18#include <type_traits>
19#include <vector>
20#include <span>
21#include <fmt/format.h>
22
23#include "util/Assert.h"
25
26namespace NAV
27{
28
33template<typename KeyType, typename Scalar, bool unordered = true>
35{
36 public:
37 // ###########################################################################################################
38 // Constructors
39 // ###########################################################################################################
40 //
41 // ###########################################################################################################
42 // Iterators
43 // ###########################################################################################################
44
48 decltype(auto) begin() { return _lookup.begin(); }
52 [[nodiscard]] decltype(auto) begin() const noexcept { return _lookup.begin(); }
56 [[nodiscard]] decltype(auto) cbegin() const noexcept { return _lookup.cbegin(); }
57
61 decltype(auto) end() { return _lookup.end(); }
65 [[nodiscard]] decltype(auto) end() const noexcept { return _lookup.end(); }
69 [[nodiscard]] decltype(auto) cend() const noexcept { return _lookup.cend(); }
70
71 // ###########################################################################################################
72 // Capacity
73 // ###########################################################################################################
74
76 [[nodiscard]] bool empty() const
77 {
78 return size() == 0;
79 }
80
82 [[nodiscard]] size_t size() const
83 {
84 return _lookup.size();
85 }
86
87 // ###########################################################################################################
88 // Modifiers
89 // ###########################################################################################################
90
92 void clear()
93 {
94 _lookup.clear();
95 _data.clear();
96 }
97
100 void addKey(const KeyType& key) { addKeys(std::vector<KeyType>{ key }); }
101
105 void addKey(const KeyType& key, const Scalar& value) { addKeys(std::vector<std::pair<KeyType, Scalar>>{ { key, value } }); }
106
109 void addKeys(std::span<const KeyType> keys)
110 {
111 std::vector<std::pair<KeyType, Scalar>> keyValues;
112 keyValues.reserve(keys.size());
113 for (const KeyType& key : keys)
114 {
115 keyValues.emplace_back(key, Scalar{});
116 }
117 addKeys(keyValues);
118 }
119
123 void addKeys(std::span<const KeyType> keys, std::span<const Scalar> values)
124 {
125 INS_ASSERT_USER_ERROR(keys.size() == values.size(), "Keys and values vector need to be same size");
126
127 std::vector<std::pair<KeyType, Scalar>> keyValues;
128 keyValues.reserve(keys.size());
129 for (size_t i = 0; i < keys.size(); i++)
130 {
131 keyValues.emplace_back(keys[i], values[i]);
132 }
133 addKeys(keyValues);
134 }
135
138 void addKeys(std::span<const std::pair<KeyType, Scalar>> keyValues)
139 {
140 INS_ASSERT_USER_ERROR(!keyValues.empty(), "The vector cannot be empty");
141 INS_ASSERT_USER_ERROR(!_data.contains(keyValues.front().first), "Duplicate keys are not allowed");
142 for ([[maybe_unused]] const auto& keyValue : keyValues)
143 {
144 INS_ASSERT_USER_ERROR(!_lookup.contains(keyValue.first), "Duplicate subkeys are not allowed");
145 }
146
147 _data.emplace(keyValues.front().first, std::vector<Scalar>(keyValues.size()));
148 for (size_t i = 0; i < keyValues.size(); i++)
149 {
150 _lookup[keyValues[i].first] = &_data.at(keyValues.front().first).at(i);
151 _data.at(keyValues.front().first).at(i) = keyValues[i].second;
152 }
153 }
154
155 // ###########################################################################################################
156 // Lookup
157 // ###########################################################################################################
158
163 Scalar& at(const KeyType& key)
164 {
165 return *_lookup.at(key);
166 }
167
172 [[nodiscard]] const Scalar& at(const KeyType& key) const
173 {
174 return *_lookup.at(key);
175 }
176
181 std::vector<Scalar>& at(std::span<const KeyType> keys)
182 {
183 INS_ASSERT_USER_ERROR(!keys.empty(), "The vector cannot be empty");
184 INS_ASSERT_USER_ERROR(_data.at(keys.front()).size() == keys.size(), "The keys vector stored and requested have different length");
185
186 return _data.at(keys.front());
187 }
188
193 [[nodiscard]] const std::vector<Scalar>& at(std::span<const KeyType> keys) const
194 {
195 INS_ASSERT_USER_ERROR(!keys.empty(), "The vector cannot be empty");
196 INS_ASSERT_USER_ERROR(_data.at(keys.front()).size() == keys.size(), "The keys vector stored and requested have different length");
197
198 return _data.at(keys.front());
199 }
200
204 [[nodiscard]] bool contains(const KeyType& key) const
205 {
206 return _lookup.contains(key);
207 }
208
212 [[nodiscard]] bool contains(std::span<const KeyType> keys) const
213 {
214 INS_ASSERT_USER_ERROR(!keys.empty(), "The vector cannot be empty");
215
216 return std::all_of(keys.begin(), keys.end(), [&](const auto& key) { return _lookup.contains(key); });
217 }
218
221 [[nodiscard]] size_t size_of(const KeyType& key) const
222 {
223 return _data.contains(key) ? _data.at(key).size() : (_lookup.contains(key) ? 1 : 0);
224 }
225
226 // ###########################################################################################################
227 // Others
228 // ###########################################################################################################
229
232 [[nodiscard]] std::vector<KeyType> keys() const
233 {
234 std::vector<KeyType> keys;
235 keys.reserve(_lookup.size());
236 for (const auto& keyVal : _lookup)
237 {
238 keys.push_back(keyVal.first);
239 }
240 return keys;
241 }
242
243 private:
246
248 std::conditional_t<unordered,
250 std::map<KeyType, std::vector<Scalar>>>
252};
253
254} // namespace NAV
255
256#ifndef DOXYGEN_IGNORE
257
259template<typename KeyType, typename Scalar, bool unordered>
260struct fmt::formatter<NAV::KeyedMap<KeyType, Scalar, unordered>> : fmt::formatter<std::string>
261{
266 auto format(const NAV::KeyedMap<KeyType, Scalar, unordered>& map, format_context& ctx) const
267 {
268 std::string result;
269 auto length = static_cast<size_t>(map.size());
270
271 if (length > 0)
272 {
273 std::vector<std::string> rowKeysStr;
274 std::vector<size_t> rowKeysLength;
275 rowKeysStr.reserve(length);
276 rowKeysLength.reserve(length);
277 size_t rowKeysColSpace = 0;
278 for (const auto& keyVal : map)
279 {
280 rowKeysStr.push_back(fmt::format("{}", keyVal.first));
281 auto rowKeyLength = rowKeysStr.back().length();
282 rowKeysColSpace = std::max(rowKeysColSpace, rowKeyLength);
283 rowKeysLength.push_back(rowKeyLength);
284 }
285
286 size_t colLength = 9UL;
287
288 result.reserve(length * (rowKeysColSpace + 2 + colLength));
289
290 size_t r = 0;
291 for (const auto& keyVal : map)
292 {
293 if (rowKeysColSpace > rowKeysLength.at(r))
294 {
295 result += std::string(rowKeysColSpace - rowKeysLength.at(r), ' '); // Spaces in front of row name (if too short)
296 }
297 result += rowKeysStr.at(r);
298
299 std::string tmp = fmt::format(" {:> {}.{}g}", *keyVal.second, colLength, colLength - 2);
300 if (tmp.length() > colLength)
301 {
302 tmp = fmt::format(" {:> {}.{}g}", *keyVal.second, colLength, colLength - 6);
303 }
304 result += tmp;
305
306 if (r != length - 1) { result += '\n'; }
307 r++;
308 }
309 }
310
311 return fmt::formatter<std::string>::format(result, ctx);
312 }
313};
314
315#endif
316
321template<typename KeyType, typename Scalar, bool unordered>
322std::ostream& operator<<(std::ostream& os, const NAV::KeyedMap<KeyType, Scalar, unordered>& obj)
323{
324 return os << fmt::format("{}", obj);
325}
Assertion helpers.
#define INS_ASSERT_USER_ERROR(_EXP, _MSG)
Assert function with message.
Definition Assert.h:21
std::ostream & operator<<(std::ostream &os, const NAV::KeyedMap< KeyType, Scalar, unordered > &obj)
Stream insertion operator overload.
Definition KeyedMap.hpp:322
Unordered map wrapper.
ankerl::unordered_dense::map< Key, T > unordered_map
Unordered map type.
Definition Unordered_map.hpp:34
Similar to KeyedMatrix, but memory is allocated in a map and therefore never reallocated.
Definition KeyedMap.hpp:35
void addKeys(std::span< const KeyType > keys, std::span< const Scalar > values)
Adds a continuous vector for the keys to the data storage.
Definition KeyedMap.hpp:123
std::conditional_t< unordered, unordered_map< KeyType, std::vector< Scalar > >, std::map< KeyType, std::vector< Scalar > > > _data
Storage container.
Definition KeyedMap.hpp:251
decltype(auto) cbegin() const noexcept
Returns an iterator to the first element.
Definition KeyedMap.hpp:56
decltype(auto) cend() const noexcept
Returns an iterator to the element following the last element of.
Definition KeyedMap.hpp:69
std::vector< Scalar > & at(std::span< const KeyType > keys)
Returns a reference to the mapped value of the element with specified keys. If no such element exists...
Definition KeyedMap.hpp:181
decltype(auto) end()
Returns an iterator to the element following the last element of.
Definition KeyedMap.hpp:61
decltype(auto) end() const noexcept
Returns an iterator to the element following the last element of.
Definition KeyedMap.hpp:65
unordered_map< KeyType, Scalar * > _lookup
Lookup for individual keys.
Definition KeyedMap.hpp:245
const std::vector< Scalar > & at(std::span< const KeyType > keys) const
Returns a reference to the mapped value of the element with specified keys. If no such element exists...
Definition KeyedMap.hpp:193
bool contains(std::span< const KeyType > keys) const
Checks if there are elements with keys equivalent to keys in the container.
Definition KeyedMap.hpp:212
Scalar & at(const KeyType &key)
Returns a reference to the mapped value of the element with specified key. If no such element exists,...
Definition KeyedMap.hpp:163
void addKey(const KeyType &key, const Scalar &value)
Adds a single element for the key to the data storage.
Definition KeyedMap.hpp:105
const Scalar & at(const KeyType &key) const
Returns a reference to the mapped value of the element with specified key. If no such element exists,...
Definition KeyedMap.hpp:172
void addKey(const KeyType &key)
Adds a single element for the key to the data storage.
Definition KeyedMap.hpp:100
bool contains(const KeyType &key) const
Checks if there is an element with key equivalent to key in the container.
Definition KeyedMap.hpp:204
void addKeys(std::span< const std::pair< KeyType, Scalar > > keyValues)
Adds a continuous vector for the keys to the data storage.
Definition KeyedMap.hpp:138
std::vector< KeyType > keys() const
Collect all keys.
Definition KeyedMap.hpp:232
size_t size_of(const KeyType &key) const
Returns the size of parameters represented by the key.
Definition KeyedMap.hpp:221
size_t size() const
Returns the number of elements in the container.
Definition KeyedMap.hpp:82
decltype(auto) begin()
Returns an iterator to the first element.
Definition KeyedMap.hpp:48
void addKeys(std::span< const KeyType > keys)
Adds a continuous vector for the keys to the data storage.
Definition KeyedMap.hpp:109
bool empty() const
Checks if the container has no elements.
Definition KeyedMap.hpp:76
void clear()
Erases all elements from the container. After this call, size() returns zero.
Definition KeyedMap.hpp:92
decltype(auto) begin() const noexcept
Returns an iterator to the first element.
Definition KeyedMap.hpp:52