27 #ifndef PSTORE_ADT_CHUNKED_SEQUENCE_HPP 28 #define PSTORE_ADT_CHUNKED_SEQUENCE_HPP 58 std::size_t ElementsPerChunk = std::max (4096 /
sizeof (T), std::size_t{1}),
59 std::size_t ActualSize =
sizeof (T), std::size_t ActualAlign =
alignof (T)>
61 static_assert (ElementsPerChunk > 0,
"Must be at least 1 element per chunk");
62 static_assert (ActualSize >=
sizeof (T),
"ActualSize must be at least sizeof(T)");
63 static_assert (ActualAlign >=
alignof (T),
"ActualAlign must be at least alignof(T)");
65 template <
bool Const = true>
70 using size_type = std::size_t;
71 using difference_type = std::ptrdiff_t;
72 using reference = value_type &;
73 using const_reference = value_type
const &;
75 using const_pointer = T
const *;
77 using iterator = iterator_base<false>;
78 using const_iterator = iterator_base<true>;
83 using chunk_list = std::list<chunk>;
86 static constexpr std::size_t elements_per_chunk = ElementsPerChunk;
97 constexpr
bool empty () const noexcept {
return size_ == 0; }
98 constexpr size_type size () const noexcept {
return size_; }
100 iterator
begin () noexcept {
return {chunks_.begin (), 0U}; }
101 const_iterator
begin () const noexcept {
102 PSTORE_ASSERT (empty () || chunks_.front ().size () > 0);
103 return {chunks_.begin (), 0U};
105 const_iterator cbegin () const noexcept {
return begin (); }
107 iterator end () noexcept {
return end_impl (*
this); }
108 const_iterator end () const noexcept {
return end_impl (*
this); }
109 const_iterator cend () const noexcept {
return end (); }
113 typename chunk_list::iterator chunks_begin () noexcept {
return chunks_.begin (); }
114 typename chunk_list::const_iterator chunks_begin () const noexcept {
115 return chunks_.begin ();
117 typename chunk_list::const_iterator chunks_cbegin () noexcept {
return chunks_.cbegin (); }
118 typename chunk_list::iterator chunks_end () noexcept {
return chunks_.end (); }
119 typename chunk_list::const_iterator chunks_end () const noexcept {
return chunks_.end (); }
120 typename chunk_list::const_iterator chunks_cend () noexcept {
return chunks_.cend (); }
122 std::size_t chunks_size () const noexcept {
return chunks_.size (); }
129 chunks_.emplace_back ();
132 void reserve (std::size_t
const ) {
139 std::size_t
capacity () const noexcept {
return chunks_.size () * ElementsPerChunk; }
150 return this->resize_grow (count);
153 this->resize_shrink (count);
157 template <
typename... Args>
158 reference emplace_back (Args &&... args);
160 reference push_back (T
const & value) {
return emplace_back (value); }
161 reference push_back (T && value) {
return emplace_back (std::move (value)); }
166 PSTORE_ASSERT (size_ > 0);
167 return chunks_.front ().front ();
172 PSTORE_ASSERT (size_ > 0);
173 return chunks_.front ().front ();
179 PSTORE_ASSERT (size_ > 0);
180 return chunks_.back ().back ();
184 const_reference
back ()
const {
185 PSTORE_ASSERT (size_ > 0);
186 return chunks_.back ().back ();
190 std::swap (chunks_, other.chunks_);
191 std::swap (size_, other.size_);
196 if (other.empty ()) {
202 size_ = other.size ();
203 chunks_ = std::move (other.chunks_);
206 size_ += other.size ();
207 chunks_.splice (chunks_.end (), std::move (other.chunks_));
211 template <
typename ChunkedSequence,
typename Result =
typename inherit_const<
212 ChunkedSequence, iterator, const_iterator>::type>
213 static Result end_impl (ChunkedSequence & cv) noexcept;
219 void resize_grow (size_type count);
224 void resize_shrink (size_type count);
233 template <
typename T,
bool IsConst>
235 using type =
typename std::conditional<IsConst, T const, T>::type;
242 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
243 std::size_t ActualAlign>
247 chunks_.emplace_back ();
250 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
251 std::size_t ActualAlign>
254 : chunks_{std::move (other.chunks_)}
255 , size_{other.size_} {
261 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
262 std::size_t ActualAlign>
265 if (
this != &other) {
266 chunks_ = std::move (other.chunks_);
275 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
276 std::size_t ActualAlign>
277 template <
typename... Args>
281 PSTORE_ASSERT (chunks_.size () > 0U);
282 auto * tail = &chunks_.back ();
283 if (PSTORE_UNLIKELY (tail->size () >= ElementsPerChunk)) {
285 chunks_.emplace_back ();
286 tail = &chunks_.back ();
289 reference result = tail->emplace_back (std::forward<Args> (args)...);
296 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
297 std::size_t ActualAlign>
298 template <
typename ChunkedSequence,
typename Result>
300 ChunkedSequence & cv) noexcept {
303 PSTORE_ASSERT (cv.chunks_.size () > 0U);
304 if (cv.size () > 0U) {
305 return {cv.chunks_.end (), 0U};
312 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
313 std::size_t ActualAlign>
316 auto const grow_chunk = [
this] (chunk *
const c, std::size_t
const limit) {
317 assert (limit <= c->capacity ());
318 for (
auto ctr = limit; ctr > 0U; --ctr) {
326 if (count <= size_) {
333 auto & tail = chunks_.back ();
334 std::size_t
const tc = tail.capacity ();
336 std::size_t
const limit = std::min (count, tc);
337 count -= grow_chunk (&tail, limit);
338 assert (tail.capacity () == tc - limit);
345 chunks_.emplace_back ();
347 count -= grow_chunk (&chunks_.back (), std::min (ElementsPerChunk, count));
353 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
354 std::size_t ActualAlign>
357 if (count >= size_) {
362 count = size_ - count;
363 auto & head = chunks_.
front ();
365 auto & tail = chunks_.back ();
366 auto in_chunk = tail.size ();
368 if (count >= in_chunk && &tail != &head) {
371 assert (in_chunk >= count);
372 tail.shrink (in_chunk - count);
386 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
387 std::size_t ActualAlign>
402 chunk & operator= (
chunk &&) noexcept =
delete;
404 T * data () noexcept {
return membs_.data (); }
405 T
const * data ()
const noexcept {
return membs_.data (); }
407 T & operator[] (std::size_t
const index) noexcept {
408 PSTORE_ASSERT (index < ElementsPerChunk);
409 return reinterpret_cast<T &
> (membs_[index]);
411 T
const & operator[] (std::size_t
const index)
const noexcept {
412 PSTORE_ASSERT (index < ElementsPerChunk);
413 return reinterpret_cast<T
const &
> (membs_[index]);
415 constexpr std::size_t size ()
const noexcept {
return size_; }
416 constexpr
bool empty ()
const noexcept {
return size_ == 0U; }
418 constexpr std::size_t capacity ()
const noexcept {
419 return ElementsPerChunk - this->size ();
422 reference front () {
return (*
this)[0]; }
423 const_reference front ()
const {
return (*
this)[0]; }
424 reference back () {
return (*
this)[size_ - 1U]; }
425 const_reference back ()
const {
return (*
this)[size_ - 1U]; }
433 template <
typename... Args>
434 reference emplace_back (Args &&... args);
436 void shrink (std::size_t new_size) noexcept;
439 std::size_t size_ = 0U;
440 std::array<typename std::aligned_storage<ActualSize, ActualAlign>::type, ElementsPerChunk>
446 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
447 std::size_t ActualAlign>
454 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
455 std::size_t ActualAlign>
456 template <
typename... Args>
458 Args &&... args) -> reference {
459 PSTORE_ASSERT (size_ < membs_.size ());
460 T & place = (*this)[size_];
461 new (&place) T (std::forward<Args> (args)...);
468 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
469 std::size_t ActualAlign>
471 std::size_t
const new_size) noexcept {
472 assert (new_size <= size_);
473 for (
auto ctr = new_size; ctr < size_; ++ctr) {
485 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
486 std::size_t ActualAlign>
487 template <
bool IsConst>
488 class chunked_sequence<T, ElementsPerChunk, ActualSize, ActualAlign>::iterator_base {
489 using list_iterator =
490 typename std::conditional<IsConst,
typename chunk_list::const_iterator,
491 typename chunk_list::iterator>::type;
493 friend class iterator_base<true>;
496 using iterator_category = std::bidirectional_iterator_tag;
497 using value_type =
typename details::value_type<T, IsConst>::type;
498 using difference_type = std::ptrdiff_t;
499 using pointer = value_type *;
500 using reference = value_type &;
502 iterator_base (list_iterator
const it, std::size_t
const index)
506 iterator_base (iterator_base<false>
const & rhs)
508 , index_{rhs.index_} {}
509 iterator_base (iterator_base<false> && rhs)
510 : it_{std::move (rhs.it_)}
511 , index_{std::move (rhs.index_)} {}
513 iterator_base & operator= (iterator_base<false>
const & rhs) {
519 iterator_base & operator= (iterator_base<false> && rhs) {
521 it_ = std::move (rhs.it_);
522 index_ = std::move (rhs.index_);
527 bool operator== (iterator_base
const & other)
const {
528 return it_ == other.it_ && index_ == other.index_;
530 bool operator!= (iterator_base
const & other)
const {
return !operator== (other); }
535 reference operator* ()
const noexcept {
return (*it_)[index_]; }
536 pointer operator-> ()
const noexcept {
return &(*it_)[index_]; }
538 iterator_base & operator++ ();
539 iterator_base operator++ (
int);
540 iterator_base & operator-- ();
541 iterator_base operator-- (
int);
549 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
550 std::size_t ActualAlign>
551 template <
bool IsConst>
553 ActualAlign>::iterator_base<IsConst>::operator++ ()
554 -> iterator_base<IsConst> & {
555 if (++index_ >= it_->size ()) {
563 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
564 std::size_t ActualAlign>
565 template <
bool IsConst>
567 ActualAlign>::iterator_base<IsConst>::operator++ (int)
568 -> iterator_base<IsConst> {
569 auto const old = *
this;
575 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
576 std::size_t ActualAlign>
577 template <
bool IsConst>
579 ActualAlign>::iterator_base<IsConst>::operator-- ()
580 -> iterator_base<IsConst> & {
585 PSTORE_ASSERT (it_->size () > 0);
586 index_ = it_->size () - 1U;
592 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
593 std::size_t ActualAlign>
594 template <
bool IsConst>
596 ActualAlign>::iterator_base<IsConst>::operator-- (int)
597 -> iterator_base<IsConst> {
609 template <
typename T, std::size_t ElementsPerChunk, std::size_t ActualSize,
610 std::size_t ActualAlign>
619 #endif // PSTORE_ADT_CHUNKED_SEQUENCE_HPP const_reference back() const
Returns a reference to the last element in the container.
Definition: chunked_sequence.hpp:184
Definition: chunked_sequence.hpp:607
reference back()
Returns a reference to the last element in the container.
Definition: chunked_sequence.hpp:178
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
Yields either 'T' or 'T const' depending on the value is IsConst.
Definition: chunked_sequence.hpp:234
void resize(size_type count)
Resizes the container to contain count elements.
Definition: chunked_sequence.hpp:148
A utility template intended to simplify the writing of the const- and non-const variants of member fu...
Definition: pointer_based_iterator.hpp:53
Definition: nonpod2.cpp:40
Provides a member typedef inherit_const::type, which is defined as R const if T is a const type and R...
Definition: inherit_const.hpp:108
Definition: chunked_sequence.hpp:388
An implementation of the standard assert() macro with the exception that it will, on failure...
const_reference front() const
Returns a reference to the first element in the container.
Definition: chunked_sequence.hpp:171
Chunked-sequence is a sequence-container which uses a list of large blocks ("chunks") to ensure very ...
Definition: chunked_sequence.hpp:60
Provides pointer_based_iterator<> an iterator wrapper for pointers.
reference front()
Returns a reference to the first element in the container.
Definition: chunked_sequence.hpp:165
std::size_t capacity() const noexcept
Returns the number of elements that the container has currently allocated space for.
Definition: chunked_sequence.hpp:139