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-12-01 01:56:34 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     1539115 : template <class T> void expectUnique(const T &map, const Dim label) {
      15     1539115 :   if (map.contains(label))
      16          12 :     throw except::DimensionError("Duplicate dimension.");
      17     1539103 : }
      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       12420 :   for (const auto &key : *this)
      42        7823 :     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    23310380 : small_stable_map<Key, Value, Capacity>::find(const Key &key) const {
      56    23310380 :   return std::find(begin(), end(), key);
      57             : }
      58             : 
      59             : template <class Key, class Value, int16_t Capacity>
      60     9999357 : bool small_stable_map<Key, Value, Capacity>::contains(const Key &key) const {
      61     9999357 :   return find(key) != end();
      62             : }
      63             : 
      64             : template <class Key, class Value, int16_t Capacity>
      65             : scipp::index
      66    13311023 : small_stable_map<Key, Value, Capacity>::index(const Key &key) const {
      67    13311023 :   const auto it = find(key);
      68    13311023 :   if (it == end())
      69          21 :     throw_dimension_not_found_error(*this, key);
      70    13311002 :   return std::distance(begin(), it);
      71             : }
      72             : 
      73             : template <class Key, class Value, int16_t Capacity>
      74             : const Value &
      75     7288448 : small_stable_map<Key, Value, Capacity>::operator[](const Key &key) const {
      76     7288448 :   return at(key);
      77             : }
      78             : 
      79             : template <class Key, class Value, int16_t Capacity>
      80     8370744 : const Value &small_stable_map<Key, Value, Capacity>::at(const Key &key) const {
      81     8370744 :   return m_values[index(key)];
      82             : }
      83             : 
      84             : template <class Key, class Value, int16_t Capacity>
      85      882890 : void small_stable_map<Key, Value, Capacity>::assign(const Key &key,
      86             :                                                     const Value &value) {
      87      882890 :   m_values[index(key)] = value;
      88      882890 : }
      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     1526526 : void small_stable_map<Key, Value, Capacity>::insert_right(const Key &key,
     100             :                                                           const Value &value) {
     101     1526526 :   expectUnique(*this, key);
     102     1526518 :   m_keys.push_back(key);
     103     1526518 :   m_values.push_back(value);
     104     1526518 : }
     105             : 
     106             : template <class Key, class Value, int16_t Capacity>
     107      453322 : void small_stable_map<Key, Value, Capacity>::erase(const Key &key) {
     108      453322 :   const auto i = index(key);
     109      453314 :   m_keys.erase(m_keys.begin() + i);
     110      453314 :   m_values.erase(m_values.begin() + i);
     111      453314 : }
     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       13577 : void small_stable_map<Key, Value, Capacity>::replace_key(const Key &key,
     121             :                                                          const Key &new_key) {
     122       13577 :   if (key != new_key)
     123       12344 :     expectUnique(*this, new_key);
     124       13576 :   m_keys[index(key)] = new_key;
     125       13576 : }
     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      882890 : void Sizes::resize(const Dim dim, const scipp::index size) {
     141      882890 :   expect::validExtent(size);
     142      882890 :   assign(dim, size);
     143      882890 : }
     144             : 
     145             : /// Return true if all dimensions of other contained in *this, with same size.
     146     1216198 : bool Sizes::includes(const Sizes &sizes) const {
     147     2432396 :   return std::all_of(sizes.begin(), sizes.end(), [&](const auto &dim) {
     148     1066160 :     return contains(dim) && at(dim) == sizes[dim];
     149     2432396 :   });
     150             : }
     151             : 
     152      715225 : Sizes Sizes::slice(const Slice &params) const {
     153      715225 :   core::expect::validSlice(*this, params);
     154      715224 :   Sizes sliced(*this);
     155      715224 :   if (params == Slice{})
     156           4 :     return sliced;
     157      715220 :   if (params.isRange()) {
     158             :     const auto remainder =
     159      707915 :         (params.end() - params.begin()) % params.stride() != 0;
     160      707915 :     sliced.resize(params.dim(),
     161           0 :                   std::max(scipp::index{0},
     162     1415830 :                            (params.end() - params.begin()) / params.stride() +
     163      707915 :                                remainder));
     164             :   } else
     165        7305 :     sliced.erase(params.dim());
     166      715220 :   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       34290 : bool is_edges(const Sizes &sizes, const Sizes &dataSizes, const Dim dim) {
     197       34290 :   if (dim == Dim::Invalid || !dataSizes.contains(dim))
     198       12436 :     return false;
     199             :   // Without this if, !sizes.contains(d) below would identify 2d coords
     200             :   // with a length-2 dim as non-edge.
     201       21854 :   if (!sizes.empty()) {
     202       64137 :     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       42301 :       if (d != dim && !(sizes.contains(d) && sizes[d] == dataSizes[d]))
     207          16 :         return false;
     208             :     }
     209             :   }
     210       21838 :   const auto size = dataSizes[dim];
     211       21838 :   return size == (sizes.contains(dim) ? sizes[dim] + 1 : 2);
     212             : }
     213             : 
     214             : } // namespace scipp::core

Generated by: LCOV version 1.14