PMDK C++ bindings  1.13.0-git107.g7e59f08f
This is the C++ bindings documentation for PMDK's libpmemobj.
vector.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_VECTOR_HPP
10 #define LIBPMEMOBJ_CPP_VECTOR_HPP
11 
19 #include <libpmemobj++/pext.hpp>
20 #include <libpmemobj++/slice.hpp>
22 #include <libpmemobj++/utils.hpp>
23 #include <libpmemobj/base.h>
24 
25 #include <algorithm>
26 #include <cassert>
27 #include <utility>
28 #include <vector>
29 
30 namespace pmem
31 {
32 
33 namespace obj
34 {
35 
40 template <typename T>
41 class vector {
42 public:
43  /* Member types */
44  using value_type = T;
45  using size_type = std::size_t;
46  using difference_type = std::ptrdiff_t;
47  using reference = value_type &;
48  using const_reference = const value_type &;
49  using pointer = value_type *;
50  using const_pointer = const value_type *;
52  using const_iterator = const_pointer;
53  using reverse_iterator = std::reverse_iterator<iterator>;
54  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
57  /* func argument type definition for 'for_each_ptr' method */
58  using for_each_ptr_function =
59  std::function<void(persistent_ptr_base &)>;
60 
61  /* Constructors */
62  vector();
63  vector(size_type count, const value_type &value);
64  explicit vector(size_type count);
65  template <typename InputIt,
66  typename std::enable_if<
68  InputIt>::type * = nullptr>
69  vector(InputIt first, InputIt last);
70  vector(const vector &other);
71  vector(vector &&other);
72  vector(std::initializer_list<T> init);
73  vector(const std::vector<T> &other);
74 
75  /* Assign operators */
76  vector &operator=(const vector &other);
77  vector &operator=(vector &&other);
78  vector &operator=(std::initializer_list<T> ilist);
79  vector &operator=(const std::vector<T> &other);
80 
81  /* Assign methods */
82  void assign(size_type count, const T &value);
83  template <typename InputIt,
84  typename std::enable_if<
86  InputIt>::type * = nullptr>
87  void assign(InputIt first, InputIt last);
88  void assign(std::initializer_list<T> ilist);
89  void assign(const vector &other);
90  void assign(vector &&other);
91  void assign(const std::vector<T> &other);
92 
93  /* Destructor */
95 
96  /* Element access */
97  reference at(size_type n);
98  const_reference at(size_type n) const;
99  const_reference const_at(size_type n) const;
100  reference operator[](size_type n);
101  const_reference operator[](size_type n) const;
102  reference front();
103  const_reference front() const;
104  const_reference cfront() const;
105  reference back();
106  const_reference back() const;
107  const_reference cback() const;
108  value_type *data();
109  const value_type *data() const noexcept;
110  const value_type *cdata() const noexcept;
111 
112  /* Iterators */
114  const_iterator begin() const noexcept;
115  const_iterator cbegin() const noexcept;
117  const_iterator end() const noexcept;
118  const_iterator cend() const noexcept;
119  reverse_iterator rbegin();
120  const_reverse_iterator rbegin() const noexcept;
121  const_reverse_iterator crbegin() const noexcept;
122  reverse_iterator rend();
123  const_reverse_iterator rend() const noexcept;
124  const_reverse_iterator crend() const noexcept;
125 
126  /* Range */
127  slice<pointer> range(size_type start, size_type n);
128  slice<range_snapshotting_iterator> range(size_type start, size_type n,
129  size_type snapshot_size);
130  slice<const_iterator> range(size_type start, size_type n) const;
131  slice<const_iterator> crange(size_type start, size_type n) const;
132  void for_each_ptr(for_each_ptr_function func);
133 
134  /* Capacity */
135  constexpr bool empty() const noexcept;
136  size_type size() const noexcept;
137  constexpr size_type max_size() const noexcept;
138  void reserve(size_type capacity_new);
139  size_type capacity() const noexcept;
141 
142  /* Modifiers */
143  void clear();
144  void free_data();
145  iterator insert(const_iterator pos, const T &value);
146  iterator insert(const_iterator pos, T &&value);
147  iterator insert(const_iterator pos, size_type count, const T &value);
148  template <typename InputIt,
149  typename std::enable_if<
150  detail::is_input_iterator<InputIt>::value,
151  InputIt>::type * = nullptr>
152  iterator insert(const_iterator pos, InputIt first, InputIt last);
153  iterator insert(const_iterator pos, std::initializer_list<T> ilist);
154  template <class... Args>
155  iterator emplace(const_iterator pos, Args &&... args);
156  template <class... Args>
157  reference emplace_back(Args &&... args);
158  iterator erase(const_iterator pos);
159  iterator erase(const_iterator first, const_iterator last);
160  void push_back(const T &value);
161  void push_back(T &&value);
162  void pop_back();
163  void resize(size_type count);
164  void resize(size_type count, const value_type &value);
165  void swap(vector &other);
166 
167 private:
168  /* helper iterator */
169  template <typename P>
170  struct single_element_iterator {
171  using iterator_category = std::input_iterator_tag;
172  using value_type = P;
173  using difference_type = std::ptrdiff_t;
174  using pointer = const P *;
175  using reference = const P &;
176 
177  const P *ptr;
178  std::size_t count;
179 
180  single_element_iterator(const P *ptr, std::size_t count = 0)
181  : ptr(ptr), count(count)
182  {
183  }
184 
185  reference operator*()
186  {
187  return *ptr;
188  }
189 
190  pointer operator->()
191  {
192  return ptr;
193  }
194 
195  single_element_iterator &
196  operator++()
197  {
198  count++;
199  return *this;
200  }
201 
202  single_element_iterator
203  operator++(int)
204  {
205  single_element_iterator tmp =
206  single_element_iterator(ptr, count);
207  count++;
208  return tmp;
209  }
210 
211  difference_type
212  operator-(const single_element_iterator &rhs)
213  {
214  return count - rhs.count;
215  }
216 
217  bool
218  operator!=(const single_element_iterator &rhs)
219  {
220  return ptr != rhs.ptr || count != rhs.count;
221  }
222  };
223 
224  /* helper functions */
225  void alloc(size_type size);
226  void check_pmem();
227  void check_tx_stage_work();
228  template <typename... Args>
229  void construct_at_end(size_type count, Args &&... args);
230  template <typename InputIt,
231  typename std::enable_if<
233  InputIt>::type * = nullptr>
234  void construct_at_end(InputIt first, InputIt last);
235  void dealloc();
236  pool_base get_pool() const;
237  template <typename InputIt>
238  void internal_insert(size_type idx, InputIt first, InputIt last);
239  void realloc(size_type size);
240  size_type get_recommended_capacity(size_type at_least) const;
241  void shrink(size_type size_new);
242  void add_data_to_tx(size_type idx_first, size_type num);
243  template <typename InputIt>
244  void construct_or_assign(size_type idx, InputIt first, InputIt last);
245  void move_elements_backward(pointer first, pointer last,
246  pointer d_last);
247 
248  p<size_type> _size;
249  p<size_type> _capacity;
250 
251  /* Underlying array */
252  persistent_ptr<T[]> _data;
253 };
254 
255 /* Non-member swap
256  * @relates vector
257  */
258 template <typename T>
259 void swap(vector<T> &lhs, vector<T> &rhs);
260 
261 /*
262  * Comparison operators between pmem::obj::vector<T> and
263  * pmem::obj::vector<T>
264  */
265 template <typename T>
266 bool operator==(const vector<T> &lhs, const vector<T> &rhs);
267 template <typename T>
268 bool operator!=(const vector<T> &lhs, const vector<T> &rhs);
269 template <typename T>
270 bool operator<(const vector<T> &lhs, const vector<T> &rhs);
271 template <typename T>
272 bool operator<=(const vector<T> &lhs, const vector<T> &rhs);
273 template <typename T>
274 bool operator>(const vector<T> &lhs, const vector<T> &rhs);
275 template <typename T>
276 bool operator>=(const vector<T> &lhs, const vector<T> &rhs);
277 
278 /*
279  * Comparison operators between pmem::obj::vector<T> and
280  * std::vector<T>
281  */
282 template <typename T>
283 bool operator==(const vector<T> &lhs, const std::vector<T> &rhs);
284 template <typename T>
285 bool operator!=(const vector<T> &lhs, const std::vector<T> &rhs);
286 template <typename T>
287 bool operator<(const vector<T> &lhs, const std::vector<T> &rhs);
288 template <typename T>
289 bool operator<=(const vector<T> &lhs, const std::vector<T> &rhs);
290 template <typename T>
291 bool operator>(const vector<T> &lhs, const std::vector<T> &rhs);
292 template <typename T>
293 bool operator>=(const vector<T> &lhs, const std::vector<T> &rhs);
294 
295 /*
296  * Comparison operators between std::vector<T> and
297  * pmem::obj::vector<T>
298  */
299 template <typename T>
300 bool operator==(const std::vector<T> &lhs, const vector<T> &rhs);
301 template <typename T>
302 bool operator!=(const std::vector<T> &lhs, const vector<T> &rhs);
303 template <typename T>
304 bool operator<(const std::vector<T> &lhs, const vector<T> &rhs);
305 template <typename T>
306 bool operator<=(const std::vector<T> &lhs, const vector<T> &rhs);
307 template <typename T>
308 bool operator>(const std::vector<T> &lhs, const vector<T> &rhs);
309 template <typename T>
310 bool operator>=(const std::vector<T> &lhs, const vector<T> &rhs);
311 
321 template <typename T>
323 {
324  check_pmem();
325  check_tx_stage_work();
326 
327  _data = nullptr;
328  _size = 0;
329  _capacity = 0;
330 }
331 
350 template <typename T>
351 vector<T>::vector(size_type count, const value_type &value)
352 {
353  check_pmem();
354  check_tx_stage_work();
355 
356  _data = nullptr;
357  _size = 0;
358  alloc(count);
359  construct_at_end(count, value);
360 }
361 
379 template <typename T>
380 vector<T>::vector(size_type count)
381 {
382  check_pmem();
383  check_tx_stage_work();
384 
385  _data = nullptr;
386  _size = 0;
387  alloc(count);
388  construct_at_end(count);
389 }
390 
413 template <typename T>
414 template <typename InputIt,
415  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
416  InputIt>::type *>
417 vector<T>::vector(InputIt first, InputIt last)
418 {
419  check_pmem();
420  check_tx_stage_work();
421 
422  _data = nullptr;
423  _size = 0;
424  alloc(static_cast<size_type>(std::distance(first, last)));
425  construct_at_end(first, last);
426 }
427 
446 template <typename T>
448 {
449  check_pmem();
450  check_tx_stage_work();
451 
452  _data = nullptr;
453  _size = 0;
454  alloc(other.capacity());
455  construct_at_end(other.cbegin(), other.cend());
456 }
457 
477 template <typename T>
479 {
480  check_pmem();
481  check_tx_stage_work();
482 
483  _data = other._data;
484  _capacity = other.capacity();
485  _size = other.size();
486  other._data = nullptr;
487  other._capacity = other._size = 0;
488 }
489 
507 template <typename T>
508 vector<T>::vector(std::initializer_list<T> init)
509  : vector(init.begin(), init.end())
510 {
511 }
512 
531 template <typename T>
532 vector<T>::vector(const std::vector<T> &other)
533  : vector(other.cbegin(), other.cend())
534 {
535 }
536 
548 template <typename T>
549 vector<T> &
551 {
552  assign(other);
553 
554  return *this;
555 }
556 
567 template <typename T>
568 vector<T> &
570 {
571  assign(std::move(other));
572 
573  return *this;
574 }
575 
585 template <typename T>
586 vector<T> &
587 vector<T>::operator=(std::initializer_list<T> ilist)
588 {
589  assign(ilist.begin(), ilist.end());
590 
591  return *this;
592 }
593 
606 template <typename T>
607 vector<T> &
608 vector<T>::operator=(const std::vector<T> &other)
609 {
610  assign(other);
611 
612  return *this;
613 }
614 
631 template <typename T>
632 void
633 vector<T>::assign(size_type count, const_reference value)
634 {
635  pool_base pb = get_pool();
636 
637  flat_transaction::run(pb, [&] {
638  if (count <= capacity()) {
639  /*
640  * Reallocation is not needed. First, replace old
641  * elements with new ones in range [0, size()).
642  * Depending on count, either call remaining old
643  * elements destructors, or append more new elements.
644  */
645  size_type size_old = _size;
646  add_data_to_tx(0, size_old);
647 
648  std::fill_n(
649  _data.get(),
650  (std::min)(count,
651  static_cast<size_type>(size_old)),
652  value);
653 
654  if (count > size_old) {
655  add_data_to_tx(size_old, count - size_old);
656  construct_at_end(count - size_old, value);
657  } else {
658  shrink(count);
659  }
660  } else {
661  dealloc();
662  alloc(count);
663  construct_at_end(count, value);
664  }
665  });
666 }
667 
686 template <typename T>
687 template <typename InputIt,
688  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
689  InputIt>::type *>
690 void
691 vector<T>::assign(InputIt first, InputIt last)
692 {
693  pool_base pb = get_pool();
694 
695  size_type size_new = static_cast<size_type>(std::distance(first, last));
696 
697  flat_transaction::run(pb, [&] {
698  if (size_new <= capacity()) {
699  /*
700  * Reallocation is not needed. First, replace old
701  * elements with new ones in range [0, size()).
702  * Depending on size_new, either call remaining old
703  * elements destructors, or append more new elements.
704  */
705  size_type size_old = _size;
706  add_data_to_tx(0, size_old);
707 
708  InputIt mid = last;
709  bool growing = size_new > size_old;
710 
711  if (growing) {
712  add_data_to_tx(size_old, size_new - size_old);
713 
714  mid = first;
715  std::advance(mid, size_old);
716  }
717 
718  iterator shrink_to = std::copy(first, mid, &_data[0]);
719 
720  if (growing) {
721  construct_at_end(mid, last);
722  } else {
723  shrink(static_cast<size_type>(std::distance(
724  iterator(&_data[0]), shrink_to)));
725  }
726  } else {
727  dealloc();
728  alloc(size_new);
729  construct_at_end(first, last);
730  }
731  });
732 }
733 
749 template <typename T>
750 void
751 vector<T>::assign(std::initializer_list<T> ilist)
752 {
753  assign(ilist.begin(), ilist.end());
754 }
755 
767 template <typename T>
768 void
770 {
771  if (this != &other)
772  assign(other.cbegin(), other.cend());
773 }
774 
786 template <typename T>
787 void
789 {
790  if (this == &other)
791  return;
792 
793  pool_base pb = get_pool();
794 
795  flat_transaction::run(pb, [&] {
796  dealloc();
797 
798  _data = other._data;
799  _capacity = other._capacity;
800  _size = other._size;
801 
802  other._data = nullptr;
803  other._capacity = other._size = 0;
804  });
805 }
806 
819 template <typename T>
820 void
821 vector<T>::assign(const std::vector<T> &other)
822 {
823  assign(other.cbegin(), other.cend());
824 }
825 
833 template <typename T>
835 {
836  try {
837  free_data();
838  } catch (...) {
839  std::terminate();
840  }
841 }
842 
855 template <typename T>
856 typename vector<T>::reference
857 vector<T>::at(size_type n)
858 {
859  if (n >= _size)
860  throw std::out_of_range("vector::at");
861 
862  detail::conditional_add_to_tx(&_data[static_cast<difference_type>(n)],
863  1, POBJ_XADD_ASSUME_INITIALIZED);
864 
865  return _data[static_cast<difference_type>(n)];
866 }
867 
877 template <typename T>
878 typename vector<T>::const_reference
879 vector<T>::at(size_type n) const
880 {
881  if (n >= _size)
882  throw std::out_of_range("vector::at");
883 
884  return _data[static_cast<difference_type>(n)];
885 }
886 
899 template <typename T>
900 typename vector<T>::const_reference
901 vector<T>::const_at(size_type n) const
902 {
903  if (n >= _size)
904  throw std::out_of_range("vector::const_at");
905 
906  return _data[static_cast<difference_type>(n)];
907 }
908 
920 template <typename T>
921 typename vector<T>::reference vector<T>::operator[](size_type n)
922 {
923  detail::conditional_add_to_tx(&_data[static_cast<difference_type>(n)],
924  1, POBJ_XADD_ASSUME_INITIALIZED);
925 
926  return _data[static_cast<difference_type>(n)];
927 }
928 
936 template <typename T>
937 typename vector<T>::const_reference vector<T>::operator[](size_type n) const
938 {
939  return _data[static_cast<difference_type>(n)];
940 }
941 
950 template <typename T>
951 typename vector<T>::reference
953 {
954  detail::conditional_add_to_tx(&_data[0], 1,
955  POBJ_XADD_ASSUME_INITIALIZED);
956 
957  return _data[0];
958 }
959 
965 template <typename T>
966 typename vector<T>::const_reference
968 {
969  return _data[0];
970 }
971 
979 template <typename T>
980 typename vector<T>::const_reference
982 {
983  return _data[0];
984 }
985 
994 template <typename T>
995 typename vector<T>::reference
997 {
999  &_data[static_cast<difference_type>(size() - 1)], 1,
1000  POBJ_XADD_ASSUME_INITIALIZED);
1001 
1002  return _data[static_cast<difference_type>(size() - 1)];
1003 }
1004 
1010 template <typename T>
1011 typename vector<T>::const_reference
1013 {
1014  return _data[static_cast<difference_type>(size() - 1)];
1015 }
1016 
1024 template <typename T>
1025 typename vector<T>::const_reference
1027 {
1028  return _data[static_cast<difference_type>(size() - 1)];
1029 }
1030 
1040 template <typename T>
1041 typename vector<T>::value_type *
1043 {
1044  add_data_to_tx(0, _size);
1045 
1046  return _data.get();
1047 }
1048 
1054 template <typename T>
1055 const typename vector<T>::value_type *
1056 vector<T>::data() const noexcept
1057 {
1058  return _data.get();
1059 }
1060 
1068 template <typename T>
1069 const typename vector<T>::value_type *
1070 vector<T>::cdata() const noexcept
1071 {
1072  return _data.get();
1073 }
1074 
1080 template <typename T>
1081 typename vector<T>::iterator
1083 {
1084  return iterator(_data.get());
1085 }
1086 
1092 template <typename T>
1093 typename vector<T>::const_iterator
1094 vector<T>::begin() const noexcept
1095 {
1096  return const_iterator(_data.get());
1097 }
1098 
1106 template <typename T>
1107 typename vector<T>::const_iterator
1108 vector<T>::cbegin() const noexcept
1109 {
1110  return const_iterator(_data.get());
1111 }
1112 
1118 template <typename T>
1119 typename vector<T>::iterator
1121 {
1122  return iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1123 }
1124 
1130 template <typename T>
1131 typename vector<T>::const_iterator
1132 vector<T>::end() const noexcept
1133 {
1134  return const_iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1135 }
1136 
1144 template <typename T>
1145 typename vector<T>::const_iterator
1146 vector<T>::cend() const noexcept
1147 {
1148  return const_iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1149 }
1150 
1156 template <typename T>
1157 typename vector<T>::reverse_iterator
1159 {
1160  return reverse_iterator(end());
1161 }
1162 
1168 template <typename T>
1169 typename vector<T>::const_reverse_iterator
1170 vector<T>::rbegin() const noexcept
1171 {
1172  return const_reverse_iterator(cend());
1173 }
1174 
1182 template <typename T>
1183 typename vector<T>::const_reverse_iterator
1184 vector<T>::crbegin() const noexcept
1185 {
1186  return const_reverse_iterator(cend());
1187 }
1188 
1195 template <typename T>
1196 typename vector<T>::reverse_iterator
1198 {
1199  return reverse_iterator(begin());
1200 }
1201 
1208 template <typename T>
1209 typename vector<T>::const_reverse_iterator
1210 vector<T>::rend() const noexcept
1211 {
1212  return const_reverse_iterator(cbegin());
1213 }
1214 
1223 template <typename T>
1224 typename vector<T>::const_reverse_iterator
1225 vector<T>::crend() const noexcept
1226 {
1227  return const_reverse_iterator(cbegin());
1228 }
1229 
1243 template <typename T>
1245 vector<T>::range(size_type start, size_type n)
1246 {
1247  if (start + n > size())
1248  throw std::out_of_range("vector::range");
1249 
1250  detail::conditional_add_to_tx(cdata() + start, n,
1251  POBJ_XADD_ASSUME_INITIALIZED);
1252 
1253  return {_data.get() + start, _data.get() + start + n};
1254 }
1255 
1271 template <typename T>
1273 vector<T>::range(size_type start, size_type n, size_type snapshot_size)
1274 {
1275  if (start + n > size())
1276  throw std::out_of_range("vector::range");
1277 
1278  if (snapshot_size > n)
1279  snapshot_size = n;
1280 
1281  return {range_snapshotting_iterator(_data.get() + start,
1282  _data.get() + start, n,
1283  snapshot_size),
1284  range_snapshotting_iterator(_data.get() + start + n,
1285  _data.get() + start, n,
1286  snapshot_size)};
1287 }
1288 
1300 template <typename T>
1302 vector<T>::range(size_type start, size_type n) const
1303 {
1304  if (start + n > size())
1305  throw std::out_of_range("vector::range");
1306 
1307  return {const_iterator(cdata() + start),
1308  const_iterator(cdata() + start + n)};
1309 }
1310 
1322 template <typename T>
1324 vector<T>::crange(size_type start, size_type n) const
1325 {
1326  if (start + n > size())
1327  throw std::out_of_range("vector::crange");
1328 
1329  return {const_iterator(cdata() + start),
1330  const_iterator(cdata() + start + n)};
1331 }
1332 
1338 template <typename T>
1339 constexpr bool
1340 vector<T>::empty() const noexcept
1341 {
1342  return _size == 0;
1343 }
1344 
1348 template <typename T>
1349 typename vector<T>::size_type
1350 vector<T>::size() const noexcept
1351 {
1352  return _size;
1353 }
1354 
1359 template <typename T>
1360 constexpr typename vector<T>::size_type
1361 vector<T>::max_size() const noexcept
1362 {
1363  return PMEMOBJ_MAX_ALLOC_SIZE / sizeof(value_type);
1364 }
1365 
1384 template <typename T>
1385 void
1386 vector<T>::reserve(size_type capacity_new)
1387 {
1388  if (capacity_new <= _capacity)
1389  return;
1390 
1391  pool_base pb = get_pool();
1392  flat_transaction::run(pb, [&] { realloc(capacity_new); });
1393 }
1394 
1398 template <typename T>
1399 typename vector<T>::size_type
1400 vector<T>::capacity() const noexcept
1401 {
1402  return _capacity;
1403 }
1404 
1419 template <typename T>
1420 void
1422 {
1423  size_type capacity_new = size();
1424  if (capacity() == capacity_new)
1425  return;
1426 
1427  pool_base pb = get_pool();
1428  flat_transaction::run(pb, [&] { realloc(capacity_new); });
1429 }
1430 
1439 template <typename T>
1440 void
1442 {
1443  pool_base pb = get_pool();
1444  flat_transaction::run(pb, [&] { shrink(0); });
1445 }
1446 
1459 template <typename T>
1460 void
1462 {
1463  if (_data == nullptr)
1464  return;
1465 
1466  pool_base pb = get_pool();
1467  flat_transaction::run(pb, [&] { dealloc(); });
1468 }
1469 
1494 template <typename T>
1495 typename vector<T>::iterator
1496 vector<T>::insert(const_iterator pos, const value_type &value)
1497 {
1498  return insert(pos, 1, value);
1499 }
1500 
1525 template <typename T>
1526 typename vector<T>::iterator
1527 vector<T>::insert(const_iterator pos, value_type &&value)
1528 {
1529  pool_base pb = get_pool();
1530 
1531  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1532 
1533  flat_transaction::run(pb, [&] {
1534  internal_insert(idx, std::make_move_iterator(&value),
1535  std::make_move_iterator(&value + 1));
1536  });
1537 
1538  return iterator(&_data[static_cast<difference_type>(idx)]);
1539 }
1540 
1569 template <typename T>
1570 typename vector<T>::iterator
1571 vector<T>::insert(const_iterator pos, size_type count, const value_type &value)
1572 {
1573  pool_base pb = get_pool();
1574 
1575  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1576 
1577  flat_transaction::run(pb, [&] {
1578  internal_insert(
1579  idx, single_element_iterator<value_type>(&value, 0),
1580  single_element_iterator<value_type>(&value, count));
1581  });
1582 
1583  return iterator(_data.get() + static_cast<difference_type>(idx));
1584 }
1585 
1620 template <typename T>
1621 template <typename InputIt,
1622  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
1623  InputIt>::type *>
1624 typename vector<T>::iterator
1625 vector<T>::insert(const_iterator pos, InputIt first, InputIt last)
1626 {
1627  pool_base pb = get_pool();
1628 
1629  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1630 
1631  flat_transaction::run(pb, [&] { internal_insert(idx, first, last); });
1632 
1633  return iterator(&_data[static_cast<difference_type>(idx)]);
1634 }
1635 
1664 template <typename T>
1665 typename vector<T>::iterator
1666 vector<T>::insert(const_iterator pos, std::initializer_list<value_type> ilist)
1667 {
1668  return insert(pos, ilist.begin(), ilist.end());
1669 }
1670 
1698 template <typename T>
1699 template <class... Args>
1700 typename vector<T>::iterator
1701 vector<T>::emplace(const_iterator pos, Args &&... args)
1702 {
1703  pool_base pb = get_pool();
1704 
1705  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1706 
1707  flat_transaction::run(pb, [&] {
1708  /*
1709  * args might be a reference to underlying array element. This
1710  * reference can be invalidated after internal_insert() call.
1711  * Hence, we must cache value_type object in temp_value.
1712  */
1713  detail::temp_value<value_type,
1714  noexcept(T(std::forward<Args>(args)...))>
1715  tmp(std::forward<Args>(args)...);
1716 
1717  auto &tmp_ref = tmp.get();
1718 
1719  internal_insert(idx, std::make_move_iterator(&tmp_ref),
1720  std::make_move_iterator(&tmp_ref + 1));
1721  });
1722 
1723  return iterator(&_data[static_cast<difference_type>(idx)]);
1724 }
1725 
1748 template <typename T>
1749 template <class... Args>
1750 typename vector<T>::reference
1751 vector<T>::emplace_back(Args &&... args)
1752 {
1753  /*
1754  * emplace() cannot be used here, because emplace_back() doesn't require
1755  * element_type to be MoveAssignable and emplace() uses
1756  * std::move_backward() function.
1757  */
1758  pool_base pb = get_pool();
1759 
1760  flat_transaction::run(pb, [&] {
1761  if (_size == _capacity) {
1762  realloc(get_recommended_capacity(_size + 1));
1763  } else {
1764  add_data_to_tx(size(), 1);
1765  }
1766 
1767  construct_at_end(1, std::forward<Args>(args)...);
1768  });
1769 
1770  return back();
1771 }
1772 
1792 template <typename T>
1793 typename vector<T>::iterator
1794 vector<T>::erase(const_iterator pos)
1795 {
1796  return erase(pos, pos + 1);
1797 }
1798 
1821 template <typename T>
1822 typename vector<T>::iterator
1823 vector<T>::erase(const_iterator first, const_iterator last)
1824 {
1825  size_type idx = static_cast<size_type>(
1826  std::distance(const_iterator(_data.get()), first));
1827  size_type count = static_cast<size_type>(std::distance(first, last));
1828 
1829  if (count == 0)
1830  return iterator(&_data[static_cast<difference_type>(idx)]);
1831 
1832  pool_base pb = get_pool();
1833 
1834  flat_transaction::run(pb, [&] {
1835  if (!std::is_trivially_destructible<T>::value ||
1836  idx + count < _size)
1837  add_data_to_tx(idx, _size - idx);
1838 
1839  pointer move_begin =
1840  &_data[static_cast<difference_type>(idx + count)];
1841  pointer move_end = &_data[static_cast<difference_type>(size())];
1842  pointer dest = &_data[static_cast<difference_type>(idx)];
1843 
1844  std::move(move_begin, move_end, dest);
1845 
1846  _size -= count;
1847  });
1848 
1849  return iterator(&_data[static_cast<difference_type>(idx)]);
1850 }
1851 
1867 template <typename T>
1868 void
1869 vector<T>::push_back(const value_type &value)
1870 {
1871  emplace_back(value);
1872 }
1873 
1890 template <typename T>
1891 void
1892 vector<T>::push_back(value_type &&value)
1893 {
1894  emplace_back(std::move(value));
1895 }
1896 
1907 template <typename T>
1908 void
1910 {
1911  if (empty())
1912  return;
1913 
1914  pool_base pb = get_pool();
1915  flat_transaction::run(pb, [&] { shrink(size() - 1); });
1916 }
1917 
1934 template <typename T>
1935 void
1936 vector<T>::resize(size_type count)
1937 {
1938  pool_base pb = get_pool();
1939  flat_transaction::run(pb, [&] {
1940  if (count <= _size)
1941  shrink(count);
1942  else {
1943  if (_capacity < count)
1944  realloc(count);
1945  construct_at_end(count - _size);
1946  }
1947  });
1948 }
1949 
1967 template <typename T>
1968 void
1969 vector<T>::resize(size_type count, const value_type &value)
1970 {
1971  if (_capacity == count)
1972  return;
1973 
1974  pool_base pb = get_pool();
1975  flat_transaction::run(pb, [&] {
1976  if (count <= _size)
1977  shrink(count);
1978  else {
1979  if (_capacity < count)
1980  realloc(count);
1981  construct_at_end(count - _size, value);
1982  }
1983  });
1984 }
1985 
1989 template <typename T>
1990 void
1992 {
1993  pool_base pb = get_pool();
1994  flat_transaction::run(pb, [&] {
1995  std::swap(this->_data, other._data);
1996  std::swap(this->_size, other._size);
1997  std::swap(this->_capacity, other._capacity);
1998  });
1999 }
2000 
2007 template <typename T>
2008 void
2009 vector<T>::for_each_ptr(for_each_ptr_function func)
2010 {
2011  func(_data);
2012 }
2013 
2031 template <typename T>
2032 void
2033 vector<T>::alloc(size_type capacity_new)
2034 {
2035  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2036  assert(_data == nullptr);
2037  assert(_size == 0);
2038 
2039  if (capacity_new > max_size())
2040  throw std::length_error("New capacity exceeds max size.");
2041 
2042  _capacity = capacity_new;
2043 
2044  if (capacity_new == 0)
2045  return;
2046 
2047  /*
2048  * We need to cache pmemobj_tx_alloc return value and only after that
2049  * assign it to _data, because when pmemobj_tx_alloc fails, it aborts
2050  * transaction.
2051  */
2052  persistent_ptr<T[]> res =
2053  pmemobj_tx_alloc(sizeof(value_type) * capacity_new,
2054  detail::type_num<value_type>());
2055 
2056  if (res == nullptr) {
2057  const char *msg = "Failed to allocate persistent memory object";
2058  if (errno == ENOMEM)
2061  else
2064  }
2065  _data = res;
2066 }
2067 
2074 template <typename T>
2075 void
2076 vector<T>::check_pmem()
2077 {
2078  if (nullptr == pmemobj_pool_by_ptr(this))
2079  throw pmem::pool_error("Invalid pool handle.");
2080 }
2081 
2089 template <typename T>
2090 void
2091 vector<T>::check_tx_stage_work()
2092 {
2093  if (pmemobj_tx_stage() != TX_STAGE_WORK)
2095  "Function called out of transaction scope.");
2096 }
2097 
2116 template <typename T>
2117 template <typename... Args>
2118 void
2119 vector<T>::construct_at_end(size_type count, Args &&... args)
2120 {
2121  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2122  assert(_capacity >= count + _size);
2123 
2124  pointer dest = _data.get() + size();
2125  const_pointer end = dest + count;
2126  for (; dest != end; ++dest)
2127  detail::create<value_type, Args...>(
2128  dest, std::forward<Args>(args)...);
2129  _size += count;
2130 }
2131 
2154 template <typename T>
2155 template <typename InputIt,
2156  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
2157  InputIt>::type *>
2158 void
2159 vector<T>::construct_at_end(InputIt first, InputIt last)
2160 {
2161  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2162  difference_type range_size = std::distance(first, last);
2163  assert(range_size >= 0);
2164  assert(_capacity >= static_cast<size_type>(range_size) + _size);
2165 
2166  pointer dest = _data.get() + size();
2167  _size += static_cast<size_type>(range_size);
2168  while (first != last)
2169  detail::create<value_type>(dest++, *first++);
2170 }
2171 
2187 template <typename T>
2188 void
2189 vector<T>::dealloc()
2190 {
2191  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2192 
2193  if (_data != nullptr) {
2194  shrink(0);
2195  if (pmemobj_tx_free(*_data.raw_ptr()) != 0)
2198  "failed to delete persistent memory object");
2199  _data = nullptr;
2200  _capacity = 0;
2201  }
2202 }
2203 
2211 template <typename T>
2212 pool_base
2213 vector<T>::get_pool() const
2214 {
2215  return pmem::obj::pool_by_vptr(this);
2216 }
2217 
2225 template <typename T>
2226 void
2227 vector<T>::move_elements_backward(pointer first, pointer last, pointer d_last)
2228 {
2229  while (first != last && d_last >= cend())
2230  detail::create<value_type>(--d_last, std::move(*(--last)));
2231 
2232  if (first != last)
2233  std::move_backward(first, last, d_last);
2234 }
2235 
2243 template <typename T>
2244 template <typename InputIt>
2245 void
2246 vector<T>::construct_or_assign(size_type idx, InputIt first, InputIt last)
2247 {
2248  auto count = static_cast<size_type>(std::distance(first, last));
2249  auto dest = _data.get() + idx;
2250  auto initialized_slots = static_cast<size_type>(cend() - dest);
2251 
2252  /* Assign new elements to initialized memory */
2253  if (dest < cend())
2254  dest = std::copy_n(first, (std::min)(initialized_slots, count),
2255  dest);
2256 
2257  std::advance(first, (std::min)(initialized_slots, count));
2258 
2259  /* Rest of the elements will be created in uninitialized memory */
2260  while (first != last)
2261  detail::create<value_type>(dest++, *first++);
2262 
2263  _size += count;
2264 }
2265 
2286 template <typename T>
2287 template <typename InputIt>
2288 void
2289 vector<T>::internal_insert(size_type idx, InputIt first, InputIt last)
2290 {
2291  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2292 
2293  auto count = static_cast<size_type>(std::distance(first, last));
2294 
2295  if (_capacity >= size() + count) {
2296  pointer dest = _data.get() +
2297  static_cast<difference_type>(size() + count);
2298  pointer begin = _data.get() + static_cast<difference_type>(idx);
2299  pointer end =
2300  _data.get() + static_cast<difference_type>(size());
2301 
2302  add_data_to_tx(idx, size() - idx + count);
2303 
2304  /* Make a gap for new elements */
2305  move_elements_backward(begin, end, dest);
2306 
2307  /* Construct new elements in the gap */
2308  construct_or_assign(idx, first, last);
2309  } else {
2310  /*
2311  * XXX: future optimization: we don't have to snapshot data
2312  * which we will copy (only snapshot for move)
2313  */
2314  add_data_to_tx(0, _size);
2315 
2316  auto old_data = _data;
2317  auto old_size = _size;
2318  pointer old_begin = _data.get();
2319  pointer old_mid =
2320  _data.get() + static_cast<difference_type>(idx);
2321  pointer old_end =
2322  _data.get() + static_cast<difference_type>(size());
2323 
2324  _data = nullptr;
2325  _size = _capacity = 0;
2326 
2327  alloc(get_recommended_capacity(old_size + count));
2328 
2329  /* Move range before the idx to new array */
2330  construct_at_end(std::make_move_iterator(old_begin),
2331  std::make_move_iterator(old_mid));
2332 
2333  /* Insert (first, last) range to the new array */
2334  construct_at_end(first, last);
2335 
2336  /* Move remaining element to the new array */
2337  construct_at_end(std::make_move_iterator(old_mid),
2338  std::make_move_iterator(old_end));
2339 
2340  /* destroy and free old data */
2341  for (size_type i = 0; i < old_size; ++i)
2342  detail::destroy<value_type>(
2343  old_data[static_cast<difference_type>(i)]);
2344  if (pmemobj_tx_free(old_data.raw()) != 0)
2347  "failed to delete persistent memory object");
2348  }
2349 }
2350 
2369 template <typename T>
2370 void
2371 vector<T>::realloc(size_type capacity_new)
2372 {
2373  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2374 
2375  /*
2376  * If _data == nullptr this object has never allocated any memory
2377  * so we need to behave as alloc instead.
2378  */
2379  if (_data == nullptr)
2380  return alloc(capacity_new);
2381 
2382  /*
2383  * XXX: future optimization: we don't have to snapshot data
2384  * which we will not overwrite
2385  */
2386  add_data_to_tx(0, _size);
2387 
2388  auto old_data = _data;
2389  auto old_size = _size;
2390  pointer old_begin = _data.get();
2391  pointer old_end = capacity_new < _size
2392  ? &_data[static_cast<difference_type>(capacity_new)]
2393  : &_data[static_cast<difference_type>(size())];
2394 
2395  _data = nullptr;
2396  _size = _capacity = 0;
2397 
2398  alloc(capacity_new);
2399 
2400  construct_at_end(std::make_move_iterator(old_begin),
2401  std::make_move_iterator(old_end));
2402 
2403  /* destroy and free old data */
2404  for (size_type i = 0; i < old_size; ++i)
2405  detail::destroy<value_type>(
2406  old_data[static_cast<difference_type>(i)]);
2407  if (pmemobj_tx_free(old_data.raw()) != 0)
2410  "failed to delete persistent memory object");
2411 }
2412 
2419 template <typename T>
2420 typename vector<T>::size_type
2421 vector<T>::get_recommended_capacity(size_type at_least) const
2422 {
2423  return detail::next_pow_2(at_least);
2424 }
2425 
2442 template <typename T>
2443 void
2444 vector<T>::shrink(size_type size_new)
2445 {
2446  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2447  assert(size_new <= _size);
2448 
2449  if (!std::is_trivially_destructible<T>::value)
2450  add_data_to_tx(size_new, _size - size_new);
2451 
2452  for (size_type i = size_new; i < _size; ++i)
2453  detail::destroy<value_type>(
2454  _data[static_cast<difference_type>(i)]);
2455  _size = size_new;
2456 }
2457 
2467 template <typename T>
2468 void
2469 vector<T>::add_data_to_tx(size_type idx_first, size_type num)
2470 {
2471  assert(idx_first + num <= capacity());
2472 
2473 #if LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED
2474  /* Make sure that only data allocated by this vector is accessed */
2475  assert(VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_data.get() + idx_first,
2476  num * sizeof(T)) == 0);
2477 #endif
2478 
2479  auto initialized_num = size() - idx_first;
2480 
2481  /* Snapshot elements in range [idx_first,size()) */
2482  detail::conditional_add_to_tx(_data.get() + idx_first,
2483  (std::min)(initialized_num, num),
2484  POBJ_XADD_ASSUME_INITIALIZED);
2485 
2486  if (num > initialized_num) {
2487  /* Elements after size() do not have to be snapshotted */
2488  detail::conditional_add_to_tx(_data.get() + size(),
2489  num - initialized_num,
2490  POBJ_XADD_NO_SNAPSHOT);
2491  }
2492 }
2493 
2506 template <typename T>
2507 bool
2508 operator==(const vector<T> &lhs, const vector<T> &rhs)
2509 {
2510  return lhs.size() == rhs.size() &&
2511  std::equal(lhs.begin(), lhs.end(), rhs.begin());
2512 }
2513 
2526 template <typename T>
2527 bool
2528 operator!=(const vector<T> &lhs, const vector<T> &rhs)
2529 {
2530  return !(lhs == rhs);
2531 }
2532 
2544 template <typename T>
2545 bool
2546 operator<(const vector<T> &lhs, const vector<T> &rhs)
2547 {
2548  return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
2549  rhs.end());
2550 }
2551 
2563 template <typename T>
2564 bool
2565 operator<=(const vector<T> &lhs, const vector<T> &rhs)
2566 {
2567  return !(rhs < lhs);
2568 }
2569 
2582 template <typename T>
2583 bool
2584 operator>(const vector<T> &lhs, const vector<T> &rhs)
2585 {
2586  return rhs < lhs;
2587 }
2588 
2600 template <typename T>
2601 bool
2602 operator>=(const vector<T> &lhs, const vector<T> &rhs)
2603 {
2604  return !(lhs < rhs);
2605 }
2606 
2619 template <typename T>
2620 bool
2621 operator==(const vector<T> &lhs, const std::vector<T> &rhs)
2622 {
2623  return lhs.size() == rhs.size() &&
2624  std::equal(lhs.begin(), lhs.end(), rhs.begin());
2625 }
2626 
2639 template <typename T>
2640 bool
2641 operator!=(const vector<T> &lhs, const std::vector<T> &rhs)
2642 {
2643  return !(lhs == rhs);
2644 }
2645 
2657 template <typename T>
2658 bool
2659 operator<(const vector<T> &lhs, const std::vector<T> &rhs)
2660 {
2661  return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
2662  rhs.end());
2663 }
2664 
2676 template <typename T>
2677 bool
2678 operator<=(const vector<T> &lhs, const std::vector<T> &rhs)
2679 {
2680  return !(std::lexicographical_compare(rhs.begin(), rhs.end(),
2681  lhs.begin(), lhs.end()));
2682 }
2683 
2695 template <typename T>
2696 bool
2697 operator>(const vector<T> &lhs, const std::vector<T> &rhs)
2698 {
2699  return !(lhs <= rhs);
2700 }
2701 
2713 template <typename T>
2714 bool
2715 operator>=(const vector<T> &lhs, const std::vector<T> &rhs)
2716 {
2717  return !(lhs < rhs);
2718 }
2719 
2732 template <typename T>
2733 bool
2734 operator==(const std::vector<T> &lhs, const vector<T> &rhs)
2735 {
2736  return rhs == lhs;
2737 }
2738 
2751 template <typename T>
2752 bool
2753 operator!=(const std::vector<T> &lhs, const vector<T> &rhs)
2754 {
2755  return !(lhs == rhs);
2756 }
2757 
2769 template <typename T>
2770 bool
2771 operator<(const std::vector<T> &lhs, const vector<T> &rhs)
2772 {
2773  return rhs > lhs;
2774 }
2775 
2787 template <typename T>
2788 bool
2789 operator<=(const std::vector<T> &lhs, const vector<T> &rhs)
2790 {
2791  return !(rhs < lhs);
2792 }
2793 
2806 template <typename T>
2807 bool
2808 operator>(const std::vector<T> &lhs, const vector<T> &rhs)
2809 {
2810  return rhs < lhs;
2811 }
2812 
2824 template <typename T>
2825 bool
2826 operator>=(const std::vector<T> &lhs, const vector<T> &rhs)
2827 {
2828  return !(lhs < rhs);
2829 }
2830 
2838 template <typename T>
2839 void
2841 {
2842  lhs.swap(rhs);
2843 }
2844 
2845 } /* namespace obj */
2846 
2847 } /* namespace pmem */
2848 
2849 #endif /* LIBPMEMOBJ_CPP_VECTOR_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:810
Persistent_ptr base (non-template) class.
Definition: persistent_ptr_base.hpp:42
The non-template pool base class.
Definition: pool.hpp:51
Provides interface to access sequence of objects.
Definition: slice.hpp:61
Persistent container with std::vector compatible interface.
Definition: vector.hpp:41
const_reference front() const
Access the first element.
Definition: vector.hpp:967
reverse_iterator rend()
Returns a reverse iterator to the end.
Definition: vector.hpp:1197
const value_type * cdata() const noexcept
Returns const raw pointer to the underlying data.
Definition: vector.hpp:1070
bool operator>=(const std::vector< T > &lhs, const vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2826
const_reverse_iterator crend() const noexcept
Returns a const reverse iterator to the beginning.
Definition: vector.hpp:1225
const value_type * data() const noexcept
Returns const raw pointer to the underlying data.
Definition: vector.hpp:1056
vector(vector &&other)
Move constructor.
Definition: vector.hpp:478
void free_data()
Clears the content of a vector and frees all allocated persistent memory for data transactionally.
Definition: vector.hpp:1461
vector(const std::vector< T > &other)
Copy constructor.
Definition: vector.hpp:532
const_reference const_at(size_type n) const
Access element at specific index with bounds checking.
Definition: vector.hpp:901
size_type size() const noexcept
Definition: vector.hpp:1350
const_reference operator[](size_type n) const
Access element at specific index.
Definition: vector.hpp:937
vector & operator=(const std::vector< T > &other)
Copy assignment operator.
Definition: vector.hpp:608
slice< pointer > range(size_type start, size_type n)
Returns slice and snapshots requested range.
Definition: vector.hpp:1245
bool operator==(const vector< T > &lhs, const vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2508
void assign(InputIt first, InputIt last)
Replaces the contents with copies of those in the range [first, last) transactionally.
Definition: vector.hpp:691
const_reference at(size_type n) const
Access element at specific index with bounds checking.
Definition: vector.hpp:879
reference back()
Access the last element and add this element to a transaction.
Definition: vector.hpp:996
slice< const_iterator > crange(size_type start, size_type n) const
Returns const slice.
Definition: vector.hpp:1324
bool operator==(const vector< T > &lhs, const std::vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2621
bool operator!=(const std::vector< T > &lhs, const vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2753
bool operator>(const vector< T > &lhs, const vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2584
void assign(const std::vector< T > &other)
Copy assignment method.
Definition: vector.hpp:821
iterator begin()
Returns an iterator to the beginning.
Definition: vector.hpp:1082
bool operator!=(const vector< T > &lhs, const std::vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2641
void assign(vector &&other)
Move assignment method.
Definition: vector.hpp:788
void pop_back()
Removes the last element of the container transactionally.
Definition: vector.hpp:1909
vector(InputIt first, InputIt last)
Constructs the container with the contents of the range [first, last).
Definition: vector.hpp:417
reference operator[](size_type n)
Access element at specific index and add it to a transaction.
Definition: vector.hpp:921
reference front()
Access the first element and add this element to a transaction.
Definition: vector.hpp:952
vector(size_type count, const value_type &value)
Constructs the container with count copies of elements with value value.
Definition: vector.hpp:351
reference at(size_type n)
Access element at specific index with bounds checking and add it to a transaction.
Definition: vector.hpp:857
void resize(size_type count)
Resizes the container to count elements transactionally.
Definition: vector.hpp:1936
void swap(vector &other)
Exchanges the contents of the container with other transactionally.
Definition: vector.hpp:1991
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: vector.hpp:1184
bool operator>=(const vector< T > &lhs, const vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2602
iterator emplace(const_iterator pos, Args &&... args)
Inserts a new element into the container directly before pos.
Definition: vector.hpp:1701
void shrink_to_fit()
Requests transactional removal of unused capacity.
Definition: vector.hpp:1421
bool operator>=(const vector< T > &lhs, const std::vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2715
iterator erase(const_iterator pos)
Removes the element at pos.
Definition: vector.hpp:1794
const_reference cfront() const
Access the first element.
Definition: vector.hpp:981
reference emplace_back(Args &&... args)
Appends a new element to the end of the container.
Definition: vector.hpp:1751
const_reference cback() const
Access the last element.
Definition: vector.hpp:1026
void clear()
Clears the content of a vector transactionally.
Definition: vector.hpp:1441
iterator insert(const_iterator pos, const T &value)
Inserts value before pos in the container transactionally.
Definition: vector.hpp:1496
vector(const vector &other)
Copy constructor.
Definition: vector.hpp:447
void for_each_ptr(for_each_ptr_function func)
Iterates over all internal pointers and executes a callback function on each of them.
Definition: vector.hpp:2009
const_reference back() const
Access the last element.
Definition: vector.hpp:1012
vector(std::initializer_list< T > init)
Constructs the container with the contents of the initializer list init.
Definition: vector.hpp:508
void assign(const vector &other)
Copy assignment method.
Definition: vector.hpp:769
reverse_iterator rbegin()
Returns a reverse iterator to the beginning.
Definition: vector.hpp:1158
vector & operator=(vector &&other)
Move assignment operator.
Definition: vector.hpp:569
vector()
Default constructor.
Definition: vector.hpp:322
~vector()
Destructor.
Definition: vector.hpp:834
vector & operator=(std::initializer_list< T > ilist)
Replaces the contents with those identified by initializer list ilist transactionally.
Definition: vector.hpp:587
size_type capacity() const noexcept
Definition: vector.hpp:1400
void reserve(size_type capacity_new)
Increases the capacity of the vector to capacity_new transactionally.
Definition: vector.hpp:1386
void assign(std::initializer_list< T > ilist)
Replaces the contents with the elements from the initializer list ilist transactionally.
Definition: vector.hpp:751
bool operator>(const vector< T > &lhs, const std::vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2697
bool operator>(const std::vector< T > &lhs, const vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2808
value_type * data()
Returns raw pointer to the underlying data and adds entire array to a transaction.
Definition: vector.hpp:1042
constexpr bool empty() const noexcept
Checks whether the container is empty.
Definition: vector.hpp:1340
bool operator==(const std::vector< T > &lhs, const vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2734
void swap(vector< T > &lhs, vector< T > &rhs)
Swaps the contents of lhs and rhs.
Definition: vector.hpp:2840
const_iterator cbegin() const noexcept
Returns const iterator to the beginning.
Definition: vector.hpp:1108
bool operator!=(const vector< T > &lhs, const vector< T > &rhs)
Comparison operator.
Definition: vector.hpp:2528
constexpr size_type max_size() const noexcept
Definition: vector.hpp:1361
void push_back(const T &value)
Appends the given element value to the end of the container transactionally.
Definition: vector.hpp:1869
const_iterator cend() const noexcept
Returns a const iterator to the end.
Definition: vector.hpp:1146
iterator end()
Returns an iterator to past the end.
Definition: vector.hpp:1120
vector & operator=(const vector &other)
Copy assignment operator.
Definition: vector.hpp:550
vector(size_type count)
Constructs the container with count copies of T default constructed values.
Definition: vector.hpp:380
Custom pool error class.
Definition: pexceptions.hpp:84
Custom transaction error class.
Definition: pexceptions.hpp:132
Custom transaction error class.
Definition: pexceptions.hpp:156
Custom out of memory error class.
Definition: pexceptions.hpp:144
Custom transaction error class.
Definition: pexceptions.hpp:167
Commonly used functionality.
Iterators for contiguous persistent containers.
Common iterator traits.
Functions for lifetime management.
persistent_ptr transactional allocation functions for objects.
void conditional_add_to_tx(const T *that, std::size_t count=1, uint64_t flags=0)
Conditionally add 'count' objects to a transaction.
Definition: common.hpp:176
ExcT exception_with_errormsg(Args &&... args)
Generic error message decorator for pmemobj-based exceptions.
Definition: pexceptions.hpp:69
uint64_t next_pow_2(uint64_t v)
Round up to the next lowest power of 2.
Definition: common.hpp:213
pool_base pool_by_vptr(const T *that)
Retrieve pool handle for the given pointer.
Definition: utils.hpp:32
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
Type trait to determine if a given parameter type satisfies requirements of InputIterator.
Definition: iterator_traits.hpp:47
Non-const iterator which adds elements to a transaction in a bulk.
Definition: contiguous_iterator.hpp:192
Template class for caching objects based on constructor's variadic template arguments and LIBPMEMOBJ_...
Definition: temp_value.hpp:35
template class for caching objects.
C++ pmemobj transactions.
Libpmemobj C++ utils.