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 <stdexcept> 9 : #include <string> 10 : 11 : #include "scipp-core_export.h" 12 : #include "scipp/common/except.h" 13 : #include "scipp/common/index.h" 14 : #include "scipp/core/dtype.h" 15 : #include "scipp/core/string.h" 16 : #include "scipp/units/except.h" 17 : #include "scipp/units/unit.h" 18 : 19 : namespace scipp::core { 20 : 21 : class Dimensions; 22 : class Sizes; 23 : class Slice; 24 : 25 : } // namespace scipp::core 26 : 27 : namespace scipp::except { 28 : 29 : struct SCIPP_CORE_EXPORT TypeError : public Error<core::DType> { 30 : explicit TypeError(const std::string &msg); 31 : 32 : template <class... Vars> 33 13 : explicit TypeError(const std::string &msg, Vars &&...vars) 34 13 : : TypeError{msg + (('\'' + pretty_dtype(vars) + "', ") + ...)} {} 35 : }; 36 : 37 : template <> 38 : [[noreturn]] SCIPP_CORE_EXPORT void 39 : throw_mismatch_error(const core::DType &expected, const core::DType &actual, 40 : const std::string &optional_message); 41 : 42 : struct SCIPP_CORE_EXPORT DimensionError : public Error<core::Dimensions> { 43 : explicit DimensionError(const std::string &msg); 44 : DimensionError(scipp::index expectedDim, scipp::index userDim); 45 : }; 46 : 47 : template <> 48 : [[noreturn]] SCIPP_CORE_EXPORT void 49 : throw_mismatch_error(const core::Sizes &expected, const core::Sizes &actual, 50 : const std::string &optional_message); 51 : 52 : template <> 53 : [[noreturn]] SCIPP_CORE_EXPORT void 54 : throw_mismatch_error(const core::Dimensions &expected, 55 : const core::Dimensions &actual, 56 : const std::string &optional_message); 57 : 58 : [[noreturn]] SCIPP_CORE_EXPORT void 59 : throw_dimension_length_error(const core::Dimensions &expected, Dim actual, 60 : scipp::index length); 61 : 62 : struct SCIPP_CORE_EXPORT BinnedDataError : public std::runtime_error { 63 : using std::runtime_error::runtime_error; 64 : }; 65 : 66 : struct SCIPP_CORE_EXPORT SizeError : public std::runtime_error { 67 : using std::runtime_error::runtime_error; 68 : }; 69 : 70 : struct SCIPP_CORE_EXPORT SliceError : public std::out_of_range { 71 : using std::out_of_range::out_of_range; 72 : }; 73 : 74 : struct SCIPP_CORE_EXPORT VariancesError : public std::runtime_error { 75 : using std::runtime_error::runtime_error; 76 : }; 77 : 78 : struct SCIPP_CORE_EXPORT BinEdgeError : public std::runtime_error { 79 : using std::runtime_error::runtime_error; 80 : }; 81 : 82 : struct SCIPP_CORE_EXPORT NotFoundError : public std::runtime_error { 83 : using std::runtime_error::runtime_error; 84 : }; 85 : 86 : struct SCIPP_CORE_EXPORT NotImplementedError : public std::runtime_error { 87 : using std::runtime_error::runtime_error; 88 : }; 89 : 90 : [[noreturn]] SCIPP_CORE_EXPORT void 91 : throw_cannot_have_variances(const DType type); 92 : 93 : } // namespace scipp::except 94 : 95 : namespace scipp::expect { 96 253 : template <class A, class B> void contains(const A &a, const B &b) { 97 : using core::to_string; 98 253 : if (!a.contains(b)) 99 2 : throw except::NotFoundError("Expected " + to_string(a) + " to contain " + 100 : to_string(b) + "."); 101 251 : } 102 : 103 : SCIPP_CORE_EXPORT void includes(const core::Sizes &a, const core::Sizes &b); 104 : SCIPP_CORE_EXPORT void includes(const core::Dimensions &a, 105 : const core::Dimensions &b); 106 : } // namespace scipp::expect 107 : 108 : namespace scipp::core::expect { 109 : template <class A, class B> 110 421784 : void equals(const A &a, const B &b, std::string optional_message = "") { 111 421784 : if (a != b) 112 54 : scipp::except::throw_mismatch_error(a, b, optional_message); 113 421730 : } 114 : 115 : template <class T, class... Ts> 116 26973 : void sizeMatches(const T &range, const Ts &...other) { 117 26973 : if (((scipp::size(range) != scipp::size(other)) || ...)) 118 0 : throw except::SizeError("Expected matching sizes."); 119 26973 : } 120 : 121 : inline auto to_string(const std::string &s) { return s; } 122 : 123 : template <class T> 124 516 : void unit(const T &object, const units::Unit &unit, 125 : std::string optional_message = "") { 126 516 : expect::equals(object.unit(), unit, optional_message); 127 513 : } 128 : 129 : void SCIPP_CORE_EXPORT ndim_is(const Sizes &dims, scipp::index expected); 130 : 131 : // TODO maybe just provide a `slice` function/method and check via that? 132 : void SCIPP_CORE_EXPORT validSlice(const Sizes &sizes, const Slice &slice); 133 : 134 : void SCIPP_CORE_EXPORT validDim(const Dim dim); 135 : void SCIPP_CORE_EXPORT validExtent(const scipp::index size); 136 37486 : template <class T> void canHaveVariances() { 137 37486 : if (!core::canHaveVariances<T>()) 138 5 : except::throw_cannot_have_variances(dtype<T>); 139 37481 : } 140 : 141 : } // namespace scipp::core::expect