Line data Source code
1 : // SPDX-License-Identifier: BSD-3-Clause
2 : // Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
3 : /// @file
4 : /// @author Simon Heybrock
5 : #include <algorithm>
6 :
7 : #include "rename.h"
8 : #include "scipp/core/except.h"
9 : #include "scipp/core/sizes.h"
10 :
11 : namespace scipp::core {
12 :
13 : namespace {
14 1514165 : template <class T> void expectUnique(const T &map, const Dim label) {
15 1514165 : if (map.contains(label))
16 12 : throw except::DimensionError("Duplicate dimension.");
17 1514153 : }
18 :
19 21 : template <class T> std::string to_string(const T &map) {
20 21 : std::string repr("[");
21 55 : for (const auto &key : map)
22 34 : repr += to_string(key) + ":" + std::to_string(map[key]) + ", ";
23 21 : repr += "]";
24 21 : return repr;
25 0 : }
26 :
27 : template <class T>
28 21 : void throw_dimension_not_found_error(const T &expected, Dim actual) {
29 21 : throw except::DimensionError{"Expected dimension to be in " +
30 : to_string(expected) + ", got " +
31 : to_string(actual) + '.'};
32 : }
33 :
34 : } // namespace
35 :
36 : template <class Key, class Value, int16_t Capacity>
37 4610 : bool small_stable_map<Key, Value, Capacity>::operator==(
38 : const small_stable_map &other) const noexcept {
39 4610 : if (size() != other.size())
40 7 : return false;
41 12404 : for (const auto &key : *this)
42 7807 : if (!other.contains(key) || at(key) != other.at(key))
43 6 : return false;
44 4597 : return true;
45 : }
46 :
47 : template <class Key, class Value, int16_t Capacity>
48 4547 : bool small_stable_map<Key, Value, Capacity>::operator!=(
49 : const small_stable_map &other) const noexcept {
50 4547 : return !operator==(other);
51 : }
52 :
53 : template <class Key, class Value, int16_t Capacity>
54 : typename boost::container::small_vector<Key, Capacity>::const_iterator
55 23036818 : small_stable_map<Key, Value, Capacity>::find(const Key &key) const {
56 23036818 : return std::find(begin(), end(), key);
57 : }
58 :
59 : template <class Key, class Value, int16_t Capacity>
60 9874137 : bool small_stable_map<Key, Value, Capacity>::contains(const Key &key) const {
61 9874137 : return find(key) != end();
62 : }
63 :
64 : template <class Key, class Value, int16_t Capacity>
65 : scipp::index
66 13162681 : small_stable_map<Key, Value, Capacity>::index(const Key &key) const {
67 13162681 : const auto it = find(key);
68 13162681 : if (it == end())
69 21 : throw_dimension_not_found_error(*this, key);
70 13162660 : return std::distance(begin(), it);
71 : }
72 :
73 : template <class Key, class Value, int16_t Capacity>
74 : const Value &
75 7195557 : small_stable_map<Key, Value, Capacity>::operator[](const Key &key) const {
76 7195557 : return at(key);
77 : }
78 :
79 : template <class Key, class Value, int16_t Capacity>
80 8259466 : const Value &small_stable_map<Key, Value, Capacity>::at(const Key &key) const {
81 8259466 : return m_values[index(key)];
82 : }
83 :
84 : template <class Key, class Value, int16_t Capacity>
85 877404 : void small_stable_map<Key, Value, Capacity>::assign(const Key &key,
86 : const Value &value) {
87 877404 : m_values[index(key)] = value;
88 877404 : }
89 :
90 : template <class Key, class Value, int16_t Capacity>
91 245 : void small_stable_map<Key, Value, Capacity>::insert_left(const Key &key,
92 : const Value &value) {
93 245 : expectUnique(*this, key);
94 242 : m_keys.insert(m_keys.begin(), key);
95 242 : m_values.insert(m_values.begin(), value);
96 242 : }
97 :
98 : template <class Key, class Value, int16_t Capacity>
99 1501671 : void small_stable_map<Key, Value, Capacity>::insert_right(const Key &key,
100 : const Value &value) {
101 1501671 : expectUnique(*this, key);
102 1501663 : m_keys.push_back(key);
103 1501663 : m_values.push_back(value);
104 1501663 : }
105 :
106 : template <class Key, class Value, int16_t Capacity>
107 452244 : void small_stable_map<Key, Value, Capacity>::erase(const Key &key) {
108 452244 : const auto i = index(key);
109 452236 : m_keys.erase(m_keys.begin() + i);
110 452236 : m_values.erase(m_values.begin() + i);
111 452236 : }
112 :
113 : template <class Key, class Value, int16_t Capacity>
114 1 : void small_stable_map<Key, Value, Capacity>::clear() noexcept {
115 1 : m_keys.clear();
116 1 : m_values.clear();
117 1 : }
118 :
119 : template <class Key, class Value, int16_t Capacity>
120 13482 : void small_stable_map<Key, Value, Capacity>::replace_key(const Key &key,
121 : const Key &new_key) {
122 13482 : if (key != new_key)
123 12249 : expectUnique(*this, new_key);
124 13481 : m_keys[index(key)] = new_key;
125 13481 : }
126 :
127 : template class small_stable_map<Dim, scipp::index, NDIM_STACK>;
128 :
129 78 : void Sizes::set(const Dim dim, const scipp::index size) {
130 78 : expect::validDim(dim);
131 78 : expect::validExtent(size);
132 78 : if (contains(dim) && operator[](dim) != size)
133 0 : throw except::DimensionError(
134 0 : "Inconsistent size for dim '" + to_string(dim) + "', given " +
135 0 : std::to_string(at(dim)) + ", requested " + std::to_string(size));
136 78 : if (!contains(dim))
137 78 : insert_right(dim, size);
138 78 : }
139 :
140 877404 : void Sizes::resize(const Dim dim, const scipp::index size) {
141 877404 : expect::validExtent(size);
142 877404 : assign(dim, size);
143 877404 : }
144 :
145 : /// Return true if all dimensions of other contained in *this, with same size.
146 1203432 : bool Sizes::includes(const Sizes &sizes) const {
147 2406864 : return std::all_of(sizes.begin(), sizes.end(), [&](const auto &dim) {
148 1047805 : return contains(dim) && at(dim) == sizes[dim];
149 2406864 : });
150 : }
151 :
152 714599 : Sizes Sizes::slice(const Slice ¶ms) const {
153 714599 : core::expect::validSlice(*this, params);
154 714598 : Sizes sliced(*this);
155 714598 : if (params == Slice{})
156 4 : return sliced;
157 714594 : if (params.isRange()) {
158 : const auto remainder =
159 707289 : (params.end() - params.begin()) % params.stride() != 0;
160 707289 : sliced.resize(params.dim(),
161 0 : std::max(scipp::index{0},
162 1414578 : (params.end() - params.begin()) / params.stride() +
163 707289 : remainder));
164 : } else
165 7305 : sliced.erase(params.dim());
166 714594 : return sliced;
167 0 : }
168 :
169 908 : Sizes Sizes::rename_dims(const std::vector<std::pair<Dim, Dim>> &names,
170 : const bool fail_on_unknown) const {
171 908 : return detail::rename_dims(*this, names, fail_on_unknown);
172 : }
173 :
174 : namespace {
175 7 : Sizes concat2(const Sizes &a, const Sizes &b, const Dim dim) {
176 7 : Sizes out = a.contains(dim) ? a.slice({dim, 0}) : a;
177 7 : out.set(dim, (a.contains(dim) ? a[dim] : 1) + (b.contains(dim) ? b[dim] : 1));
178 7 : return out;
179 0 : }
180 : } // namespace
181 :
182 7 : Sizes concat(const scipp::span<const Sizes> sizes, const Dim dim) {
183 7 : auto out = sizes.front();
184 14 : for (scipp::index i = 1; i < scipp::size(sizes); ++i)
185 7 : out = concat2(out, sizes[i], dim);
186 7 : return out;
187 0 : }
188 :
189 0 : Sizes merge(const Sizes &a, const Sizes &b) {
190 0 : auto out(a);
191 0 : for (const auto &dim : b)
192 0 : out.set(dim, b[dim]);
193 0 : return out;
194 0 : }
195 :
196 34284 : bool is_edges(const Sizes &sizes, const Sizes &dataSizes, const Dim dim) {
197 34284 : if (dim == Dim::Invalid || !dataSizes.contains(dim))
198 12428 : return false;
199 : // Without this if, !sizes.contains(d) below would identify 2d coords
200 : // with a length-2 dim as non-edge.
201 21856 : if (!sizes.empty()) {
202 64141 : for (const auto &d : dataSizes) {
203 : // !(sizes[d] == dataSizes[d]) assumes that a coordinate can only be
204 : // bin-edges in one dim. I.e. if its size does not match the data in `d`,
205 : // it cannot be a bin-edge in `dim`.
206 42303 : if (d != dim && !(sizes.contains(d) && sizes[d] == dataSizes[d]))
207 16 : return false;
208 : }
209 : }
210 21840 : const auto size = dataSizes[dim];
211 21840 : return size == (sizes.contains(dim) ? sizes[dim] + 1 : 2);
212 : }
213 :
214 : } // namespace scipp::core
|