PMDK C++ bindings  1.8.2
This is the C++ bindings documentation for PMDK's libpmemobj.
array.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2018-2019, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
38 #ifndef LIBPMEMOBJ_CPP_ARRAY_HPP
39 #define LIBPMEMOBJ_CPP_ARRAY_HPP
40 
41 #include <algorithm>
42 #include <functional>
43 
47 #include <libpmemobj++/pext.hpp>
48 #include <libpmemobj++/slice.hpp>
50 #include <libpmemobj/base.h>
51 
52 namespace pmem
53 {
54 
55 namespace obj
56 {
57 
73 template <typename T, std::size_t N>
74 struct array {
75 
76  template <typename Y, std::size_t M>
77  struct standard_array_traits {
78  using type = Y[N];
79  };
80 
81  /* zero-sized array support */
82  template <typename Y>
83  struct standard_array_traits<Y, 0> {
84  struct _alignment_struct {
85  Y _data[1];
86  };
87 
88  struct alignas(_alignment_struct) type {
89  char _data[sizeof(_alignment_struct)];
90  };
91  };
92 
93  /* Member types */
94  using value_type = T;
95  using pointer = value_type *;
96  using const_pointer = const value_type *;
97  using reference = value_type &;
98  using const_reference = const value_type &;
100  using const_iterator = const_pointer;
101  using size_type = std::size_t;
102  using difference_type = std::ptrdiff_t;
103  using reverse_iterator = std::reverse_iterator<iterator>;
104  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
107 
108  /* Underlying array */
109  typename standard_array_traits<T, N>::type _data;
110 
114  array() = default;
115 
119  array(const array &) = default;
120 
127  array(array &&) = default;
128 
139  array &
140  operator=(const array &other)
141  {
142  /*
143  * _get_pool should be called before self assignment check to
144  * maintain the same behaviour for all arguments.
145  */
146  auto pop = _get_pool();
147 
148  if (this == &other)
149  return *this;
150 
151  transaction::run(pop, [&] {
152  detail::conditional_add_to_tx(
153  this, 1, POBJ_XADD_ASSUME_INITIALIZED);
154  std::copy(other.cbegin(), other.cend(), _get_data());
155  });
156 
157  return *this;
158  }
159 
170  array &
171  operator=(array &&other)
172  {
173  /*
174  * _get_pool should be called before self assignment check to
175  * maintain the same behaviour for all arguments.
176  */
177  auto pop = _get_pool();
178 
179  if (this == &other)
180  return *this;
181 
182  transaction::run(pop, [&] {
183  detail::conditional_add_to_tx(
184  this, 1, POBJ_XADD_ASSUME_INITIALIZED);
185  detail::conditional_add_to_tx(
186  &other, 1, POBJ_XADD_ASSUME_INITIALIZED);
187  std::move(other._get_data(), other._get_data() + size(),
188  _get_data());
189  });
190 
191  return *this;
192  }
193 
201  reference
202  at(size_type n)
203  {
204  if (n >= N)
205  throw std::out_of_range("array::at");
206 
207  detail::conditional_add_to_tx(_get_data() + n, 1,
208  POBJ_XADD_ASSUME_INITIALIZED);
209 
210  return _get_data()[n];
211  }
212 
218  const_reference
219  at(size_type n) const
220  {
221  if (n >= N)
222  throw std::out_of_range("array::at");
223 
224  return _get_data()[n];
225  }
226 
232  const_reference
233  const_at(size_type n) const
234  {
235  if (n >= N)
236  throw std::out_of_range("array::const_at");
237 
238  return _get_data()[n];
239  }
240 
248  reference operator[](size_type n)
249  {
250  detail::conditional_add_to_tx(_get_data() + n, 1,
251  POBJ_XADD_ASSUME_INITIALIZED);
252 
253  return _get_data()[n];
254  }
255 
260  const_reference operator[](size_type n) const
261  {
262  return _get_data()[n];
263  }
264 
272  T *
274  {
275  detail::conditional_add_to_tx(this, 1,
276  POBJ_XADD_ASSUME_INITIALIZED);
277  return _get_data();
278  }
279 
283  const T *
284  data() const noexcept
285  {
286  return _get_data();
287  }
288 
292  const T *
293  cdata() const noexcept
294  {
295  return _get_data();
296  }
297 
304  iterator
306  {
307  return iterator(_get_data());
308  }
309 
316  iterator
317  end()
318  {
319  return iterator(_get_data() + size());
320  }
321 
325  const_iterator
326  begin() const noexcept
327  {
328  return const_iterator(_get_data());
329  }
330 
334  const_iterator
335  cbegin() const noexcept
336  {
337  return const_iterator(_get_data());
338  }
339 
343  const_iterator
344  end() const noexcept
345  {
346  return const_iterator(_get_data() + size());
347  }
348 
352  const_iterator
353  cend() const noexcept
354  {
355  return const_iterator(_get_data() + size());
356  }
357 
364  reverse_iterator
366  {
367  return reverse_iterator(iterator(_get_data() + size()));
368  }
369 
376  reverse_iterator
378  {
379  return reverse_iterator(iterator(_get_data()));
380  }
381 
385  const_reverse_iterator
386  rbegin() const noexcept
387  {
388  return const_reverse_iterator(cend());
389  }
390 
394  const_reverse_iterator
395  crbegin() const noexcept
396  {
397  return const_reverse_iterator(cend());
398  }
399 
403  const_reverse_iterator
404  rend() const noexcept
405  {
406  return const_reverse_iterator(cbegin());
407  }
408 
412  const_reverse_iterator
413  crend() const noexcept
414  {
415  return const_reverse_iterator(cbegin());
416  }
417 
424  reference
426  {
427  detail::conditional_add_to_tx(_get_data(), 1,
428  POBJ_XADD_ASSUME_INITIALIZED);
429  return _get_data()[0];
430  }
431 
438  reference
440  {
441  detail::conditional_add_to_tx(&_get_data()[size() - 1], 1,
442  POBJ_XADD_ASSUME_INITIALIZED);
443  return _get_data()[size() - 1];
444  }
445 
449  const_reference
450  front() const
451  {
452  return _get_data()[0];
453  }
454 
458  const_reference
459  cfront() const
460  {
461  return _get_data()[0];
462  }
463 
467  const_reference
468  back() const
469  {
470  return _get_data()[size() - 1];
471  }
472 
476  const_reference
477  cback() const
478  {
479  return _get_data()[size() - 1];
480  }
481 
494  range(size_type start, size_type n)
495  {
496  if (start + n > N)
497  throw std::out_of_range("array::range");
498 
499  detail::conditional_add_to_tx(_get_data() + start, n,
500  POBJ_XADD_ASSUME_INITIALIZED);
501 
502  return {_get_data() + start, _get_data() + start + n};
503  }
504 
522  range(size_type start, size_type n, size_type snapshot_size)
523  {
524  if (start + n > N)
525  throw std::out_of_range("array::range");
526 
527  if (snapshot_size > n)
528  snapshot_size = n;
529 
530  return {range_snapshotting_iterator(_get_data() + start,
531  _get_data() + start, n,
532  snapshot_size),
534  _get_data() + start, n,
535  snapshot_size)};
536  }
537 
550  range(size_type start, size_type n) const
551  {
552  if (start + n > N)
553  throw std::out_of_range("array::range");
554 
555  return {const_iterator(_get_data() + start),
556  const_iterator(_get_data() + start + n)};
557  }
558 
571  crange(size_type start, size_type n) const
572  {
573  if (start + n > N)
574  throw std::out_of_range("array::crange");
575 
576  return {const_iterator(_get_data() + start),
577  const_iterator(_get_data() + start + n)};
578  }
579 
583  constexpr size_type
584  size() const noexcept
585  {
586  return N;
587  }
588 
592  constexpr size_type
593  max_size() const noexcept
594  {
595  return N;
596  }
597 
601  constexpr bool
602  empty() const noexcept
603  {
604  return size() == 0;
605  }
606 
614  void
615  fill(const_reference value)
616  {
617  auto pop = _get_pool();
618 
619  transaction::run(pop, [&] {
620  detail::conditional_add_to_tx(
621  this, 1, POBJ_XADD_ASSUME_INITIALIZED);
622  std::fill(_get_data(), _get_data() + size(), value);
623  });
624  }
625 
633  template <std::size_t Size = N>
634  typename std::enable_if<Size != 0>::type
635  swap(array &other)
636  {
637  /*
638  * _get_pool should be called before self assignment check to
639  * maintain the same behaviour for all arguments.
640  */
641  auto pop = _get_pool();
642 
643  if (this == &other)
644  return;
645 
646  transaction::run(pop, [&] {
647  detail::conditional_add_to_tx(
648  this, 1, POBJ_XADD_ASSUME_INITIALIZED);
649  detail::conditional_add_to_tx(
650  &other, 1, POBJ_XADD_ASSUME_INITIALIZED);
651 
652  std::swap_ranges(_get_data(), _get_data() + size(),
653  other._get_data());
654  });
655  }
656 
660  template <std::size_t Size = N>
661  typename std::enable_if<Size == 0>::type
662  swap(array &other)
663  {
664  static_assert(!std::is_const<T>::value,
665  "cannot swap zero-sized array of type 'const T'");
666  }
667 
668 private:
672  template <std::size_t Size = N>
673  typename std::enable_if<Size != 0, T *>::type
675  {
676  return this->_data;
677  }
678 
682  template <std::size_t Size = N>
683  typename std::enable_if<Size != 0, const T *>::type
684  _get_data() const
685  {
686  return this->_data;
687  }
688 
693  template <std::size_t Size = N>
694  typename std::enable_if<Size == 0, T *>::type
696  {
697  return reinterpret_cast<T *>(&this->_data);
698  }
699 
703  template <std::size_t Size = N>
704  typename std::enable_if<Size == 0, const T *>::type
705  _get_data() const
706  {
707  return reinterpret_cast<const T *>(&this->_data);
708  }
709 
715  pool_base
716  _get_pool() const
717  {
718  auto pop = pmemobj_pool_by_ptr(this);
719  if (pop == nullptr)
720  throw pmem::pool_error(
721  "Object outside of pmemobj pool.");
722 
723  return pool_base(pop);
724  }
725 };
726 
730 template <typename T, std::size_t N>
731 inline bool
732 operator==(const array<T, N> &lhs, const array<T, N> &rhs)
733 {
734  return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
735 }
736 
740 template <typename T, std::size_t N>
741 inline bool
742 operator!=(const array<T, N> &lhs, const array<T, N> &rhs)
743 {
744  return !(lhs == rhs);
745 }
746 
750 template <typename T, std::size_t N>
751 inline bool
752 operator<(const array<T, N> &lhs, const array<T, N> &rhs)
753 {
754  return std::lexicographical_compare(lhs.cbegin(), lhs.cend(),
755  rhs.cbegin(), rhs.cend());
756 }
757 
761 template <typename T, std::size_t N>
762 inline bool
763 operator>(const array<T, N> &lhs, const array<T, N> &rhs)
764 {
765  return rhs < lhs;
766 }
767 
771 template <typename T, std::size_t N>
772 inline bool
773 operator>=(const array<T, N> &lhs, const array<T, N> &rhs)
774 {
775  return !(lhs < rhs);
776 }
777 
781 template <typename T, std::size_t N>
782 inline bool
783 operator<=(const array<T, N> &lhs, const array<T, N> &rhs)
784 {
785  return !(lhs > rhs);
786 }
787 
791 template <typename T, std::size_t N>
792 typename pmem::obj::array<T, N>::const_iterator
794 {
795  return a.cbegin();
796 }
797 
801 template <typename T, std::size_t N>
802 typename pmem::obj::array<T, N>::const_iterator
804 {
805  return a.cend();
806 }
807 
811 template <typename T, std::size_t N>
812 typename pmem::obj::array<T, N>::const_reverse_iterator
814 {
815  return a.crbegin();
816 }
817 
821 template <typename T, std::size_t N>
822 typename pmem::obj::array<T, N>::const_reverse_iterator
824 {
825  return a.crend();
826 }
827 
831 template <typename T, std::size_t N>
834 {
835  return a.begin();
836 }
837 
841 template <typename T, std::size_t N>
842 typename pmem::obj::array<T, N>::const_iterator
844 {
845  return a.begin();
846 }
847 
851 template <typename T, std::size_t N>
854 {
855  return a.end();
856 }
857 
861 template <typename T, std::size_t N>
862 typename pmem::obj::array<T, N>::const_iterator
864 {
865  return a.end();
866 }
867 
871 template <typename T, std::size_t N>
872 typename pmem::obj::array<T, N>::reverse_iterator
874 {
875  return a.rbegin();
876 }
877 
881 template <typename T, std::size_t N>
882 typename pmem::obj::array<T, N>::const_reverse_iterator
884 {
885  return a.rbegin();
886 }
887 
891 template <typename T, std::size_t N>
892 typename pmem::obj::array<T, N>::reverse_iterator
894 {
895  return a.rend();
896 }
897 
901 template <typename T, std::size_t N>
902 typename pmem::obj::array<T, N>::const_reverse_iterator
904 {
905  return a.rend();
906 }
907 
911 template <typename T, size_t N>
912 inline void
914 {
915  lhs.swap(rhs);
916 }
917 
921 template <size_t I, typename T, size_t N>
922 T &
924 {
925  static_assert(I < N,
926  "Index out of bounds in std::get<> (pmem::obj::array)");
927  return a.at(I);
928 }
929 
933 template <size_t I, typename T, size_t N>
934 T &&
936 {
937  static_assert(I < N,
938  "Index out of bounds in std::get<> (pmem::obj::array)");
939  return std::move(a.at(I));
940 }
941 
945 template <size_t I, typename T, size_t N>
946 const T &
947 get(const pmem::obj::array<T, N> &a) noexcept
948 {
949  static_assert(I < N,
950  "Index out of bounds in std::get<> (pmem::obj::array)");
951  return a.at(I);
952 }
953 
957 template <size_t I, typename T, size_t N>
958 const T &&
959 get(const pmem::obj::array<T, N> &&a) noexcept
960 {
961  static_assert(I < N,
962  "Index out of bounds in std::get<> (pmem::obj::array)");
963  return std::move(a.at(I));
964 }
965 
966 } /* namespace obj */
967 
968 } /* namespace pmem */
969 
970 #endif /* LIBPMEMOBJ_CPP_ARRAY_HPP */
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:402
const T * cdata() const noexcept
Returns const raw pointer to the underlying data.
Definition: array.hpp:293
std::enable_if< Size !=0 >::type swap(array &other)
Swaps content with other array's content inside internal transaction.
Definition: array.hpp:635
std::enable_if< Size !=0, T * >::type _get_data()
Support for non-zero sized array.
Definition: array.hpp:674
const_reverse_iterator rend() const noexcept
Returns a const reverse iterator to the end.
Definition: array.hpp:404
reference at(size_type n)
Access element at specific index and add it to a transaction.
Definition: array.hpp:202
const_reverse_iterator crend() const noexcept
Returns a const reverse iterator to the beginning.
Definition: array.hpp:413
reverse_iterator rend()
Returns a reverse iterator to the end.
Definition: array.hpp:377
const_reference const_at(size_type n) const
Access element at specific index.
Definition: array.hpp:233
The non-template pool base class.
Definition: pool.hpp:67
Custom pool error class.
Definition: pexceptions.hpp:72
iterator begin()
Returns an iterator to the beginning.
Definition: array.hpp:305
std::enable_if< Size !=0, const T * >::type _get_data() const
Support for non-zero sized array.
Definition: array.hpp:684
std::enable_if< Size==0 >::type swap(array &other)
Swap for zero-sized array.
Definition: array.hpp:662
T & get(pmem::obj::array< T, N > &a)
Non-member get function.
Definition: array.hpp:923
pmem::obj::slice - provides interface to access sequence of objects.
Definition: slice.hpp:56
bool operator<(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member less than operator.
Definition: array.hpp:752
reference back()
Access the last element and add this element to a transaction.
Definition: array.hpp:439
T * data()
Returns raw pointer to the underlying data and adds entire array to a transaction.
Definition: array.hpp:273
const_reference cback() const
Access the last element.
Definition: array.hpp:477
C++ pmemobj transactions.
Convenience extensions for the resides on pmem property template.
slice< pointer > range(size_type start, size_type n)
Returns slice and snapshots requested range.
Definition: array.hpp:494
const_iterator cend() const noexcept
Returns a const iterator to the end.
Definition: array.hpp:353
Commonly used functionality.
bool operator<=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member less or equal operator.
Definition: array.hpp:783
array & operator=(const array &other)
Copy assignment operator - perform assignment from other pmem::obj::array.
Definition: array.hpp:140
const_reference operator[](size_type n) const
Access element at specific index.
Definition: array.hpp:260
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: array.hpp:395
Iterators for contiguous persistent containers.
reverse_iterator rbegin()
Returns a reverse iterator to the beginning.
Definition: array.hpp:365
Non-const iterator which adds elements to a transaction in a bulk.
Definition: contiguous_iterator.hpp:220
const_reference front() const
Access the first element.
Definition: array.hpp:450
iterator end()
Returns an iterator to the end.
Definition: array.hpp:317
constexpr size_type max_size() const noexcept
Returns the maximum size of the array.
Definition: array.hpp:593
constexpr size_type size() const noexcept
Returns size of the array.
Definition: array.hpp:584
slice< const_iterator > crange(size_type start, size_type n) const
Returns const slice.
Definition: array.hpp:571
Default non-const iterator which adds element to a transaction on every access.
Definition: contiguous_iterator.hpp:359
const_iterator cbegin() const noexcept
Returns const iterator to the beginning.
Definition: array.hpp:335
const_reference cfront() const
Access the first element.
Definition: array.hpp:459
void fill(const_reference value)
Fills array with specified value inside internal transaction.
Definition: array.hpp:615
const_reference at(size_type n) const
Access element at specific index.
Definition: array.hpp:219
reference operator[](size_type n)
Access element at specific index and add it to a transaction.
Definition: array.hpp:248
bool operator>(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater than operator.
Definition: array.hpp:763
Persistent smart pointer.
Iterface to access sequence of objects.
array & operator=(array &&other)
Move assignment operator - perform move assignment from other pmem::obj::array.
Definition: array.hpp:171
slice< const_iterator > range(size_type start, size_type n) const
Returns const slice.
Definition: array.hpp:550
constexpr bool empty() const noexcept
Checks whether array is empty.
Definition: array.hpp:602
const_reverse_iterator rbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: array.hpp:386
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:518
const_reference back() const
Access the last element.
Definition: array.hpp:468
A persistent version of concurrent hash map implementation Ref: https://arxiv.org/abs/1509....
Definition: allocation_flag.hpp:43
const T * data() const noexcept
Returns const raw pointer to the underlying data.
Definition: array.hpp:284
pool_base _get_pool() const
Check whether object is on pmem and return pool_base instance.
Definition: array.hpp:716
const_iterator end() const noexcept
Returns a const iterator to the end.
Definition: array.hpp:344
reference front()
Access the first element and add this element to a transaction.
Definition: array.hpp:425
std::enable_if< Size==0, const T * >::type _get_data() const
Support for zero sized array.
Definition: array.hpp:705
bool operator>=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater or equal operator.
Definition: array.hpp:773
std::enable_if< Size==0, T * >::type _get_data()
Support for zero sized array.
Definition: array.hpp:695
pmem::obj::array - persistent container with std::array compatible interface.
Definition: array.hpp:74
array()=default
Defaulted constructor.
static void run(pool_base &pool, std::function< void()> tx, Locks &... locks)
Execute a closure-like transaction and lock locks.
Definition: transaction.hpp:403
slice< range_snapshotting_iterator > range(size_type start, size_type n, size_type snapshot_size)
Returns slice.
Definition: array.hpp:522
const_iterator begin() const noexcept
Returns const iterator to the beginning.
Definition: array.hpp:326