PMDK C++ bindings 1.13.0
This is the C++ bindings documentation for PMDK's libpmemobj.
array.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2/* Copyright 2018-2021, Intel Corporation */
3
9#ifndef LIBPMEMOBJ_CPP_ARRAY_HPP
10#define LIBPMEMOBJ_CPP_ARRAY_HPP
11
12#include <algorithm>
13#include <functional>
14#include <initializer_list>
15
19#include <libpmemobj++/pext.hpp>
23#include <libpmemobj/base.h>
24
25namespace pmem
26{
27
28namespace obj
29{
30
55template <typename T, std::size_t N>
56struct array {
57
58 template <typename Y, std::size_t M>
59 struct standard_array_traits {
60 using type = Y[N];
61 };
62
63 /* zero-sized array support */
64 template <typename Y>
65 struct standard_array_traits<Y, 0> {
66 struct _alignment_struct {
67 Y _data[1];
68 };
69
70 struct alignas(_alignment_struct) type {
71 char _data[sizeof(_alignment_struct)];
72 };
73 };
74
75 /* Member types */
76 using value_type = T;
77 using pointer = value_type *;
78 using const_pointer = const value_type *;
79 using reference = value_type &;
80 using const_reference = const value_type &;
82 using const_iterator = const_pointer;
83 using size_type = std::size_t;
84 using difference_type = std::ptrdiff_t;
85 using reverse_iterator = std::reverse_iterator<iterator>;
86 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
89
90 /* Underlying array */
91 typename standard_array_traits<T, N>::type _data;
92
96 array() = default;
97
101 array(const array &) = default;
102
109 array(array &&) = default;
110
111#if __cplusplus > 201703L
118 array(std::initializer_list<T> list)
119 {
120 if constexpr (N > 0) {
121 size_t i = 0;
122 for (auto &v : list) {
123 (*this)[i] = v;
124 i++;
125 }
126 }
127 }
128#endif /* __cplusplus */
129
140 array &
141 operator=(const array &other)
142 {
143 /*
144 * _get_pool should be called before self assignment check to
145 * maintain the same behaviour for all arguments.
146 */
147 auto pop = _get_pool();
148
149 if (this == &other)
150 return *this;
151
152 flat_transaction::run(pop, [&] {
153 detail::conditional_add_to_tx(
154 this, 1, POBJ_XADD_ASSUME_INITIALIZED);
155 std::copy(other.cbegin(), other.cend(), _get_data());
156 });
157
158 return *this;
159 }
160
171 array &
173 {
174 /*
175 * _get_pool should be called before self assignment check to
176 * maintain the same behaviour for all arguments.
177 */
178 auto pop = _get_pool();
179
180 if (this == &other)
181 return *this;
182
183 flat_transaction::run(pop, [&] {
184 detail::conditional_add_to_tx(
185 this, 1, POBJ_XADD_ASSUME_INITIALIZED);
186 detail::conditional_add_to_tx(
187 &other, 1, POBJ_XADD_ASSUME_INITIALIZED);
188 std::move(other._get_data(), other._get_data() + size(),
189 _get_data());
190 });
191
192 return *this;
193 }
194
202 reference
203 at(size_type n)
204 {
205 if (n >= N)
206 throw std::out_of_range("array::at");
207
208 detail::conditional_add_to_tx(_get_data() + n, 1,
209 POBJ_XADD_ASSUME_INITIALIZED);
210
211 return _get_data()[n];
212 }
213
219 const_reference
220 at(size_type n) const
221 {
222 if (n >= N)
223 throw std::out_of_range("array::at");
224
225 return _get_data()[n];
226 }
227
233 const_reference
234 const_at(size_type n) const
235 {
236 if (n >= N)
237 throw std::out_of_range("array::const_at");
238
239 return _get_data()[n];
240 }
241
249 reference operator[](size_type n)
250 {
251 detail::conditional_add_to_tx(_get_data() + n, 1,
252 POBJ_XADD_ASSUME_INITIALIZED);
253
254 return _get_data()[n];
255 }
256
261 const_reference operator[](size_type n) const
262 {
263 return _get_data()[n];
264 }
265
273 T *
275 {
276 detail::conditional_add_to_tx(this, 1,
277 POBJ_XADD_ASSUME_INITIALIZED);
278 return _get_data();
279 }
280
284 const T *
285 data() const noexcept
286 {
287 return _get_data();
288 }
289
293 const T *
294 cdata() const noexcept
295 {
296 return _get_data();
297 }
298
305 iterator
307 {
308 return iterator(_get_data());
309 }
310
317 iterator
319 {
320 return iterator(_get_data() + size());
321 }
322
326 const_iterator
327 begin() const noexcept
328 {
329 return const_iterator(_get_data());
330 }
331
335 const_iterator
336 cbegin() const noexcept
337 {
338 return const_iterator(_get_data());
339 }
340
344 const_iterator
345 end() const noexcept
346 {
347 return const_iterator(_get_data() + size());
348 }
349
353 const_iterator
354 cend() const noexcept
355 {
356 return const_iterator(_get_data() + size());
357 }
358
365 reverse_iterator
367 {
368 return reverse_iterator(iterator(_get_data() + size()));
369 }
370
377 reverse_iterator
379 {
380 return reverse_iterator(iterator(_get_data()));
381 }
382
386 const_reverse_iterator
387 rbegin() const noexcept
388 {
389 return const_reverse_iterator(cend());
390 }
391
395 const_reverse_iterator
396 crbegin() const noexcept
397 {
398 return const_reverse_iterator(cend());
399 }
400
404 const_reverse_iterator
405 rend() const noexcept
406 {
407 return const_reverse_iterator(cbegin());
408 }
409
413 const_reverse_iterator
414 crend() const noexcept
415 {
416 return const_reverse_iterator(cbegin());
417 }
418
425 reference
427 {
428 detail::conditional_add_to_tx(_get_data(), 1,
429 POBJ_XADD_ASSUME_INITIALIZED);
430 return _get_data()[0];
431 }
432
439 reference
441 {
442 detail::conditional_add_to_tx(&_get_data()[size() - 1], 1,
443 POBJ_XADD_ASSUME_INITIALIZED);
444 return _get_data()[size() - 1];
445 }
446
450 const_reference
451 front() const
452 {
453 return _get_data()[0];
454 }
455
459 const_reference
460 cfront() const
461 {
462 return _get_data()[0];
463 }
464
468 const_reference
469 back() const
470 {
471 return _get_data()[size() - 1];
472 }
473
477 const_reference
478 cback() const
479 {
480 return _get_data()[size() - 1];
481 }
482
495 range(size_type start, size_type n)
496 {
497 if (start + n > N)
498 throw std::out_of_range("array::range");
499
500 detail::conditional_add_to_tx(_get_data() + start, n,
501 POBJ_XADD_ASSUME_INITIALIZED);
502
503 return {_get_data() + start, _get_data() + start + n};
504 }
505
523 range(size_type start, size_type n, size_type snapshot_size)
524 {
525 if (start + n > N)
526 throw std::out_of_range("array::range");
527
528 if (snapshot_size > n)
529 snapshot_size = n;
530
531 return {range_snapshotting_iterator(_get_data() + start,
532 _get_data() + start, n,
533 snapshot_size),
535 _get_data() + start, n,
536 snapshot_size)};
537 }
538
551 range(size_type start, size_type n) const
552 {
553 if (start + n > N)
554 throw std::out_of_range("array::range");
555
556 return {const_iterator(_get_data() + start),
557 const_iterator(_get_data() + start + n)};
558 }
559
572 crange(size_type start, size_type n) const
573 {
574 if (start + n > N)
575 throw std::out_of_range("array::crange");
576
577 return {const_iterator(_get_data() + start),
578 const_iterator(_get_data() + start + n)};
579 }
580
584 constexpr size_type
585 size() const noexcept
586 {
587 return N;
588 }
589
593 constexpr size_type
594 max_size() const noexcept
595 {
596 return N;
597 }
598
602 constexpr bool
603 empty() const noexcept
604 {
605 return size() == 0;
606 }
607
615 void
616 fill(const_reference value)
617 {
618 auto pop = _get_pool();
619
620 flat_transaction::run(pop, [&] {
621 detail::conditional_add_to_tx(
622 this, 1, POBJ_XADD_ASSUME_INITIALIZED);
623 std::fill(_get_data(), _get_data() + size(), value);
624 });
625 }
626
634 template <std::size_t Size = N>
635 typename std::enable_if<Size != 0>::type
636 swap(array &other)
637 {
638 /*
639 * _get_pool should be called before self assignment check to
640 * maintain the same behaviour for all arguments.
641 */
642 auto pop = _get_pool();
643
644 if (this == &other)
645 return;
646
647 flat_transaction::run(pop, [&] {
648 detail::conditional_add_to_tx(
649 this, 1, POBJ_XADD_ASSUME_INITIALIZED);
650 detail::conditional_add_to_tx(
651 &other, 1, POBJ_XADD_ASSUME_INITIALIZED);
652
653 std::swap_ranges(_get_data(), _get_data() + size(),
654 other._get_data());
655 });
656 }
657
661 template <std::size_t Size = N>
662 typename std::enable_if<Size == 0>::type
663 swap(array &other)
664 {
665 static_assert(!std::is_const<T>::value,
666 "cannot swap zero-sized array of type 'const T'");
667 }
668
669private:
673 template <std::size_t Size = N>
674 typename std::enable_if<Size != 0, T *>::type
676 {
677 return this->_data;
678 }
679
683 template <std::size_t Size = N>
684 typename std::enable_if<Size != 0, const T *>::type
685 _get_data() const
686 {
687 return this->_data;
688 }
689
694 template <std::size_t Size = N>
695 typename std::enable_if<Size == 0, T *>::type
697 {
698 return reinterpret_cast<T *>(&this->_data);
699 }
700
704 template <std::size_t Size = N>
705 typename std::enable_if<Size == 0, const T *>::type
706 _get_data() const
707 {
708 return reinterpret_cast<const T *>(&this->_data);
709 }
710
717 _get_pool() const
718 {
719 return pmem::obj::pool_by_vptr(this);
720 }
721};
722
726template <typename T, std::size_t N>
727inline bool
728operator==(const array<T, N> &lhs, const array<T, N> &rhs)
729{
730 return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
731}
732
736template <typename T, std::size_t N>
737inline bool
738operator!=(const array<T, N> &lhs, const array<T, N> &rhs)
739{
740 return !(lhs == rhs);
741}
742
746template <typename T, std::size_t N>
747inline bool
748operator<(const array<T, N> &lhs, const array<T, N> &rhs)
749{
750 return std::lexicographical_compare(lhs.cbegin(), lhs.cend(),
751 rhs.cbegin(), rhs.cend());
752}
753
757template <typename T, std::size_t N>
758inline bool
759operator>(const array<T, N> &lhs, const array<T, N> &rhs)
760{
761 return rhs < lhs;
762}
763
767template <typename T, std::size_t N>
768inline bool
769operator>=(const array<T, N> &lhs, const array<T, N> &rhs)
770{
771 return !(lhs < rhs);
772}
773
777template <typename T, std::size_t N>
778inline bool
779operator<=(const array<T, N> &lhs, const array<T, N> &rhs)
780{
781 return !(lhs > rhs);
782}
783
787template <typename T, std::size_t N>
788typename pmem::obj::array<T, N>::const_iterator
790{
791 return a.cbegin();
792}
793
797template <typename T, std::size_t N>
798typename pmem::obj::array<T, N>::const_iterator
800{
801 return a.cend();
802}
803
807template <typename T, std::size_t N>
808typename pmem::obj::array<T, N>::const_reverse_iterator
810{
811 return a.crbegin();
812}
813
817template <typename T, std::size_t N>
818typename pmem::obj::array<T, N>::const_reverse_iterator
820{
821 return a.crend();
822}
823
827template <typename T, std::size_t N>
830{
831 return a.begin();
832}
833
837template <typename T, std::size_t N>
838typename pmem::obj::array<T, N>::const_iterator
840{
841 return a.begin();
842}
843
847template <typename T, std::size_t N>
850{
851 return a.end();
852}
853
857template <typename T, std::size_t N>
858typename pmem::obj::array<T, N>::const_iterator
860{
861 return a.end();
862}
863
867template <typename T, std::size_t N>
868typename pmem::obj::array<T, N>::reverse_iterator
870{
871 return a.rbegin();
872}
873
877template <typename T, std::size_t N>
878typename pmem::obj::array<T, N>::const_reverse_iterator
880{
881 return a.rbegin();
882}
883
887template <typename T, std::size_t N>
888typename pmem::obj::array<T, N>::reverse_iterator
890{
891 return a.rend();
892}
893
897template <typename T, std::size_t N>
898typename pmem::obj::array<T, N>::const_reverse_iterator
900{
901 return a.rend();
902}
903
907template <typename T, size_t N>
908inline void
910{
911 lhs.swap(rhs);
912}
913
917template <size_t I, typename T, size_t N>
918T &
920{
921 static_assert(I < N,
922 "Index out of bounds in std::get<> (pmem::obj::array)");
923 return a.at(I);
924}
925
929template <size_t I, typename T, size_t N>
930T &&
932{
933 static_assert(I < N,
934 "Index out of bounds in std::get<> (pmem::obj::array)");
935 return std::move(a.at(I));
936}
937
941template <size_t I, typename T, size_t N>
942const T &
943get(const pmem::obj::array<T, N> &a) noexcept
944{
945 static_assert(I < N,
946 "Index out of bounds in std::get<> (pmem::obj::array)");
947 return a.at(I);
948}
949
953template <size_t I, typename T, size_t N>
954const T &&
955get(const pmem::obj::array<T, N> &&a) noexcept
956{
957 static_assert(I < N,
958 "Index out of bounds in std::get<> (pmem::obj::array)");
959 return std::move(a.at(I));
960}
961
962} /* namespace obj */
963
964} /* namespace pmem */
965
966#endif /* LIBPMEMOBJ_CPP_ARRAY_HPP */
static void run(obj::pool_base &pool, std::function< void()> tx, Locks &... locks)
Execute a closure-like transaction and lock locks.
Definition: transaction.hpp:823
The non-template pool base class.
Definition: pool.hpp:50
pmem::obj::slice - provides interface to access sequence of objects.
Definition: slice.hpp:50
Commonly used functionality.
Iterators for contiguous persistent containers.
bool operator<=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member less or equal operator.
Definition: array.hpp:779
bool operator<(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member less than operator.
Definition: array.hpp:748
T & get(pmem::obj::array< T, N > &a)
Non-member get function.
Definition: array.hpp:919
bool operator>=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater or equal operator.
Definition: array.hpp:769
bool operator!=(const allocator< T, P, Tr > &lhs, const OtherAllocator &rhs)
Determines if memory from another allocator can be deallocated from this one.
Definition: allocator.hpp:536
pool_base pool_by_vptr(const T *that)
Retrieve pool handle for the given pointer.
Definition: utils.hpp:32
bool operator==(standard_alloc_policy< T > const &, standard_alloc_policy< T2 > const &)
Determines if memory from another allocator can be deallocated from this one.
Definition: allocator.hpp:420
bool operator>(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater than operator.
Definition: array.hpp:759
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Persistent smart pointer.
Convenience extensions for the resides on pmem property template.
Interface to access sequence of objects.
Default non-const iterator which adds element to a transaction on every access.
Definition: contiguous_iterator.hpp:331
Non-const iterator which adds elements to a transaction in a bulk.
Definition: contiguous_iterator.hpp:192
pmem::obj::array - persistent container with std::array compatible interface.
Definition: array.hpp:56
reverse_iterator rbegin()
Returns a reverse iterator to the beginning.
Definition: array.hpp:366
reference at(size_type n)
Access element at specific index and add it to a transaction.
Definition: array.hpp:203
constexpr size_type max_size() const noexcept
Returns the maximum size of the array.
Definition: array.hpp:594
const T * cdata() const noexcept
Returns const raw pointer to the underlying data.
Definition: array.hpp:294
void fill(const_reference value)
Fills array with specified value inside internal transaction.
Definition: array.hpp:616
const T * data() const noexcept
Returns const raw pointer to the underlying data.
Definition: array.hpp:285
const_reference front() const
Access the first element.
Definition: array.hpp:451
iterator begin()
Returns an iterator to the beginning.
Definition: array.hpp:306
iterator end()
Returns an iterator to the end.
Definition: array.hpp:318
const_reference at(size_type n) const
Access element at specific index.
Definition: array.hpp:220
array(array &&)=default
Defaulted move constructor.
const_reverse_iterator crend() const noexcept
Returns a const reverse iterator to the beginning.
Definition: array.hpp:414
const_iterator end() const noexcept
Returns a const iterator to the end.
Definition: array.hpp:345
slice< const_iterator > crange(size_type start, size_type n) const
Returns const slice.
Definition: array.hpp:572
std::enable_if< Size!=0 >::type swap(array &other)
Swaps content with other array's content inside internal transaction.
Definition: array.hpp:636
const_reverse_iterator rend() const noexcept
Returns a const reverse iterator to the end.
Definition: array.hpp:405
pool_base _get_pool() const
Check whether object is on pmem and return pool_base instance.
Definition: array.hpp:717
array(const array &)=default
Defaulted copy constructor.
reference operator[](size_type n)
Access element at specific index and add it to a transaction.
Definition: array.hpp:249
const_reverse_iterator rbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: array.hpp:387
slice< range_snapshotting_iterator > range(size_type start, size_type n, size_type snapshot_size)
Returns slice.
Definition: array.hpp:523
std::enable_if< Size==0 >::type swap(array &other)
Swap for zero-sized array.
Definition: array.hpp:663
array & operator=(const array &other)
Copy assignment operator - perform assignment from other pmem::obj::array.
Definition: array.hpp:141
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: array.hpp:396
array & operator=(array &&other)
Move assignment operator - perform move assignment from other pmem::obj::array.
Definition: array.hpp:172
std::enable_if< Size==0, T * >::type _get_data()
Support for zero sized array.
Definition: array.hpp:696
T * data()
Returns raw pointer to the underlying data and adds entire array to a transaction.
Definition: array.hpp:274
std::enable_if< Size!=0, constT * >::type _get_data() const
Support for non-zero sized array.
Definition: array.hpp:685
const_reference const_at(size_type n) const
Access element at specific index.
Definition: array.hpp:234
const_reference back() const
Access the last element.
Definition: array.hpp:469
const_reference cback() const
Access the last element.
Definition: array.hpp:478
slice< pointer > range(size_type start, size_type n)
Returns slice and snapshots requested range.
Definition: array.hpp:495
reference back()
Access the last element and add this element to a transaction.
Definition: array.hpp:440
const_iterator cend() const noexcept
Returns a const iterator to the end.
Definition: array.hpp:354
const_reference cfront() const
Access the first element.
Definition: array.hpp:460
const_iterator cbegin() const noexcept
Returns const iterator to the beginning.
Definition: array.hpp:336
const_iterator begin() const noexcept
Returns const iterator to the beginning.
Definition: array.hpp:327
reference front()
Access the first element and add this element to a transaction.
Definition: array.hpp:426
constexpr bool empty() const noexcept
Checks whether array is empty.
Definition: array.hpp:603
std::enable_if< Size!=0, T * >::type _get_data()
Support for non-zero sized array.
Definition: array.hpp:675
array()=default
Defaulted constructor.
constexpr size_type size() const noexcept
Returns size of the array.
Definition: array.hpp:585
slice< const_iterator > range(size_type start, size_type n) const
Returns const slice.
Definition: array.hpp:551
const_reference operator[](size_type n) const
Access element at specific index.
Definition: array.hpp:261
std::enable_if< Size==0, constT * >::type _get_data() const
Support for zero sized array.
Definition: array.hpp:706
reverse_iterator rend()
Returns a reverse iterator to the end.
Definition: array.hpp:378
C++ pmemobj transactions.
Libpmemobj C++ utils.