PMDK C++ bindings  1.7.1
This is the C++ bindings documentation for PMDK's libpmemobj.
vector.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2018-2019, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
38 #ifndef LIBPMEMOBJ_CPP_VECTOR_HPP
39 #define LIBPMEMOBJ_CPP_VECTOR_HPP
40 
49 #include <libpmemobj++/pext.hpp>
51 #include <libpmemobj.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 
64 namespace experimental
65 {
66 
71 template <typename T>
72 class vector {
73 public:
74  /* Member types */
75  using value_type = T;
76  using size_type = std::size_t;
77  using difference_type = std::ptrdiff_t;
78  using reference = value_type &;
79  using const_reference = const value_type &;
80  using pointer = value_type *;
81  using const_pointer = const value_type *;
83  using const_iterator = const_pointer;
84  using reverse_iterator = std::reverse_iterator<iterator>;
85  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
86 
87  /* Constructors */
88  vector();
89  vector(size_type count, const value_type &value);
90  explicit vector(size_type count);
91  template <typename InputIt,
92  typename std::enable_if<
94  InputIt>::type * = nullptr>
95  vector(InputIt first, InputIt last);
96  vector(const vector &other);
97  vector(vector &&other);
98  vector(std::initializer_list<T> init);
99  vector(const std::vector<T> &other);
100 
101  /* Assign operators */
102  vector &operator=(const vector &other);
103  vector &operator=(vector &&other);
104  vector &operator=(std::initializer_list<T> ilist);
105  vector &operator=(const std::vector<T> &other);
106 
107  /* Assign methods */
108  void assign(size_type count, const T &value);
109  template <typename InputIt,
110  typename std::enable_if<
112  InputIt>::type * = nullptr>
113  void assign(InputIt first, InputIt last);
114  void assign(std::initializer_list<T> ilist);
115  void assign(const vector &other);
116  void assign(vector &&other);
117  void assign(const std::vector<T> &other);
118 
119  /* Destructor */
120  ~vector();
121 
122  /* Element access */
123  reference at(size_type n);
124  const_reference at(size_type n) const;
125  const_reference const_at(size_type n) const;
126  reference operator[](size_type n);
127  const_reference operator[](size_type n) const;
128  reference front();
129  const_reference front() const;
130  const_reference cfront() const;
131  reference back();
132  const_reference back() const;
133  const_reference cback() const;
134  value_type *data();
135  const value_type *data() const noexcept;
136  const value_type *cdata() const noexcept;
137 
138  /* Iterators */
139  iterator begin();
140  const_iterator begin() const noexcept;
141  const_iterator cbegin() const noexcept;
142  iterator end();
143  const_iterator end() const noexcept;
144  const_iterator cend() const noexcept;
145  reverse_iterator rbegin();
146  const_reverse_iterator rbegin() const noexcept;
147  const_reverse_iterator crbegin() const noexcept;
148  reverse_iterator rend();
149  const_reverse_iterator rend() const noexcept;
150  const_reverse_iterator crend() const noexcept;
151 
152  /* Range */
153  slice<pointer> range(size_type start, size_type n);
155  range(size_type start, size_type n, size_type snapshot_size);
156  slice<const_iterator> range(size_type start, size_type n) const;
157  slice<const_iterator> crange(size_type start, size_type n) const;
158 
159  /* Capacity */
160  constexpr bool empty() const noexcept;
161  size_type size() const noexcept;
162  constexpr size_type max_size() const noexcept;
163  void reserve(size_type capacity_new);
164  size_type capacity() const noexcept;
165  void shrink_to_fit();
166 
167  /* Modifiers */
168  void clear();
169  void free_data();
170  iterator insert(const_iterator pos, const T &value);
171  iterator insert(const_iterator pos, T &&value);
172  iterator insert(const_iterator pos, size_type count, const T &value);
173  template <typename InputIt,
174  typename std::enable_if<
176  InputIt>::type * = nullptr>
177  iterator insert(const_iterator pos, InputIt first, InputIt last);
178  iterator insert(const_iterator pos, std::initializer_list<T> ilist);
179  template <class... Args>
180  iterator emplace(const_iterator pos, Args &&... args);
181  template <class... Args>
182  reference emplace_back(Args &&... args);
183  iterator erase(const_iterator pos);
184  iterator erase(const_iterator first, const_iterator last);
185  void push_back(const T &value);
186  void push_back(T &&value);
187  void pop_back();
188  void resize(size_type count);
189  void resize(size_type count, const value_type &value);
190  void swap(vector &other);
191 
192 private:
193  /* helper functions */
194  void alloc(size_type size);
195  void check_pmem();
196  void check_tx_stage_work();
197  template <typename... Args>
198  void construct(size_type idx, size_type count, Args &&... args);
199  template <typename InputIt,
200  typename std::enable_if<
202  InputIt>::type * = nullptr>
203  void construct_range(size_type idx, InputIt first, InputIt last);
204  template <typename InputIt,
205  typename std::enable_if<
207  InputIt>::type * = nullptr>
208  void construct_range_copy(size_type idx, InputIt first, InputIt last);
209  void dealloc();
210  pool_base get_pool() const noexcept;
211  void insert_gap(size_type idx, size_type count);
212  void realloc(size_type size);
213  size_type get_recommended_capacity(size_type at_least) const;
214  void shrink(size_type size_new);
215  void snapshot_data(size_type idx_first, size_type idx_last);
216 
217  p<size_type> _size;
218  p<size_type> _capacity;
219 
220  /* Underlying array */
221  persistent_ptr<T[]> _data;
222 };
223 
224 /* Non-member swap */
225 template <typename T>
226 void swap(vector<T> &lhs, vector<T> &rhs);
227 
228 /*
229  * Comparison operators between pmem::obj::experimental::vector<T> and
230  * pmem::obj::experimental::vector<T>
231  */
232 template <typename T>
233 bool operator==(const vector<T> &lhs, const vector<T> &rhs);
234 template <typename T>
235 bool operator!=(const vector<T> &lhs, const vector<T> &rhs);
236 template <typename T>
237 bool operator<(const vector<T> &lhs, const vector<T> &rhs);
238 template <typename T>
239 bool operator<=(const vector<T> &lhs, const vector<T> &rhs);
240 template <typename T>
241 bool operator>(const vector<T> &lhs, const vector<T> &rhs);
242 template <typename T>
243 bool operator>=(const vector<T> &lhs, const vector<T> &rhs);
244 
245 /*
246  * Comparison operators between pmem::obj::experimental::vector<T> and
247  * std::vector<T>
248  */
249 template <typename T>
250 bool operator==(const vector<T> &lhs, const std::vector<T> &rhs);
251 template <typename T>
252 bool operator!=(const vector<T> &lhs, const std::vector<T> &rhs);
253 template <typename T>
254 bool operator<(const vector<T> &lhs, const std::vector<T> &rhs);
255 template <typename T>
256 bool operator<=(const vector<T> &lhs, const std::vector<T> &rhs);
257 template <typename T>
258 bool operator>(const vector<T> &lhs, const std::vector<T> &rhs);
259 template <typename T>
260 bool operator>=(const vector<T> &lhs, const std::vector<T> &rhs);
261 
262 /*
263  * Comparison operators between std::vector<T> and
264  * pmem::obj::experimental::vector<T>
265  */
266 template <typename T>
267 bool operator==(const std::vector<T> &lhs, const vector<T> &rhs);
268 template <typename T>
269 bool operator!=(const std::vector<T> &lhs, const vector<T> &rhs);
270 template <typename T>
271 bool operator<(const std::vector<T> &lhs, const vector<T> &rhs);
272 template <typename T>
273 bool operator<=(const std::vector<T> &lhs, const vector<T> &rhs);
274 template <typename T>
275 bool operator>(const std::vector<T> &lhs, const vector<T> &rhs);
276 template <typename T>
277 bool operator>=(const std::vector<T> &lhs, const vector<T> &rhs);
278 
287 template <typename T>
289 {
290  check_pmem();
291  check_tx_stage_work();
292 
293  _data = nullptr;
294  _size = 0;
295  _capacity = 0;
296 }
297 
315 template <typename T>
316 vector<T>::vector(size_type count, const value_type &value)
317 {
318  check_pmem();
319  check_tx_stage_work();
320 
321  _data = nullptr;
322  _size = 0;
323  alloc(count);
324  construct(0, count, value);
325 }
326 
343 template <typename T>
344 vector<T>::vector(size_type count)
345 {
346  check_pmem();
347  check_tx_stage_work();
348 
349  _data = nullptr;
350  _size = 0;
351  alloc(count);
352  construct(0, count);
353 }
354 
376 template <typename T>
377 template <typename InputIt,
378  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
379  InputIt>::type *>
380 vector<T>::vector(InputIt first, InputIt last)
381 {
382  check_pmem();
383  check_tx_stage_work();
384 
385  _data = nullptr;
386  _size = 0;
387  alloc(static_cast<size_type>(std::distance(first, last)));
388  construct_range_copy(0, first, last);
389 }
390 
408 template <typename T>
410 {
411  check_pmem();
412  check_tx_stage_work();
413 
414  _data = nullptr;
415  _size = 0;
416  alloc(other.capacity());
417  construct_range_copy(0, other.cbegin(), other.cend());
418 }
419 
438 template <typename T>
440 {
441  check_pmem();
442  check_tx_stage_work();
443 
444  _data = other._data;
445  _capacity = other.capacity();
446  _size = other.size();
447  other._data = nullptr;
448  other._capacity = other._size = 0;
449 }
450 
467 template <typename T>
468 vector<T>::vector(std::initializer_list<T> init)
469  : vector(init.begin(), init.end())
470 {
471 }
472 
490 template <typename T>
491 vector<T>::vector(const std::vector<T> &other)
492  : vector(other.cbegin(), other.cend())
493 {
494 }
495 
507 template <typename T>
508 vector<T> &
510 {
511  assign(other);
512 
513  return *this;
514 }
515 
526 template <typename T>
527 vector<T> &
529 {
530  assign(std::move(other));
531 
532  return *this;
533 }
534 
544 template <typename T>
545 vector<T> &
546 vector<T>::operator=(std::initializer_list<T> ilist)
547 {
548  assign(ilist.begin(), ilist.end());
549 
550  return *this;
551 }
552 
565 template <typename T>
566 vector<T> &
567 vector<T>::operator=(const std::vector<T> &other)
568 {
569  assign(other);
570 
571  return *this;
572 }
573 
590 template <typename T>
591 void
592 vector<T>::assign(size_type count, const_reference value)
593 {
594  pool_base pb = get_pool();
595 
596  transaction::run(pb, [&] {
597  if (count <= capacity()) {
598  /*
599  * Reallocation is not needed. First, replace old
600  * elements with new ones in range [0, size()).
601  * Depending on count, either call remaining old
602  * elements destructors, or append more new elements.
603  */
604  size_type size_old = _size;
605  snapshot_data(0, size_old);
606 
607  std::fill_n(
608  &_data[0],
609  (std::min)(count,
610  static_cast<size_type>(size_old)),
611  value);
612 
613  if (count > size_old) {
614 #if LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED
615  /*
616  * Range of memory:
617  * [&_data[size_old], &_data[count])
618  * is undefined, there is no need to snapshot
619  * and eventually rollback old data.
620  */
621  VALGRIND_PMC_ADD_TO_TX(
622  &_data[static_cast<difference_type>(
623  size_old)],
624  sizeof(T) * (count - size_old));
625 #endif
626 
627  construct(size_old, count - size_old, value);
628  /*
629  * XXX: explicit persist is required here
630  * because given range wasn't snapshotted and
631  * won't be persisted automatically on tx
632  * commit. This can be changed once we will have
633  * implemented "uninitialized" flag for
634  * pmemobj_tx_xadd in libpmemobj.
635  */
636  pb.persist(&_data[static_cast<difference_type>(
637  size_old)],
638  sizeof(T) * (count - size_old));
639  } else {
640  shrink(count);
641  }
642  } else {
643  dealloc();
644  alloc(count);
645  construct(0, count, value);
646  }
647  });
648 }
649 
668 template <typename T>
669 template <typename InputIt,
670  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
671  InputIt>::type *>
672 void
673 vector<T>::assign(InputIt first, InputIt last)
674 {
675  pool_base pb = get_pool();
676 
677  size_type size_new = static_cast<size_type>(std::distance(first, last));
678 
679  transaction::run(pb, [&] {
680  if (size_new <= capacity()) {
681  /*
682  * Reallocation is not needed. First, replace old
683  * elements with new ones in range [0, size()).
684  * Depending on size_new, either call remaining old
685  * elements destructors, or append more new elements.
686  */
687  size_type size_old = _size;
688  snapshot_data(0, size_old);
689 
690  InputIt mid = last;
691  bool growing = size_new > size_old;
692 
693  if (growing) {
694 #if LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED
695  /*
696  * Range of memory:
697  * [&_data[size_old], &_data[size_new])
698  * is undefined, there is no need to snapshot
699  * and eventually rollback old data.
700  */
701  VALGRIND_PMC_ADD_TO_TX(
702  &_data[static_cast<difference_type>(
703  size_old)],
704  sizeof(T) * (size_new - size_old));
705 #endif
706 
707  mid = first;
708  std::advance(mid, size_old);
709  }
710 
711  iterator shrink_to = std::copy(first, mid, &_data[0]);
712 
713  if (growing) {
714  construct_range_copy(size_old, mid, last);
715  /*
716  * XXX: explicit persist is required here
717  * because given range wasn't snapshotted and
718  * won't be persisted automatically on tx
719  * commit. This can be changed once we will have
720  * implemented "uninitialized" flag for
721  * pmemobj_tx_xadd in libpmemobj.
722  */
723  pb.persist(&_data[static_cast<difference_type>(
724  size_old)],
725  sizeof(T) * (size_new - size_old));
726  } else {
727  shrink(static_cast<size_type>(std::distance(
728  iterator(&_data[0]), shrink_to)));
729  }
730  } else {
731  dealloc();
732  alloc(size_new);
733  construct_range_copy(0, first, last);
734  }
735  });
736 }
737 
753 template <typename T>
754 void
755 vector<T>::assign(std::initializer_list<T> ilist)
756 {
757  assign(ilist.begin(), ilist.end());
758 }
759 
771 template <typename T>
772 void
774 {
775  if (this != &other)
776  assign(other.cbegin(), other.cend());
777 }
778 
790 template <typename T>
791 void
793 {
794  if (this == &other)
795  return;
796 
797  pool_base pb = get_pool();
798 
799  transaction::run(pb, [&] {
800  dealloc();
801 
802  _data = other._data;
803  _capacity = other._capacity;
804  _size = other._size;
805 
806  other._data = nullptr;
807  other._capacity = other._size = 0;
808  });
809 }
810 
823 template <typename T>
824 void
825 vector<T>::assign(const std::vector<T> &other)
826 {
827  assign(other.cbegin(), other.cend());
828 }
829 
839 template <typename T>
841 {
842  free_data();
843 }
844 
857 template <typename T>
858 typename vector<T>::reference
859 vector<T>::at(size_type n)
860 {
861  if (n >= _size)
862  throw std::out_of_range("vector::at");
863 
864  detail::conditional_add_to_tx(&_data[static_cast<difference_type>(n)]);
865 
866  return _data[static_cast<difference_type>(n)];
867 }
868 
878 template <typename T>
879 typename vector<T>::const_reference
880 vector<T>::at(size_type n) const
881 {
882  if (n >= _size)
883  throw std::out_of_range("vector::at");
884 
885  return _data[static_cast<difference_type>(n)];
886 }
887 
900 template <typename T>
901 typename vector<T>::const_reference
902 vector<T>::const_at(size_type n) const
903 {
904  if (n >= _size)
905  throw std::out_of_range("vector::const_at");
906 
907  return _data[static_cast<difference_type>(n)];
908 }
909 
921 template <typename T>
922 typename vector<T>::reference vector<T>::operator[](size_type n)
923 {
924  detail::conditional_add_to_tx(&_data[static_cast<difference_type>(n)]);
925 
926  return _data[static_cast<difference_type>(n)];
927 }
928 
936 template <typename T>
937 typename vector<T>::const_reference vector<T>::operator[](size_type n) const
938 {
939  return _data[static_cast<difference_type>(n)];
940 }
941 
950 template <typename T>
951 typename vector<T>::reference
953 {
954  detail::conditional_add_to_tx(&_data[0]);
955 
956  return _data[0];
957 }
958 
964 template <typename T>
965 typename vector<T>::const_reference
967 {
968  return _data[0];
969 }
970 
978 template <typename T>
979 typename vector<T>::const_reference
981 {
982  return _data[0];
983 }
984 
993 template <typename T>
994 typename vector<T>::reference
996 {
997  detail::conditional_add_to_tx(
998  &_data[static_cast<difference_type>(size() - 1)]);
999 
1000  return _data[static_cast<difference_type>(size() - 1)];
1001 }
1002 
1008 template <typename T>
1009 typename vector<T>::const_reference
1011 {
1012  return _data[static_cast<difference_type>(size() - 1)];
1013 }
1014 
1022 template <typename T>
1023 typename vector<T>::const_reference
1025 {
1026  return _data[static_cast<difference_type>(size() - 1)];
1027 }
1028 
1038 template <typename T>
1039 typename vector<T>::value_type *
1041 {
1042  snapshot_data(0, _size);
1043 
1044  return _data.get();
1045 }
1046 
1052 template <typename T>
1053 const typename vector<T>::value_type *
1054 vector<T>::data() const noexcept
1055 {
1056  return _data.get();
1057 }
1058 
1066 template <typename T>
1067 const typename vector<T>::value_type *
1068 vector<T>::cdata() const noexcept
1069 {
1070  return _data.get();
1071 }
1072 
1078 template <typename T>
1079 typename vector<T>::iterator
1081 {
1082  return iterator(_data.get());
1083 }
1084 
1090 template <typename T>
1091 typename vector<T>::const_iterator
1092 vector<T>::begin() const noexcept
1093 {
1094  return const_iterator(_data.get());
1095 }
1096 
1104 template <typename T>
1105 typename vector<T>::const_iterator
1106 vector<T>::cbegin() const noexcept
1107 {
1108  return const_iterator(_data.get());
1109 }
1110 
1116 template <typename T>
1117 typename vector<T>::iterator
1119 {
1120  return iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1121 }
1122 
1128 template <typename T>
1129 typename vector<T>::const_iterator
1130 vector<T>::end() const noexcept
1131 {
1132  return const_iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1133 }
1134 
1142 template <typename T>
1143 typename vector<T>::const_iterator
1144 vector<T>::cend() const noexcept
1145 {
1146  return const_iterator(_data.get() + static_cast<std::ptrdiff_t>(_size));
1147 }
1148 
1154 template <typename T>
1155 typename vector<T>::reverse_iterator
1157 {
1158  return reverse_iterator(end());
1159 }
1160 
1166 template <typename T>
1167 typename vector<T>::const_reverse_iterator
1168 vector<T>::rbegin() const noexcept
1169 {
1170  return const_reverse_iterator(cend());
1171 }
1172 
1180 template <typename T>
1181 typename vector<T>::const_reverse_iterator
1182 vector<T>::crbegin() const noexcept
1183 {
1184  return const_reverse_iterator(cend());
1185 }
1186 
1193 template <typename T>
1194 typename vector<T>::reverse_iterator
1196 {
1197  return reverse_iterator(begin());
1198 }
1199 
1206 template <typename T>
1207 typename vector<T>::const_reverse_iterator
1208 vector<T>::rend() const noexcept
1209 {
1210  return const_reverse_iterator(cbegin());
1211 }
1212 
1221 template <typename T>
1222 typename vector<T>::const_reverse_iterator
1223 vector<T>::crend() const noexcept
1224 {
1225  return const_reverse_iterator(cbegin());
1226 }
1227 
1241 template <typename T>
1243 vector<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 
1250  return {_data.get() + start, _data.get() + start + n};
1251 }
1252 
1268 template <typename T>
1270 vector<T>::range(size_type start, size_type n, size_type snapshot_size)
1271 {
1272  if (start + n > size())
1273  throw std::out_of_range("vector::range");
1274 
1275  if (snapshot_size > n)
1276  snapshot_size = n;
1277 
1278  return {range_snapshotting_iterator<T>(_data.get() + start,
1279  _data.get() + start, n,
1280  snapshot_size),
1281  range_snapshotting_iterator<T>(_data.get() + start + n,
1282  _data.get() + start, n,
1283  snapshot_size)};
1284 }
1285 
1297 template <typename T>
1299 vector<T>::range(size_type start, size_type n) const
1300 {
1301  if (start + n > size())
1302  throw std::out_of_range("vector::range");
1303 
1304  return {const_iterator(cdata() + start),
1305  const_iterator(cdata() + start + n)};
1306 }
1307 
1319 template <typename T>
1321 vector<T>::crange(size_type start, size_type n) const
1322 {
1323  if (start + n > size())
1324  throw std::out_of_range("vector::crange");
1325 
1326  return {const_iterator(cdata() + start),
1327  const_iterator(cdata() + start + n)};
1328 }
1329 
1335 template <typename T>
1336 constexpr bool
1337 vector<T>::empty() const noexcept
1338 {
1339  return _size == 0;
1340 }
1341 
1345 template <typename T>
1346 typename vector<T>::size_type
1347 vector<T>::size() const noexcept
1348 {
1349  return _size;
1350 }
1351 
1356 template <typename T>
1357 constexpr typename vector<T>::size_type
1358 vector<T>::max_size() const noexcept
1359 {
1360  return PMEMOBJ_MAX_ALLOC_SIZE / sizeof(value_type);
1361 }
1362 
1381 template <typename T>
1382 void
1383 vector<T>::reserve(size_type capacity_new)
1384 {
1385  if (capacity_new <= _capacity)
1386  return;
1387 
1388  pool_base pb = get_pool();
1389  transaction::run(pb, [&] { realloc(capacity_new); });
1390 }
1391 
1395 template <typename T>
1396 typename vector<T>::size_type
1397 vector<T>::capacity() const noexcept
1398 {
1399  return _capacity;
1400 }
1401 
1416 template <typename T>
1417 void
1419 {
1420  size_type capacity_new = size();
1421  if (capacity() == capacity_new)
1422  return;
1423 
1424  pool_base pb = get_pool();
1425  transaction::run(pb, [&] { realloc(capacity_new); });
1426 }
1427 
1436 template <typename T>
1437 void
1439 {
1440  pool_base pb = get_pool();
1441  transaction::run(pb, [&] { shrink(0); });
1442 }
1443 
1456 template <typename T>
1457 void
1459 {
1460  if (_data == nullptr)
1461  return;
1462 
1463  pool_base pb = get_pool();
1464  transaction::run(pb, [&] { dealloc(); });
1465 }
1466 
1491 template <typename T>
1492 typename vector<T>::iterator
1493 vector<T>::insert(const_iterator pos, const value_type &value)
1494 {
1495  return insert(pos, 1, value);
1496 }
1497 
1522 template <typename T>
1523 typename vector<T>::iterator
1524 vector<T>::insert(const_iterator pos, value_type &&value)
1525 {
1526  pool_base pb = get_pool();
1527 
1528  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1529 
1530  transaction::run(pb, [&] {
1531  insert_gap(idx, 1);
1532  construct(idx, 1, std::move(value));
1533  });
1534 
1535  return iterator(&_data[static_cast<difference_type>(idx)]);
1536 }
1537 
1566 template <typename T>
1567 typename vector<T>::iterator
1568 vector<T>::insert(const_iterator pos, size_type count, const value_type &value)
1569 {
1570  pool_base pb = get_pool();
1571 
1572  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1573 
1574  transaction::run(pb, [&] {
1575  insert_gap(idx, count);
1576  construct(idx, count, value);
1577  });
1578 
1579  return iterator(&_data[static_cast<difference_type>(idx)]);
1580 }
1581 
1616 template <typename T>
1617 template <typename InputIt,
1618  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
1619  InputIt>::type *>
1620 typename vector<T>::iterator
1621 vector<T>::insert(const_iterator pos, InputIt first, InputIt last)
1622 {
1623  pool_base pb = get_pool();
1624 
1625  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1626  size_type gap_size = static_cast<size_type>(std::distance(first, last));
1627 
1628  transaction::run(pb, [&] {
1629  insert_gap(idx, gap_size);
1630  construct_range_copy(idx, first, last);
1631  });
1632 
1633  return iterator(&_data[static_cast<difference_type>(idx)]);
1634 }
1635 
1664 template <typename T>
1665 typename vector<T>::iterator
1666 vector<T>::insert(const_iterator pos, std::initializer_list<value_type> ilist)
1667 {
1668  return insert(pos, ilist.begin(), ilist.end());
1669 }
1670 
1698 template <typename T>
1699 template <class... Args>
1700 typename vector<T>::iterator
1701 vector<T>::emplace(const_iterator pos, Args &&... args)
1702 {
1703  pool_base pb = get_pool();
1704 
1705  size_type idx = static_cast<size_type>(std::distance(cbegin(), pos));
1706 
1707  transaction::run(pb, [&] {
1708  /*
1709  * args might be a reference to underlying array element. This
1710  * reference can be invalidated after insert_gap() call. Hence,
1711  * we must cache value_type object in temp_value.
1712  */
1713  detail::temp_value<value_type,
1714  noexcept(T(std::forward<Args>(args)...))>
1715  tmp(std::forward<Args>(args)...);
1716 
1717  insert_gap(idx, 1);
1718  construct(idx, 1, std::move(tmp.get()));
1719  });
1720 
1721  return iterator(&_data[static_cast<difference_type>(idx)]);
1722 }
1723 
1746 template <typename T>
1747 template <class... Args>
1748 typename vector<T>::reference
1749 vector<T>::emplace_back(Args &&... args)
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  transaction::run(pb, [&] {
1759  if (_size == _capacity) {
1760  realloc(get_recommended_capacity(_size + 1));
1761  } else {
1762 #if LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED
1763  /*
1764  * Range of memory: [&_data[_size], &_data[_size + 1])
1765  * is undefined, there is no need to snapshot and
1766  * eventually rollback old data.
1767  */
1768  VALGRIND_PMC_ADD_TO_TX(
1769  &_data[static_cast<difference_type>(size())],
1770  sizeof(T));
1771 #endif
1772  }
1773 
1774  construct(size(), 1, std::forward<Args>(args)...);
1775  /*
1776  * XXX: explicit persist is required here because given range
1777  * wasn't snapshotted and won't be persisted automatically on tx
1778  * commit. This can be changed once we will have implemented
1779  * "uninitialized" flag for pmemobj_tx_xadd in libpmemobj.
1780  */
1781  pb.persist(&_data[static_cast<difference_type>(size() - 1)],
1782  sizeof(T));
1783  });
1784 
1785  return back();
1786 }
1787 
1807 template <typename T>
1808 typename vector<T>::iterator
1809 vector<T>::erase(const_iterator pos)
1810 {
1811  return erase(pos, pos + 1);
1812 }
1813 
1836 template <typename T>
1837 typename vector<T>::iterator
1838 vector<T>::erase(const_iterator first, const_iterator last)
1839 {
1840  size_type idx = static_cast<size_type>(
1841  std::distance(const_iterator(&_data[0]), first));
1842  size_type count = static_cast<size_type>(std::distance(first, last));
1843 
1844  if (count == 0)
1845  return iterator(&_data[static_cast<difference_type>(idx)]);
1846 
1847  pool_base pb = get_pool();
1848 
1849  transaction::run(pb, [&] {
1850  /*
1851  * XXX: future optimization: no need to snapshot trivial types,
1852  * if idx + count = _size
1853  */
1854  snapshot_data(idx, _size);
1855 
1856  pointer move_begin =
1857  &_data[static_cast<difference_type>(idx + count)];
1858  pointer move_end = &_data[static_cast<difference_type>(size())];
1859  pointer dest = &_data[static_cast<difference_type>(idx)];
1860 
1861  std::move(move_begin, move_end, dest);
1862 
1863  _size -= count;
1864  });
1865 
1866  return iterator(&_data[static_cast<difference_type>(idx)]);
1867 }
1868 
1884 template <typename T>
1885 void
1886 vector<T>::push_back(const value_type &value)
1887 {
1888  emplace_back(value);
1889 }
1890 
1907 template <typename T>
1908 void
1909 vector<T>::push_back(value_type &&value)
1910 {
1911  emplace_back(std::move(value));
1912 }
1913 
1924 template <typename T>
1925 void
1927 {
1928  if (empty())
1929  return;
1930 
1931  pool_base pb = get_pool();
1932  transaction::run(pb, [&] { shrink(size() - 1); });
1933 }
1934 
1951 template <typename T>
1952 void
1953 vector<T>::resize(size_type count)
1954 {
1955  pool_base pb = get_pool();
1956  transaction::run(pb, [&] {
1957  if (count <= _size)
1958  shrink(count);
1959  else {
1960  if (_capacity < count)
1961  realloc(count);
1962  construct(_size, count - _size);
1963  }
1964  });
1965 }
1966 
1984 template <typename T>
1985 void
1986 vector<T>::resize(size_type count, const value_type &value)
1987 {
1988  if (_capacity == count)
1989  return;
1990 
1991  pool_base pb = get_pool();
1992  transaction::run(pb, [&] {
1993  if (count <= _size)
1994  shrink(count);
1995  else {
1996  if (_capacity < count)
1997  realloc(count);
1998  construct(_size, count - _size, value);
1999  }
2000  });
2001 }
2002 
2006 template <typename T>
2007 void
2009 {
2010  pool_base pb = get_pool();
2011  transaction::run(pb, [&] {
2012  std::swap(this->_data, other._data);
2013  std::swap(this->_size, other._size);
2014  std::swap(this->_capacity, other._capacity);
2015  });
2016 }
2017 
2035 template <typename T>
2036 void
2037 vector<T>::alloc(size_type capacity_new)
2038 {
2039  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2040  assert(_data == nullptr);
2041  assert(_size == 0);
2042 
2043  if (capacity_new > max_size())
2044  throw std::length_error("New capacity exceeds max size.");
2045 
2046  _capacity = capacity_new;
2047 
2048  if (capacity_new == 0)
2049  return;
2050 
2051  /*
2052  * We need to cache pmemobj_tx_alloc return value and only after that
2053  * assign it to _data, because when pmemobj_tx_alloc fails, it aborts
2054  * transaction.
2055  */
2056  persistent_ptr<T[]> res =
2057  pmemobj_tx_alloc(sizeof(value_type) * capacity_new,
2058  detail::type_num<value_type>());
2059 
2060  if (res == nullptr)
2062  "Failed to allocate persistent memory object");
2063 
2064  _data = res;
2065 }
2066 
2073 template <typename T>
2074 void
2076 {
2077  if (nullptr == pmemobj_pool_by_ptr(this))
2078  throw pool_error("Invalid pool handle.");
2079 }
2080 
2088 template <typename T>
2089 void
2091 {
2092  if (pmemobj_tx_stage() != TX_STAGE_WORK)
2093  throw transaction_error(
2094  "Function called out of transaction scope.");
2095 }
2096 
2116 template <typename T>
2117 template <typename... Args>
2118 void
2119 vector<T>::construct(size_type idx, 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() + idx;
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 
2155 template <typename T>
2156 template <typename InputIt,
2157  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
2158  InputIt>::type *>
2159 void
2160 vector<T>::construct_range(size_type idx, InputIt first, InputIt last)
2161 {
2162  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2163  difference_type range_size = std::distance(first, last);
2164  assert(range_size >= 0);
2165  assert(_capacity >= static_cast<size_type>(range_size) + _size);
2166 
2167  pointer dest = _data.get() + idx;
2168  _size += static_cast<size_type>(range_size);
2169  while (first != last)
2170  detail::create<value_type>(dest++, std::move(*first++));
2171 }
2172 
2194 template <typename T>
2195 template <typename InputIt,
2196  typename std::enable_if<detail::is_input_iterator<InputIt>::value,
2197  InputIt>::type *>
2198 void
2199 vector<T>::construct_range_copy(size_type idx, InputIt first, InputIt last)
2200 {
2201  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2202  difference_type diff = std::distance(first, last);
2203  assert(diff >= 0);
2204  assert(_capacity >= static_cast<size_type>(diff) + _size);
2205 
2206  pointer dest = _data.get() + idx;
2207  _size += static_cast<size_type>(diff);
2208  while (first != last)
2209  detail::create<value_type>(dest++, *first++);
2210 }
2211 
2227 template <typename T>
2228 void
2230 {
2231  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2232 
2233  if (_data != nullptr) {
2234  shrink(0);
2235  if (pmemobj_tx_free(*_data.raw_ptr()) != 0)
2236  throw transaction_free_error(
2237  "failed to delete persistent memory object");
2238  _data = nullptr;
2239  _capacity = 0;
2240  }
2241 }
2242 
2250 template <typename T>
2251 pool_base
2252 vector<T>::get_pool() const noexcept
2253 {
2254  auto pop = pmemobj_pool_by_ptr(this);
2255  assert(pop != nullptr);
2256  return pool_base(pop);
2257 }
2258 
2277 template <typename T>
2278 void
2279 vector<T>::insert_gap(size_type idx, size_type count)
2280 {
2281  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2282 
2283  if (_capacity >= _size + count) {
2284  pointer dest =
2285  &_data[static_cast<difference_type>(size() + count)];
2286  pointer begin = &_data[static_cast<difference_type>(idx)];
2287  pointer end = &_data[static_cast<difference_type>(size())];
2288 
2289  /*
2290  * XXX: There is no necessity to snapshot uninitialized data, so
2291  * we can optimize it by calling:
2292  * transaction::snapshot<T>(begin, size() - idx).
2293  * However, we need libpmemobj support for that, because right
2294  * now pmemcheck will report an error (uninitialized part of
2295  * data not added to tx).
2296  *
2297  * XXX: future optimization: we don't have to snapshot data
2298  * which we will not overwrite
2299  */
2300 #if LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED
2301  VALGRIND_MAKE_MEM_DEFINED(end, sizeof(T) * count);
2302 #endif
2303  snapshot_data(idx, _size + count);
2304 
2305  std::move_backward(begin, end, dest);
2306  } else {
2307  /*
2308  * XXX: future optimization: we don't have to snapshot data
2309  * which we will not overwrite
2310  */
2311  snapshot_data(0, _size);
2312 
2313  auto old_data = _data;
2314  auto old_size = _size;
2315  pointer old_begin = &_data[0];
2316  pointer old_mid = &_data[static_cast<difference_type>(idx)];
2317  pointer old_end = &_data[static_cast<difference_type>(size())];
2318 
2319  _data = nullptr;
2320  _size = _capacity = 0;
2321 
2322  alloc(get_recommended_capacity(old_size + count));
2323 
2324  construct_range(0, old_begin, old_mid);
2325  construct_range(idx + count, old_mid, old_end);
2326 
2327  /* destroy and free old data */
2328  for (size_type i = 0; i < old_size; ++i)
2329  detail::destroy<value_type>(
2330  old_data[static_cast<difference_type>(i)]);
2331  if (pmemobj_tx_free(old_data.raw()) != 0)
2332  throw transaction_free_error(
2333  "failed to delete persistent memory object");
2334  }
2335 }
2336 
2354 template <typename T>
2355 void
2356 vector<T>::realloc(size_type capacity_new)
2357 {
2358  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2359 
2360  /*
2361  * XXX: future optimization: we don't have to snapshot data
2362  * which we will not overwrite
2363  */
2364  snapshot_data(0, _size);
2365 
2366  auto old_data = _data;
2367  auto old_size = _size;
2368  pointer old_begin = &_data[0];
2369  pointer old_end = capacity_new < _size
2370  ? &_data[static_cast<difference_type>(capacity_new)]
2371  : &_data[static_cast<difference_type>(size())];
2372 
2373  _data = nullptr;
2374  _size = _capacity = 0;
2375 
2376  alloc(capacity_new);
2377 
2378  construct_range(0, old_begin, old_end);
2379 
2380  /* destroy and free old data */
2381  for (size_type i = 0; i < old_size; ++i)
2382  detail::destroy<value_type>(
2383  old_data[static_cast<difference_type>(i)]);
2384  if (pmemobj_tx_free(old_data.raw()) != 0)
2385  throw transaction_free_error(
2386  "failed to delete persistent memory object");
2387 }
2388 
2395 template <typename T>
2396 typename vector<T>::size_type
2397 vector<T>::get_recommended_capacity(size_type at_least) const
2398 {
2399  return detail::next_pow_2(at_least);
2400 }
2401 
2418 template <typename T>
2419 void
2420 vector<T>::shrink(size_type size_new)
2421 {
2422  assert(pmemobj_tx_stage() == TX_STAGE_WORK);
2423  assert(size_new <= _size);
2424 
2425  snapshot_data(size_new, _size);
2426 
2427  for (size_type i = size_new; i < _size; ++i)
2428  detail::destroy<value_type>(
2429  _data[static_cast<difference_type>(i)]);
2430  _size = size_new;
2431 }
2432 
2442 template <typename T>
2443 void
2444 vector<T>::snapshot_data(size_type idx_first, size_type idx_last)
2445 {
2446  detail::conditional_add_to_tx(_data.get() + idx_first,
2447  idx_last - idx_first);
2448 }
2449 
2461 template <typename T>
2462 bool
2463 operator==(const vector<T> &lhs, const vector<T> &rhs)
2464 {
2465  return lhs.size() == rhs.size() &&
2466  std::equal(lhs.begin(), lhs.end(), rhs.begin());
2467 }
2468 
2480 template <typename T>
2481 bool
2482 operator!=(const vector<T> &lhs, const vector<T> &rhs)
2483 {
2484  return !(lhs == rhs);
2485 }
2486 
2497 template <typename T>
2498 bool
2499 operator<(const vector<T> &lhs, const vector<T> &rhs)
2500 {
2501  return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
2502  rhs.end());
2503 }
2504 
2515 template <typename T>
2516 bool
2517 operator<=(const vector<T> &lhs, const vector<T> &rhs)
2518 {
2519  return !(rhs < lhs);
2520 }
2521 
2533 template <typename T>
2534 bool
2535 operator>(const vector<T> &lhs, const vector<T> &rhs)
2536 {
2537  return rhs < lhs;
2538 }
2539 
2550 template <typename T>
2551 bool
2552 operator>=(const vector<T> &lhs, const vector<T> &rhs)
2553 {
2554  return !(lhs < rhs);
2555 }
2556 
2568 template <typename T>
2569 bool
2570 operator==(const vector<T> &lhs, const std::vector<T> &rhs)
2571 {
2572  return lhs.size() == rhs.size() &&
2573  std::equal(lhs.begin(), lhs.end(), rhs.begin());
2574 }
2575 
2587 template <typename T>
2588 bool
2589 operator!=(const vector<T> &lhs, const std::vector<T> &rhs)
2590 {
2591  return !(lhs == rhs);
2592 }
2593 
2604 template <typename T>
2605 bool
2606 operator<(const vector<T> &lhs, const std::vector<T> &rhs)
2607 {
2608  return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
2609  rhs.end());
2610 }
2611 
2622 template <typename T>
2623 bool
2624 operator<=(const vector<T> &lhs, const std::vector<T> &rhs)
2625 {
2626  return !(std::lexicographical_compare(rhs.begin(), rhs.end(),
2627  lhs.begin(), lhs.end()));
2628 }
2629 
2641 template <typename T>
2642 bool
2643 operator>(const vector<T> &lhs, const std::vector<T> &rhs)
2644 {
2645  return !(lhs <= rhs);
2646 }
2647 
2658 template <typename T>
2659 bool
2660 operator>=(const vector<T> &lhs, const std::vector<T> &rhs)
2661 {
2662  return !(lhs < rhs);
2663 }
2664 
2676 template <typename T>
2677 bool
2678 operator==(const std::vector<T> &lhs, const vector<T> &rhs)
2679 {
2680  return rhs == lhs;
2681 }
2682 
2694 template <typename T>
2695 bool
2696 operator!=(const std::vector<T> &lhs, const vector<T> &rhs)
2697 {
2698  return !(lhs == rhs);
2699 }
2700 
2711 template <typename T>
2712 bool
2713 operator<(const std::vector<T> &lhs, const vector<T> &rhs)
2714 {
2715  return rhs > lhs;
2716 }
2717 
2728 template <typename T>
2729 bool
2730 operator<=(const std::vector<T> &lhs, const vector<T> &rhs)
2731 {
2732  return !(rhs < lhs);
2733 }
2734 
2746 template <typename T>
2747 bool
2748 operator>(const std::vector<T> &lhs, const vector<T> &rhs)
2749 {
2750  return rhs < lhs;
2751 }
2752 
2763 template <typename T>
2764 bool
2765 operator>=(const std::vector<T> &lhs, const vector<T> &rhs)
2766 {
2767  return !(lhs < rhs);
2768 }
2769 
2776 template <typename T>
2777 void
2779 {
2780  lhs.swap(rhs);
2781 }
2782 
2783 } /* namespace experimental */
2784 
2785 } /* namespace obj */
2786 
2787 } /* namespace pmem */
2788 
2789 #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:400
Non-const iterator which adds elements to a transaction in a bulk.
Definition: contiguous_iterator.hpp:223
Custom transaction error class.
Definition: pexceptions.hpp:84
iterator begin()
Returns an iterator to the beginning.
Definition: vector.hpp:1080
bool operator>=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater or equal operator.
Definition: array.hpp:757
constexpr bool empty() const noexcept
Checks whether the container is empty.
Definition: vector.hpp:1337
~vector()
Destructor.
Definition: vector.hpp:840
constexpr size_type max_size() const noexcept
Definition: vector.hpp:1358
void free_data()
Clears the content of a vector and frees all allocated persistent memory for data transactionally.
Definition: vector.hpp:1458
reference at(size_type n)
Access element at specific index with bounds checking and add it to a transaction.
Definition: vector.hpp:859
pmem::obj::experimental::array< T, N >::const_iterator cend(const pmem::obj::experimental::array< T, N > &a)
Non-member cend.
Definition: array.hpp:787
slice< pointer > range(size_type start, size_type n)
Returns slice and snapshots requested range.
Definition: vector.hpp:1243
Default non-const iterator which adds element to a transaction on every access.
Definition: contiguous_iterator.hpp:360
void shrink_to_fit()
Requests transactional removal of unused capacity.
Definition: vector.hpp:1418
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition: vector.hpp:1182
Persistent_ptr transactional allocation functions for objects.
void construct(size_type idx, size_type count, Args &&... args)
Private helper function.
Definition: vector.hpp:2119
Common iterator traits.
The non-template pool base class.
Definition: pool.hpp:67
const_reference cback() const
Access the last element.
Definition: vector.hpp:1024
temp_value template class for caching objects.
void check_tx_stage_work()
Private helper function.
Definition: vector.hpp:2090
pmem::obj::experimental::array< T, N >::iterator begin(pmem::obj::experimental::array< T, N > &a)
Non-member begin.
Definition: array.hpp:817
iterator emplace(const_iterator pos, Args &&... args)
Inserts a new element into the container directly before pos.
Definition: vector.hpp:1701
size_type get_recommended_capacity(size_type at_least) const
Private helper function.
Definition: vector.hpp:2397
Custom pool error class.
Definition: pexceptions.hpp:53
const_reference cfront() const
Access the first element.
Definition: vector.hpp:980
reverse_iterator rbegin()
Returns a reverse iterator to the beginning.
Definition: vector.hpp:1156
vector()
Default constructor.
Definition: vector.hpp:288
pool_base get_pool() const noexcept
Private helper function.
Definition: vector.hpp:2252
reference back()
Access the last element and add this element to a transaction.
Definition: vector.hpp:995
reference emplace_back(Args &&... args)
Appends a new element to the end of the container.
Definition: vector.hpp:1749
iterator end()
Returns an iterator to past the end.
Definition: vector.hpp:1118
C++ pmemobj transactions.
Convenience extensions for the resides on pmem property template.
Functions for destroying arrays.
reference operator[](size_type n)
Access element at specific index and add it to a transaction.
Definition: vector.hpp:922
void clear()
Clears the content of a vector transactionally.
Definition: vector.hpp:1438
Commonly used functionality.
Iterators for pmem::obj::array.
void reserve(size_type capacity_new)
Increases the capacity of the vector to capacity_new transactionally.
Definition: vector.hpp:1383
value_type * data()
Returns raw pointer to the underlying data and adds entire array to a transaction.
Definition: vector.hpp:1040
void alloc(size_type size)
Private helper function.
Definition: vector.hpp:2037
vector & operator=(const vector &other)
Copy assignment operator.
Definition: vector.hpp:509
const value_type * cdata() const noexcept
Returns const raw pointer to the underlying data.
Definition: vector.hpp:1068
void pop_back()
Removes the last element of the container transactionally.
Definition: vector.hpp:1926
void swap(pmem::obj::experimental::array< T, N > &lhs, pmem::obj::experimental::array< T, N > &rhs)
Non-member swap function.
Definition: array.hpp:897
const_iterator cend() const noexcept
Returns a const iterator to the end.
Definition: vector.hpp:1144
void persist(const void *addr, size_t len) noexcept
Performs persist operation on a given chunk of memory.
Definition: pool.hpp:284
pmem::obj::experimental::slice - provides interface to access sequence of objects.
Definition: slice.hpp:59
iterator insert(const_iterator pos, const T &value)
Inserts value before pos in the container transactionally.
Definition: vector.hpp:1493
pmem::obj::experimental::vector - EXPERIMENTAL persistent container with std::vector compatible inter...
Definition: vector.hpp:72
Custom transaction error class.
Definition: pexceptions.hpp:63
void shrink(size_type size_new)
Private helper function.
Definition: vector.hpp:2420
void realloc(size_type size)
Private helper function.
Definition: vector.hpp:2356
Type trait to determine if a given parameter type satisfies requirements of InputIterator.
Definition: iterator_traits.hpp:75
void swap(vector &other)
Exchanges the contents of the container with other transactionally.
Definition: vector.hpp:2008
void construct_range_copy(size_type idx, InputIt first, InputIt last)
Private helper function.
Definition: vector.hpp:2199
Template class for caching objects based on constructor's variadic template arguments and LIBPMEMOBJ_...
Definition: temp_value.hpp:64
const_reference const_at(size_type n) const
Access element at specific index with bounds checking.
Definition: vector.hpp:902
void dealloc()
Private helper function.
Definition: vector.hpp:2229
void resize(size_type count)
Resizes the container to count elements transactionally.
Definition: vector.hpp:1953
reverse_iterator rend()
Returns a reverse iterator to the end.
Definition: vector.hpp:1195
pmem::obj::experimental::array< T, N >::iterator end(pmem::obj::experimental::array< T, N > &a)
Non-member end.
Definition: array.hpp:837
bool operator<=(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member less or equal operator.
Definition: array.hpp:767
slice< const_iterator > crange(size_type start, size_type n) const
Returns const slice.
Definition: vector.hpp:1321
Persistent smart pointer.
bool operator>(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member greater than operator.
Definition: array.hpp:747
Iterface to access sequence of objects.
size_type capacity() const noexcept
Definition: vector.hpp:1397
const_reverse_iterator crend() const noexcept
Returns a const reverse iterator to the beginning.
Definition: vector.hpp:1223
reference front()
Access the first element and add this element to a transaction.
Definition: vector.hpp:952
Custom transaction error class.
Definition: pexceptions.hpp:94
void check_pmem()
Private helper function.
Definition: vector.hpp:2075
bool operator<(const array< T, N > &lhs, const array< T, N > &rhs)
Non-member less than operator.
Definition: array.hpp:736
bool operator!=(const allocator< T, P, Tr > &lhs, const OtherAllocator &rhs)
Determines if memory from another allocator can be deallocated from this one.
Definition: allocator.hpp:516
pmem::obj::experimental::array< T, N >::const_iterator cbegin(const pmem::obj::experimental::array< T, N > &a)
Non-member cbegin.
Definition: array.hpp:777
void construct_range(size_type idx, InputIt first, InputIt last)
Private helper function.
Definition: vector.hpp:2160
void push_back(const T &value)
Appends the given element value to the end of the container transactionally.
Definition: vector.hpp:1886
void snapshot_data(size_type idx_first, size_type idx_last)
Private helper function.
Definition: vector.hpp:2444
size_type size() const noexcept
Definition: vector.hpp:1347
const_iterator cbegin() const noexcept
Returns const iterator to the beginning.
Definition: vector.hpp:1106
iterator erase(const_iterator pos)
Removes the element at pos.
Definition: vector.hpp:1809
void insert_gap(size_type idx, size_type count)
Private helper function.
Definition: vector.hpp:2279