inlined_vector.h 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. // Copyright 2019 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. // -----------------------------------------------------------------------------
  16. // File: inlined_vector.h
  17. // -----------------------------------------------------------------------------
  18. //
  19. // This header file contains the declaration and definition of an "inlined
  20. // vector" which behaves in an equivalent fashion to a `std::vector`, except
  21. // that storage for small sequences of the vector are provided inline without
  22. // requiring any heap allocation.
  23. //
  24. // An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of
  25. // its template parameters. Instances where `size() <= N` hold contained
  26. // elements in inline space. Typically `N` is very small so that sequences that
  27. // are expected to be short do not require allocations.
  28. //
  29. // An `absl::InlinedVector` does not usually require a specific allocator. If
  30. // the inlined vector grows beyond its initial constraints, it will need to
  31. // allocate (as any normal `std::vector` would). This is usually performed with
  32. // the default allocator (defined as `std::allocator<T>`). Optionally, a custom
  33. // allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`.
  34. #ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
  35. #define ABSL_CONTAINER_INLINED_VECTOR_H_
  36. #include <algorithm>
  37. #include <cstddef>
  38. #include <cstdlib>
  39. #include <cstring>
  40. #include <initializer_list>
  41. #include <iterator>
  42. #include <memory>
  43. #include <type_traits>
  44. #include <utility>
  45. #include "absl/algorithm/algorithm.h"
  46. #include "absl/base/internal/throw_delegate.h"
  47. #include "absl/base/macros.h"
  48. #include "absl/base/optimization.h"
  49. #include "absl/base/port.h"
  50. #include "absl/container/internal/inlined_vector.h"
  51. #include "absl/memory/memory.h"
  52. #include "absl/meta/type_traits.h"
  53. namespace absl {
  54. ABSL_NAMESPACE_BEGIN
  55. // -----------------------------------------------------------------------------
  56. // InlinedVector
  57. // -----------------------------------------------------------------------------
  58. //
  59. // An `absl::InlinedVector` is designed to be a drop-in replacement for
  60. // `std::vector` for use cases where the vector's size is sufficiently small
  61. // that it can be inlined. If the inlined vector does grow beyond its estimated
  62. // capacity, it will trigger an initial allocation on the heap, and will behave
  63. // as a `std::vector`. The API of the `absl::InlinedVector` within this file is
  64. // designed to cover the same API footprint as covered by `std::vector`.
  65. template <typename T, size_t N, typename A = std::allocator<T>>
  66. class InlinedVector {
  67. static_assert(N > 0, "`absl::InlinedVector` requires an inlined capacity.");
  68. using Storage = inlined_vector_internal::Storage<T, N, A>;
  69. template <typename TheA>
  70. using AllocatorTraits = inlined_vector_internal::AllocatorTraits<TheA>;
  71. template <typename TheA>
  72. using MoveIterator = inlined_vector_internal::MoveIterator<TheA>;
  73. template <typename TheA>
  74. using IsMoveAssignOk = inlined_vector_internal::IsMoveAssignOk<TheA>;
  75. template <typename TheA, typename Iterator>
  76. using IteratorValueAdapter =
  77. inlined_vector_internal::IteratorValueAdapter<TheA, Iterator>;
  78. template <typename TheA>
  79. using CopyValueAdapter = inlined_vector_internal::CopyValueAdapter<TheA>;
  80. template <typename TheA>
  81. using DefaultValueAdapter =
  82. inlined_vector_internal::DefaultValueAdapter<TheA>;
  83. template <typename Iterator>
  84. using EnableIfAtLeastForwardIterator = absl::enable_if_t<
  85. inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
  86. template <typename Iterator>
  87. using DisableIfAtLeastForwardIterator = absl::enable_if_t<
  88. !inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
  89. using MemcpyPolicy = typename Storage::MemcpyPolicy;
  90. using ElementwiseAssignPolicy = typename Storage::ElementwiseAssignPolicy;
  91. using ElementwiseConstructPolicy =
  92. typename Storage::ElementwiseConstructPolicy;
  93. using MoveAssignmentPolicy = typename Storage::MoveAssignmentPolicy;
  94. public:
  95. using allocator_type = A;
  96. using value_type = inlined_vector_internal::ValueType<A>;
  97. using pointer = inlined_vector_internal::Pointer<A>;
  98. using const_pointer = inlined_vector_internal::ConstPointer<A>;
  99. using size_type = inlined_vector_internal::SizeType<A>;
  100. using difference_type = inlined_vector_internal::DifferenceType<A>;
  101. using reference = inlined_vector_internal::Reference<A>;
  102. using const_reference = inlined_vector_internal::ConstReference<A>;
  103. using iterator = inlined_vector_internal::Iterator<A>;
  104. using const_iterator = inlined_vector_internal::ConstIterator<A>;
  105. using reverse_iterator = inlined_vector_internal::ReverseIterator<A>;
  106. using const_reverse_iterator =
  107. inlined_vector_internal::ConstReverseIterator<A>;
  108. // ---------------------------------------------------------------------------
  109. // InlinedVector Constructors and Destructor
  110. // ---------------------------------------------------------------------------
  111. // Creates an empty inlined vector with a value-initialized allocator.
  112. InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {}
  113. // Creates an empty inlined vector with a copy of `allocator`.
  114. explicit InlinedVector(const allocator_type& allocator) noexcept
  115. : storage_(allocator) {}
  116. // Creates an inlined vector with `n` copies of `value_type()`.
  117. explicit InlinedVector(size_type n,
  118. const allocator_type& allocator = allocator_type())
  119. : storage_(allocator) {
  120. storage_.Initialize(DefaultValueAdapter<A>(), n);
  121. }
  122. // Creates an inlined vector with `n` copies of `v`.
  123. InlinedVector(size_type n, const_reference v,
  124. const allocator_type& allocator = allocator_type())
  125. : storage_(allocator) {
  126. storage_.Initialize(CopyValueAdapter<A>(std::addressof(v)), n);
  127. }
  128. // Creates an inlined vector with copies of the elements of `list`.
  129. InlinedVector(std::initializer_list<value_type> list,
  130. const allocator_type& allocator = allocator_type())
  131. : InlinedVector(list.begin(), list.end(), allocator) {}
  132. // Creates an inlined vector with elements constructed from the provided
  133. // forward iterator range [`first`, `last`).
  134. //
  135. // NOTE: the `enable_if` prevents ambiguous interpretation between a call to
  136. // this constructor with two integral arguments and a call to the above
  137. // `InlinedVector(size_type, const_reference)` constructor.
  138. template <typename ForwardIterator,
  139. EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
  140. InlinedVector(ForwardIterator first, ForwardIterator last,
  141. const allocator_type& allocator = allocator_type())
  142. : storage_(allocator) {
  143. storage_.Initialize(IteratorValueAdapter<A, ForwardIterator>(first),
  144. static_cast<size_t>(std::distance(first, last)));
  145. }
  146. // Creates an inlined vector with elements constructed from the provided input
  147. // iterator range [`first`, `last`).
  148. template <typename InputIterator,
  149. DisableIfAtLeastForwardIterator<InputIterator> = 0>
  150. InlinedVector(InputIterator first, InputIterator last,
  151. const allocator_type& allocator = allocator_type())
  152. : storage_(allocator) {
  153. std::copy(first, last, std::back_inserter(*this));
  154. }
  155. // Creates an inlined vector by copying the contents of `other` using
  156. // `other`'s allocator.
  157. InlinedVector(const InlinedVector& other)
  158. : InlinedVector(other, other.storage_.GetAllocator()) {}
  159. // Creates an inlined vector by copying the contents of `other` using the
  160. // provided `allocator`.
  161. InlinedVector(const InlinedVector& other, const allocator_type& allocator)
  162. : storage_(allocator) {
  163. // Fast path: if the other vector is empty, there's nothing for us to do.
  164. if (other.empty()) {
  165. return;
  166. }
  167. // Fast path: if the value type is trivially copy constructible, we know the
  168. // allocator doesn't do anything fancy, and there is nothing on the heap
  169. // then we know it is legal for us to simply memcpy the other vector's
  170. // inlined bytes to form our copy of its elements.
  171. if (absl::is_trivially_copy_constructible<value_type>::value &&
  172. std::is_same<A, std::allocator<value_type>>::value &&
  173. !other.storage_.GetIsAllocated()) {
  174. storage_.MemcpyFrom(other.storage_);
  175. return;
  176. }
  177. storage_.InitFrom(other.storage_);
  178. }
  179. // Creates an inlined vector by moving in the contents of `other` without
  180. // allocating. If `other` contains allocated memory, the newly-created inlined
  181. // vector will take ownership of that memory. However, if `other` does not
  182. // contain allocated memory, the newly-created inlined vector will perform
  183. // element-wise move construction of the contents of `other`.
  184. //
  185. // NOTE: since no allocation is performed for the inlined vector in either
  186. // case, the `noexcept(...)` specification depends on whether moving the
  187. // underlying objects can throw. It is assumed assumed that...
  188. // a) move constructors should only throw due to allocation failure.
  189. // b) if `value_type`'s move constructor allocates, it uses the same
  190. // allocation function as the inlined vector's allocator.
  191. // Thus, the move constructor is non-throwing if the allocator is non-throwing
  192. // or `value_type`'s move constructor is specified as `noexcept`.
  193. InlinedVector(InlinedVector&& other) noexcept(
  194. absl::allocator_is_nothrow<allocator_type>::value ||
  195. std::is_nothrow_move_constructible<value_type>::value)
  196. : storage_(other.storage_.GetAllocator()) {
  197. // Fast path: if the value type can be trivially relocated (i.e. moved from
  198. // and destroyed), and we know the allocator doesn't do anything fancy, then
  199. // it's safe for us to simply adopt the contents of the storage for `other`
  200. // and remove its own reference to them. It's as if we had individually
  201. // move-constructed each value and then destroyed the original.
  202. if (absl::is_trivially_relocatable<value_type>::value &&
  203. std::is_same<A, std::allocator<value_type>>::value) {
  204. storage_.MemcpyFrom(other.storage_);
  205. other.storage_.SetInlinedSize(0);
  206. return;
  207. }
  208. // Fast path: if the other vector is on the heap, we can simply take over
  209. // its allocation.
  210. if (other.storage_.GetIsAllocated()) {
  211. storage_.SetAllocation({other.storage_.GetAllocatedData(),
  212. other.storage_.GetAllocatedCapacity()});
  213. storage_.SetAllocatedSize(other.storage_.GetSize());
  214. other.storage_.SetInlinedSize(0);
  215. return;
  216. }
  217. // Otherwise we must move each element individually.
  218. IteratorValueAdapter<A, MoveIterator<A>> other_values(
  219. MoveIterator<A>(other.storage_.GetInlinedData()));
  220. inlined_vector_internal::ConstructElements<A>(
  221. storage_.GetAllocator(), storage_.GetInlinedData(), other_values,
  222. other.storage_.GetSize());
  223. storage_.SetInlinedSize(other.storage_.GetSize());
  224. }
  225. // Creates an inlined vector by moving in the contents of `other` with a copy
  226. // of `allocator`.
  227. //
  228. // NOTE: if `other`'s allocator is not equal to `allocator`, even if `other`
  229. // contains allocated memory, this move constructor will still allocate. Since
  230. // allocation is performed, this constructor can only be `noexcept` if the
  231. // specified allocator is also `noexcept`.
  232. InlinedVector(
  233. InlinedVector&& other,
  234. const allocator_type&
  235. allocator) noexcept(absl::allocator_is_nothrow<allocator_type>::value)
  236. : storage_(allocator) {
  237. // Fast path: if the value type can be trivially relocated (i.e. moved from
  238. // and destroyed), and we know the allocator doesn't do anything fancy, then
  239. // it's safe for us to simply adopt the contents of the storage for `other`
  240. // and remove its own reference to them. It's as if we had individually
  241. // move-constructed each value and then destroyed the original.
  242. if (absl::is_trivially_relocatable<value_type>::value &&
  243. std::is_same<A, std::allocator<value_type>>::value) {
  244. storage_.MemcpyFrom(other.storage_);
  245. other.storage_.SetInlinedSize(0);
  246. return;
  247. }
  248. // Fast path: if the other vector is on the heap and shared the same
  249. // allocator, we can simply take over its allocation.
  250. if ((storage_.GetAllocator() == other.storage_.GetAllocator()) &&
  251. other.storage_.GetIsAllocated()) {
  252. storage_.SetAllocation({other.storage_.GetAllocatedData(),
  253. other.storage_.GetAllocatedCapacity()});
  254. storage_.SetAllocatedSize(other.storage_.GetSize());
  255. other.storage_.SetInlinedSize(0);
  256. return;
  257. }
  258. // Otherwise we must move each element individually.
  259. storage_.Initialize(
  260. IteratorValueAdapter<A, MoveIterator<A>>(MoveIterator<A>(other.data())),
  261. other.size());
  262. }
  263. ~InlinedVector() {}
  264. // ---------------------------------------------------------------------------
  265. // InlinedVector Member Accessors
  266. // ---------------------------------------------------------------------------
  267. // `InlinedVector::empty()`
  268. //
  269. // Returns whether the inlined vector contains no elements.
  270. bool empty() const noexcept { return !size(); }
  271. // `InlinedVector::size()`
  272. //
  273. // Returns the number of elements in the inlined vector.
  274. size_type size() const noexcept { return storage_.GetSize(); }
  275. // `InlinedVector::max_size()`
  276. //
  277. // Returns the maximum number of elements the inlined vector can hold.
  278. size_type max_size() const noexcept {
  279. // One bit of the size storage is used to indicate whether the inlined
  280. // vector contains allocated memory. As a result, the maximum size that the
  281. // inlined vector can express is the minimum of the limit of how many
  282. // objects we can allocate and std::numeric_limits<size_type>::max() / 2.
  283. return (std::min)(AllocatorTraits<A>::max_size(storage_.GetAllocator()),
  284. (std::numeric_limits<size_type>::max)() / 2);
  285. }
  286. // `InlinedVector::capacity()`
  287. //
  288. // Returns the number of elements that could be stored in the inlined vector
  289. // without requiring a reallocation.
  290. //
  291. // NOTE: for most inlined vectors, `capacity()` should be equal to the
  292. // template parameter `N`. For inlined vectors which exceed this capacity,
  293. // they will no longer be inlined and `capacity()` will equal the capactity of
  294. // the allocated memory.
  295. size_type capacity() const noexcept {
  296. return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity()
  297. : storage_.GetInlinedCapacity();
  298. }
  299. // `InlinedVector::data()`
  300. //
  301. // Returns a `pointer` to the elements of the inlined vector. This pointer
  302. // can be used to access and modify the contained elements.
  303. //
  304. // NOTE: only elements within [`data()`, `data() + size()`) are valid.
  305. pointer data() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  306. return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
  307. : storage_.GetInlinedData();
  308. }
  309. // Overload of `InlinedVector::data()` that returns a `const_pointer` to the
  310. // elements of the inlined vector. This pointer can be used to access but not
  311. // modify the contained elements.
  312. //
  313. // NOTE: only elements within [`data()`, `data() + size()`) are valid.
  314. const_pointer data() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  315. return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
  316. : storage_.GetInlinedData();
  317. }
  318. // `InlinedVector::operator[](...)`
  319. //
  320. // Returns a `reference` to the `i`th element of the inlined vector.
  321. reference operator[](size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  322. ABSL_HARDENING_ASSERT(i < size());
  323. return data()[i];
  324. }
  325. // Overload of `InlinedVector::operator[](...)` that returns a
  326. // `const_reference` to the `i`th element of the inlined vector.
  327. const_reference operator[](size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
  328. ABSL_HARDENING_ASSERT(i < size());
  329. return data()[i];
  330. }
  331. // `InlinedVector::at(...)`
  332. //
  333. // Returns a `reference` to the `i`th element of the inlined vector.
  334. //
  335. // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
  336. // in both debug and non-debug builds, `std::out_of_range` will be thrown.
  337. reference at(size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  338. if (ABSL_PREDICT_FALSE(i >= size())) {
  339. base_internal::ThrowStdOutOfRange(
  340. "`InlinedVector::at(size_type)` failed bounds check");
  341. }
  342. return data()[i];
  343. }
  344. // Overload of `InlinedVector::at(...)` that returns a `const_reference` to
  345. // the `i`th element of the inlined vector.
  346. //
  347. // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
  348. // in both debug and non-debug builds, `std::out_of_range` will be thrown.
  349. const_reference at(size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
  350. if (ABSL_PREDICT_FALSE(i >= size())) {
  351. base_internal::ThrowStdOutOfRange(
  352. "`InlinedVector::at(size_type) const` failed bounds check");
  353. }
  354. return data()[i];
  355. }
  356. // `InlinedVector::front()`
  357. //
  358. // Returns a `reference` to the first element of the inlined vector.
  359. reference front() ABSL_ATTRIBUTE_LIFETIME_BOUND {
  360. ABSL_HARDENING_ASSERT(!empty());
  361. return data()[0];
  362. }
  363. // Overload of `InlinedVector::front()` that returns a `const_reference` to
  364. // the first element of the inlined vector.
  365. const_reference front() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
  366. ABSL_HARDENING_ASSERT(!empty());
  367. return data()[0];
  368. }
  369. // `InlinedVector::back()`
  370. //
  371. // Returns a `reference` to the last element of the inlined vector.
  372. reference back() ABSL_ATTRIBUTE_LIFETIME_BOUND {
  373. ABSL_HARDENING_ASSERT(!empty());
  374. return data()[size() - 1];
  375. }
  376. // Overload of `InlinedVector::back()` that returns a `const_reference` to the
  377. // last element of the inlined vector.
  378. const_reference back() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
  379. ABSL_HARDENING_ASSERT(!empty());
  380. return data()[size() - 1];
  381. }
  382. // `InlinedVector::begin()`
  383. //
  384. // Returns an `iterator` to the beginning of the inlined vector.
  385. iterator begin() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
  386. // Overload of `InlinedVector::begin()` that returns a `const_iterator` to
  387. // the beginning of the inlined vector.
  388. const_iterator begin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  389. return data();
  390. }
  391. // `InlinedVector::end()`
  392. //
  393. // Returns an `iterator` to the end of the inlined vector.
  394. iterator end() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  395. return data() + size();
  396. }
  397. // Overload of `InlinedVector::end()` that returns a `const_iterator` to the
  398. // end of the inlined vector.
  399. const_iterator end() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  400. return data() + size();
  401. }
  402. // `InlinedVector::cbegin()`
  403. //
  404. // Returns a `const_iterator` to the beginning of the inlined vector.
  405. const_iterator cbegin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  406. return begin();
  407. }
  408. // `InlinedVector::cend()`
  409. //
  410. // Returns a `const_iterator` to the end of the inlined vector.
  411. const_iterator cend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  412. return end();
  413. }
  414. // `InlinedVector::rbegin()`
  415. //
  416. // Returns a `reverse_iterator` from the end of the inlined vector.
  417. reverse_iterator rbegin() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  418. return reverse_iterator(end());
  419. }
  420. // Overload of `InlinedVector::rbegin()` that returns a
  421. // `const_reverse_iterator` from the end of the inlined vector.
  422. const_reverse_iterator rbegin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  423. return const_reverse_iterator(end());
  424. }
  425. // `InlinedVector::rend()`
  426. //
  427. // Returns a `reverse_iterator` from the beginning of the inlined vector.
  428. reverse_iterator rend() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  429. return reverse_iterator(begin());
  430. }
  431. // Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator`
  432. // from the beginning of the inlined vector.
  433. const_reverse_iterator rend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  434. return const_reverse_iterator(begin());
  435. }
  436. // `InlinedVector::crbegin()`
  437. //
  438. // Returns a `const_reverse_iterator` from the end of the inlined vector.
  439. const_reverse_iterator crbegin() const noexcept
  440. ABSL_ATTRIBUTE_LIFETIME_BOUND {
  441. return rbegin();
  442. }
  443. // `InlinedVector::crend()`
  444. //
  445. // Returns a `const_reverse_iterator` from the beginning of the inlined
  446. // vector.
  447. const_reverse_iterator crend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
  448. return rend();
  449. }
  450. // `InlinedVector::get_allocator()`
  451. //
  452. // Returns a copy of the inlined vector's allocator.
  453. allocator_type get_allocator() const { return storage_.GetAllocator(); }
  454. // ---------------------------------------------------------------------------
  455. // InlinedVector Member Mutators
  456. // ---------------------------------------------------------------------------
  457. // `InlinedVector::operator=(...)`
  458. //
  459. // Replaces the elements of the inlined vector with copies of the elements of
  460. // `list`.
  461. InlinedVector& operator=(std::initializer_list<value_type> list) {
  462. assign(list.begin(), list.end());
  463. return *this;
  464. }
  465. // Overload of `InlinedVector::operator=(...)` that replaces the elements of
  466. // the inlined vector with copies of the elements of `other`.
  467. InlinedVector& operator=(const InlinedVector& other) {
  468. if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
  469. const_pointer other_data = other.data();
  470. assign(other_data, other_data + other.size());
  471. }
  472. return *this;
  473. }
  474. // Overload of `InlinedVector::operator=(...)` that moves the elements of
  475. // `other` into the inlined vector.
  476. //
  477. // NOTE: as a result of calling this overload, `other` is left in a valid but
  478. // unspecified state.
  479. InlinedVector& operator=(InlinedVector&& other) {
  480. if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
  481. MoveAssignment(MoveAssignmentPolicy{}, std::move(other));
  482. }
  483. return *this;
  484. }
  485. // `InlinedVector::assign(...)`
  486. //
  487. // Replaces the contents of the inlined vector with `n` copies of `v`.
  488. void assign(size_type n, const_reference v) {
  489. storage_.Assign(CopyValueAdapter<A>(std::addressof(v)), n);
  490. }
  491. // Overload of `InlinedVector::assign(...)` that replaces the contents of the
  492. // inlined vector with copies of the elements of `list`.
  493. void assign(std::initializer_list<value_type> list) {
  494. assign(list.begin(), list.end());
  495. }
  496. // Overload of `InlinedVector::assign(...)` to replace the contents of the
  497. // inlined vector with the range [`first`, `last`).
  498. //
  499. // NOTE: this overload is for iterators that are "forward" category or better.
  500. template <typename ForwardIterator,
  501. EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
  502. void assign(ForwardIterator first, ForwardIterator last) {
  503. storage_.Assign(IteratorValueAdapter<A, ForwardIterator>(first),
  504. static_cast<size_t>(std::distance(first, last)));
  505. }
  506. // Overload of `InlinedVector::assign(...)` to replace the contents of the
  507. // inlined vector with the range [`first`, `last`).
  508. //
  509. // NOTE: this overload is for iterators that are "input" category.
  510. template <typename InputIterator,
  511. DisableIfAtLeastForwardIterator<InputIterator> = 0>
  512. void assign(InputIterator first, InputIterator last) {
  513. size_type i = 0;
  514. for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
  515. data()[i] = *first;
  516. }
  517. erase(data() + i, data() + size());
  518. std::copy(first, last, std::back_inserter(*this));
  519. }
  520. // `InlinedVector::resize(...)`
  521. //
  522. // Resizes the inlined vector to contain `n` elements.
  523. //
  524. // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
  525. // is larger than `size()`, new elements are value-initialized.
  526. void resize(size_type n) {
  527. ABSL_HARDENING_ASSERT(n <= max_size());
  528. storage_.Resize(DefaultValueAdapter<A>(), n);
  529. }
  530. // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
  531. // contain `n` elements.
  532. //
  533. // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
  534. // is larger than `size()`, new elements are copied-constructed from `v`.
  535. void resize(size_type n, const_reference v) {
  536. ABSL_HARDENING_ASSERT(n <= max_size());
  537. storage_.Resize(CopyValueAdapter<A>(std::addressof(v)), n);
  538. }
  539. // `InlinedVector::insert(...)`
  540. //
  541. // Inserts a copy of `v` at `pos`, returning an `iterator` to the newly
  542. // inserted element.
  543. iterator insert(const_iterator pos,
  544. const_reference v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  545. return emplace(pos, v);
  546. }
  547. // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
  548. // move semantics, returning an `iterator` to the newly inserted element.
  549. iterator insert(const_iterator pos,
  550. value_type&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  551. return emplace(pos, std::move(v));
  552. }
  553. // Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies
  554. // of `v` starting at `pos`, returning an `iterator` pointing to the first of
  555. // the newly inserted elements.
  556. iterator insert(const_iterator pos, size_type n,
  557. const_reference v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  558. ABSL_HARDENING_ASSERT(pos >= begin());
  559. ABSL_HARDENING_ASSERT(pos <= end());
  560. if (ABSL_PREDICT_TRUE(n != 0)) {
  561. value_type dealias = v;
  562. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2
  563. // It appears that GCC thinks that since `pos` is a const pointer and may
  564. // point to uninitialized memory at this point, a warning should be
  565. // issued. But `pos` is actually only used to compute an array index to
  566. // write to.
  567. #if !defined(__clang__) && defined(__GNUC__)
  568. #pragma GCC diagnostic push
  569. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  570. #endif
  571. return storage_.Insert(pos, CopyValueAdapter<A>(std::addressof(dealias)),
  572. n);
  573. #if !defined(__clang__) && defined(__GNUC__)
  574. #pragma GCC diagnostic pop
  575. #endif
  576. } else {
  577. return const_cast<iterator>(pos);
  578. }
  579. }
  580. // Overload of `InlinedVector::insert(...)` that inserts copies of the
  581. // elements of `list` starting at `pos`, returning an `iterator` pointing to
  582. // the first of the newly inserted elements.
  583. iterator insert(const_iterator pos, std::initializer_list<value_type> list)
  584. ABSL_ATTRIBUTE_LIFETIME_BOUND {
  585. return insert(pos, list.begin(), list.end());
  586. }
  587. // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
  588. // `last`) starting at `pos`, returning an `iterator` pointing to the first
  589. // of the newly inserted elements.
  590. //
  591. // NOTE: this overload is for iterators that are "forward" category or better.
  592. template <typename ForwardIterator,
  593. EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
  594. iterator insert(const_iterator pos, ForwardIterator first,
  595. ForwardIterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  596. ABSL_HARDENING_ASSERT(pos >= begin());
  597. ABSL_HARDENING_ASSERT(pos <= end());
  598. if (ABSL_PREDICT_TRUE(first != last)) {
  599. return storage_.Insert(
  600. pos, IteratorValueAdapter<A, ForwardIterator>(first),
  601. static_cast<size_type>(std::distance(first, last)));
  602. } else {
  603. return const_cast<iterator>(pos);
  604. }
  605. }
  606. // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
  607. // `last`) starting at `pos`, returning an `iterator` pointing to the first
  608. // of the newly inserted elements.
  609. //
  610. // NOTE: this overload is for iterators that are "input" category.
  611. template <typename InputIterator,
  612. DisableIfAtLeastForwardIterator<InputIterator> = 0>
  613. iterator insert(const_iterator pos, InputIterator first,
  614. InputIterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  615. ABSL_HARDENING_ASSERT(pos >= begin());
  616. ABSL_HARDENING_ASSERT(pos <= end());
  617. size_type index = static_cast<size_type>(std::distance(cbegin(), pos));
  618. for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
  619. insert(data() + i, *first);
  620. }
  621. return iterator(data() + index);
  622. }
  623. // `InlinedVector::emplace(...)`
  624. //
  625. // Constructs and inserts an element using `args...` in the inlined vector at
  626. // `pos`, returning an `iterator` pointing to the newly emplaced element.
  627. template <typename... Args>
  628. iterator emplace(const_iterator pos,
  629. Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  630. ABSL_HARDENING_ASSERT(pos >= begin());
  631. ABSL_HARDENING_ASSERT(pos <= end());
  632. value_type dealias(std::forward<Args>(args)...);
  633. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2
  634. // It appears that GCC thinks that since `pos` is a const pointer and may
  635. // point to uninitialized memory at this point, a warning should be
  636. // issued. But `pos` is actually only used to compute an array index to
  637. // write to.
  638. #if !defined(__clang__) && defined(__GNUC__)
  639. #pragma GCC diagnostic push
  640. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  641. #endif
  642. return storage_.Insert(pos,
  643. IteratorValueAdapter<A, MoveIterator<A>>(
  644. MoveIterator<A>(std::addressof(dealias))),
  645. 1);
  646. #if !defined(__clang__) && defined(__GNUC__)
  647. #pragma GCC diagnostic pop
  648. #endif
  649. }
  650. // `InlinedVector::emplace_back(...)`
  651. //
  652. // Constructs and inserts an element using `args...` in the inlined vector at
  653. // `end()`, returning a `reference` to the newly emplaced element.
  654. template <typename... Args>
  655. reference emplace_back(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  656. return storage_.EmplaceBack(std::forward<Args>(args)...);
  657. }
  658. // `InlinedVector::push_back(...)`
  659. //
  660. // Inserts a copy of `v` in the inlined vector at `end()`.
  661. void push_back(const_reference v) { static_cast<void>(emplace_back(v)); }
  662. // Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
  663. // using move semantics.
  664. void push_back(value_type&& v) {
  665. static_cast<void>(emplace_back(std::move(v)));
  666. }
  667. // `InlinedVector::pop_back()`
  668. //
  669. // Destroys the element at `back()`, reducing the size by `1`.
  670. void pop_back() noexcept {
  671. ABSL_HARDENING_ASSERT(!empty());
  672. AllocatorTraits<A>::destroy(storage_.GetAllocator(), data() + (size() - 1));
  673. storage_.SubtractSize(1);
  674. }
  675. // `InlinedVector::erase(...)`
  676. //
  677. // Erases the element at `pos`, returning an `iterator` pointing to where the
  678. // erased element was located.
  679. //
  680. // NOTE: may return `end()`, which is not dereferenceable.
  681. iterator erase(const_iterator pos) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  682. ABSL_HARDENING_ASSERT(pos >= begin());
  683. ABSL_HARDENING_ASSERT(pos < end());
  684. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2
  685. // It appears that GCC thinks that since `pos` is a const pointer and may
  686. // point to uninitialized memory at this point, a warning should be
  687. // issued. But `pos` is actually only used to compute an array index to
  688. // write to.
  689. #if !defined(__clang__) && defined(__GNUC__)
  690. #pragma GCC diagnostic push
  691. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  692. #pragma GCC diagnostic ignored "-Wuninitialized"
  693. #endif
  694. return storage_.Erase(pos, pos + 1);
  695. #if !defined(__clang__) && defined(__GNUC__)
  696. #pragma GCC diagnostic pop
  697. #endif
  698. }
  699. // Overload of `InlinedVector::erase(...)` that erases every element in the
  700. // range [`from`, `to`), returning an `iterator` pointing to where the first
  701. // erased element was located.
  702. //
  703. // NOTE: may return `end()`, which is not dereferenceable.
  704. iterator erase(const_iterator from,
  705. const_iterator to) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  706. ABSL_HARDENING_ASSERT(from >= begin());
  707. ABSL_HARDENING_ASSERT(from <= to);
  708. ABSL_HARDENING_ASSERT(to <= end());
  709. if (ABSL_PREDICT_TRUE(from != to)) {
  710. return storage_.Erase(from, to);
  711. } else {
  712. return const_cast<iterator>(from);
  713. }
  714. }
  715. // `InlinedVector::clear()`
  716. //
  717. // Destroys all elements in the inlined vector, setting the size to `0` and
  718. // deallocating any held memory.
  719. void clear() noexcept {
  720. inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
  721. storage_.GetAllocator(), data(), size());
  722. storage_.DeallocateIfAllocated();
  723. storage_.SetInlinedSize(0);
  724. }
  725. // `InlinedVector::reserve(...)`
  726. //
  727. // Ensures that there is enough room for at least `n` elements.
  728. void reserve(size_type n) { storage_.Reserve(n); }
  729. // `InlinedVector::shrink_to_fit()`
  730. //
  731. // Attempts to reduce memory usage by moving elements to (or keeping elements
  732. // in) the smallest available buffer sufficient for containing `size()`
  733. // elements.
  734. //
  735. // If `size()` is sufficiently small, the elements will be moved into (or kept
  736. // in) the inlined space.
  737. void shrink_to_fit() {
  738. if (storage_.GetIsAllocated()) {
  739. storage_.ShrinkToFit();
  740. }
  741. }
  742. // `InlinedVector::swap(...)`
  743. //
  744. // Swaps the contents of the inlined vector with `other`.
  745. void swap(InlinedVector& other) {
  746. if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
  747. storage_.Swap(std::addressof(other.storage_));
  748. }
  749. }
  750. private:
  751. template <typename H, typename TheT, size_t TheN, typename TheA>
  752. friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
  753. void MoveAssignment(MemcpyPolicy, InlinedVector&& other) {
  754. // Assumption check: we shouldn't be told to use memcpy to implement move
  755. // assignment unless we have trivially destructible elements and an
  756. // allocator that does nothing fancy.
  757. static_assert(absl::is_trivially_destructible<value_type>::value, "");
  758. static_assert(std::is_same<A, std::allocator<value_type>>::value, "");
  759. // Throw away our existing heap allocation, if any. There is no need to
  760. // destroy the existing elements one by one because we know they are
  761. // trivially destructible.
  762. storage_.DeallocateIfAllocated();
  763. // Adopt the other vector's inline elements or heap allocation.
  764. storage_.MemcpyFrom(other.storage_);
  765. other.storage_.SetInlinedSize(0);
  766. }
  767. // Destroy our existing elements, if any, and adopt the heap-allocated
  768. // elements of the other vector.
  769. //
  770. // REQUIRES: other.storage_.GetIsAllocated()
  771. void DestroyExistingAndAdopt(InlinedVector&& other) {
  772. ABSL_HARDENING_ASSERT(other.storage_.GetIsAllocated());
  773. inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
  774. storage_.GetAllocator(), data(), size());
  775. storage_.DeallocateIfAllocated();
  776. storage_.MemcpyFrom(other.storage_);
  777. other.storage_.SetInlinedSize(0);
  778. }
  779. void MoveAssignment(ElementwiseAssignPolicy, InlinedVector&& other) {
  780. // Fast path: if the other vector is on the heap then we don't worry about
  781. // actually move-assigning each element. Instead we only throw away our own
  782. // existing elements and adopt the heap allocation of the other vector.
  783. if (other.storage_.GetIsAllocated()) {
  784. DestroyExistingAndAdopt(std::move(other));
  785. return;
  786. }
  787. storage_.Assign(IteratorValueAdapter<A, MoveIterator<A>>(
  788. MoveIterator<A>(other.storage_.GetInlinedData())),
  789. other.size());
  790. }
  791. void MoveAssignment(ElementwiseConstructPolicy, InlinedVector&& other) {
  792. // Fast path: if the other vector is on the heap then we don't worry about
  793. // actually move-assigning each element. Instead we only throw away our own
  794. // existing elements and adopt the heap allocation of the other vector.
  795. if (other.storage_.GetIsAllocated()) {
  796. DestroyExistingAndAdopt(std::move(other));
  797. return;
  798. }
  799. inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
  800. storage_.GetAllocator(), data(), size());
  801. storage_.DeallocateIfAllocated();
  802. IteratorValueAdapter<A, MoveIterator<A>> other_values(
  803. MoveIterator<A>(other.storage_.GetInlinedData()));
  804. inlined_vector_internal::ConstructElements<A>(
  805. storage_.GetAllocator(), storage_.GetInlinedData(), other_values,
  806. other.storage_.GetSize());
  807. storage_.SetInlinedSize(other.storage_.GetSize());
  808. }
  809. Storage storage_;
  810. };
  811. // -----------------------------------------------------------------------------
  812. // InlinedVector Non-Member Functions
  813. // -----------------------------------------------------------------------------
  814. // `swap(...)`
  815. //
  816. // Swaps the contents of two inlined vectors.
  817. template <typename T, size_t N, typename A>
  818. void swap(absl::InlinedVector<T, N, A>& a,
  819. absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
  820. a.swap(b);
  821. }
  822. // `operator==(...)`
  823. //
  824. // Tests for value-equality of two inlined vectors.
  825. template <typename T, size_t N, typename A>
  826. bool operator==(const absl::InlinedVector<T, N, A>& a,
  827. const absl::InlinedVector<T, N, A>& b) {
  828. auto a_data = a.data();
  829. auto b_data = b.data();
  830. return std::equal(a_data, a_data + a.size(), b_data, b_data + b.size());
  831. }
  832. // `operator!=(...)`
  833. //
  834. // Tests for value-inequality of two inlined vectors.
  835. template <typename T, size_t N, typename A>
  836. bool operator!=(const absl::InlinedVector<T, N, A>& a,
  837. const absl::InlinedVector<T, N, A>& b) {
  838. return !(a == b);
  839. }
  840. // `operator<(...)`
  841. //
  842. // Tests whether the value of an inlined vector is less than the value of
  843. // another inlined vector using a lexicographical comparison algorithm.
  844. template <typename T, size_t N, typename A>
  845. bool operator<(const absl::InlinedVector<T, N, A>& a,
  846. const absl::InlinedVector<T, N, A>& b) {
  847. auto a_data = a.data();
  848. auto b_data = b.data();
  849. return std::lexicographical_compare(a_data, a_data + a.size(), b_data,
  850. b_data + b.size());
  851. }
  852. // `operator>(...)`
  853. //
  854. // Tests whether the value of an inlined vector is greater than the value of
  855. // another inlined vector using a lexicographical comparison algorithm.
  856. template <typename T, size_t N, typename A>
  857. bool operator>(const absl::InlinedVector<T, N, A>& a,
  858. const absl::InlinedVector<T, N, A>& b) {
  859. return b < a;
  860. }
  861. // `operator<=(...)`
  862. //
  863. // Tests whether the value of an inlined vector is less than or equal to the
  864. // value of another inlined vector using a lexicographical comparison algorithm.
  865. template <typename T, size_t N, typename A>
  866. bool operator<=(const absl::InlinedVector<T, N, A>& a,
  867. const absl::InlinedVector<T, N, A>& b) {
  868. return !(b < a);
  869. }
  870. // `operator>=(...)`
  871. //
  872. // Tests whether the value of an inlined vector is greater than or equal to the
  873. // value of another inlined vector using a lexicographical comparison algorithm.
  874. template <typename T, size_t N, typename A>
  875. bool operator>=(const absl::InlinedVector<T, N, A>& a,
  876. const absl::InlinedVector<T, N, A>& b) {
  877. return !(a < b);
  878. }
  879. // `AbslHashValue(...)`
  880. //
  881. // Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to
  882. // call this directly.
  883. template <typename H, typename T, size_t N, typename A>
  884. H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
  885. auto size = a.size();
  886. return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
  887. }
  888. ABSL_NAMESPACE_END
  889. } // namespace absl
  890. #endif // ABSL_CONTAINER_INLINED_VECTOR_H_