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 : #pragma once 6 : 7 : #include <algorithm> 8 : #include <tuple> 9 : 10 : #include "scipp/core/except.h" 11 : 12 : namespace scipp::core { 13 : 14 : /// Return params for computing bin index for linear edges (constant bin width). 15 22721837 : constexpr static auto linear_edge_params = [](const auto &edges) { 16 22721837 : auto len = scipp::size(edges) - 1; 17 22721837 : const auto offset = edges.front(); 18 22721837 : const auto nbin = len; 19 22721837 : const auto scale = static_cast<double>(nbin) / (edges.back() - edges.front()); 20 22721837 : return std::tuple{offset, nbin, scale}; 21 : }; 22 : 23 : namespace expect::histogram { 24 1327 : template <class T> void sorted_edges(const T &edges) { 25 1327 : if (!std::is_sorted(edges.begin(), edges.end())) 26 1 : throw except::BinEdgeError("Bin edges of histogram must be sorted."); 27 1326 : } 28 : } // namespace expect::histogram 29 : 30 : template <class Index, class T, class Edges, class Params> 31 30757173 : Index get_bin(const T &x, const Edges &edges, const Params ¶ms) { 32 : // Explicitly check for x outside edges here as otherwise we may run into an 33 : // integer overflow when converting the "bin" computation result to `Index`. 34 30757173 : if (x < edges.front() || x >= edges.back()) 35 109991 : return -1; 36 : // If x is NaN we also return early as it cannot be in any bin. 37 : if constexpr (!std::is_same_v<T, time_point>) 38 30647073 : if (std::isnan(x)) 39 4 : return -1; 40 30647178 : const auto [offset, nbin, scale] = params; 41 30647178 : Index bin = (x - offset) * scale; 42 30647178 : bin = std::clamp(bin, Index(0), Index(nbin - 1)); 43 30647178 : if (x < edges[bin]) { 44 88 : return bin - 1; 45 30647090 : } else if (x >= edges[bin + 1]) { 46 2211 : return bin + 1; 47 : } else { 48 30644879 : return bin; 49 : } 50 : } 51 : 52 : } // namespace scipp::core