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 1467041 : template <class T> void expectUnique(const T &map, const Dim label) {
15 1467041 : if (map.contains(label))
16 12 : throw except::DimensionError("Duplicate dimension.");
17 1467029 : }
18 :
19 21 : template <class T> std::string to_string(const T &map) {
20 21 : std::string repr("[");
21 76 : 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 4557 : bool small_stable_map<Key, Value, Capacity>::operator==(
38 : const small_stable_map &other) const noexcept {
39 4557 : if (size() != other.size())
40 7 : return false;
41 16772 : for (const auto &key : *this)
42 7678 : if (!other.contains(key) || at(key) != other.at(key))
43 6 : return false;
44 4544 : return true;
45 : }
46 :
47 : template <class Key, class Value, int16_t Capacity>
48 4494 : bool small_stable_map<Key, Value, Capacity>::operator!=(
49 : const small_stable_map &other) const noexcept {
50 4494 : 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 22546950 : small_stable_map<Key, Value, Capacity>::find(const Key &key) const {
56 22546950 : return std::find(begin(), end(), key);
57 : }
58 :
59 : template <class Key, class Value, int16_t Capacity>
60 9634444 : bool small_stable_map<Key, Value, Capacity>::contains(const Key &key) const {
61 19268888 : return find(key) != end();
62 : }
63 :
64 : template <class Key, class Value, int16_t Capacity>
65 : scipp::index
66 12912506 : small_stable_map<Key, Value, Capacity>::index(const Key &key) const {
67 12912506 : const auto it = find(key);
68 25825012 : if (it == end())
69 21 : throw_dimension_not_found_error(*this, key);
70 12912485 : return std::distance(begin(), it);
71 : }
72 :
73 : template <class Key, class Value, int16_t Capacity>
74 : const Value &
75 7045293 : small_stable_map<Key, Value, Capacity>::operator[](const Key &key) const {
76 7045293 : return at(key);
77 : }
78 :
79 : template <class Key, class Value, int16_t Capacity>
80 8085454 : const Value &small_stable_map<Key, Value, Capacity>::at(const Key &key) const {
81 16170897 : return m_values[index(key)];
82 : }
83 :
84 : template <class Key, class Value, int16_t Capacity>
85 872486 : void small_stable_map<Key, Value, Capacity>::assign(const Key &key,
86 : const Value &value) {
87 872486 : m_values[index(key)] = value;
88 872486 : }
89 :
90 : template <class Key, class Value, int16_t Capacity>
91 240 : void small_stable_map<Key, Value, Capacity>::insert_left(const Key &key,
92 : const Value &value) {
93 240 : expectUnique(*this, key);
94 237 : m_keys.insert(m_keys.begin(), key);
95 237 : m_values.insert(m_values.begin(), value);
96 237 : }
97 :
98 : template <class Key, class Value, int16_t Capacity>
99 1455198 : void small_stable_map<Key, Value, Capacity>::insert_right(const Key &key,
100 : const Value &value) {
101 1455198 : expectUnique(*this, key);
102 1455190 : m_keys.push_back(key);
103 1455190 : m_values.push_back(value);
104 1455190 : }
105 :
106 : template <class Key, class Value, int16_t Capacity>
107 446932 : void small_stable_map<Key, Value, Capacity>::erase(const Key &key) {
108 446932 : const auto i = index(key);
109 893848 : m_keys.erase(m_keys.begin() + i);
110 893848 : m_values.erase(m_values.begin() + i);
111 446924 : }
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 12811 : void small_stable_map<Key, Value, Capacity>::replace_key(const Key &key,
121 : const Key &new_key) {
122 12811 : if (key != new_key)
123 11603 : expectUnique(*this, new_key);
124 12810 : m_keys[index(key)] = new_key;
125 12810 : }
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 872486 : void Sizes::resize(const Dim dim, const scipp::index size) {
141 872486 : expect::validExtent(size);
142 872486 : assign(dim, size);
143 872486 : }
144 :
145 : /// Return true if all dimensions of other contained in *this, with same size.
146 1183538 : bool Sizes::includes(const Sizes &sizes) const {
147 2367076 : return std::all_of(sizes.begin(), sizes.end(), [&](const auto &dim) {
148 1024494 : return contains(dim) && at(dim) == sizes[dim];
149 2367076 : });
150 : }
151 :
152 713413 : Sizes Sizes::slice(const Slice ¶ms) const {
153 713413 : core::expect::validSlice(*this, params);
154 713412 : Sizes sliced(*this);
155 713412 : if (params == Slice{})
156 4 : return sliced;
157 713408 : if (params.isRange()) {
158 : const auto remainder =
159 706319 : (params.end() - params.begin()) % params.stride() != 0;
160 706319 : sliced.resize(params.dim(),
161 0 : std::max(scipp::index{0},
162 1412638 : (params.end() - params.begin()) / params.stride() +
163 706319 : remainder));
164 : } else
165 7089 : sliced.erase(params.dim());
166 713408 : return sliced;
167 0 : }
168 :
169 893 : Sizes Sizes::rename_dims(const std::vector<std::pair<Dim, Dim>> &names,
170 : const bool fail_on_unknown) const {
171 893 : 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 33104 : bool is_edges(const Sizes &sizes, const Sizes &dataSizes, const Dim dim) {
197 33104 : if (dim == Dim::Invalid || !dataSizes.contains(dim))
198 12144 : return false;
199 : // Without this if, !sizes.contains(d) below would identify 2d coords
200 : // with a length-2 dim as non-edge.
201 20960 : if (!sizes.empty()) {
202 82916 : 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 41016 : if (d != dim && !(sizes.contains(d) && sizes[d] == dataSizes[d]))
207 16 : return false;
208 : }
209 : }
210 20944 : const auto size = dataSizes[dim];
211 20944 : return size == (sizes.contains(dim) ? sizes[dim] + 1 : 2);
212 : }
213 :
214 : } // namespace scipp::core
|