PMDK C++ bindings  1.13.0-git23.gf49772ac
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>
20 #include <libpmemobj++/slice.hpp>
22 #include <libpmemobj++/utils.hpp>
23 #include <libpmemobj/base.h>
24 
25 namespace pmem
26 {
27 
28 namespace obj
29 {
30 
55 template <typename T, std::size_t N>
56 struct 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 &
172  operator=(array &&other)
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
318  end()
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 
669 private:
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 
716  pool_base
717  _get_pool() const
718  {
719  return pmem::obj::pool_by_vptr(this);
720  }
721 };
722 
726 template <typename T, std::size_t N>
727 inline bool
728 operator==(const array<T, N> &lhs, const array<T, N> &rhs)
729 {
730  return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
731 }
732 
736 template <typename T, std::size_t N>
737 inline bool
738 operator!=(const array<T, N> &lhs, const array<T, N> &rhs)
739 {
740  return !(lhs == rhs);
741 }
742 
746 template <typename T, std::size_t N>
747 inline bool
748 operator<(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 
757 template <typename T, std::size_t N>
758 inline bool
759 operator>(const array<T, N> &lhs, const array<T, N> &rhs)
760 {
761  return rhs < lhs;
762 }
763 
767 template <typename T, std::size_t N>
768 inline bool
769 operator>=(const array<T, N> &lhs, const array<T, N> &rhs)
770 {
771  return !(lhs < rhs);
772 }
773 
777 template <typename T, std::size_t N>
778 inline bool
779 operator<=(const array<T, N> &lhs, const array<T, N> &rhs)
780 {
781  return !(lhs > rhs);
782 }
783 
787 template <typename T, std::size_t N>
788 typename pmem::obj::array<T, N>::const_iterator
790 {
791  return a.cbegin();
792 }
793 
797 template <typename T, std::size_t N>
798 typename pmem::obj::array<T, N>::const_iterator
800 {
801  return a.cend();
802 }
803 
807 template <typename T, std::size_t N>
808 typename pmem::obj::array<T, N>::const_reverse_iterator
810 {
811  return a.crbegin();
812 }
813 
817 template <typename T, std::size_t N>
818 typename pmem::obj::array<T, N>::const_reverse_iterator
820 {
821  return a.crend();
822 }
823 
827 template <typename T, std::size_t N>
830 {
831  return a.begin();
832 }
833 
837 template <typename T, std::size_t N>
838 typename pmem::obj::array<T, N>::const_iterator
840 {
841  return a.begin();
842 }
843 
847 template <typename T, std::size_t N>
850 {
851  return a.end();
852 }
853 
857 template <typename T, std::size_t N>
858 typename pmem::obj::array<T, N>::const_iterator
860 {
861  return a.end();
862 }
863 
867 template <typename T, std::size_t N>
868 typename pmem::obj::array<T, N>::reverse_iterator
870 {
871  return a.rbegin();
872 }
873 
877 template <typename T, std::size_t N>
878 typename pmem::obj::array<T, N>::const_reverse_iterator
880 {
881  return a.rbegin();
882 }
883 
887 template <typename T, std::size_t N>
888 typename pmem::obj::array<T, N>::reverse_iterator
890 {
891  return a.rend();
892 }
893 
897 template <typename T, std::size_t N>
898 typename pmem::obj::array<T, N>::const_reverse_iterator
900 {
901  return a.rend();
902 }
903 
907 template <typename T, size_t N>
908 inline void
910 {
911  lhs.swap(rhs);
912 }
913 
917 template <size_t I, typename T, size_t N>
918 T &
920 {
921  static_assert(I < N,
922  "Index out of bounds in std::get<> (pmem::obj::array)");
923  return a.at(I);
924 }
925 
929 template <size_t I, typename T, size_t N>
930 T &&
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 
941 template <size_t I, typename T, size_t N>
942 const T &
943 get(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 
953 template <size_t I, typename T, size_t N>
954 const T &&
955 get(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
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
T & get(pmem::obj::array< T, N > &a)
Non-member get function.
Definition: array.hpp:919
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
std::enable_if< Size==0, T * >::type _get_data()
Support for zero sized array.
Definition: array.hpp:696
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
slice< range_snapshotting_iterator > range(size_type start, size_type n, size_type snapshot_size)
Returns slice.
Definition: array.hpp:523
constexpr size_type max_size() const noexcept
Returns the maximum size of the array.
Definition: array.hpp:594
void fill(const_reference value)
Fills array with specified value inside internal transaction.
Definition: array.hpp:616
slice< const_iterator > crange(size_type start, size_type n) const
Returns const slice.
Definition: array.hpp:572
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
array & operator=(array &&other)
Move assignment operator - perform move assignment from other pmem::obj::array.
Definition: array.hpp:172
std::enable_if< Size==0, const T * >::type _get_data() const
Support for zero sized array.
Definition: array.hpp:706
const_reverse_iterator rend() const noexcept
Returns a const reverse iterator to the end.
Definition: array.hpp:405
const T * data() const noexcept
Returns const raw pointer to the underlying data.
Definition: array.hpp:285
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
T * data()
Returns raw pointer to the underlying data and adds entire array to a transaction.
Definition: array.hpp:274
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
slice< pointer > range(size_type start, size_type n)
Returns slice and snapshots requested range.
Definition: array.hpp:495
const_reference const_at(size_type n) const
Access element at specific index.
Definition: array.hpp:234
std::enable_if< Size !=0, T * >::type _get_data()
Support for non-zero sized array.
Definition: array.hpp:675
const_reference back() const
Access the last element.
Definition: array.hpp:469
std::enable_if< Size !=0 >::type swap(array &other)
Swaps content with other array's content inside internal transaction.
Definition: array.hpp:636
const_reference cback() const
Access the last element.
Definition: array.hpp:478
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, const T * >::type _get_data() const
Support for non-zero sized array.
Definition: array.hpp:685
const T * cdata() const noexcept
Returns const raw pointer to the underlying data.
Definition: array.hpp:294
array()=default
Defaulted constructor.
constexpr size_type size() const noexcept
Returns size of the array.
Definition: array.hpp:585
const_reference operator[](size_type n) const
Access element at specific index.
Definition: array.hpp:261
std::enable_if< Size==0 >::type swap(array &other)
Swap for zero-sized array.
Definition: array.hpp:663
slice< const_iterator > range(size_type start, size_type n) const
Returns const slice.
Definition: array.hpp:551
reverse_iterator rend()
Returns a reverse iterator to the end.
Definition: array.hpp:378
C++ pmemobj transactions.
Libpmemobj C++ utils.