32 #include <initializer_list>
35 #include <type_traits>
40 namespace histogram_impl {
48 template<
typename T, std::
size_t NDimensions>
51 using Index = std::array<std::size_t, NDimensions>;
55 NArray(
const NArray&) =
default;
56 NArray(NArray&&) =
default;
57 NArray& operator=(
const NArray&) =
default;
58 NArray& operator=(NArray&&) =
default;
62 constexpr
const Index& size()
const {
return m_size; }
64 constexpr
const T& operator[](
Index idx)
const {
return m_data[linear(idx)]; }
66 constexpr
T& operator[](
Index idx) {
return m_data[linear(idx)]; }
73 constexpr std::size_t linear(
Index idx)
const;
74 constexpr
bool within_bounds(
Index idx)
const;
153 template<
typename T,
typename... Axes>
156 using Data = dfe::histogram_impl::NArray<
T,
sizeof...(Axes)>;
171 m_data[
index(std::index_sequence_for<Axes...>(), values...)] += weight;
175 template<std::size_t... Is>
177 std::index_sequence<Is...>,
typename Axes::Value... values)
const {
193 template<
typename T, std::
size_t NDimensions>
194 inline histogram_impl::NArray<T, NDimensions>::NArray(
199 size.begin(), size.end(), static_cast<std::size_t>(1),
200 std::multiplies<std::size_t>()),
204 template<
typename T, std::
size_t NDimensions>
205 constexpr std::size_t
206 histogram_impl::NArray<T, NDimensions>::linear(
Index idx)
const {
207 std::size_t result = 0;
208 std::size_t
step = 1;
209 for (std::size_t i = 0; i < NDimensions; ++i) {
210 result += step * idx[i];
216 template<
typename T, std::
size_t NDimensions>
218 histogram_impl::NArray<T, NDimensions>::within_bounds(
Index idx)
const {
219 for (std::size_t i = 0; i < NDimensions; ++i) {
220 if (
m_size[i] <= idx[i]) {
227 template<
typename T, std::
size_t NDimensions>
230 if (!within_bounds(idx)) {
231 throw std::out_of_range(
"NArray index is out of valid range");
233 return m_data[linear(idx)];
236 template<
typename T, std::
size_t NDimensions>
239 if (!within_bounds(idx)) {
240 throw std::out_of_range(
"NArray index is out of valid range");
242 return m_data[linear(idx)];
249 : m_nbins(nbins), m_lower(lower), m_upper(upper) {}
254 if (value < this->m_lower) {
255 throw std::out_of_range(
"Value is smaller than lower axis limit");
257 if (m_upper <= value) {
258 throw std::out_of_range(
"Value is equal or larger than upper axis limit");
261 return static_cast<std::size_t
>(
262 m_nbins * (value - m_lower) / (m_upper - m_lower));
270 : m_ndatabins(nbins), m_lower(lower), m_upper(upper) {}
273 constexpr std::size_t
275 if (value < m_lower) {
278 if (m_upper <= value) {
279 return m_ndatabins + 1;
283 +
static_cast<std::size_t
>(
284 m_ndatabins * (value - m_lower) / (m_upper - m_lower));
291 : m_edges(std::move(edges)) {
293 throw std::invalid_argument(
"Less than two bin edges");
298 throw std::invalid_argument(
"Bin edges are not sorted or have duplicates");
310 auto it = std::upper_bound(m_edges.begin(), m_edges.end(),
value);
311 if (
it == m_edges.begin()) {
312 throw std::out_of_range(
"Value is smaller than lower axis limit");
314 if (
it == m_edges.end()) {
315 throw std::out_of_range(
"Value is equal or larger than upper axis limit");
317 return std::distance(m_edges.begin(),
it) - 1;
322 template<
typename T,
typename... Axes>