LCOV - code coverage report
Current view: top level - core - sizes.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 108 122 88.5 %
Date: 2024-11-17 01:47:58 Functions: 25 26 96.2 %

          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 &params) 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

Generated by: LCOV version 1.14