PMDK C++ bindings  1.8.2
This is the C++ bindings documentation for PMDK's libpmemobj.
vector.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2018-2021, 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_VECTOR_HPP
39 #define LIBPMEMOBJ_CPP_VECTOR_HPP
40 
48 #include <libpmemobj++/pext.hpp>
49 #include <libpmemobj++/slice.hpp>
51 #include <libpmemobj/base.h>
52 
53 #include <algorithm>
54 #include <cassert>
55 #include <utility>
56 #include <vector>
57 
58 namespace pmem
59 {
60 
61 namespace obj
62 {
63 
68 template <typename T>
69 class vector {
70 public:
71  /* Member types */
72  using value_type = T;
73  using size_type = std::size_t;
74  using difference_type = std::ptrdiff_t;
75  using reference = value_type &;
76  using const_reference = const value_type &;
77  using pointer = value_type *;
78  using const_pointer = const value_type *;
80  using const_iterator = const_pointer;
81  using reverse_iterator = std::reverse_iterator<iterator>;
82  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
85 
86  /* Constructors */
87  vector();
88  vector(size_type count, const value_type &value);
89  explicit vector(size_type count);
90  template <typename InputIt,
91  typename std::enable_if<
93  InputIt>::type * = nullptr>
94  vector(InputIt first, InputIt last);
95  vector(const vector &other);
96  vector(vector &&other);
97  vector(std::initializer_list<T> init);
98  vector(const std::vector<T> &other);
99 
100  /* Assign operators */
101  vector &operator=(const vector &other);
102  vector &operator=(vector &&other);
103  vector &operator=(std::initializer_list<T> ilist);
104  vector &operator=(const std::vector<T> &other);
105 
106  /* Assign methods */
107  void assign(size_type count, const T &value);
108  template <typename InputIt,
109  typename std::enable_if<
111  InputIt>::type * = nullptr>
112  void assign(InputIt first, InputIt last);
113  void assign(std::initializer_list<T> ilist);
114  void assign(const vector &other);
115  void assign(vector &&other);
116  void assign(const std::vector<T> &other);
117 
118  /* Destructor */
119  ~vector();
120 
121  /* Element access */
122  reference at(size_type n);
123  const_reference at(size_type n) const;
124  const_reference const_at(size_type n) const;
125  reference operator[](size_type n);
126  const_reference operator[](size_type n) const;
127  reference front();
128  const_reference front() const;
129  const_reference cfront() const;
130  reference back();
131  const_reference back() const;
132  const_reference cback() const;
133  value_type *data();
134  const value_type *data() const noexcept;
135  const value_type *cdata() const noexcept;
136 
137  /* Iterators */
138  iterator begin();
139  const_iterator begin() const noexcept;
140  const_iterator cbegin() const noexcept;
141  iterator end();
142  const_iterator end() const noexcept;
143  const_iterator cend() const noexcept;
144  reverse_iterator rbegin();
145  const_reverse_iterator rbegin() const noexcept;
146  const_reverse_iterator crbegin() const noexcept;
147  reverse_iterator rend();
148  const_reverse_iterator rend() const noexcept;
149  const_reverse_iterator crend() const noexcept;
150 
151  /* Range */
152  slice<pointer> range(size_type start, size_type n);
153  slice<range_snapshotting_iterator> range(size_type start, size_type n,
154  size_type snapshot_size);
155  slice<const_iterator> range(size_type start, size_type n) const;
156  slice<const_iterator> crange(size_type start, size_type n) const;
157 
158  /* Capacity */
159  constexpr bool empty() const noexcept;
160  size_type size() const noexcept;
161  constexpr size_type max_size() const noexcept;
162  void reserve(size_type capacity_new);
163  size_type capacity() const noexcept;
164  void shrink_to_fit();
165 
166  /* Modifiers */
167  void clear();
168  void free_data();
169  iterator insert(const_iterator pos, const T &value);
170  iterator insert(const_iterator pos, T &&value);
171  iterator insert(const_iterator pos, size_type count, const T &value);
172  template <typename InputIt,
173  typename std::enable_if<
175  InputIt>::type * = nullptr>
176  iterator insert(const_iterator pos, InputIt first, InputIt last);
177  iterator insert(const_iterator pos, std::initializer_list<T> ilist);
178  template <class... Args>
179  iterator emplace(const_iterator pos, Args &&... args);
180  template <class... Args>
181  reference emplace_back(Args &&... args);
182  iterator erase(const_iterator pos);
183  iterator erase(const_iterator first, const_iterator last);
184  void push_back(const T &value);
185  void push_back(T &&value);
186  void pop_back();
187  void resize(size_type count);
188  void resize(size_type count, const value_type &value);
189  void swap(vector &other);
190 
191 private:
192  /* helper iterator */
193  template <typename P>
194  struct single_element_iterator {
195  using iterator_category = std::input_iterator_tag;
196  using value_type = P;
197  using difference_type = std::ptrdiff_t;
198  using pointer = const P *;
199  using reference = const P &;
200 
201  const P *ptr;
202  std::size_t count;
203 
204  single_element_iterator(const P *ptr, std::size_t count = 0)
205  : ptr(ptr), count(count)
206  {
207  }
208 
209  reference operator*()
210  {
211  return *ptr;
212  }
213 
214  pointer operator->()
215  {
216  return ptr;
217  }
218 
219  single_element_iterator &
220  operator++()
221  {
222  count++;
223  return *this;
224  }
225 
226  single_element_iterator
227  operator++(int)
228  {
229  single_element_iterator tmp =
230  single_element_iterator(ptr, count);
231  count++;
232  return tmp;
233  }
234 
235  difference_type
236  operator-(const single_element_iterator &rhs)
237  {
238  return count - rhs.count;
239  }
240 
241  bool
242  operator!=(const single_element_iterator &rhs)
243  {
244  return ptr != rhs.ptr || count != rhs.count;
245  }
246  };
247 
248  /* helper functions */
249  void alloc(size_type size);
250  void check_pmem();
251  void check_tx_stage_work();
252  template <typename... Args>
253  void construct_at_end(size_type count, Args &&... args);
254  template <typename InputIt,
255  typename std::enable_if<
257  InputIt>::type * = nullptr>
258  void construct_at_end(InputIt first, InputIt last);
259  void dealloc();
260  pool_base get_pool() const noexcept;
261  template <typename InputIt>
262  void internal_insert(size_type idx, InputIt first, InputIt last);
263  void realloc(size_type size);
264  size_type get_recommended_capacity(size_type at_least) const;
265  void shrink(size_type size_new);
266  void add_data_to_tx(size_type idx_first, size_type num);
267  template <typename InputIt>
268  void construct_or_assign(size_type idx, InputIt first, InputIt last);
269  void move_elements_backward(pointer first, pointer last,
270  pointer d_last);
271 
272  p<size_type> _size;
273  p<size_type> _capacity;
274 
275  /* Underlying array */
276  persistent_ptr<T[]> _data;
277 };
278 
279 /* Non-member swap */
280 template <typename T>
281 void swap(vector<T> &lhs, vector<T> &rhs);
282 
283 /*
284  * Comparison operators between pmem::obj::vector<T> and
285  * pmem::obj::vector<T>
286  */
287 template <typename T>
288 bool operator==(const vector<T> &lhs, const vector<T> &rhs);
289 template <typename T>
290 bool operator!=(const vector<T> &lhs, const vector<T> &rhs);
291 template <typename T>
292 bool operator<(const vector<T> &lhs, const vector<T> &rhs);
293 template <typename T>
294 bool operator<=(const vector<T> &lhs, const vector<T> &rhs);
295 template <typename T>
296 bool operator>(const vector<T> &lhs, const vector<T> &rhs);
297 template <typename T>
298 bool operator>=(const vector<T> &lhs, const vector<T> &rhs);
299 
300 /*
301  * Comparison operators between pmem::obj::vector<T> and
302  * std::vector<T>
303  */
304 template <typename T>
305 bool operator==(const vector<T> &lhs, const std::vector<T> &rhs);
306 template <typename T>
307 bool operator!=(const vector<T> &lhs, const std::vector<T> &rhs);
308 template <typename T>
309 bool operator<(const vector<T> &lhs, const std::vector<T> &rhs);
310 template <typename T>
311 bool operator<=(const vector<T> &lhs, const std::vector<T> &rhs);
312 template <typename T>
313 bool operator>(const vector<T> &lhs, const std::vector<T> &rhs);
314 template <typename T>
315 bool operator>=(const vector<T> &lhs, const std::vector<T> &rhs);
316 
317 /*
318  * Comparison operators between std::vector<T> and
319  * pmem::obj::vector<T>
320  */
321 template <typename T>
322 bool operator==(const std::vector<T> &lhs, const vector<T> &rhs);
323 template <typename T>
324 bool operator!=(const std::vector<T> &lhs, const vector<T> &rhs);
325 template <typename T>
326 bool operator<(const std::vector<T> &lhs, const vector<T> &rhs);
327 template <typename T>
328 bool operator<=(const std::vector<T> &lhs, const vector<T> &rhs);
329 template <typename T>
330 bool operator>(const std::vector<T> &lhs, const vector<T> &rhs);
331 template <typename T>
332 bool operator>=(const std::vector<T> &lhs, const vector<T> &rhs);
333 
343 template <typename T>
345 {
346  check_pmem();
347  check_tx_stage_work();
348 
349  _data = nullptr;
350  _size = 0;
351  _capacity = 0;
352 }
353 
372 template <typename T>
373 vector<T>::vector(size_type count, const value_type &value)
374 {
375  check_pmem();
376  check_tx_stage_work();
377 
378  _data = nullptr;
379  _size = 0;
380  alloc(count);
381  construct_at_end(count, value);
382 }
383 
401 template <typename T>
402 vector<T>::vector(size_type count)
403 {
404  check_pmem();
405  check_tx_stage_work();
406 
407  _data = nullptr;
408  _size = 0;
409  alloc(count);
410  construct_at_end(count);
411 }
412 
435 template <typename T>
436 template <typename InputIt,
437  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
438  InputIt>::type *>
439 vector<T>::vector(InputIt first, InputIt last)
440 {
441  check_pmem();
442  check_tx_stage_work();
443 
444  _data = nullptr;
445  _size = 0;
446  alloc(static_cast<size_type>(std::distance(first, last)));
447  construct_at_end(first, last);
448 }
449 
468 template <typename T>
470 {
471  check_pmem();
472  check_tx_stage_work();
473 
474  _data = nullptr;
475  _size = 0;
476  alloc(other.capacity());
477  construct_at_end(other.cbegin(), other.cend());
478 }
479 
499 template <typename T>
501 {
502  check_pmem();
503  check_tx_stage_work();
504 
505  _data = other._data;
506  _capacity = other.capacity();
507  _size = other.size();
508  other._data = nullptr;
509  other._capacity = other._size = 0;
510 }
511 
529 template <typename T>
530 vector<T>::vector(std::initializer_list<T> init)
531  : vector(init.begin(), init.end())
532 {
533 }
534 
553 template <typename T>
554 vector<T>::vector(const std::vector<T> &other)
555  : vector(other.cbegin(), other.cend())
556 {
557 }
558 
570 template <typename T>
571 vector<T> &
573 {
574  assign(other);
575 
576  return *this;
577 }
578 
589 template <typename T>
590 vector<T> &
592 {
593  assign(std::move(other));
594 
595  return *this;
596 }
597 
607 template <typename T>
608 vector<T> &
609 vector<T>::operator=(std::initializer_list<T> ilist)
610 {
611  assign(ilist.begin(), ilist.end());
612 
613  return *this;
614 }
615 
628 template <typename T>
629 vector<T> &
630 vector<T>::operator=(const std::vector<T> &other)
631 {
632  assign(other);
633 
634  return *this;
635 }
636 
653 template <typename T>
654 void
655 vector<T>::assign(size_type count, const_reference value)
656 {
657  pool_base pb = get_pool();
658 
659  transaction::run(pb, [&] {
660  if (count <= capacity()) {
661  /*
662  * Reallocation is not needed. First, replace old
663  * elements with new ones in range [0, size()).
664  * Depending on count, either call remaining old
665  * elements destructors, or append more new elements.
666  */
667  size_type size_old = _size;
668  add_data_to_tx(0, size_old);
669 
670  std::fill_n(
671  _data.get(),
672  (std::min)(count,
673  static_cast<size_type>(size_old)),
674  value);
675 
676  if (count > size_old) {
677  add_data_to_tx(size_old, count - size_old);
678  construct_at_end(count - size_old, value);
679  } else {
680  shrink(count);
681  }
682  } else {
683  dealloc();
684  alloc(count);
685  construct_at_end(count, value);
686  }
687  });
688 }
689 
708 template <typename T>
709 template <typename InputIt,
710  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
711  InputIt>::type *>
712 void
713 vector<T>::assign(InputIt first, InputIt last)
714 {
715  pool_base pb = get_pool();
716 
717  size_type size_new = static_cast<size_type>(std::distance(first, last));
718 
719  transaction::run(pb, [&] {
720  if (size_new <= capacity()) {
721  /*
722  * Reallocation is not needed. First, replace old
723  * elements with new ones in range [0, size()).
724  * Depending on size_new, either call remaining old
725  * elements destructors, or append more new elements.
726  */
727  size_type size_old = _size;
728  add_data_to_tx(0, size_old);
729 
730  InputIt mid = last;
731  bool growing = size_new > size_old;
732 
733  if (growing) {
734  add_data_to_tx(size_old, size_new - size_old);
735 
736  mid = first;
737  std::advance(mid, size_old);
738  }
739 
740  iterator shrink_to = std::copy(first, mid, &_data[0]);
741 
742  if (growing) {
743  construct_at_end(mid, last);
744  } else {
745  shrink(static_cast<size_type>(std::distance(
746  iterator(&_data[0]), shrink_to)));
747  }
748  } else {
749  dealloc();
750  alloc(size_new);
751  construct_at_end(first, last);
752  }
753  });
754 }
755 
771 template <typename T>
772 void
773 vector<T>::assign(std::initializer_list<T> ilist)
774 {
775  assign(ilist.begin(), ilist.end());
776 }
777 
789 template <typename T>
790 void
792 {
793  if (this != &other)
794  assign(other.cbegin(), other.cend());
795 }
796 
808 template <typename T>
809 void
811 {
812  if (this == &other)
813  return;
814 
815  pool_base pb = get_pool();
816 
817  transaction::run(pb, [&] {
818  dealloc();
819 
820  _data = other._data;
821  _capacity = other._capacity;
822  _size = other._size;
823 
824  other._data = nullptr;
825  other._capacity = other._size = 0;
826  });
827 }
828 
841 template <typename T>
842 void
843 vector<T>::assign(const std::vector<T> &other)
844 {
845  assign(other.cbegin(), other.cend());
846 }
847 
857 template <typename T>
859 {
860  free_data();
861 }
862 
875 template <typename T>
876 typename vector<T>::reference
877 vector<T>::at(size_type n)
878 {
879  if (n >= _size)
880  throw std::out_of_range("vector::at");
881 
882  detail::conditional_add_to_tx(&_data[static_cast<difference_type>(n)],
883  1, POBJ_XADD_ASSUME_INITIALIZED);
884 
885  return _data[static_cast<difference_type>(n)];
886 }
887 
897 template <typename T>
898 typename vector<T>::const_reference
899 vector<T>::at(size_type n) const
900 {
901  if (n >= _size)
902  throw std::out_of_range("vector::at");
903 
904  return _data[static_cast<difference_type>(n)];
905 }
906 
919 template <typename T>
920 typename vector<T>::const_reference
921 vector<T>::const_at(size_type n) const
922 {
923  if (n >= _size)
924  throw std::out_of_range("vector::const_at");
925 
926  return _data[static_cast<difference_type>(n)];
927 }
928 
940 template <typename T>
941 typename vector<T>::reference vector<T>::operator[](size_type n)
942 {
943  detail::conditional_add_to_tx(&_data[static_cast<difference_type>(n)],
944  1, POBJ_XADD_ASSUME_INITIALIZED);
945 
946  return _data[static_cast<difference_type>(n)];
947 }
948 
956 template <typename T>
957 typename vector<T>::const_reference vector<T>::operator[](size_type n) const
958 {
959  return _data[static_cast<difference_type>(n)];
960 }
961 
970 template <typename T>
971 typename vector<T>::reference
973 {
974  detail::conditional_add_to_tx(&_data[0], 1,
975  POBJ_XADD_ASSUME_INITIALIZED);
976 
977  return _data[0];
978 }
979 
985 template <typename T>
986 typename vector<T>::const_reference
988 {
989  return _data[0];
990 }
991 
999 template <typename T>
1000 typename vector<T>::const_reference
1002 {
1003  return _data[0];
1004 }
1005 
1014 template <typename T>
1015 typename vector<T>::reference
1017 {
1018  detail::conditional_add_to_tx(
1019  &_data[static_cast<difference_type>(size() - 1)], 1,
1020  POBJ_XADD_ASSUME_INITIALIZED);
1021 
1022  return _data[static_cast<difference_type>(size() - 1)];
1023 }
1024 
1030 template <typename T>
1031 typename vector<T>::const_reference
1033 {
1034  return _data[static_cast<difference_type>(size() - 1)];
1035 }
1036 
1044 template <typename T>
1045 typename vector<T>::const_reference
1047 {
1048  return _data[static_cast<difference_type>(size() - 1)];
1049 }
1050 
1060 template <typename T>
1061 typename vector<T>::value_type *
1063 {
1064  add_data_to_tx(0, _size);
1065 
1066  return _data.get();
1067 }
1068 
1074 template <typename T>
1075 const typename vector<T>::value_type *
1076 vector<T>::data() const noexcept
1077 {
1078  return _data.get();
1079 }
1080 
1088 template <typename T>
1089 const typename vector<T>::value_type *
1090 vector<T>::cdata() const noexcept
1091 {
1092  return _data.get();
1093 }
1094 
1100 template <typename T>
1101 typename vector<T>::iterator
1103 {
1104  return iterator(_data.get());
1105 }
1106 
1112 template <typename T>
1113 typename vector<T>::const_iterator
1114 vector<T>::begin() const noexcept
1115 {
1116  return const_iterator(_data.get());
1117 }
1118 
1126 template <typename T>
1127 typename vector<T>::const_iterator
1128 vector<T>::cbegin() const noexcept
1129 {
1130  return const_iterator(_data.get());
1131 }
1132 
1138 template <typename T>
1139 typename vector<T>::iterator
1141 {
1142  return iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1143 }
1144 
1150 template <typename T>
1151 typename vector<T>::const_iterator
1152 vector<T>::end() const noexcept
1153 {
1154  return const_iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1155 }
1156 
1164 template <typename T>
1165 typename vector<T>::const_iterator
1166 vector<T>::cend() const noexcept
1167 {
1168  return const_iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1169 }
1170 
1176 template <typename T>
1177 typename vector<T>::reverse_iterator
1179 {
1180  return reverse_iterator(end());
1181 }
1182 
1188 template <typename T>
1189 typename vector<T>::const_reverse_iterator
1190 vector<T>::rbegin() const noexcept
1191 {
1192  return const_reverse_iterator(cend());
1193 }
1194 
1202 template <typename T>
1203 typename vector<T>::const_reverse_iterator
1204 vector<T>::crbegin() const noexcept
1205 {
1206  return const_reverse_iterator(cend());
1207 }
1208 
1215 template <typename T>
1216 typename vector<T>::reverse_iterator
1218 {
1219  return reverse_iterator(begin());
1220 }
1221 
1228 template <typename T>
1229 typename vector<T>::const_reverse_iterator
1230 vector<T>::rend() const noexcept
1231 {
1232  return const_reverse_iterator(cbegin());
1233 }
1234 
1243 template <typename T>
1244 typename vector<T>::const_reverse_iterator
1245 vector<T>::crend() const noexcept
1246 {
1247  return const_reverse_iterator(cbegin());
1248 }
1249 
1263 template <typename T>
1265 vector<T>::range(size_type start, size_type n)
1266 {
1267  if (start + n > size())
1268  throw std::out_of_range("vector::range");
1269 
1270  detail::conditional_add_to_tx(cdata() + start, n,
1271  POBJ_XADD_ASSUME_INITIALIZED);
1272 
1273  return {_data.get() + start, _data.get() + start + n};
1274 }
1275 
1291 template <typename T>
1293 vector<T>::range(size_type start, size_type n, size_type snapshot_size)
1294 {
1295  if (start + n > size())
1296  throw std::out_of_range("vector::range");
1297 
1298  if (snapshot_size > n)
1299  snapshot_size = n;
1300 
1301  return {range_snapshotting_iterator(_data.get() + start,
1302  _data.get() + start, n,
1303  snapshot_size),
1304  range_snapshotting_iterator(_data.get() + start + n,
1305  _data.get() + start, n,
1306  snapshot_size)};
1307 }
1308 
1320 template <typename T>
1322 vector<T>::range(size_type start, size_type n) const
1323 {
1324  if (start + n > size())
1325  throw std::out_of_range("vector::range");
1326 
1327  return {const_iterator(cdata() + start),
1328  const_iterator(cdata() + start + n)};
1329 }
1330 
1342 template <typename T>
1344 vector<T>::crange(size_type start, size_type n) const
1345 {
1346  if (start + n > size())
1347  throw std::out_of_range("vector::crange");
1348 
1349  return {const_iterator(cdata() + start),
1350  const_iterator(cdata() + start + n)};
1351 }
1352 
1358 template <typename T>
1359 constexpr bool
1360 vector<T>::empty() const noexcept
1361 {
1362  return _size == 0;
1363 }
1364 
1368 template <typename T>
1369 typename vector<T>::size_type
1370 vector<T>::size() const noexcept
1371 {
1372  return _size;
1373 }
1374 
1379 template <typename T>
1380 constexpr typename vector<T>::size_type
1381 vector<T>::max_size() const noexcept
1382 {
1383  return PMEMOBJ_MAX_ALLOC_SIZE / sizeof(value_type);
1384 }
1385 
1404 template <typename T>
1405 void
1406 vector<T>::reserve(size_type capacity_new)
1407 {
1408  if (capacity_new <= _capacity)
1409  return;
1410 
1411  pool_base pb = get_pool();
1412  transaction::run(pb, [&] { realloc(capacity_new); });
1413 }
1414 
1418 template <typename T>
1419 typename vector<T>::size_type
1420 vector<T>::capacity() const noexcept
1421 {
1422  return _capacity;
1423 }
1424 
1439 template <typename T>
1440 void
1442 {
1443  size_type capacity_new = size();
1444  if (capacity() == capacity_new)
1445  return;
1446 
1447  pool_base pb = get_pool();
1448  transaction::run(pb, [&] { realloc(capacity_new); });
1449 }
1450 
1459 template <typename T>
1460 void
1462 {
1463  pool_base pb = get_pool();
1464  transaction::run(pb, [&] { shrink(0); });
1465 }
1466 
1479 template <typename T>
1480 void
1482 {
1483  if (_data == nullptr)
1484  return;
1485 
1486  pool_base pb = get_pool();
1487  transaction::run(pb, [&] { dealloc(); });
1488 }
1489 
1514 template <typename T>
1515 typename vector<T>::iterator
1516 vector<T>::insert(const_iterator pos, const value_type &value)
1517 {
1518  return insert(pos, 1, value);
1519 }
1520 
1545 template <typename T>
1546 typename vector<T>::iterator
1547 vector<T>::insert(const_iterator pos, value_type &&value)
1548 {
1549  pool_base pb = get_pool();
1550 
1551  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1552 
1553  transaction::run(pb, [&] {
1554  internal_insert(idx, std::make_move_iterator(&value),
1555  std::make_move_iterator(&value + 1));
1556  });
1557 
1558  return iterator(&_data[static_cast<difference_type>(idx)]);
1559 }
1560 
1589 template <typename T>
1590 typename vector<T>::iterator
1591 vector<T>::insert(const_iterator pos, size_type count, const value_type &value)
1592 {
1593  pool_base pb = get_pool();
1594 
1595  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1596 
1597  transaction::run(pb, [&] {
1598  internal_insert(
1599  idx, single_element_iterator<value_type>(&value, 0),
1600  single_element_iterator<value_type>(&value, count));
1601  });
1602 
1603  return iterator(_data.get() + static_cast<difference_type>(idx));
1604 }
1605 
1640 template <typename T>
1641 template <typename InputIt,
1642  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
1643  InputIt>::type *>
1644 typename vector<T>::iterator
1645 vector<T>::insert(const_iterator pos, InputIt first, InputIt last)
1646 {
1647  pool_base pb = get_pool();
1648 
1649  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1650 
1651  transaction::run(pb, [&] { internal_insert(idx, first, last); });
1652 
1653  return iterator(&_data[static_cast<difference_type>(idx)]);
1654 }
1655 
1684 template <typename T>
1685 typename vector<T>::iterator
1686 vector<T>::insert(const_iterator pos, std::initializer_list<value_type> ilist)
1687 {
1688  return insert(pos, ilist.begin(), ilist.end());
1689 }
1690 
1718 template <typename T>
1719 template <class... Args>
1720 typename vector<T>::iterator
1721 vector<T>::emplace(const_iterator pos, Args &&... args)
1722 {
1723  pool_base pb = get_pool();
1724 
1725  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1726 
1727  transaction::run(pb, [&] {
1728  /*
1729  * args might be a reference to underlying array element. This
1730  * reference can be invalidated after internal_insert() call.
1731  * Hence, we must cache value_type object in temp_value.
1732  */
1733  detail::temp_value<value_type,
1734  noexcept(T(std::forward<Args>(args)...))>
1735  tmp(std::forward<Args>(args)...);
1736 
1737  auto &tmp_ref = tmp.get();
1738 
1739  internal_insert(idx, std::make_move_iterator(&tmp_ref),
1740  std::make_move_iterator(&tmp_ref + 1));
1741  });
1742 
1743  return iterator(&_data[static_cast<difference_type>(idx)]);
1744 }
1745 
1768 template <typename T>
1769 template <class... Args>
1770 typename vector<T>::reference
1771 vector<T>::emplace_back(Args &&... args)
1772 {
1773  /*
1774  * emplace() cannot be used here, because emplace_back() doesn't require
1775  * element_type to be MoveAssignable and emplace() uses
1776  * std::move_backward() function.
1777  */
1778  pool_base pb = get_pool();
1779 
1780  transaction::run(pb, [&] {
1781  if (_size == _capacity) {
1782  realloc(get_recommended_capacity(_size + 1));
1783  } else {
1784  add_data_to_tx(size(), 1);
1785  }
1786 
1787  construct_at_end(1, std::forward<Args>(args)...);
1788  });
1789 
1790  return back();
1791 }
1792 
1812 template <typename T>
1813 typename vector<T>::iterator
1814 vector<T>::erase(const_iterator pos)
1815 {
1816  return erase(pos, pos + 1);
1817 }
1818 
1841 template <typename T>
1842 typename vector<T>::iterator
1843 vector<T>::erase(const_iterator first, const_iterator last)
1844 {
1845  size_type idx = static_cast<size_type>(
1846  std::distance(const_iterator(_data.get()), first));
1847  size_type count = static_cast<size_type>(std::distance(first, last));
1848 
1849  if (count == 0)
1850  return iterator(&_data[static_cast<difference_type>(idx)]);
1851 
1852  pool_base pb = get_pool();
1853 
1854  transaction::run(pb, [&] {
1855  /*
1856  * XXX: future optimization: no need to snapshot trivial types,
1857  * if idx + count = _size
1858  */
1859  add_data_to_tx(idx, _size - idx);
1860 
1861  pointer move_begin =
1862  &_data[static_cast<difference_type>(idx + count)];
1863  pointer move_end = &_data[static_cast<difference_type>(size())];
1864  pointer dest = &_data[static_cast<difference_type>(idx)];
1865 
1866  std::move(move_begin, move_end, dest);
1867 
1868  _size -= count;
1869  });
1870 
1871  return iterator(&_data[static_cast<difference_type>(idx)]);
1872 }
1873 
1889 template <typename T>
1890 void
1891 vector<T>::push_back(const value_type &value)
1892 {
1893  emplace_back(value);
1894 }
1895 
1912 template <typename T>
1913 void
1914 vector<T>::push_back(value_type &&value)
1915 {
1916  emplace_back(std::move(value));
1917 }
1918 
1929 template <typename T>
1930 void
1932 {
1933  if (empty())
1934  return;
1935 
1936  pool_base pb = get_pool();
1937  transaction::run(pb, [&] { shrink(size() - 1); });
1938 }
1939 
1956 template <typename T>
1957 void
1958 vector<T>::resize(size_type count)
1959 {
1960  pool_base pb = get_pool();
1961  transaction::run(pb, [&] {
1962  if (count <= _size)
1963  shrink(count);
1964  else {
1965  if (_capacity < count)
1966  realloc(count);
1967  construct_at_end(count - _size);
1968  }
1969  });
1970 }
1971 
1989 template <typename T>
1990 void
1991 vector<T>::resize(size_type count, const value_type &value)
1992 {
1993  if (_capacity == count)
1994  return;
1995 
1996  pool_base pb = get_pool();
1997  transaction::run(pb, [&] {
1998  if (count <= _size)
1999  shrink(count);
2000  else {
2001  if (_capacity < count)
2002  realloc(count);
2003  construct_at_end(count - _size, value);
2004  }
2005  });
2006 }
2007 
2011 template <typename T>
2012 void
2014 {
2015  pool_base pb = get_pool();
2016  transaction::run(pb, [&] {
2017  std::swap(this->_data, other._data);
2018  std::swap(this->_size, other._size);
2019  std::swap(this->_capacity, other._capacity);
2020  });
2021 }
2022 
2040 template <typename T>
2041 void
2042 vector<T>::alloc(size_type capacity_new)
2043 {
2044  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2045  assert(_data == nullptr);
2046  assert(_size == 0);
2047 
2048  if (capacity_new > max_size())
2049  throw std::length_error("New capacity exceeds max size.");
2050 
2051  _capacity = capacity_new;
2052 
2053  if (capacity_new == 0)
2054  return;
2055 
2056  /*
2057  * We need to cache pmemobj_tx_alloc return value and only after that
2058  * assign it to _data, because when pmemobj_tx_alloc fails, it aborts
2059  * transaction.
2060  */
2061  persistent_ptr<T[]> res =
2062  pmemobj_tx_alloc(sizeof(value_type) * capacity_new,
2063  detail::type_num<value_type>());
2064 
2065  if (res == nullptr) {
2066  if (errno == ENOMEM)
2068  "Failed to allocate persistent memory object")
2069  .with_pmemobj_errormsg();
2070  else
2072  "Failed to allocate persistent memory object")
2073  .with_pmemobj_errormsg();
2074  }
2075 
2076  _data = res;
2077 }
2078 
2085 template <typename T>
2086 void
2088 {
2089  if (nullptr == pmemobj_pool_by_ptr(this))
2090  throw pmem::pool_error("Invalid pool handle.");
2091 }
2092 
2100 template <typename T>
2101 void
2103 {
2104  if (pmemobj_tx_stage() != TX_STAGE_WORK)
2106  "Function called out of transaction scope.");
2107 }
2108 
2127 template <typename T>
2128 template <typename... Args>
2129 void
2130 vector<T>::construct_at_end(size_type count, Args &&... args)
2131 {
2132  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2133  assert(_capacity >= count + _size);
2134 
2135  pointer dest = _data.get() + size();
2136  const_pointer end = dest + count;
2137  for (; dest != end; ++dest)
2138  detail::create<value_type, Args...>(
2139  dest, std::forward<Args>(args)...);
2140  _size += count;
2141 }
2142 
2165 template <typename T>
2166 template <typename InputIt,
2167  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
2168  InputIt>::type *>
2169 void
2170 vector<T>::construct_at_end(InputIt first, InputIt last)
2171 {
2172  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2173  difference_type range_size = std::distance(first, last);
2174  assert(range_size >= 0);
2175  assert(_capacity >= static_cast<size_type>(range_size) + _size);
2176 
2177  pointer dest = _data.get() + size();
2178  _size += static_cast<size_type>(range_size);
2179  while (first != last)
2180  detail::create<value_type>(dest++, *first++);
2181 }
2182 
2198 template <typename T>
2199 void
2201 {
2202  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2203 
2204  if (_data != nullptr) {
2205  shrink(0);
2206  if (pmemobj_tx_free(*_data.raw_ptr()) != 0)
2208  "failed to delete persistent memory object")
2209  .with_pmemobj_errormsg();
2210  _data = nullptr;
2211  _capacity = 0;
2212  }
2213 }
2214 
2222 template <typename T>
2223 pool_base
2224 vector<T>::get_pool() const noexcept
2225 {
2226  auto pop = pmemobj_pool_by_ptr(this);
2227  assert(pop != nullptr);
2228  return pool_base(pop);
2229 }
2230 
2238 template <typename T>
2239 void
2240 vector<T>::move_elements_backward(pointer first, pointer last, pointer d_last)
2241 {
2242  while (first != last && d_last >= cend())
2243  detail::create<value_type>(--d_last, std::move(*(--last)));
2244 
2245  if (first != last)
2246  std::move_backward(first, last, d_last);
2247 }
2248 
2256 template <typename T>
2257 template <typename InputIt>
2258 void
2259 vector<T>::construct_or_assign(size_type idx, InputIt first, InputIt last)
2260 {
2261  auto count = static_cast<size_type>(std::distance(first, last));
2262  auto dest = _data.get() + idx;
2263  auto initialized_slots = static_cast<size_type>(cend() - dest);
2264 
2265  /* Assign new elements to initialized memory */
2266  if (dest < cend())
2267  dest = std::copy_n(first, (std::min)(initialized_slots, count),
2268  dest);
2269 
2270  std::advance(first, (std::min)(initialized_slots, count));
2271 
2272  /* Rest of the elements will be created in uninitialized memory */
2273  while (first != last)
2274  detail::create<value_type>(dest++, *first++);
2275 
2276  _size += count;
2277 }
2278 
2299 template <typename T>
2300 template <typename InputIt>
2301 void
2302 vector<T>::internal_insert(size_type idx, InputIt first, InputIt last)
2303 {
2304  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2305 
2306  auto count = static_cast<size_type>(std::distance(first, last));
2307 
2308  if (_capacity >= size() + count) {
2309  pointer dest = _data.get() +
2310  static_cast<difference_type>(size() + count);
2311  pointer begin = _data.get() + static_cast<difference_type>(idx);
2312  pointer end =
2313  _data.get() + static_cast<difference_type>(size());
2314 
2315  add_data_to_tx(idx, size() - idx + count);
2316 
2317  /* Make a gap for new elements */
2318  move_elements_backward(begin, end, dest);
2319 
2320  /* Construct new elements in the gap */
2321  construct_or_assign(idx, first, last);
2322  } else {
2323  /*
2324  * XXX: future optimization: we don't have to snapshot data
2325  * which we will copy (only snapshot for move)
2326  */
2327  add_data_to_tx(0, _size);
2328 
2329  auto old_data = _data;
2330  auto old_size = _size;
2331  pointer old_begin = _data.get();
2332  pointer old_mid =
2333  _data.get() + static_cast<difference_type>(idx);
2334  pointer old_end =
2335  _data.get() + static_cast<difference_type>(size());
2336 
2337  _data = nullptr;
2338  _size = _capacity = 0;
2339 
2340  alloc(get_recommended_capacity(old_size + count));
2341 
2342  /* Move range before the idx to new array */
2343  construct_at_end(std::make_move_iterator(old_begin),
2344  std::make_move_iterator(old_mid));
2345 
2346  /* Insert (first, last) range to the new array */
2347  construct_at_end(first, last);
2348 
2349  /* Move remaining element ot the new array */
2350  construct_at_end(std::make_move_iterator(old_mid),
2351  std::make_move_iterator(old_end));
2352 
2353  /* destroy and free old data */
2354  for (size_type i = 0; i < old_size; ++i)
2355  detail::destroy<value_type>(
2356  old_data[static_cast<difference_type>(i)]);
2357  if (pmemobj_tx_free(old_data.raw()) != 0)
2359  "failed to delete persistent memory object")
2360  .with_pmemobj_errormsg();
2361  }
2362 }
2363 
2382 template <typename T>
2383 void
2384 vector<T>::realloc(size_type capacity_new)
2385 {
2386  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2387 
2388  /*
2389  * If _data == nullptr this object has never allocated any memory
2390  * so we need to behave as alloc instead.
2391  */
2392  if (_data == nullptr)
2393  return alloc(capacity_new);
2394 
2395  /*
2396  * XXX: future optimization: we don't have to snapshot data
2397  * which we will not overwrite
2398  */
2399  add_data_to_tx(0, _size);
2400 
2401  auto old_data = _data;
2402  auto old_size = _size;
2403  pointer old_begin = _data.get();
2404  pointer old_end = capacity_new < _size
2405  ? &_data[static_cast<difference_type>(capacity_new)]
2406  : &_data[static_cast<difference_type>(size())];
2407 
2408  _data = nullptr;
2409  _size = _capacity = 0;
2410 
2411  alloc(capacity_new);
2412 
2413  construct_at_end(std::make_move_iterator(old_begin),
2414  std::make_move_iterator(old_end));
2415 
2416  /* destroy and free old data */
2417  for (size_type i = 0; i < old_size; ++i)
2418  detail::destroy<value_type>(
2419  old_data[static_cast<difference_type>(i)]);
2420  if (pmemobj_tx_free(old_data.raw()) != 0)
2422  "failed to delete persistent memory object")
2423  .with_pmemobj_errormsg();
2424 }
2425 
2432 template <typename T>
2433 typename vector<T>::size_type
2434 vector<T>::get_recommended_capacity(size_type at_least) const
2435 {
2436  return detail::next_pow_2(at_least);
2437 }
2438 
2455 template <typename T>
2456 void
2457 vector<T>::shrink(size_type size_new)
2458 {
2459  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2460  assert(size_new <= _size);
2461 
2462  add_data_to_tx(size_new, _size - size_new);
2463 
2464  for (size_type i = size_new; i < _size; ++i)
2465  detail::destroy<value_type>(
2466  _data[static_cast<difference_type>(i)]);
2467  _size = size_new;
2468 }
2469 
2479 template <typename T>
2480 void
2481 vector<T>::add_data_to_tx(size_type idx_first, size_type num)
2482 {
2483  assert(idx_first + num <= capacity());
2484 
2485 #if LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED
2486  /* Make sure that only data allocated by this vector is accessed */
2487  assert(VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_data.get() + idx_first,
2488  num * sizeof(T)) == 0);
2489 #endif
2490 
2491  auto initialized_num = size() - idx_first;
2492 
2493  /* Snapshot elements in range [idx_first,size()) */
2494  detail::conditional_add_to_tx(_data.get() + idx_first,
2495  (std::min)(initialized_num, num),
2496  POBJ_XADD_ASSUME_INITIALIZED);
2497 
2498  if (num > initialized_num) {
2499  /* Elements after size() do not have to be snapshotted */
2500  detail::conditional_add_to_tx(_data.get() + size(),
2501  num - initialized_num,
2502  POBJ_XADD_NO_SNAPSHOT);
2503  }
2504 }
2505 
2517 template <typename T>
2518 bool
2519 operator==(const vector<T> &lhs, const vector<T> &rhs)
2520 {
2521  return lhs.size() == rhs.size() &&
2522  std::equal(lhs.begin(), lhs.end(), rhs.begin());
2523 }
2524 
2536 template <typename T>
2537 bool
2538 operator!=(const vector<T> &lhs, const vector<T> &rhs)
2539 {
2540  return !(lhs == rhs);
2541 }
2542 
2553 template <typename T>
2554 bool
2555 operator<(const vector<T> &lhs, const vector<T> &rhs)
2556 {
2557  return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
2558  rhs.end());
2559 }
2560 
2571 template <typename T>
2572 bool
2573 operator<=(const vector<T> &lhs, const vector<T> &rhs)
2574 {
2575  return !(rhs < lhs);
2576 }
2577 
2589 template <typename T>
2590 bool
2591 operator>(const vector<T> &lhs, const vector<T> &rhs)
2592 {
2593  return rhs < lhs;
2594 }
2595 
2606 template <typename T>
2607 bool
2608 operator>=(const vector<T> &lhs, const vector<T> &rhs)
2609 {
2610  return !(lhs < rhs);
2611 }
2612 
2624 template <typename T>
2625 bool
2626 operator==(const vector<T> &lhs, const std::vector<T> &rhs)
2627 {
2628  return lhs.size() == rhs.size() &&
2629  std::equal(lhs.begin(), lhs.end(), rhs.begin());
2630 }
2631 
2643 template <typename T>
2644 bool
2645 operator!=(const vector<T> &lhs, const std::vector<T> &rhs)
2646 {
2647  return !(lhs == rhs);
2648 }
2649 
2660 template <typename T>
2661 bool
2662 operator<(const vector<T> &lhs, const std::vector<T> &rhs)
2663 {
2664  return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
2665  rhs.end());
2666 }
2667 
2678 template <typename T>
2679 bool
2680 operator<=(const vector<T> &lhs, const std::vector<T> &rhs)
2681 {
2682  return !(std::lexicographical_compare(rhs.begin(), rhs.end(),
2683  lhs.begin(), lhs.end()));
2684 }
2685 
2697 template <typename T>
2698 bool
2699 operator>(const vector<T> &lhs, const std::vector<T> &rhs)
2700 {
2701  return !(lhs <= rhs);
2702 }
2703 
2714 template <typename T>
2715 bool
2716 operator>=(const vector<T> &lhs, const std::vector<T> &rhs)
2717 {
2718  return !(lhs < rhs);
2719 }
2720 
2732 template <typename T>
2733 bool
2734 operator==(const std::vector<T> &lhs, const vector<T> &rhs)
2735 {
2736  return rhs == lhs;
2737 }
2738 
2750 template <typename T>
2751 bool
2752 operator!=(const std::vector<T> &lhs, const vector<T> &rhs)
2753 {
2754  return !(lhs == rhs);
2755 }
2756 
2767 template <typename T>
2768 bool
2769 operator<(const std::vector<T> &lhs, const vector<T> &rhs)
2770 {
2771  return rhs > lhs;
2772 }
2773 
2784 template <typename T>
2785 bool
2786 operator<=(const std::vector<T> &lhs, const vector<T> &rhs)
2787 {
2788  return !(rhs < lhs);
2789 }
2790 
2802 template <typename T>
2803 bool
2804 operator>(const std::vector<T> &lhs, const vector<T> &rhs)
2805 {
2806  return rhs < lhs;
2807 }
2808 
2819 template <typename T>
2820 bool
2821 operator>=(const std::vector<T> &lhs, const vector<T> &rhs)
2822 {
2823  return !(lhs < rhs);
2824 }
2825 
2832 template <typename T>
2833 void
2835 {
2836  lhs.swap(rhs);
2837 }
2838 
2839 } /* namespace obj */
2840 
2841 } /* namespace pmem */
2842 
2843 #endif /* LIBPMEMOBJ_CPP_VECTOR_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
Custom transaction error class.
Definition: pexceptions.hpp:128
void shrink(size_type size_new)
Private helper function.
Definition: vector.hpp:2457
vector & operator=(const vector &other)
Copy assignment operator.
Definition: vector.hpp:572
void free_data()
Clears the content of a vector and frees all allocated persistent memory for data transactionally.
Definition: vector.hpp:1481
void swap(pmem::obj::array< T, N > &lhs, pmem::obj::array< T, N > &rhs)
Non-member swap function.
Definition: array.hpp:913
void move_elements_backward(pointer first, pointer last, pointer d_last)
Private helper function.
Definition: vector.hpp:2240
Persistent_ptr transactional allocation functions for objects.
void pop_back()
Removes the last element of the container transactionally.
Definition: vector.hpp:1931
slice< const_iterator > crange(size_type start, size_type n) const
Returns const slice.
Definition: vector.hpp:1344
Common iterator traits.
size_type capacity() const noexcept
Definition: vector.hpp:1420
The non-template pool base class.
Definition: pool.hpp:67
temp_value template class for caching objects.
void clear()
Clears the content of a vector transactionally.
Definition: vector.hpp:1461
Custom pool error class.
Definition: pexceptions.hpp:72
const_iterator cbegin() const noexcept
Returns const iterator to the beginning.
Definition: vector.hpp:1128
void construct_or_assign(size_type idx, InputIt first, InputIt last)
Private helper function.
Definition: vector.hpp:2259
void internal_insert(size_type idx, InputIt first, InputIt last)
Private helper function.
Definition: vector.hpp:2302
pmem::obj::slice - provides interface to access sequence of objects.
Definition: slice.hpp:56
reverse_iterator rbegin()
Returns a reverse iterator to the beginning.
Definition: vector.hpp:1178
bool operator<(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member less than operator.
Definition: array.hpp:752
const_reference cfront() const
Access the first element.
Definition: vector.hpp:1001
iterator begin()
Returns an iterator to the beginning.
Definition: vector.hpp:1102
C++ pmemobj transactions.
void construct_at_end(size_type count, Args &&... args)
Private helper function.
Definition: vector.hpp:2130
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: vector.hpp:1204
Convenience extensions for the resides on pmem property template.
reference operator[](size_type n)
Access element at specific index and add it to a transaction.
Definition: vector.hpp:941
void check_pmem()
Private helper function.
Definition: vector.hpp:2087
size_type get_recommended_capacity(size_type at_least) const
Private helper function.
Definition: vector.hpp:2434
Functions for destroying arrays.
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
~vector()
Destructor.
Definition: vector.hpp:858
size_type size() const noexcept
Definition: vector.hpp:1370
void shrink_to_fit()
Requests transactional removal of unused capacity.
Definition: vector.hpp:1441
Iterators for contiguous persistent containers.
constexpr bool empty() const noexcept
Checks whether the container is empty.
Definition: vector.hpp:1360
slice< pointer > range(size_type start, size_type n)
Returns slice and snapshots requested range.
Definition: vector.hpp:1265
void check_tx_stage_work()
Private helper function.
Definition: vector.hpp:2102
Non-const iterator which adds elements to a transaction in a bulk.
Definition: contiguous_iterator.hpp:220
iterator erase(const_iterator pos)
Removes the element at pos.
Definition: vector.hpp:1814
void resize(size_type count)
Resizes the container to count elements transactionally.
Definition: vector.hpp:1958
reference front()
Access the first element and add this element to a transaction.
Definition: vector.hpp:972
constexpr size_type max_size() const noexcept
Definition: vector.hpp:1381
pmem::obj::array< T, N >::iterator end(pmem::obj::array< T, N > &a)
Non-member end.
Definition: array.hpp:853
pool_base get_pool() const noexcept
Private helper function.
Definition: vector.hpp:2224
Custom out of memory error class.
Definition: pexceptions.hpp:146
Default non-const iterator which adds element to a transaction on every access.
Definition: contiguous_iterator.hpp:359
Type trait to determine if a given parameter type satisfies requirements of InputIterator.
Definition: iterator_traits.hpp:75
pmem::obj::array< T, N >::iterator begin(pmem::obj::array< T, N > &a)
Non-member begin.
Definition: array.hpp:833
Template class for caching objects based on constructor's variadic template arguments and LIBPMEMOBJ_...
Definition: temp_value.hpp:64
void add_data_to_tx(size_type idx_first, size_type num)
Private helper function.
Definition: vector.hpp:2481
persistent_ptr< T > operator-(persistent_ptr< T > const &lhs, std::ptrdiff_t s)
Subtraction operator for persistent pointers.
Definition: persistent_ptr.hpp:621
pmem::obj::vector - persistent container with std::vector compatible interface.
Definition: vector.hpp:69
const_iterator cend() const noexcept
Returns a const iterator to the end.
Definition: vector.hpp:1166
reference emplace_back(Args &&... args)
Appends a new element to the end of the container.
Definition: vector.hpp:1771
reverse_iterator rend()
Returns a reverse iterator to the end.
Definition: vector.hpp:1217
iterator emplace(const_iterator pos, Args &&... args)
Inserts a new element into the container directly before pos.
Definition: vector.hpp:1721
bool operator>(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater than operator.
Definition: array.hpp:763
reference back()
Access the last element and add this element to a transaction.
Definition: vector.hpp:1016
void alloc(size_type size)
Private helper function.
Definition: vector.hpp:2042
Persistent smart pointer.
void dealloc()
Private helper function.
Definition: vector.hpp:2200
Iterface to access sequence of objects.
void reserve(size_type capacity_new)
Increases the capacity of the vector to capacity_new transactionally.
Definition: vector.hpp:1406
const_reverse_iterator crend() const noexcept
Returns a const reverse iterator to the beginning.
Definition: vector.hpp:1245
pmem::obj::array< T, N >::const_iterator cbegin(const pmem::obj::array< T, N > &a)
Non-member cbegin.
Definition: array.hpp:793
const_reference const_at(size_type n) const
Access element at specific index with bounds checking.
Definition: vector.hpp:921
const_reference cback() const
Access the last element.
Definition: vector.hpp:1046
Custom transaction error class.
Definition: pexceptions.hpp:167
vector()
Default constructor.
Definition: vector.hpp:344
void push_back(const T &value)
Appends the given element value to the end of the container transactionally.
Definition: vector.hpp:1891
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
Custom transaction error class.
Definition: pexceptions.hpp:185
A persistent version of concurrent hash map implementation Ref: https://arxiv.org/abs/1509....
Definition: allocation_flag.hpp:43
iterator insert(const_iterator pos, const T &value)
Inserts value before pos in the container transactionally.
Definition: vector.hpp:1516
iterator end()
Returns an iterator to past the end.
Definition: vector.hpp:1140
reference at(size_type n)
Access element at specific index with bounds checking and add it to a transaction.
Definition: vector.hpp:877
p< T > & operator++(p< T > &pp)
Prefix increment operator overload.
Definition: pext.hpp:77
const value_type * cdata() const noexcept
Returns const raw pointer to the underlying data.
Definition: vector.hpp:1090
void swap(vector &other)
Exchanges the contents of the container with other transactionally.
Definition: vector.hpp:2013
pmem::obj::array< T, N >::const_iterator cend(const pmem::obj::array< T, N > &a)
Non-member cend.
Definition: array.hpp:803
bool operator>=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater or equal operator.
Definition: array.hpp:773
void realloc(size_type size)
Private helper function.
Definition: vector.hpp:2384
value_type * data()
Returns raw pointer to the underlying data and adds entire array to a transaction.
Definition: vector.hpp:1062