pstore2
sparse_array.hpp
Go to the documentation of this file.
1 //===- include/pstore/adt/sparse_array.hpp ----------------*- mode: C++ -*-===//
2 //* *
3 //* ___ _ __ __ _ _ __ ___ ___ __ _ _ __ _ __ __ _ _ _ *
4 //* / __| '_ \ / _` | '__/ __|/ _ \ / _` | '__| '__/ _` | | | | *
5 //* \__ \ |_) | (_| | | \__ \ __/ | (_| | | | | | (_| | |_| | *
6 //* |___/ .__/ \__,_|_| |___/\___| \__,_|_| |_| \__,_|\__, | *
7 //* |_| |___/ *
8 //===----------------------------------------------------------------------===//
9 //
10 // Part of the pstore project, under the Apache License v2.0 with LLVM Exceptions.
11 // See https://github.com/SNSystems/pstore/blob/master/LICENSE.txt for license
12 // information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //===----------------------------------------------------------------------===//
18 
19 #ifndef PSTORE_ADT_SPARSE_ARRAY_HPP
20 #define PSTORE_ADT_SPARSE_ARRAY_HPP
21 
22 #include <numeric>
23 #include <type_traits>
24 
26 #include "pstore/support/error.hpp"
27 
28 namespace pstore {
29 
30  namespace details {
31 
37  template <typename Iterator, typename Accessor>
39  using return_type = typename std::result_of<Accessor (Iterator)>::type;
40  static_assert (std::is_reference<return_type>::value,
41  "return type from Accessor must be a reference");
42 
43  public:
44  using value_type = typename std::remove_reference<return_type>::type;
45  using pointer = value_type *;
46  using const_pointer = value_type const *;
47  using reference = value_type &;
48  using const_reference = value_type const &;
49 
50  using difference_type = typename std::iterator_traits<Iterator>::difference_type;
51  using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
52 
53  pair_field_iterator (Iterator it, Accessor acc)
54  : it_{std::move (it)}
55  , acc_{std::move (acc)} {}
56 
57  pair_field_iterator & operator+= (difference_type rhs) {
58  it_ += rhs;
59  return *this;
60  }
61  pair_field_iterator & operator-= (difference_type rhs) {
62  it_ -= rhs;
63  return *this;
64  }
65 
66  difference_type operator- (pair_field_iterator const & other) const {
67  return it_ - other.it_;
68  }
69 
70  pair_field_iterator operator- (difference_type rhs) {
71  pair_field_iterator res{*this};
72  it_ -= rhs;
73  return res;
74  }
75  pair_field_iterator operator+ (difference_type rhs) {
76  pair_field_iterator res{*this};
77  it_ += rhs;
78  return res;
79  }
80 
81  pair_field_iterator & operator++ () {
82  it_++;
83  return *this;
84  }
85  pair_field_iterator operator++ (int) {
86  auto ret_val = *this;
87  ++(*this);
88  return ret_val;
89  }
90  bool operator< (pair_field_iterator const & other) const { return it_ < other.it_; }
91  bool operator== (pair_field_iterator const & other) const {
92  return it_ == other.it_ && acc_ == other.acc_;
93  }
94  bool operator!= (pair_field_iterator const & other) const { return !(*this == other); }
95 
96  const_reference operator* () const {
97  // Delegate the actual deferencing of the iterator to the accessor function.
98  return acc_ (it_);
99  }
100  const_pointer operator-> () const {
101  // Delegate the actual deferencing of the iterator to the accessor function.
102  // Since we statically assert that the return type of acc_ is a reference,
103  // we can take the address of its returned value.
104  return &acc_ (it_);
105  }
106 
107  private:
108  Iterator it_;
111  Accessor acc_;
112  };
113 
120  template <size_t I, typename Iterator>
121  constexpr decltype (auto) get_accessor () noexcept {
122  return [] (Iterator it)
123  -> std::tuple_element_t<
124  I, typename std::iterator_traits<Iterator>::value_type> const & {
125  return std::get<I> (*it);
126  };
127  }
128 
129  } // end namespace details
130 
133  template <std::uintmax_t V, typename Enable = void>
135  template <std::uintmax_t V>
136  struct sparray_bitmap<V, typename std::enable_if_t<(V <= 8U)>> {
137  using type = std::uint8_t;
138  };
139  template <std::uintmax_t V>
140  struct sparray_bitmap<V, typename std::enable_if_t<(V > 8U && V <= 16U)>> {
141  using type = std::uint16_t;
142  };
143  template <std::uintmax_t V>
144  struct sparray_bitmap<V, typename std::enable_if_t<(V > 16U && V <= 32U)>> {
145  using type = std::uint32_t;
146  };
147  template <std::uintmax_t V>
148  struct sparray_bitmap<V, typename std::enable_if_t<(V > 32U && V <= 64U)>> {
149  using type = std::uint64_t;
150  };
151 
152  template <std::uintmax_t V>
153  using sparray_bitmap_t = typename sparray_bitmap<V>::type;
154 
155 
156 
166  template <typename ValueType, typename BitmapType = std::uint64_t>
167  class sparse_array {
168  template <typename V, typename B>
169  friend bool operator== (sparse_array<V, B> const & lhs, sparse_array<V, B> const & rhs);
170 
171  public:
172  using bitmap_type = BitmapType;
173 
174  using value_type = ValueType;
175  using size_type = std::size_t;
176  using reference = value_type &;
177  using const_reference = value_type const &;
178  using iterator = ValueType *;
179  using const_iterator = ValueType const *;
180  using reverse_iterator = std::reverse_iterator<iterator>;
181  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
182 
188  template <typename IteratorIdx, typename IteratorV>
189  sparse_array (IteratorIdx first_index, IteratorIdx last_index, IteratorV first_value,
190  IteratorV last_value);
191 
194  template <typename IteratorIdx>
195  sparse_array (IteratorIdx first_index, IteratorIdx last_index);
196 
197  sparse_array (sparse_array const &) = delete;
198  sparse_array (sparse_array &&) noexcept = delete;
199 
200  ~sparse_array () noexcept;
201 
202  sparse_array & operator= (sparse_array const &) = delete;
203  sparse_array & operator= (sparse_array &&) noexcept = delete;
204 
205 
209  template <typename IteratorIdx, typename IteratorV>
210  static auto make_unique (IteratorIdx first_index, IteratorIdx last_index,
211  IteratorV first_value, IteratorV last_value)
212  -> std::unique_ptr<sparse_array>;
213 
214  template <typename IteratorIdx>
215  static auto make_unique (IteratorIdx first_index, IteratorIdx last_index,
216  std::initializer_list<ValueType> values)
217  -> std::unique_ptr<sparse_array>;
218 
219  template <typename Iterator>
220  static auto make_unique (Iterator begin, Iterator end) -> std::unique_ptr<sparse_array>;
221 
222  static auto make_unique (std::initializer_list<size_type> indices,
223  std::initializer_list<ValueType> values = {})
224  -> std::unique_ptr<sparse_array>;
225 
226  static auto make_unique (std::initializer_list<std::pair<size_type, ValueType>> v)
227  -> std::unique_ptr<sparse_array> {
228  return make_unique (std::begin (v), std::end (v));
229  }
230 
233  constexpr bool empty () const noexcept { return bitmap_ == 0U; }
234  constexpr size_type size () const noexcept { return bit_count::pop_count (bitmap_); }
235 
238  static constexpr size_type max_size () noexcept { return sizeof (BitmapType) * 8; }
239 
241  constexpr bool has_index (size_type pos) const noexcept {
242  return pos < max_size () ? (bitmap_ & (BitmapType{1U} << pos)) != 0U : false;
243  }
245 
249  iterator begin () { return data (); }
250  const_iterator begin () const { return data (); }
251  const_iterator cbegin () const { return begin (); }
252 
253  iterator end () { return begin () + size (); }
254  const_iterator end () const { return begin () + size (); }
255  const_iterator cend () const { return end (); }
256 
257  reverse_iterator rbegin () { return reverse_iterator{end ()}; }
258  const_reverse_iterator rbegin () const { return const_reverse_iterator{end ()}; }
259  const_reverse_iterator crbegin () const { return rbegin (); }
260 
261  reverse_iterator rend () { return reverse_iterator{begin ()}; }
262  const_reverse_iterator rend () const { return const_reverse_iterator{begin ()}; }
263  const_reverse_iterator crend () const { return rend (); }
264 
265  class indices {
266  public:
268  public:
269  using iterator_category = std::forward_iterator_tag;
270  using value_type = std::size_t;
271  using difference_type = std::ptrdiff_t;
272  using pointer = value_type const *;
273  using reference = value_type const &;
274 
275  constexpr explicit const_iterator (BitmapType bitmap) noexcept
276  : bitmap_{bitmap} {
277  next ();
278  }
279 
280  constexpr bool operator== (const_iterator const & rhs) const noexcept {
281  return bitmap_ == rhs.bitmap_;
282  }
283  constexpr bool operator!= (const_iterator const & rhs) const noexcept {
284  return !operator== (rhs);
285  }
286 
287  constexpr reference operator* () const noexcept { return pos_; }
288  constexpr pointer operator-> () const noexcept { return pos_; }
289 
290  const_iterator & operator++ () noexcept {
291  bitmap_ >>= 1U;
292  ++pos_;
293  next ();
294  return *this;
295  }
296 
297  const_iterator operator++ (int) noexcept {
298  auto prev = *this;
299  next ();
300  return prev;
301  }
302 
303  const_iterator operator+ (unsigned x) const {
304  auto result = *this;
305  std::advance (result, x);
306  return result;
307  }
308 
309  private:
310  void next () noexcept {
311  for (; bitmap_ != 0U && (bitmap_ & 1U) == 0U; bitmap_ >>= 1U) {
312  ++pos_;
313  }
314  }
315  BitmapType bitmap_;
316  std::size_t pos_ = 0;
317  };
318  constexpr explicit indices (sparse_array const & arr) noexcept
319  : bitmap_{arr.bitmap_} {}
320  constexpr const_iterator begin () const noexcept { return const_iterator{bitmap_}; }
321  constexpr const_iterator end () const noexcept { return const_iterator{0U}; }
322 
323  constexpr bool empty () const noexcept { return bitmap_ == 0U; }
327  constexpr unsigned front () const noexcept {
328  PSTORE_ASSERT (!empty ());
329  return bit_count::ctz (bitmap_);
330  }
334  constexpr unsigned back () const noexcept {
335  PSTORE_ASSERT (!empty ());
336  return sizeof (bitmap_) * 8U - bit_count::clz (bitmap_) - 1U;
337  }
338 
339  private:
340  BitmapType const bitmap_;
341  };
342 
343  indices get_indices () const noexcept { return indices{*this}; }
344 
346 
349 
350  ValueType * data () noexcept { return &elements_[0]; }
351  ValueType const * data () const noexcept { return &elements_[0]; }
352 
353  reference operator[] (size_type pos) noexcept {
354  return sparse_array::index_impl (*this, pos);
355  }
356  const_reference operator[] (size_type pos) const noexcept {
357  return sparse_array::index_impl (*this, pos);
358  }
359 
360  reference at (size_type pos) { return sparse_array::at_impl (*this, pos); }
361  const_reference at (size_type pos) const { return sparse_array::at_impl (*this, pos); }
362 
365  constexpr reference front () {
366  PSTORE_ASSERT (!empty ());
367  return (*this)[get_indices ().front ()];
368  }
371  constexpr const_reference front () const {
372  PSTORE_ASSERT (!empty ());
373  return (*this)[get_indices ().front ()];
374  }
377  constexpr reference back () {
378  PSTORE_ASSERT (!empty ());
379  return (*this)[get_indices ().back ()];
380  }
383  constexpr const_reference back () const {
384  PSTORE_ASSERT (!empty ());
385  return (*this)[get_indices ().back ()];
386  }
387 
389 
390  void fill (ValueType const & value) { std::fill_n (begin (), size (), value); }
391 
392  constexpr std::size_t size_bytes () const {
393  return sparse_array::size_bytes (this->size ());
394  }
395  static constexpr std::size_t size_bytes (std::size_t const num_entries) noexcept {
396  static_assert (sizeof (elements_) / sizeof (ValueType) == 1U,
397  "Expected elements_ to be an array of 1 ValueType");
398  return sizeof (sparse_array) +
399  (std::max (std::size_t{1}, num_entries) - 1U) * sizeof (ValueType);
400  }
401 
402  void * operator new (std::size_t const /*count*/, void * const ptr) { return ptr; }
403  void operator delete (void * const /*ptr*/, void * const /*place*/) {}
404  void operator delete (void * const p) { ::operator delete (p); }
405 
406  private:
417  template <typename InputIterator>
418  static std::size_t required_bytes (std::size_t const count, InputIterator const first,
419  InputIterator const last) {
420  // There will always be sufficient storage for at least 1 instance of
421  // ValueType (this comes from the built-in array).
422  static_assert (sizeof (elements_) / sizeof (ValueType) == 1U,
423  "Expected elements_ to be an array of 1 ValueType");
424  auto const elements = std::max (bit_count::pop_count (bitmap (first, last)), 1U);
425  return count - sizeof (elements_) + elements * sizeof (ValueType);
426  }
427 
435  template <typename InputIterator>
436  void * operator new (std::size_t count, InputIterator indices_first,
437  InputIterator indices_last) {
438  return ::operator new (
439  sparse_array::required_bytes (count, indices_first, indices_last));
440  }
441 
444  template <typename InputIterator>
445  void operator delete (void * const p, InputIterator const /*indices_first*/,
446  InputIterator const /*indices_last*/) {
447  return ::operator delete (p);
448  }
449 
450  BitmapType const bitmap_;
451  ValueType elements_[1];
452 
455  template <typename InputIterator,
456  typename = typename std::enable_if_t<std::is_unsigned<
457  typename std::iterator_traits<InputIterator>::value_type>::value>>
458  static BitmapType bitmap (InputIterator first, InputIterator last);
459 
461  template <typename SparseArray,
462  typename ResultType = typename inherit_const<SparseArray, ValueType>::type>
463  static ResultType & index_impl (SparseArray && sa, size_type pos) noexcept;
464 
466  template <typename SparseArray,
467  typename ResultType = typename inherit_const<SparseArray, ValueType>::type>
468  static ResultType & at_impl (SparseArray && sa, size_type pos);
469  };
470 
471  // (ctor)
472  // ~~~~~~
473  template <typename ValueType, typename BitmapType>
474  template <typename IteratorIdx, typename IteratorV>
476  IteratorIdx last_index,
477  IteratorV first_value, IteratorV last_value)
478  : bitmap_{bitmap (first_index, last_index)} {
479 
480  // Deal with the first element. This is the odd-one-out becuase it's in the
481  // declaration of the object and will have been default-constructed by the
482  // compiler.
483  if (first_index != last_index) {
484  if (first_value != last_value) {
485  elements_[0] = *(first_value++);
486  }
487  ++first_index;
488  }
489 
490  auto out = &elements_[1];
491 
492  // Now construct any remaining elements into the uninitialized memory past the
493  // end of the object using placement new.
494  for (; first_index != last_index && first_value != last_value;
495  ++first_index, ++first_value, ++out) {
496  new (out) ValueType (*first_value);
497  }
498  // Default-construct any remaining objects for which we don't have a value.
499  for (; first_index != last_index; ++first_index, ++out) {
500  new (out) ValueType ();
501  }
502  }
503 
504  template <typename ValueType, typename BitmapType>
505  template <typename IteratorIdx>
507  IteratorIdx last_index)
508  : bitmap_{sparse_array<ValueType, BitmapType>::bitmap (first_index, last_index)} {
509  // The first element will have been default-constructed by the compiler.
510  if (first_index != last_index) {
511  ++first_index;
512  }
513  auto * out = &elements_[1];
514  // Default-construct the remaining objects.
515  for (; first_index != last_index; ++first_index, ++out) {
516  new (out) ValueType ();
517  }
518  }
519 
520  // (dtor)
521  // ~~~~~~
522  template <typename ValueType, typename BitmapType>
524  auto const elements = size ();
525  if (elements > 1) {
526  for (auto it = &elements_[1], end = &elements_[0] + elements; it != end; ++it) {
527  it->~ValueType ();
528  }
529  }
530  }
531 
532  // make unique
533  // ~~~~~~~~~~~
534  template <typename ValueType, typename BitmapType>
535  template <typename Iterator>
536  auto sparse_array<ValueType, BitmapType>::make_unique (Iterator begin, Iterator end)
537  -> std::unique_ptr<sparse_array> {
538 
539  using details::get_accessor;
541 
542  auto const accessor0 = get_accessor<0U, Iterator> ();
543  auto const accessor1 = get_accessor<1U, Iterator> ();
544 
545  // [begin0, end0) is the range of indices; [begin1, end1] is the range of values.
546  auto const begin0 = pair_field_iterator<Iterator, decltype (accessor0)>{begin, accessor0};
547  auto const end0 = pair_field_iterator<Iterator, decltype (accessor0)>{end, accessor0};
548  auto const begin1 = pair_field_iterator<Iterator, decltype (accessor1)>{begin, accessor1};
549  auto const end1 = pair_field_iterator<Iterator, decltype (accessor1)>{end, accessor1};
550 
551  return std::unique_ptr<sparse_array<ValueType, BitmapType>>{
552  new (begin0, end0) sparse_array<ValueType, BitmapType> (begin0, end0, begin1, end1)};
553  }
554 
555  template <typename ValueType, typename BitmapType>
556  template <typename IteratorIdx, typename IteratorV>
558  IteratorIdx last_index,
559  IteratorV first_value,
560  IteratorV last_value)
561  -> std::unique_ptr<sparse_array> {
562 
563  return std::unique_ptr<sparse_array<ValueType, BitmapType>>{
564  new (first_index, last_index) sparse_array<ValueType, BitmapType> (
565  first_index, last_index, first_value, last_value)};
566  }
567 
568  template <typename ValueType, typename BitmapType>
569  auto sparse_array<ValueType, BitmapType>::make_unique (std::initializer_list<size_type> indices,
570  std::initializer_list<ValueType> values)
571  -> std::unique_ptr<sparse_array> {
572 
573  return make_unique (std::begin (indices), std::end (indices), std::begin (values),
574  std::end (values));
575  }
576 
577  template <typename ValueType, typename BitmapType>
578  template <typename IteratorIdx>
579  auto sparse_array<ValueType, BitmapType>::make_unique (IteratorIdx first_index,
580  IteratorIdx last_index,
581  std::initializer_list<ValueType> values)
582  -> std::unique_ptr<sparse_array> {
583 
584  return std::unique_ptr<sparse_array<ValueType, BitmapType>>{
585  new (first_index, last_index) sparse_array<ValueType, BitmapType> (
586  first_index, last_index, std::begin (values), std::end (values))};
587  }
588 
589  // bitmap
590  // ~~~~~~
591  template <typename ValueType, typename BitmapType>
592  template <typename InputIterator, typename>
593  BitmapType sparse_array<ValueType, BitmapType>::bitmap (InputIterator first,
594  InputIterator last) {
595  return std::accumulate (
596  first, last, BitmapType{0U},
597  [] (BitmapType const mm, typename std::iterator_traits<InputIterator>::value_type const idx) {
598  PSTORE_ASSERT (idx < max_size ());
599  auto const mask = BitmapType{1U} << idx;
600  PSTORE_ASSERT ((mm & mask) == 0U &&
601  "The same index must not appear more than once in the "
602  "collection of sparse indices");
603  return static_cast<BitmapType> (mm | mask);
604  });
605  }
606 
607  // index impl
608  // ~~~~~~~~~~
609  template <typename ValueType, typename BitmapType>
610  template <typename SparseArray, typename ResultType>
611  ResultType & sparse_array<ValueType, BitmapType>::index_impl (SparseArray && sa,
612  size_type pos) noexcept {
613  PSTORE_ASSERT (pos < max_size ());
614  auto mask = BitmapType{1U} << pos;
615  PSTORE_ASSERT ((sa.bitmap_ & mask) != 0U);
616  mask--;
617  return sa.elements_[bit_count::pop_count (static_cast<BitmapType> (sa.bitmap_ & mask))];
618  }
619 
620  // at impl
621  // ~~~~~~~
622  template <typename ValueType, typename BitmapType>
623  template <typename SparseArray, typename ResultType>
624  ResultType & sparse_array<ValueType, BitmapType>::at_impl (SparseArray && sa, size_type pos) {
625  if (pos < max_size ()) {
626  auto const bit_position = BitmapType{1} << pos;
627  if ((sa.bitmap_ & bit_position) != 0) {
628  return sa.elements_[bit_count::pop_count (sa.bitmap_ & (bit_position - 1U))];
629  }
630  }
631  raise_exception (std::out_of_range ("spare array index out of range"));
632  }
633 
634 
635  // operator==
636  // ~~~~~~~~~~
637  template <typename ValueType, typename BitmapType>
638  inline bool operator== (sparse_array<ValueType, BitmapType> const & lhs,
640  return lhs.bitmap_ == rhs.bitmap_ &&
641  std::equal (std::begin (lhs), std::end (lhs), std::begin (rhs));
642  }
643 
644  // operator!=
645  // ~~~~~~~~~~
646  template <typename ValueType, typename BitmapType>
647  inline bool operator!= (sparse_array<ValueType, BitmapType> const & lhs,
649  return !(lhs == rhs);
650  }
651 
652  // get
653  // ~~~
654  template <std::size_t Ip, typename ValueType, typename BitmapType>
655  constexpr ValueType & get (sparse_array<ValueType, BitmapType> & arr) noexcept {
656  static_assert (Ip < sparse_array<ValueType, BitmapType>::max_size (),
657  "Index out of bounds in std::get<> (sparse_array)");
658  return arr[Ip];
659  }
660 
661  template <std::size_t Ip, typename ValueType, typename BitmapType>
662  constexpr ValueType const & get (sparse_array<ValueType, BitmapType> const & arr) noexcept {
663  static_assert (Ip < sparse_array<ValueType, BitmapType>::max_size (),
664  "Index out of bounds in std::get<> (const sparse_array)");
665  return arr[Ip];
666  }
667 
668 } // end namespace pstore
669 
670 #endif // PSTORE_ADT_SPARSE_ARRAY_HPP
A sparse array type.
Definition: sparse_array.hpp:167
constexpr reference back()
Returns a reference to the last element in the container.
Definition: sparse_array.hpp:377
static constexpr size_type max_size() noexcept
Returns the maximum number of indices that could be contained by an instance of this sparse_array typ...
Definition: sparse_array.hpp:238
Definition: sparse_array.hpp:38
Definition: chunked_sequence.hpp:607
transaction< transaction_lock > begin(database &db, transaction_lock &lock)
Creates a new transaction. Every operation performed on a transaction instance can be potentially und...
Definition: transaction.hpp:311
constexpr bool has_index(size_type pos) const noexcept
Returns true if the sparse array has an index &#39;pos&#39;.
Definition: sparse_array.hpp:241
constexpr reference front()
Returns a reference to the first element in the container.
Definition: sparse_array.hpp:365
Definition: print.cpp:18
constexpr unsigned back() const noexcept
Returns the index of the last element in the container.
Definition: sparse_array.hpp:334
constexpr unsigned front() const noexcept
Returns the index of the first element in the container.
Definition: sparse_array.hpp:327
sparse_array(IteratorIdx first_index, IteratorIdx last_index, IteratorV first_value, IteratorV last_value)
Constructs a sparse array whose available indices are defined by the iterator range from [first_index...
Definition: sparse_array.hpp:475
Definition: sparse_array.hpp:265
Definition: nonpod2.cpp:40
Derives the correct type for the bitmap field of a sparse_array<> given the maximum index value...
Definition: sparse_array.hpp:134
Implements portable functions for bit twiddling operations including counting leading and trailing ze...
constexpr const_reference back() const
Returns a reference to the last element in the container.
Definition: sparse_array.hpp:383
Provides an pstore-specific error codes and a suitable error category for them.
Definition: sparse_array.hpp:267
constexpr const_reference front() const
Returns a reference to the first element in the container.
Definition: sparse_array.hpp:371
typename std::conditional< std::is_const< typename std::remove_reference< T >::type >::value, RC, R >::type type
If T is const, R const otherwise R.
Definition: inherit_const.hpp:112