chunk_vector.hpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright 2019 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. #ifndef BOOST_HISTOGRAM_DETAIL_CHUNK_VECTOR_HPP
  7. #define BOOST_HISTOGRAM_DETAIL_CHUNK_VECTOR_HPP
  8. #include <boost/core/span.hpp>
  9. #include <boost/throw_exception.hpp>
  10. #include <stdexcept>
  11. #include <vector>
  12. namespace boost {
  13. namespace histogram {
  14. namespace detail {
  15. // Warning: this is not a proper container and is only used to
  16. // test the feasibility of using accumulators::collector with a
  17. // custom container type. If time permits, this will be expanded
  18. // into a proper container type.
  19. template <class ValueType>
  20. class chunk_vector {
  21. public:
  22. using base = std::vector<ValueType>;
  23. using allocator_type = typename base::allocator_type;
  24. using pointer = typename base::pointer;
  25. using const_pointer = typename base::const_pointer;
  26. using size_type = typename base::size_type;
  27. using const_reference = boost::span<const ValueType>;
  28. using reference = boost::span<ValueType>;
  29. // this is wrong and should make a copy; it is not a problem for
  30. // the current use-case, but a general purpose implementation cannot
  31. // violate concepts like this
  32. using value_type = const_reference;
  33. template <class Pointer>
  34. struct iterator_t {
  35. iterator_t& operator++() {
  36. ptr_ += chunk_;
  37. return *this;
  38. }
  39. iterator_t operator++(int) {
  40. iterator_t copy(*this);
  41. ptr_ += chunk_;
  42. return copy;
  43. }
  44. value_type operator*() const { return value_type(ptr_, ptr_ + chunk_); }
  45. Pointer ptr_;
  46. size_type chunk_;
  47. };
  48. using iterator = iterator_t<pointer>;
  49. using const_iterator = iterator_t<const_pointer>;
  50. // this creates an empty chunk_vector
  51. explicit chunk_vector(size_type chunk, const allocator_type& alloc = {})
  52. : chunk_(chunk), vec_(alloc) {}
  53. chunk_vector(std::initializer_list<value_type> list, size_type chunk,
  54. const allocator_type& alloc = {})
  55. : chunk_(chunk), vec_(list, alloc) {}
  56. allocator_type get_allocator() noexcept(noexcept(allocator_type())) {
  57. return vec_.get_allocator();
  58. }
  59. void push_back(const_reference x) {
  60. if (x.size() != chunk_)
  61. BOOST_THROW_EXCEPTION(std::runtime_error("argument has wrong size"));
  62. // we don't use std::vector::insert here to have amortized constant complexity
  63. for (auto&& elem : x) vec_.push_back(elem);
  64. }
  65. auto insert(const_iterator pos, const_iterator o_begin, const_iterator o_end) {
  66. if (std::distance(o_begin, o_end) % chunk_ == 0)
  67. BOOST_THROW_EXCEPTION(std::runtime_error("argument has wrong size"));
  68. return vec_.insert(pos, o_begin, o_end);
  69. }
  70. const_iterator begin() const noexcept { return {vec_.data(), chunk_}; }
  71. const_iterator end() const noexcept { return {vec_.data() + vec_.size(), chunk_}; }
  72. value_type operator[](size_type idx) const noexcept {
  73. return {vec_.data() + idx * chunk_, vec_.data() + (idx + 1) * chunk_};
  74. }
  75. size_type size() const noexcept { return vec_.size() / chunk_; }
  76. private:
  77. size_type chunk_;
  78. base vec_;
  79. };
  80. } // namespace detail
  81. } // namespace histogram
  82. } // namespace boost
  83. #endif