1 // Copyright 2020 Hans Dembinski 2 // 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt 5 // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_HISTOGRAM_MULTI_INDEX_HPP 8 #define BOOST_HISTOGRAM_MULTI_INDEX_HPP 9 10 #include <algorithm> 11 #include <boost/histogram/detail/detect.hpp> 12 #include <boost/histogram/detail/nonmember_container_access.hpp> 13 #include <boost/histogram/fwd.hpp> 14 #include <boost/mp11/integer_sequence.hpp> 15 #include <boost/throw_exception.hpp> 16 #include <initializer_list> 17 #include <iterator> 18 #include <stdexcept> 19 #include <tuple> 20 21 namespace boost { 22 namespace histogram { 23 24 /** Holder for multiple axis indices. 25 26 Adapts external iterable, tuple, or explicit list of indices to the same representation. 27 */ 28 template <std::size_t Size> 29 struct multi_index { 30 using value_type = axis::index_type; 31 using iterator = value_type*; 32 using const_iterator = const value_type*; 33 createboost::histogram::multi_index34 static multi_index create(std::size_t s) { 35 if (s != size()) 36 BOOST_THROW_EXCEPTION(std::invalid_argument("size does not match static size")); 37 return multi_index(priv_tag{}); 38 } 39 40 template <class... Is> multi_indexboost::histogram::multi_index41 multi_index(axis::index_type i, Is... is) 42 : multi_index(std::initializer_list<axis::index_type>{ 43 i, static_cast<axis::index_type>(is)...}) {} 44 45 template <class... Is> multi_indexboost::histogram::multi_index46 multi_index(const std::tuple<axis::index_type, Is...>& is) 47 : multi_index(is, mp11::make_index_sequence<(1 + sizeof...(Is))>{}) {} 48 49 template <class Iterable, class = detail::requires_iterable<Iterable>> multi_indexboost::histogram::multi_index50 multi_index(const Iterable& is) { 51 if (detail::size(is) != size()) 52 BOOST_THROW_EXCEPTION(std::invalid_argument("no. of axes != no. of indices")); 53 using std::begin; 54 using std::end; 55 std::copy(begin(is), end(is), data_); 56 } 57 beginboost::histogram::multi_index58 iterator begin() noexcept { return data_; } endboost::histogram::multi_index59 iterator end() noexcept { return data_ + size(); } beginboost::histogram::multi_index60 const_iterator begin() const noexcept { return data_; } endboost::histogram::multi_index61 const_iterator end() const noexcept { return data_ + size(); } sizeboost::histogram::multi_index62 static constexpr std::size_t size() noexcept { return Size; } 63 64 private: 65 struct priv_tag {}; 66 multi_indexboost::histogram::multi_index67 multi_index(priv_tag) {} 68 69 template <class T, std::size_t... Is> multi_indexboost::histogram::multi_index70 multi_index(const T& is, mp11::index_sequence<Is...>) 71 : multi_index(static_cast<axis::index_type>(std::get<Is>(is))...) {} 72 73 axis::index_type data_[size()]; 74 }; 75 76 template <> 77 struct multi_index<static_cast<std::size_t>(-1)> { 78 using value_type = axis::index_type; 79 using iterator = value_type*; 80 using const_iterator = const value_type*; 81 createboost::histogram::multi_index82 static multi_index create(std::size_t s) { return multi_index(priv_tag{}, s); } 83 84 template <class... Is> multi_indexboost::histogram::multi_index85 multi_index(axis::index_type i, Is... is) 86 : multi_index(std::initializer_list<axis::index_type>{ 87 i, static_cast<axis::index_type>(is)...}) {} 88 89 template <class... Is> multi_indexboost::histogram::multi_index90 multi_index(const std::tuple<axis::index_type, Is...>& is) 91 : multi_index(is, mp11::make_index_sequence<(1 + sizeof...(Is))>{}) {} 92 93 template <class Iterable, class = detail::requires_iterable<Iterable>> multi_indexboost::histogram::multi_index94 multi_index(const Iterable& is) : size_(detail::size(is)) { 95 using std::begin; 96 using std::end; 97 std::copy(begin(is), end(is), data_); 98 } 99 beginboost::histogram::multi_index100 iterator begin() noexcept { return data_; } endboost::histogram::multi_index101 iterator end() noexcept { return data_ + size_; } beginboost::histogram::multi_index102 const_iterator begin() const noexcept { return data_; } endboost::histogram::multi_index103 const_iterator end() const noexcept { return data_ + size_; } sizeboost::histogram::multi_index104 std::size_t size() const noexcept { return size_; } 105 106 private: 107 struct priv_tag {}; 108 multi_indexboost::histogram::multi_index109 multi_index(priv_tag, std::size_t s) : size_(s) {} 110 111 template <class T, std::size_t... Ns> multi_indexboost::histogram::multi_index112 multi_index(const T& is, mp11::index_sequence<Ns...>) 113 : multi_index(static_cast<axis::index_type>(std::get<Ns>(is))...) {} 114 115 std::size_t size_ = 0; 116 static constexpr std::size_t max_size_ = BOOST_HISTOGRAM_DETAIL_AXES_LIMIT; 117 axis::index_type data_[max_size_]; 118 }; 119 120 } // namespace histogram 121 } // namespace boost 122 123 #endif 124