PMDK C++ bindings  1.2.0
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 
48 #include <libpmemobj++/pext.hpp>
50 #include <libpmemobj.h>
51 
52 namespace pmem
53 {
54 
55 namespace obj
56 {
57 
58 namespace experimental
59 {
60 
77 template <typename T, std::size_t N>
78 struct array {
79 
80  template <typename Y, std::size_t M>
81  struct standard_array_traits {
82  using type = Y[N];
83  };
84 
85  /* zero-sized array support */
86  template <typename Y>
87  struct standard_array_traits<Y, 0> {
88  struct _alignment_struct {
89  Y _data[1];
90  };
91 
92  struct alignas(_alignment_struct) type {
93  char _data[sizeof(_alignment_struct)];
94  };
95  };
96 
97  /* Member types */
98  using value_type = T;
99  using pointer = value_type *;
100  using const_pointer = const value_type *;
101  using reference = value_type &;
102  using const_reference = const value_type &;
104  using const_iterator = const_pointer;
105  using size_type = std::size_t;
106  using difference_type = std::ptrdiff_t;
107  using reverse_iterator = std::reverse_iterator<iterator>;
108  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
109 
110  /* Underlying array */
111  typename standard_array_traits<T, N>::type _data;
112 
116  array() = default;
117 
121  array(const array &) = default;
122 
126  array(array &&) = default;
127 
138  array &
139  operator=(const array &other)
140  {
141  /*
142  * _get_pool should be called before self assignment check to
143  * maintain the same behaviour for all arguments.
144  */
145  auto pop = _get_pool();
146 
147  if (this == &other)
148  return *this;
149 
150  transaction::run(pop, [&] {
151  detail::conditional_add_to_tx(this);
152  std::copy(other.cbegin(), other.cend(), _get_data());
153  });
154 
155  return *this;
156  }
157 
168  array &
169  operator=(array &&other)
170  {
171  /*
172  * _get_pool should be called before self assignment check to
173  * maintain the same behaviour for all arguments.
174  */
175  auto pop = _get_pool();
176 
177  if (this == &other)
178  return *this;
179 
180  transaction::run(pop, [&] {
181  detail::conditional_add_to_tx(this);
182  std::copy(other.cbegin(), other.cend(), _get_data());
183  });
184 
185  return *this;
186  }
187 
195  reference
196  at(size_type n)
197  {
198  if (n >= N)
199  throw std::out_of_range("array::at");
200 
201  detail::conditional_add_to_tx(_get_data() + n);
202 
203  return _get_data()[n];
204  }
205 
211  const_reference
212  at(size_type n) const
213  {
214  if (n >= N)
215  throw std::out_of_range("array::at");
216 
217  return _get_data()[n];
218  }
219 
225  const_reference
226  const_at(size_type n) const
227  {
228  if (n >= N)
229  throw std::out_of_range("array::const_at");
230 
231  return _get_data()[n];
232  }
233 
241  reference operator[](size_type n)
242  {
243  detail::conditional_add_to_tx(_get_data() + n);
244 
245  return _get_data()[n];
246  }
247 
252  const_reference operator[](size_type n) const
253  {
254  return _get_data()[n];
255  }
256 
264  T *
266  {
267  detail::conditional_add_to_tx(this);
268  return _get_data();
269  }
270 
274  const T *
275  data() const noexcept
276  {
277  return _get_data();
278  }
279 
283  const T *
284  cdata() const noexcept
285  {
286  return _get_data();
287  }
288 
295  iterator
297  {
298  return iterator(_get_data());
299  }
300 
307  iterator
308  end()
309  {
310  return iterator(_get_data() + size());
311  }
312 
316  const_iterator
317  begin() const noexcept
318  {
319  return const_iterator(_get_data());
320  }
321 
325  const_iterator
326  cbegin() const noexcept
327  {
328  return const_iterator(_get_data());
329  }
330 
334  const_iterator
335  end() const noexcept
336  {
337  return const_iterator(_get_data() + size());
338  }
339 
343  const_iterator
344  cend() const noexcept
345  {
346  return const_iterator(_get_data() + size());
347  }
348 
355  reverse_iterator
357  {
358  return reverse_iterator(iterator(_get_data() + size()));
359  }
360 
367  reverse_iterator
369  {
370  return reverse_iterator(iterator(_get_data()));
371  }
372 
376  const_reverse_iterator
377  rbegin() const noexcept
378  {
379  return const_reverse_iterator(cend());
380  }
381 
385  const_reverse_iterator
386  crbegin() const noexcept
387  {
388  return const_reverse_iterator(cend());
389  }
390 
394  const_reverse_iterator
395  rend() const noexcept
396  {
397  return const_reverse_iterator(cbegin());
398  }
399 
403  const_reverse_iterator
404  crend() const noexcept
405  {
406  return const_reverse_iterator(cbegin());
407  }
408 
415  reference
417  {
418  detail::conditional_add_to_tx(_get_data());
419  return _get_data()[0];
420  }
421 
428  reference
430  {
431  detail::conditional_add_to_tx(&_get_data()[size() - 1]);
432  return _get_data()[size() - 1];
433  }
434 
438  const_reference
439  front() const
440  {
441  return _get_data()[0];
442  }
443 
447  const_reference
448  cfront() const
449  {
450  return _get_data()[0];
451  }
452 
456  const_reference
457  back() const
458  {
459  return _get_data()[size() - 1];
460  }
461 
465  const_reference
466  cback() const
467  {
468  return _get_data()[size() - 1];
469  }
470 
483  range(size_type start, size_type n)
484  {
485  if (start + n > N)
486  throw std::out_of_range("array::range");
487 
488  detail::conditional_add_to_tx(_get_data() + start, n);
489 
490  return {_get_data() + start, _get_data() + start + n};
491  }
492 
510  range(size_type start, size_type n, size_type snapshot_size)
511  {
512  if (start + n > N)
513  throw std::out_of_range("array::range");
514 
515  if (snapshot_size > n)
516  snapshot_size = n;
517 
518  return {range_snapshotting_iterator<T>(_get_data() + start,
519  _get_data() + start, n,
520  snapshot_size),
522  _get_data() + start, n,
523  snapshot_size)};
524  }
525 
538  range(size_type start, size_type n) const
539  {
540  if (start + n > N)
541  throw std::out_of_range("array::range");
542 
543  return {const_iterator(_get_data() + start),
544  const_iterator(_get_data() + start + n)};
545  }
546 
559  crange(size_type start, size_type n) const
560  {
561  if (start + n > N)
562  throw std::out_of_range("array::crange");
563 
564  return {const_iterator(_get_data() + start),
565  const_iterator(_get_data() + start + n)};
566  }
567 
571  constexpr size_type
572  size() const noexcept
573  {
574  return N;
575  }
576 
580  constexpr size_type
581  max_size() const noexcept
582  {
583  return N;
584  }
585 
589  constexpr bool
590  empty() const noexcept
591  {
592  return size() == 0;
593  }
594 
602  void
603  fill(const_reference value)
604  {
605  auto pop = _get_pool();
606 
607  transaction::run(pop, [&] {
608  detail::conditional_add_to_tx(this);
609  std::fill(_get_data(), _get_data() + size(), value);
610  });
611  }
612 
620  template <std::size_t Size = N>
621  typename std::enable_if<Size != 0>::type
622  swap(array &other)
623  {
624  /*
625  * _get_pool should be called before self assignment check to
626  * maintain the same behaviour for all arguments.
627  */
628  auto pop = _get_pool();
629 
630  if (this == &other)
631  return;
632 
633  transaction::run(pop, [&] {
634  detail::conditional_add_to_tx(this);
635  detail::conditional_add_to_tx(&other);
636 
637  std::swap_ranges(_get_data(), _get_data() + size(),
638  other._get_data());
639  });
640  }
641 
645  template <std::size_t Size = N>
646  typename std::enable_if<Size == 0>::type
647  swap(array &other)
648  {
649  static_assert(!std::is_const<T>::value,
650  "cannot swap zero-sized array of type 'const T'");
651  }
652 
653 private:
657  template <std::size_t Size = N>
658  typename std::enable_if<Size != 0, T *>::type
660  {
661  return this->_data;
662  }
663 
667  template <std::size_t Size = N>
668  typename std::enable_if<Size != 0, const T *>::type
669  _get_data() const
670  {
671  return this->_data;
672  }
673 
678  template <std::size_t Size = N>
679  typename std::enable_if<Size == 0, T *>::type
681  {
682  return reinterpret_cast<T *>(&this->_data);
683  }
684 
688  template <std::size_t Size = N>
689  typename std::enable_if<Size == 0, const T *>::type
690  _get_data() const
691  {
692  return reinterpret_cast<const T *>(&this->_data);
693  }
694 
700  pool_base
701  _get_pool() const
702  {
703  auto pop = pmemobj_pool_by_ptr(this);
704  if (pop == nullptr)
705  throw pool_error("Object outside of pmemobj pool.");
706 
707  return pool_base(pop);
708  }
709 };
710 
714 template <typename T, std::size_t N>
715 inline bool
716 operator==(const array<T, N> &lhs, const array<T, N> &rhs)
717 {
718  return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
719 }
720 
724 template <typename T, std::size_t N>
725 inline bool
726 operator!=(const array<T, N> &lhs, const array<T, N> &rhs)
727 {
728  return !(lhs == rhs);
729 }
730 
734 template <typename T, std::size_t N>
735 inline bool
736 operator<(const array<T, N> &lhs, const array<T, N> &rhs)
737 {
738  return std::lexicographical_compare(lhs.cbegin(), lhs.cend(),
739  rhs.cbegin(), rhs.cend());
740 }
741 
745 template <typename T, std::size_t N>
746 inline bool
747 operator>(const array<T, N> &lhs, const array<T, N> &rhs)
748 {
749  return rhs < lhs;
750 }
751 
755 template <typename T, std::size_t N>
756 inline bool
757 operator>=(const array<T, N> &lhs, const array<T, N> &rhs)
758 {
759  return !(lhs < rhs);
760 }
761 
765 template <typename T, std::size_t N>
766 inline bool
767 operator<=(const array<T, N> &lhs, const array<T, N> &rhs)
768 {
769  return !(lhs > rhs);
770 }
771 
775 template <typename T, std::size_t N>
776 typename pmem::obj::experimental::array<T, N>::const_iterator
778 {
779  return a.cbegin();
780 }
781 
785 template <typename T, std::size_t N>
786 typename pmem::obj::experimental::array<T, N>::const_iterator
788 {
789  return a.cend();
790 }
791 
795 template <typename T, std::size_t N>
796 typename pmem::obj::experimental::array<T, N>::const_reverse_iterator
798 {
799  return a.crbegin();
800 }
801 
805 template <typename T, std::size_t N>
806 typename pmem::obj::experimental::array<T, N>::const_reverse_iterator
808 {
809  return a.crend();
810 }
811 
815 template <typename T, std::size_t N>
818 {
819  return a.begin();
820 }
821 
825 template <typename T, std::size_t N>
826 typename pmem::obj::experimental::array<T, N>::const_iterator
828 {
829  return a.begin();
830 }
831 
835 template <typename T, std::size_t N>
838 {
839  return a.end();
840 }
841 
845 template <typename T, std::size_t N>
846 typename pmem::obj::experimental::array<T, N>::const_iterator
848 {
849  return a.end();
850 }
851 
855 template <typename T, std::size_t N>
856 typename pmem::obj::experimental::array<T, N>::reverse_iterator
858 {
859  return a.rbegin();
860 }
861 
865 template <typename T, std::size_t N>
866 typename pmem::obj::experimental::array<T, N>::const_reverse_iterator
868 {
869  return a.rbegin();
870 }
871 
875 template <typename T, std::size_t N>
876 typename pmem::obj::experimental::array<T, N>::reverse_iterator
878 {
879  return a.rend();
880 }
881 
885 template <typename T, std::size_t N>
886 typename pmem::obj::experimental::array<T, N>::const_reverse_iterator
888 {
889  return a.rend();
890 }
891 
895 template <typename T, size_t N>
896 inline void
899 {
900  lhs.swap(rhs);
901 }
902 
906 template <size_t I, typename T, size_t N>
907 T &
909 {
910  static_assert(I < N,
911  "Index out of bounds in std::get<> (pmem::obj::array)");
912  return a.at(I);
913 }
914 
918 template <size_t I, typename T, size_t N>
919 T &&
921 {
922  static_assert(I < N,
923  "Index out of bounds in std::get<> (pmem::obj::array)");
924  return std::move(a.at(I));
925 }
926 
930 template <size_t I, typename T, size_t N>
931 const T &
933 {
934  static_assert(I < N,
935  "Index out of bounds in std::get<> (pmem::obj::array)");
936  return a.at(I);
937 }
938 
942 template <size_t I, typename T, size_t N>
943 const T &&
945 {
946  static_assert(I < N,
947  "Index out of bounds in std::get<> (pmem::obj::array)");
948  return std::move(a.at(I));
949 }
950 
951 } /* namespace experimental */
952 
953 } /* namespace obj */
954 
955 } /* namespace pmem */
956 
957 #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:400
slice< const_iterator > range(size_type start, size_type n) const
Returns const slice.
Definition: array.hpp:538
Non-const iterator which adds elements to a transaction in a bulk.
Definition: contiguous_iterator.hpp:223
constexpr bool empty() const noexcept
Checks whether array is empty.
Definition: array.hpp:590
bool operator>=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater or equal operator.
Definition: array.hpp:757
std::enable_if< Size !=0 >::type swap(array &other)
Swaps content with other array&#39;s content inside internal transaction.
Definition: array.hpp:622
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: array.hpp:386
Default non-const iterator which adds element to a transaction on every access.
Definition: contiguous_iterator.hpp:360
const_iterator cbegin() const noexcept
Returns const iterator to the beginning.
Definition: array.hpp:326
slice< range_snapshotting_iterator< T > > range(size_type start, size_type n, size_type snapshot_size)
Returns slice.
Definition: array.hpp:510
slice< const_iterator > crange(size_type start, size_type n) const
Returns const slice.
Definition: array.hpp:559
const_reference const_at(size_type n) const
Access element at specific index.
Definition: array.hpp:226
void fill(const_reference value)
Fills array with specified value inside internal transaction.
Definition: array.hpp:603
The non-template pool base class.
Definition: pool.hpp:67
Custom pool error class.
Definition: pexceptions.hpp:53
iterator end()
Returns an iterator to the end.
Definition: array.hpp:308
const_iterator begin() const noexcept
Returns const iterator to the beginning.
Definition: array.hpp:317
array & operator=(const array &other)
Copy assignment operator - perform assignment from other pmem::obj::experimental::array.
Definition: array.hpp:139
iterator begin()
Returns an iterator to the beginning.
Definition: array.hpp:296
std::enable_if< Size !=0, T * >::type _get_data()
Support for non-zero sized array.
Definition: array.hpp:659
reverse_iterator rend()
Returns a reverse iterator to the end.
Definition: array.hpp:368
const_reference cback() const
Access the last element.
Definition: array.hpp:466
reference back()
Access the last element and add this element to a transaction.
Definition: array.hpp:429
C++ pmemobj transactions.
Convenience extensions for the resides on pmem property template.
const_reference back() const
Access the last element.
Definition: array.hpp:457
Commonly used functionality.
Iterators for pmem::obj::array.
pmem::obj::experimental::array - EXPERIMENTAL persistent container with std::array compatible interfa...
Definition: array.hpp:78
std::enable_if< Size !=0, const T * >::type _get_data() const
Support for non-zero sized array.
Definition: array.hpp:669
reference operator[](size_type n)
Access element at specific index and add it to a transaction.
Definition: array.hpp:241
T * data()
Returns raw pointer to the underlying data and adds entire array to a transaction.
Definition: array.hpp:265
constexpr size_type max_size() const noexcept
Returns the maximum size of the array.
Definition: array.hpp:581
array()=default
Defaulted constructor.
const_reverse_iterator rbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: array.hpp:377
std::enable_if< Size==0, T * >::type _get_data()
Support for zero sized array.
Definition: array.hpp:680
pmem::obj::experimental::slice - provides interface to access sequence of objects.
Definition: slice.hpp:58
slice< pointer > range(size_type start, size_type n)
Returns slice and snapshots requested range.
Definition: array.hpp:483
reverse_iterator rbegin()
Returns a reverse iterator to the beginning.
Definition: array.hpp:356
const T * cdata() const noexcept
Returns const raw pointer to the underlying data.
Definition: array.hpp:284
const_reverse_iterator rend() const noexcept
Returns a const reverse iterator to the end.
Definition: array.hpp:395
const_reference operator[](size_type n) const
Access element at specific index.
Definition: array.hpp:252
const_reference front() const
Access the first element.
Definition: array.hpp:439
const_iterator end() const noexcept
Returns a const iterator to the end.
Definition: array.hpp:335
const T * data() const noexcept
Returns const raw pointer to the underlying data.
Definition: array.hpp:275
pool_base _get_pool() const
Check whether object is on pmem and return pool_base instance.
Definition: array.hpp:701
const_iterator cend() const noexcept
Returns a const iterator to the end.
Definition: array.hpp:344
std::enable_if< Size==0, const T * >::type _get_data() const
Support for zero sized array.
Definition: array.hpp:690
std::enable_if< Size==0 >::type swap(array &other)
Swap for zero-sized array.
Definition: array.hpp:647
Persistent smart pointer.
bool operator>(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater than operator.
Definition: array.hpp:747
Iterface to access sequence of objects.
const_reference cfront() const
Access the first element.
Definition: array.hpp:448
reference at(size_type n)
Access element at specific index and add it to a transaction.
Definition: array.hpp:196
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:516
const_reverse_iterator crend() const noexcept
Returns a const reverse iterator to the beginning.
Definition: array.hpp:404
Definition: allocation_flag.hpp:43
constexpr size_type size() const noexcept
Returns size of the array.
Definition: array.hpp:572
array & operator=(array &&other)
Move assignment operator - perform move assignment from other pmem::obj::experimental::array.
Definition: array.hpp:169
reference front()
Access the first element and add this element to a transaction.
Definition: array.hpp:416
static void run(pool_base &pool, std::function< void()> tx, Locks &... locks)
Execute a closure-like transaction and lock locks.
Definition: transaction.hpp:398
const_reference at(size_type n) const
Access element at specific index.
Definition: array.hpp:212