PMDK C++ bindings 1.13.0
This is the C++ bindings documentation for PMDK's libpmemobj.
Loading...
Searching...
No Matches
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
16#include <libpmemobj++/detail/temp_value.hpp>
19#include <libpmemobj++/pext.hpp>
23#include <libpmemobj/base.h>
24
25#include <algorithm>
26#include <cassert>
27#include <utility>
28#include <vector>
29
30namespace pmem
31{
32
33namespace obj
34{
35
40template <typename T>
41class vector {
42public:
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 */
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);
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
167private:
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);
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();
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 */
253};
254
255/* Non-member swap */
256template <typename T>
257void swap(vector<T> &lhs, vector<T> &rhs);
258
259/*
260 * Comparison operators between pmem::obj::vector<T> and
261 * pmem::obj::vector<T>
262 */
263template <typename T>
264bool operator==(const vector<T> &lhs, const vector<T> &rhs);
265template <typename T>
266bool operator!=(const vector<T> &lhs, const vector<T> &rhs);
267template <typename T>
268bool operator<(const vector<T> &lhs, const vector<T> &rhs);
269template <typename T>
270bool operator<=(const vector<T> &lhs, const vector<T> &rhs);
271template <typename T>
272bool operator>(const vector<T> &lhs, const vector<T> &rhs);
273template <typename T>
274bool operator>=(const vector<T> &lhs, const vector<T> &rhs);
275
276/*
277 * Comparison operators between pmem::obj::vector<T> and
278 * std::vector<T>
279 */
280template <typename T>
281bool operator==(const vector<T> &lhs, const std::vector<T> &rhs);
282template <typename T>
283bool operator!=(const vector<T> &lhs, const std::vector<T> &rhs);
284template <typename T>
285bool operator<(const vector<T> &lhs, const std::vector<T> &rhs);
286template <typename T>
287bool operator<=(const vector<T> &lhs, const std::vector<T> &rhs);
288template <typename T>
289bool operator>(const vector<T> &lhs, const std::vector<T> &rhs);
290template <typename T>
291bool operator>=(const vector<T> &lhs, const std::vector<T> &rhs);
292
293/*
294 * Comparison operators between std::vector<T> and
295 * pmem::obj::vector<T>
296 */
297template <typename T>
298bool operator==(const std::vector<T> &lhs, const vector<T> &rhs);
299template <typename T>
300bool operator!=(const std::vector<T> &lhs, const vector<T> &rhs);
301template <typename T>
302bool operator<(const std::vector<T> &lhs, const vector<T> &rhs);
303template <typename T>
304bool operator<=(const std::vector<T> &lhs, const vector<T> &rhs);
305template <typename T>
306bool operator>(const std::vector<T> &lhs, const vector<T> &rhs);
307template <typename T>
308bool operator>=(const std::vector<T> &lhs, const vector<T> &rhs);
309
319template <typename T>
321{
322 check_pmem();
323 check_tx_stage_work();
324
325 _data = nullptr;
326 _size = 0;
327 _capacity = 0;
328}
329
348template <typename T>
349vector<T>::vector(size_type count, const value_type &value)
350{
351 check_pmem();
352 check_tx_stage_work();
353
354 _data = nullptr;
355 _size = 0;
356 alloc(count);
357 construct_at_end(count, value);
358}
359
377template <typename T>
378vector<T>::vector(size_type count)
379{
380 check_pmem();
381 check_tx_stage_work();
382
383 _data = nullptr;
384 _size = 0;
385 alloc(count);
386 construct_at_end(count);
387}
388
411template <typename T>
412template <typename InputIt,
413 typename std::enable_if<detail::is_input_iterator<InputIt>::value,
414 InputIt>::type *>
415vector<T>::vector(InputIt first, InputIt last)
416{
417 check_pmem();
418 check_tx_stage_work();
419
420 _data = nullptr;
421 _size = 0;
422 alloc(static_cast<size_type>(std::distance(first, last)));
423 construct_at_end(first, last);
424}
425
444template <typename T>
446{
447 check_pmem();
448 check_tx_stage_work();
449
450 _data = nullptr;
451 _size = 0;
452 alloc(other.capacity());
453 construct_at_end(other.cbegin(), other.cend());
454}
455
475template <typename T>
477{
478 check_pmem();
479 check_tx_stage_work();
480
481 _data = other._data;
482 _capacity = other.capacity();
483 _size = other.size();
484 other._data = nullptr;
485 other._capacity = other._size = 0;
486}
487
505template <typename T>
506vector<T>::vector(std::initializer_list<T> init)
507 : vector(init.begin(), init.end())
508{
509}
510
529template <typename T>
530vector<T>::vector(const std::vector<T> &other)
531 : vector(other.cbegin(), other.cend())
532{
533}
534
546template <typename T>
547vector<T> &
549{
550 assign(other);
551
552 return *this;
553}
554
565template <typename T>
566vector<T> &
568{
569 assign(std::move(other));
570
571 return *this;
572}
573
583template <typename T>
584vector<T> &
585vector<T>::operator=(std::initializer_list<T> ilist)
586{
587 assign(ilist.begin(), ilist.end());
588
589 return *this;
590}
591
604template <typename T>
605vector<T> &
606vector<T>::operator=(const std::vector<T> &other)
607{
608 assign(other);
609
610 return *this;
611}
612
629template <typename T>
630void
631vector<T>::assign(size_type count, const_reference value)
632{
633 pool_base pb = get_pool();
634
635 flat_transaction::run(pb, [&] {
636 if (count <= capacity()) {
637 /*
638 * Reallocation is not needed. First, replace old
639 * elements with new ones in range [0, size()).
640 * Depending on count, either call remaining old
641 * elements destructors, or append more new elements.
642 */
643 size_type size_old = _size;
644 add_data_to_tx(0, size_old);
645
646 std::fill_n(
647 _data.get(),
648 (std::min)(count,
649 static_cast<size_type>(size_old)),
650 value);
651
652 if (count > size_old) {
653 add_data_to_tx(size_old, count - size_old);
654 construct_at_end(count - size_old, value);
655 } else {
656 shrink(count);
657 }
658 } else {
659 dealloc();
660 alloc(count);
661 construct_at_end(count, value);
662 }
663 });
664}
665
684template <typename T>
685template <typename InputIt,
686 typename std::enable_if<detail::is_input_iterator<InputIt>::value,
687 InputIt>::type *>
688void
689vector<T>::assign(InputIt first, InputIt last)
690{
691 pool_base pb = get_pool();
692
693 size_type size_new = static_cast<size_type>(std::distance(first, last));
694
695 flat_transaction::run(pb, [&] {
696 if (size_new <= capacity()) {
697 /*
698 * Reallocation is not needed. First, replace old
699 * elements with new ones in range [0, size()).
700 * Depending on size_new, either call remaining old
701 * elements destructors, or append more new elements.
702 */
703 size_type size_old = _size;
704 add_data_to_tx(0, size_old);
705
706 InputIt mid = last;
707 bool growing = size_new > size_old;
708
709 if (growing) {
710 add_data_to_tx(size_old, size_new - size_old);
711
712 mid = first;
713 std::advance(mid, size_old);
714 }
715
716 iterator shrink_to = std::copy(first, mid, &_data[0]);
717
718 if (growing) {
719 construct_at_end(mid, last);
720 } else {
721 shrink(static_cast<size_type>(std::distance(
722 iterator(&_data[0]), shrink_to)));
723 }
724 } else {
725 dealloc();
726 alloc(size_new);
727 construct_at_end(first, last);
728 }
729 });
730}
731
747template <typename T>
748void
749vector<T>::assign(std::initializer_list<T> ilist)
750{
751 assign(ilist.begin(), ilist.end());
752}
753
765template <typename T>
766void
768{
769 if (this != &other)
770 assign(other.cbegin(), other.cend());
771}
772
784template <typename T>
785void
787{
788 if (this == &other)
789 return;
790
791 pool_base pb = get_pool();
792
793 flat_transaction::run(pb, [&] {
794 dealloc();
795
796 _data = other._data;
797 _capacity = other._capacity;
798 _size = other._size;
799
800 other._data = nullptr;
801 other._capacity = other._size = 0;
802 });
803}
804
817template <typename T>
818void
819vector<T>::assign(const std::vector<T> &other)
820{
821 assign(other.cbegin(), other.cend());
822}
823
831template <typename T>
833{
834 try {
835 free_data();
836 } catch (...) {
837 std::terminate();
838 }
839}
840
853template <typename T>
854typename vector<T>::reference
855vector<T>::at(size_type n)
856{
857 if (n >= _size)
858 throw std::out_of_range("vector::at");
859
860 detail::conditional_add_to_tx(&_data[static_cast<difference_type>(n)],
861 1, POBJ_XADD_ASSUME_INITIALIZED);
862
863 return _data[static_cast<difference_type>(n)];
864}
865
875template <typename T>
876typename vector<T>::const_reference
877vector<T>::at(size_type n) const
878{
879 if (n >= _size)
880 throw std::out_of_range("vector::at");
881
882 return _data[static_cast<difference_type>(n)];
883}
884
897template <typename T>
898typename vector<T>::const_reference
899vector<T>::const_at(size_type n) const
900{
901 if (n >= _size)
902 throw std::out_of_range("vector::const_at");
903
904 return _data[static_cast<difference_type>(n)];
905}
906
918template <typename T>
919typename vector<T>::reference vector<T>::operator[](size_type n)
920{
921 detail::conditional_add_to_tx(&_data[static_cast<difference_type>(n)],
922 1, POBJ_XADD_ASSUME_INITIALIZED);
923
924 return _data[static_cast<difference_type>(n)];
925}
926
934template <typename T>
935typename vector<T>::const_reference vector<T>::operator[](size_type n) const
936{
937 return _data[static_cast<difference_type>(n)];
938}
939
948template <typename T>
949typename vector<T>::reference
951{
952 detail::conditional_add_to_tx(&_data[0], 1,
953 POBJ_XADD_ASSUME_INITIALIZED);
954
955 return _data[0];
956}
957
963template <typename T>
964typename vector<T>::const_reference
966{
967 return _data[0];
968}
969
977template <typename T>
978typename vector<T>::const_reference
980{
981 return _data[0];
982}
983
992template <typename T>
993typename vector<T>::reference
995{
996 detail::conditional_add_to_tx(
997 &_data[static_cast<difference_type>(size() - 1)], 1,
998 POBJ_XADD_ASSUME_INITIALIZED);
999
1000 return _data[static_cast<difference_type>(size() - 1)];
1001}
1002
1008template <typename T>
1009typename vector<T>::const_reference
1011{
1012 return _data[static_cast<difference_type>(size() - 1)];
1013}
1014
1022template <typename T>
1023typename vector<T>::const_reference
1025{
1026 return _data[static_cast<difference_type>(size() - 1)];
1027}
1028
1038template <typename T>
1039typename vector<T>::value_type *
1041{
1042 add_data_to_tx(0, _size);
1043
1044 return _data.get();
1045}
1046
1052template <typename T>
1053const typename vector<T>::value_type *
1054vector<T>::data() const noexcept
1055{
1056 return _data.get();
1057}
1058
1066template <typename T>
1067const typename vector<T>::value_type *
1068vector<T>::cdata() const noexcept
1069{
1070 return _data.get();
1071}
1072
1078template <typename T>
1079typename vector<T>::iterator
1081{
1082 return iterator(_data.get());
1083}
1084
1090template <typename T>
1091typename vector<T>::const_iterator
1092vector<T>::begin() const noexcept
1093{
1094 return const_iterator(_data.get());
1095}
1096
1104template <typename T>
1105typename vector<T>::const_iterator
1106vector<T>::cbegin() const noexcept
1107{
1108 return const_iterator(_data.get());
1109}
1110
1116template <typename T>
1117typename vector<T>::iterator
1119{
1120 return iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1121}
1122
1128template <typename T>
1129typename vector<T>::const_iterator
1130vector<T>::end() const noexcept
1131{
1132 return const_iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1133}
1134
1142template <typename T>
1143typename vector<T>::const_iterator
1144vector<T>::cend() const noexcept
1145{
1146 return const_iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1147}
1148
1154template <typename T>
1155typename vector<T>::reverse_iterator
1157{
1158 return reverse_iterator(end());
1159}
1160
1166template <typename T>
1167typename vector<T>::const_reverse_iterator
1168vector<T>::rbegin() const noexcept
1169{
1170 return const_reverse_iterator(cend());
1171}
1172
1180template <typename T>
1181typename vector<T>::const_reverse_iterator
1182vector<T>::crbegin() const noexcept
1183{
1184 return const_reverse_iterator(cend());
1185}
1186
1193template <typename T>
1194typename vector<T>::reverse_iterator
1196{
1197 return reverse_iterator(begin());
1198}
1199
1206template <typename T>
1207typename vector<T>::const_reverse_iterator
1208vector<T>::rend() const noexcept
1209{
1210 return const_reverse_iterator(cbegin());
1211}
1212
1221template <typename T>
1222typename vector<T>::const_reverse_iterator
1223vector<T>::crend() const noexcept
1224{
1225 return const_reverse_iterator(cbegin());
1226}
1227
1241template <typename T>
1243vector<T>::range(size_type start, size_type n)
1244{
1245 if (start + n > size())
1246 throw std::out_of_range("vector::range");
1247
1248 detail::conditional_add_to_tx(cdata() + start, n,
1249 POBJ_XADD_ASSUME_INITIALIZED);
1250
1251 return {_data.get() + start, _data.get() + start + n};
1252}
1253
1269template <typename T>
1271vector<T>::range(size_type start, size_type n, size_type snapshot_size)
1272{
1273 if (start + n > size())
1274 throw std::out_of_range("vector::range");
1275
1276 if (snapshot_size > n)
1277 snapshot_size = n;
1278
1279 return {range_snapshotting_iterator(_data.get() + start,
1280 _data.get() + start, n,
1281 snapshot_size),
1282 range_snapshotting_iterator(_data.get() + start + n,
1283 _data.get() + start, n,
1284 snapshot_size)};
1285}
1286
1298template <typename T>
1300vector<T>::range(size_type start, size_type n) const
1301{
1302 if (start + n > size())
1303 throw std::out_of_range("vector::range");
1304
1305 return {const_iterator(cdata() + start),
1306 const_iterator(cdata() + start + n)};
1307}
1308
1320template <typename T>
1322vector<T>::crange(size_type start, size_type n) const
1323{
1324 if (start + n > size())
1325 throw std::out_of_range("vector::crange");
1326
1327 return {const_iterator(cdata() + start),
1328 const_iterator(cdata() + start + n)};
1329}
1330
1336template <typename T>
1337constexpr bool
1338vector<T>::empty() const noexcept
1339{
1340 return _size == 0;
1341}
1342
1346template <typename T>
1347typename vector<T>::size_type
1348vector<T>::size() const noexcept
1349{
1350 return _size;
1351}
1352
1357template <typename T>
1358constexpr typename vector<T>::size_type
1359vector<T>::max_size() const noexcept
1360{
1361 return PMEMOBJ_MAX_ALLOC_SIZE / sizeof(value_type);
1362}
1363
1382template <typename T>
1383void
1384vector<T>::reserve(size_type capacity_new)
1385{
1386 if (capacity_new <= _capacity)
1387 return;
1388
1389 pool_base pb = get_pool();
1390 flat_transaction::run(pb, [&] { realloc(capacity_new); });
1391}
1392
1396template <typename T>
1397typename vector<T>::size_type
1398vector<T>::capacity() const noexcept
1399{
1400 return _capacity;
1401}
1402
1417template <typename T>
1418void
1420{
1421 size_type capacity_new = size();
1422 if (capacity() == capacity_new)
1423 return;
1424
1425 pool_base pb = get_pool();
1426 flat_transaction::run(pb, [&] { realloc(capacity_new); });
1427}
1428
1437template <typename T>
1438void
1440{
1441 pool_base pb = get_pool();
1442 flat_transaction::run(pb, [&] { shrink(0); });
1443}
1444
1457template <typename T>
1458void
1460{
1461 if (_data == nullptr)
1462 return;
1463
1464 pool_base pb = get_pool();
1465 flat_transaction::run(pb, [&] { dealloc(); });
1466}
1467
1492template <typename T>
1493typename vector<T>::iterator
1494vector<T>::insert(const_iterator pos, const value_type &value)
1495{
1496 return insert(pos, 1, value);
1497}
1498
1523template <typename T>
1524typename vector<T>::iterator
1525vector<T>::insert(const_iterator pos, value_type &&value)
1526{
1527 pool_base pb = get_pool();
1528
1529 size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1530
1531 flat_transaction::run(pb, [&] {
1532 internal_insert(idx, std::make_move_iterator(&value),
1533 std::make_move_iterator(&value + 1));
1534 });
1535
1536 return iterator(&_data[static_cast<difference_type>(idx)]);
1537}
1538
1567template <typename T>
1568typename vector<T>::iterator
1569vector<T>::insert(const_iterator pos, size_type count, const value_type &value)
1570{
1571 pool_base pb = get_pool();
1572
1573 size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1574
1575 flat_transaction::run(pb, [&] {
1576 internal_insert(
1577 idx, single_element_iterator<value_type>(&value, 0),
1578 single_element_iterator<value_type>(&value, count));
1579 });
1580
1581 return iterator(_data.get() + static_cast<difference_type>(idx));
1582}
1583
1618template <typename T>
1619template <typename InputIt,
1620 typename std::enable_if<detail::is_input_iterator<InputIt>::value,
1621 InputIt>::type *>
1622typename vector<T>::iterator
1623vector<T>::insert(const_iterator pos, InputIt first, InputIt last)
1624{
1625 pool_base pb = get_pool();
1626
1627 size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1628
1629 flat_transaction::run(pb, [&] { internal_insert(idx, first, last); });
1630
1631 return iterator(&_data[static_cast<difference_type>(idx)]);
1632}
1633
1662template <typename T>
1663typename vector<T>::iterator
1664vector<T>::insert(const_iterator pos, std::initializer_list<value_type> ilist)
1665{
1666 return insert(pos, ilist.begin(), ilist.end());
1667}
1668
1696template <typename T>
1697template <class... Args>
1698typename vector<T>::iterator
1699vector<T>::emplace(const_iterator pos, Args &&... args)
1700{
1701 pool_base pb = get_pool();
1702
1703 size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1704
1705 flat_transaction::run(pb, [&] {
1706 /*
1707 * args might be a reference to underlying array element. This
1708 * reference can be invalidated after internal_insert() call.
1709 * Hence, we must cache value_type object in temp_value.
1710 */
1711 detail::temp_value<value_type,
1712 noexcept(T(std::forward<Args>(args)...))>
1713 tmp(std::forward<Args>(args)...);
1714
1715 auto &tmp_ref = tmp.get();
1716
1717 internal_insert(idx, std::make_move_iterator(&tmp_ref),
1718 std::make_move_iterator(&tmp_ref + 1));
1719 });
1720
1721 return iterator(&_data[static_cast<difference_type>(idx)]);
1722}
1723
1746template <typename T>
1747template <class... Args>
1748typename vector<T>::reference
1750{
1751 /*
1752 * emplace() cannot be used here, because emplace_back() doesn't require
1753 * element_type to be MoveAssignable and emplace() uses
1754 * std::move_backward() function.
1755 */
1756 pool_base pb = get_pool();
1757
1758 flat_transaction::run(pb, [&] {
1759 if (_size == _capacity) {
1760 realloc(get_recommended_capacity(_size + 1));
1761 } else {
1762 add_data_to_tx(size(), 1);
1763 }
1764
1765 construct_at_end(1, std::forward<Args>(args)...);
1766 });
1767
1768 return back();
1769}
1770
1790template <typename T>
1791typename vector<T>::iterator
1792vector<T>::erase(const_iterator pos)
1793{
1794 return erase(pos, pos + 1);
1795}
1796
1819template <typename T>
1820typename vector<T>::iterator
1821vector<T>::erase(const_iterator first, const_iterator last)
1822{
1823 size_type idx = static_cast<size_type>(
1824 std::distance(const_iterator(_data.get()), first));
1825 size_type count = static_cast<size_type>(std::distance(first, last));
1826
1827 if (count == 0)
1828 return iterator(&_data[static_cast<difference_type>(idx)]);
1829
1830 pool_base pb = get_pool();
1831
1832 flat_transaction::run(pb, [&] {
1833 if (!std::is_trivially_destructible<T>::value ||
1834 idx + count < _size)
1835 add_data_to_tx(idx, _size - idx);
1836
1837 pointer move_begin =
1838 &_data[static_cast<difference_type>(idx + count)];
1839 pointer move_end = &_data[static_cast<difference_type>(size())];
1840 pointer dest = &_data[static_cast<difference_type>(idx)];
1841
1842 std::move(move_begin, move_end, dest);
1843
1844 _size -= count;
1845 });
1846
1847 return iterator(&_data[static_cast<difference_type>(idx)]);
1848}
1849
1865template <typename T>
1866void
1867vector<T>::push_back(const value_type &value)
1868{
1869 emplace_back(value);
1870}
1871
1888template <typename T>
1889void
1890vector<T>::push_back(value_type &&value)
1891{
1892 emplace_back(std::move(value));
1893}
1894
1905template <typename T>
1906void
1908{
1909 if (empty())
1910 return;
1911
1912 pool_base pb = get_pool();
1913 flat_transaction::run(pb, [&] { shrink(size() - 1); });
1914}
1915
1932template <typename T>
1933void
1934vector<T>::resize(size_type count)
1935{
1936 pool_base pb = get_pool();
1937 flat_transaction::run(pb, [&] {
1938 if (count <= _size)
1939 shrink(count);
1940 else {
1941 if (_capacity < count)
1942 realloc(count);
1943 construct_at_end(count - _size);
1944 }
1945 });
1946}
1947
1965template <typename T>
1966void
1967vector<T>::resize(size_type count, const value_type &value)
1968{
1969 if (_capacity == count)
1970 return;
1971
1972 pool_base pb = get_pool();
1973 flat_transaction::run(pb, [&] {
1974 if (count <= _size)
1975 shrink(count);
1976 else {
1977 if (_capacity < count)
1978 realloc(count);
1979 construct_at_end(count - _size, value);
1980 }
1981 });
1982}
1983
1987template <typename T>
1988void
1990{
1991 pool_base pb = get_pool();
1992 flat_transaction::run(pb, [&] {
1993 std::swap(this->_data, other._data);
1994 std::swap(this->_size, other._size);
1995 std::swap(this->_capacity, other._capacity);
1996 });
1997}
1998
2005template <typename T>
2006void
2007vector<T>::for_each_ptr(for_each_ptr_function func)
2008{
2009 func(_data);
2010}
2011
2029template <typename T>
2030void
2031vector<T>::alloc(size_type capacity_new)
2032{
2033 assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2034 assert(_data == nullptr);
2035 assert(_size == 0);
2036
2037 if (capacity_new > max_size())
2038 throw std::length_error("New capacity exceeds max size.");
2039
2040 _capacity = capacity_new;
2041
2042 if (capacity_new == 0)
2043 return;
2044
2045 /*
2046 * We need to cache pmemobj_tx_alloc return value and only after that
2047 * assign it to _data, because when pmemobj_tx_alloc fails, it aborts
2048 * transaction.
2049 */
2051 pmemobj_tx_alloc(sizeof(value_type) * capacity_new,
2052 detail::type_num<value_type>());
2053
2054 if (res == nullptr) {
2055 if (errno == ENOMEM)
2057 "Failed to allocate persistent memory object")
2058 .with_pmemobj_errormsg();
2059 else
2061 "Failed to allocate persistent memory object")
2062 .with_pmemobj_errormsg();
2063 }
2064
2065 _data = res;
2066}
2067
2074template <typename T>
2075void
2077{
2078 if (nullptr == pmemobj_pool_by_ptr(this))
2079 throw pmem::pool_error("Invalid pool handle.");
2080}
2081
2089template <typename T>
2090void
2092{
2093 if (pmemobj_tx_stage() != TX_STAGE_WORK)
2095 "Function called out of transaction scope.");
2096}
2097
2116template <typename T>
2117template <typename... Args>
2118void
2119vector<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
2154template <typename T>
2155template <typename InputIt,
2156 typename std::enable_if<detail::is_input_iterator<InputIt>::value,
2157 InputIt>::type *>
2158void
2159vector<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
2187template <typename T>
2188void
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)
2197 "failed to delete persistent memory object")
2198 .with_pmemobj_errormsg();
2199 _data = nullptr;
2200 _capacity = 0;
2201 }
2202}
2203
2211template <typename T>
2214{
2215 return pmem::obj::pool_by_vptr(this);
2216}
2217
2225template <typename T>
2226void
2227vector<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
2243template <typename T>
2244template <typename InputIt>
2245void
2246vector<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
2286template <typename T>
2287template <typename InputIt>
2288void
2289vector<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)
2346 "failed to delete persistent memory object")
2347 .with_pmemobj_errormsg();
2348 }
2349}
2350
2369template <typename T>
2370void
2371vector<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)
2409 "failed to delete persistent memory object")
2410 .with_pmemobj_errormsg();
2411}
2412
2419template <typename T>
2420typename vector<T>::size_type
2422{
2423 return detail::next_pow_2(at_least);
2424}
2425
2442template <typename T>
2443void
2444vector<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
2467template <typename T>
2468void
2469vector<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
2505template <typename T>
2506bool
2507operator==(const vector<T> &lhs, const vector<T> &rhs)
2508{
2509 return lhs.size() == rhs.size() &&
2510 std::equal(lhs.begin(), lhs.end(), rhs.begin());
2511}
2512
2524template <typename T>
2525bool
2526operator!=(const vector<T> &lhs, const vector<T> &rhs)
2527{
2528 return !(lhs == rhs);
2529}
2530
2541template <typename T>
2542bool
2543operator<(const vector<T> &lhs, const vector<T> &rhs)
2544{
2545 return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
2546 rhs.end());
2547}
2548
2559template <typename T>
2560bool
2561operator<=(const vector<T> &lhs, const vector<T> &rhs)
2562{
2563 return !(rhs < lhs);
2564}
2565
2577template <typename T>
2578bool
2579operator>(const vector<T> &lhs, const vector<T> &rhs)
2580{
2581 return rhs < lhs;
2582}
2583
2594template <typename T>
2595bool
2596operator>=(const vector<T> &lhs, const vector<T> &rhs)
2597{
2598 return !(lhs < rhs);
2599}
2600
2612template <typename T>
2613bool
2614operator==(const vector<T> &lhs, const std::vector<T> &rhs)
2615{
2616 return lhs.size() == rhs.size() &&
2617 std::equal(lhs.begin(), lhs.end(), rhs.begin());
2618}
2619
2631template <typename T>
2632bool
2633operator!=(const vector<T> &lhs, const std::vector<T> &rhs)
2634{
2635 return !(lhs == rhs);
2636}
2637
2648template <typename T>
2649bool
2650operator<(const vector<T> &lhs, const std::vector<T> &rhs)
2651{
2652 return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
2653 rhs.end());
2654}
2655
2666template <typename T>
2667bool
2668operator<=(const vector<T> &lhs, const std::vector<T> &rhs)
2669{
2670 return !(std::lexicographical_compare(rhs.begin(), rhs.end(),
2671 lhs.begin(), lhs.end()));
2672}
2673
2685template <typename T>
2686bool
2687operator>(const vector<T> &lhs, const std::vector<T> &rhs)
2688{
2689 return !(lhs <= rhs);
2690}
2691
2702template <typename T>
2703bool
2704operator>=(const vector<T> &lhs, const std::vector<T> &rhs)
2705{
2706 return !(lhs < rhs);
2707}
2708
2720template <typename T>
2721bool
2722operator==(const std::vector<T> &lhs, const vector<T> &rhs)
2723{
2724 return rhs == lhs;
2725}
2726
2738template <typename T>
2739bool
2740operator!=(const std::vector<T> &lhs, const vector<T> &rhs)
2741{
2742 return !(lhs == rhs);
2743}
2744
2755template <typename T>
2756bool
2757operator<(const std::vector<T> &lhs, const vector<T> &rhs)
2758{
2759 return rhs > lhs;
2760}
2761
2772template <typename T>
2773bool
2774operator<=(const std::vector<T> &lhs, const vector<T> &rhs)
2775{
2776 return !(rhs < lhs);
2777}
2778
2790template <typename T>
2791bool
2792operator>(const std::vector<T> &lhs, const vector<T> &rhs)
2793{
2794 return rhs < lhs;
2795}
2796
2807template <typename T>
2808bool
2809operator>=(const std::vector<T> &lhs, const vector<T> &rhs)
2810{
2811 return !(lhs < rhs);
2812}
2813
2820template <typename T>
2821void
2823{
2824 lhs.swap(rhs);
2825}
2826
2827} /* namespace obj */
2828
2829} /* namespace pmem */
2830
2831#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:823
Resides on pmem class.
Definition: p.hpp:35
Persistent_ptr base (non-template) class.
Definition: persistent_ptr_base.hpp:42
Persistent pointer class.
Definition: persistent_ptr.hpp:152
The non-template pool base class.
Definition: pool.hpp:50
pmem::obj::slice - provides interface to access sequence of objects.
Definition: slice.hpp:50
pmem::obj::vector - persistent container with std::vector compatible interface.
Definition: vector.hpp:41
const_reference front() const
Access the first element.
Definition: vector.hpp:965
reverse_iterator rend()
Returns a reverse iterator to the end.
Definition: vector.hpp:1195
const value_type * cdata() const noexcept
Returns const raw pointer to the underlying data.
Definition: vector.hpp:1068
const_reverse_iterator crend() const noexcept
Returns a const reverse iterator to the beginning.
Definition: vector.hpp:1223
const value_type * data() const noexcept
Returns const raw pointer to the underlying data.
Definition: vector.hpp:1054
vector(vector &&other)
Move constructor.
Definition: vector.hpp:476
void free_data()
Clears the content of a vector and frees all allocated persistent memory for data transactionally.
Definition: vector.hpp:1459
vector(const std::vector< T > &other)
Copy constructor.
Definition: vector.hpp:530
const_reference const_at(size_type n) const
Access element at specific index with bounds checking.
Definition: vector.hpp:899
size_type size() const noexcept
Definition: vector.hpp:1348
const_reference operator[](size_type n) const
Access element at specific index.
Definition: vector.hpp:935
vector & operator=(const std::vector< T > &other)
Copy assignment operator.
Definition: vector.hpp:606
slice< pointer > range(size_type start, size_type n)
Returns slice and snapshots requested range.
Definition: vector.hpp:1243
void check_pmem()
Private helper function.
Definition: vector.hpp:2076
void assign(InputIt first, InputIt last)
Replaces the contents with copies of those in the range [first, last) transactionally.
Definition: vector.hpp:689
const_reference at(size_type n) const
Access element at specific index with bounds checking.
Definition: vector.hpp:877
reference back()
Access the last element and add this element to a transaction.
Definition: vector.hpp:994
void construct_at_end(size_type count, Args &&... args)
Private helper function.
Definition: vector.hpp:2119
slice< const_iterator > crange(size_type start, size_type n) const
Returns const slice.
Definition: vector.hpp:1322
void assign(const std::vector< T > &other)
Copy assignment method.
Definition: vector.hpp:819
iterator begin()
Returns an iterator to the beginning.
Definition: vector.hpp:1080
void check_tx_stage_work()
Private helper function.
Definition: vector.hpp:2091
void assign(vector &&other)
Move assignment method.
Definition: vector.hpp:786
void pop_back()
Removes the last element of the container transactionally.
Definition: vector.hpp:1907
vector(InputIt first, InputIt last)
Constructs the container with the contents of the range [first, last).
Definition: vector.hpp:415
reference operator[](size_type n)
Access element at specific index and add it to a transaction.
Definition: vector.hpp:919
reference front()
Access the first element and add this element to a transaction.
Definition: vector.hpp:950
vector(size_type count, const value_type &value)
Constructs the container with count copies of elements with value value.
Definition: vector.hpp:349
void alloc(size_type size)
Private helper function.
Definition: vector.hpp:2031
reference at(size_type n)
Access element at specific index with bounds checking and add it to a transaction.
Definition: vector.hpp:855
pool_base get_pool() const
Private helper function.
Definition: vector.hpp:2213
void resize(size_type count)
Resizes the container to count elements transactionally.
Definition: vector.hpp:1934
void swap(vector &other)
Exchanges the contents of the container with other transactionally.
Definition: vector.hpp:1989
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: vector.hpp:1182
iterator emplace(const_iterator pos, Args &&... args)
Inserts a new element into the container directly before pos.
Definition: vector.hpp:1699
void shrink_to_fit()
Requests transactional removal of unused capacity.
Definition: vector.hpp:1419
iterator erase(const_iterator pos)
Removes the element at pos.
Definition: vector.hpp:1792
const_reference cfront() const
Access the first element.
Definition: vector.hpp:979
reference emplace_back(Args &&... args)
Appends a new element to the end of the container.
Definition: vector.hpp:1749
void dealloc()
Private helper function.
Definition: vector.hpp:2189
const_reference cback() const
Access the last element.
Definition: vector.hpp:1024
void clear()
Clears the content of a vector transactionally.
Definition: vector.hpp:1439
iterator insert(const_iterator pos, const T &value)
Inserts value before pos in the container transactionally.
Definition: vector.hpp:1494
void construct_or_assign(size_type idx, InputIt first, InputIt last)
Private helper function.
Definition: vector.hpp:2246
vector(const vector &other)
Copy constructor.
Definition: vector.hpp:445
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:2007
const_reference back() const
Access the last element.
Definition: vector.hpp:1010
void construct_at_end(InputIt first, InputIt last)
Private helper function.
Definition: vector.hpp:2159
vector(std::initializer_list< T > init)
Constructs the container with the contents of the initializer list init.
Definition: vector.hpp:506
void assign(const vector &other)
Copy assignment method.
Definition: vector.hpp:767
reverse_iterator rbegin()
Returns a reverse iterator to the beginning.
Definition: vector.hpp:1156
vector & operator=(vector &&other)
Move assignment operator.
Definition: vector.hpp:567
void realloc(size_type size)
Private helper function.
Definition: vector.hpp:2371
vector()
Default constructor.
Definition: vector.hpp:320
~vector()
Destructor.
Definition: vector.hpp:832
vector & operator=(std::initializer_list< T > ilist)
Replaces the contents with those identified by initializer list ilist transactionally.
Definition: vector.hpp:585
size_type capacity() const noexcept
Definition: vector.hpp:1398
size_type get_recommended_capacity(size_type at_least) const
Private helper function.
Definition: vector.hpp:2421
void reserve(size_type capacity_new)
Increases the capacity of the vector to capacity_new transactionally.
Definition: vector.hpp:1384
void assign(std::initializer_list< T > ilist)
Replaces the contents with the elements from the initializer list ilist transactionally.
Definition: vector.hpp:749
void internal_insert(size_type idx, InputIt first, InputIt last)
Private helper function.
Definition: vector.hpp:2289
value_type * data()
Returns raw pointer to the underlying data and adds entire array to a transaction.
Definition: vector.hpp:1040
constexpr bool empty() const noexcept
Checks whether the container is empty.
Definition: vector.hpp:1338
void shrink(size_type size_new)
Private helper function.
Definition: vector.hpp:2444
void add_data_to_tx(size_type idx_first, size_type num)
Private helper function.
Definition: vector.hpp:2469
const_iterator cbegin() const noexcept
Returns const iterator to the beginning.
Definition: vector.hpp:1106
void move_elements_backward(pointer first, pointer last, pointer d_last)
Private helper function.
Definition: vector.hpp:2227
constexpr size_type max_size() const noexcept
Definition: vector.hpp:1359
void push_back(const T &value)
Appends the given element value to the end of the container transactionally.
Definition: vector.hpp:1867
const_iterator cend() const noexcept
Returns a const iterator to the end.
Definition: vector.hpp:1144
iterator end()
Returns an iterator to past the end.
Definition: vector.hpp:1118
vector & operator=(const vector &other)
Copy assignment operator.
Definition: vector.hpp:548
vector(size_type count)
Constructs the container with count copies of T default constructed values.
Definition: vector.hpp:378
Custom pool error class.
Definition: pexceptions.hpp:45
Custom transaction error class.
Definition: pexceptions.hpp:119
Custom transaction error class.
Definition: pexceptions.hpp:158
Custom out of memory error class.
Definition: pexceptions.hpp:138
Custom transaction error class.
Definition: pexceptions.hpp:176
Commonly used functionality.
Iterators for contiguous persistent containers.
Common iterator traits.
Functions for destroying arrays.
Persistent_ptr transactional allocation functions for objects.
uint64_t next_pow_2(uint64_t v)
Round up to the next lowest power of 2.
Definition: common.hpp:214
bool operator<=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member less or equal operator.
Definition: array.hpp:779
pmem::obj::array< T, N >::const_iterator cend(const pmem::obj::array< T, N > &a)
Non-member cend.
Definition: array.hpp:799
pmem::obj::array< T, N >::iterator end(pmem::obj::array< T, N > &a)
Non-member end.
Definition: array.hpp:849
bool operator<(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member less than operator.
Definition: array.hpp:748
bool operator>=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater or equal operator.
Definition: array.hpp:769
bool operator!=(const allocator< T, P, Tr > &lhs, const OtherAllocator &rhs)
Determines if memory from another allocator can be deallocated from this one.
Definition: allocator.hpp:536
p< T > & operator++(p< T > &pp)
Prefix increment operator overload.
Definition: pext.hpp:48
pool_base pool_by_vptr(const T *that)
Retrieve pool handle for the given pointer.
Definition: utils.hpp:32
bool operator==(standard_alloc_policy< T > const &, standard_alloc_policy< T2 > const &)
Determines if memory from another allocator can be deallocated from this one.
Definition: allocator.hpp:420
bool operator>(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater than operator.
Definition: array.hpp:759
persistent_ptr< T > operator-(persistent_ptr< T > const &lhs, std::ptrdiff_t s)
Subtraction operator for persistent pointers.
Definition: persistent_ptr.hpp:822
pmem::obj::array< T, N >::const_iterator cbegin(const pmem::obj::array< T, N > &a)
Non-member cbegin.
Definition: array.hpp:789
pmem::obj::array< T, N >::iterator begin(pmem::obj::array< T, N > &a)
Non-member begin.
Definition: array.hpp:829
void swap(pmem::obj::array< T, N > &lhs, pmem::obj::array< T, N > &rhs)
Non-member swap function.
Definition: array.hpp:909
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
C++ pmemobj transactions.
Libpmemobj C++ utils.