inlined_vector.h 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  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. return storage_.Erase(pos, pos + 1);
  685. }
  686. // Overload of `InlinedVector::erase(...)` that erases every element in the
  687. // range [`from`, `to`), returning an `iterator` pointing to where the first
  688. // erased element was located.
  689. //
  690. // NOTE: may return `end()`, which is not dereferenceable.
  691. iterator erase(const_iterator from,
  692. const_iterator to) ABSL_ATTRIBUTE_LIFETIME_BOUND {
  693. ABSL_HARDENING_ASSERT(from >= begin());
  694. ABSL_HARDENING_ASSERT(from <= to);
  695. ABSL_HARDENING_ASSERT(to <= end());
  696. if (ABSL_PREDICT_TRUE(from != to)) {
  697. return storage_.Erase(from, to);
  698. } else {
  699. return const_cast<iterator>(from);
  700. }
  701. }
  702. // `InlinedVector::clear()`
  703. //
  704. // Destroys all elements in the inlined vector, setting the size to `0` and
  705. // deallocating any held memory.
  706. void clear() noexcept {
  707. inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
  708. storage_.GetAllocator(), data(), size());
  709. storage_.DeallocateIfAllocated();
  710. storage_.SetInlinedSize(0);
  711. }
  712. // `InlinedVector::reserve(...)`
  713. //
  714. // Ensures that there is enough room for at least `n` elements.
  715. void reserve(size_type n) { storage_.Reserve(n); }
  716. // `InlinedVector::shrink_to_fit()`
  717. //
  718. // Attempts to reduce memory usage by moving elements to (or keeping elements
  719. // in) the smallest available buffer sufficient for containing `size()`
  720. // elements.
  721. //
  722. // If `size()` is sufficiently small, the elements will be moved into (or kept
  723. // in) the inlined space.
  724. void shrink_to_fit() {
  725. if (storage_.GetIsAllocated()) {
  726. storage_.ShrinkToFit();
  727. }
  728. }
  729. // `InlinedVector::swap(...)`
  730. //
  731. // Swaps the contents of the inlined vector with `other`.
  732. void swap(InlinedVector& other) {
  733. if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
  734. storage_.Swap(std::addressof(other.storage_));
  735. }
  736. }
  737. private:
  738. template <typename H, typename TheT, size_t TheN, typename TheA>
  739. friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
  740. void MoveAssignment(MemcpyPolicy, InlinedVector&& other) {
  741. // Assumption check: we shouldn't be told to use memcpy to implement move
  742. // assignment unless we have trivially destructible elements and an
  743. // allocator that does nothing fancy.
  744. static_assert(absl::is_trivially_destructible<value_type>::value, "");
  745. static_assert(std::is_same<A, std::allocator<value_type>>::value, "");
  746. // Throw away our existing heap allocation, if any. There is no need to
  747. // destroy the existing elements one by one because we know they are
  748. // trivially destructible.
  749. storage_.DeallocateIfAllocated();
  750. // Adopt the other vector's inline elements or heap allocation.
  751. storage_.MemcpyFrom(other.storage_);
  752. other.storage_.SetInlinedSize(0);
  753. }
  754. // Destroy our existing elements, if any, and adopt the heap-allocated
  755. // elements of the other vector.
  756. //
  757. // REQUIRES: other.storage_.GetIsAllocated()
  758. void DestroyExistingAndAdopt(InlinedVector&& other) {
  759. ABSL_HARDENING_ASSERT(other.storage_.GetIsAllocated());
  760. inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
  761. storage_.GetAllocator(), data(), size());
  762. storage_.DeallocateIfAllocated();
  763. storage_.MemcpyFrom(other.storage_);
  764. other.storage_.SetInlinedSize(0);
  765. }
  766. void MoveAssignment(ElementwiseAssignPolicy, InlinedVector&& other) {
  767. // Fast path: if the other vector is on the heap then we don't worry about
  768. // actually move-assigning each element. Instead we only throw away our own
  769. // existing elements and adopt the heap allocation of the other vector.
  770. if (other.storage_.GetIsAllocated()) {
  771. DestroyExistingAndAdopt(std::move(other));
  772. return;
  773. }
  774. storage_.Assign(IteratorValueAdapter<A, MoveIterator<A>>(
  775. MoveIterator<A>(other.storage_.GetInlinedData())),
  776. other.size());
  777. }
  778. void MoveAssignment(ElementwiseConstructPolicy, InlinedVector&& other) {
  779. // Fast path: if the other vector is on the heap then we don't worry about
  780. // actually move-assigning each element. Instead we only throw away our own
  781. // existing elements and adopt the heap allocation of the other vector.
  782. if (other.storage_.GetIsAllocated()) {
  783. DestroyExistingAndAdopt(std::move(other));
  784. return;
  785. }
  786. inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
  787. storage_.GetAllocator(), data(), size());
  788. storage_.DeallocateIfAllocated();
  789. IteratorValueAdapter<A, MoveIterator<A>> other_values(
  790. MoveIterator<A>(other.storage_.GetInlinedData()));
  791. inlined_vector_internal::ConstructElements<A>(
  792. storage_.GetAllocator(), storage_.GetInlinedData(), other_values,
  793. other.storage_.GetSize());
  794. storage_.SetInlinedSize(other.storage_.GetSize());
  795. }
  796. Storage storage_;
  797. };
  798. // -----------------------------------------------------------------------------
  799. // InlinedVector Non-Member Functions
  800. // -----------------------------------------------------------------------------
  801. // `swap(...)`
  802. //
  803. // Swaps the contents of two inlined vectors.
  804. template <typename T, size_t N, typename A>
  805. void swap(absl::InlinedVector<T, N, A>& a,
  806. absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
  807. a.swap(b);
  808. }
  809. // `operator==(...)`
  810. //
  811. // Tests for value-equality of two inlined vectors.
  812. template <typename T, size_t N, typename A>
  813. bool operator==(const absl::InlinedVector<T, N, A>& a,
  814. const absl::InlinedVector<T, N, A>& b) {
  815. auto a_data = a.data();
  816. auto b_data = b.data();
  817. return std::equal(a_data, a_data + a.size(), b_data, b_data + b.size());
  818. }
  819. // `operator!=(...)`
  820. //
  821. // Tests for value-inequality of two inlined vectors.
  822. template <typename T, size_t N, typename A>
  823. bool operator!=(const absl::InlinedVector<T, N, A>& a,
  824. const absl::InlinedVector<T, N, A>& b) {
  825. return !(a == b);
  826. }
  827. // `operator<(...)`
  828. //
  829. // Tests whether the value of an inlined vector is less than the value of
  830. // another inlined vector using a lexicographical comparison algorithm.
  831. template <typename T, size_t N, typename A>
  832. bool operator<(const absl::InlinedVector<T, N, A>& a,
  833. const absl::InlinedVector<T, N, A>& b) {
  834. auto a_data = a.data();
  835. auto b_data = b.data();
  836. return std::lexicographical_compare(a_data, a_data + a.size(), b_data,
  837. b_data + b.size());
  838. }
  839. // `operator>(...)`
  840. //
  841. // Tests whether the value of an inlined vector is greater than the value of
  842. // another inlined vector using a lexicographical comparison algorithm.
  843. template <typename T, size_t N, typename A>
  844. bool operator>(const absl::InlinedVector<T, N, A>& a,
  845. const absl::InlinedVector<T, N, A>& b) {
  846. return b < a;
  847. }
  848. // `operator<=(...)`
  849. //
  850. // Tests whether the value of an inlined vector is less than or equal to the
  851. // value of another inlined vector using a lexicographical comparison algorithm.
  852. template <typename T, size_t N, typename A>
  853. bool operator<=(const absl::InlinedVector<T, N, A>& a,
  854. const absl::InlinedVector<T, N, A>& b) {
  855. return !(b < a);
  856. }
  857. // `operator>=(...)`
  858. //
  859. // Tests whether the value of an inlined vector is greater than or equal to the
  860. // value of another inlined vector using a lexicographical comparison algorithm.
  861. template <typename T, size_t N, typename A>
  862. bool operator>=(const absl::InlinedVector<T, N, A>& a,
  863. const absl::InlinedVector<T, N, A>& b) {
  864. return !(a < b);
  865. }
  866. // `AbslHashValue(...)`
  867. //
  868. // Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to
  869. // call this directly.
  870. template <typename H, typename T, size_t N, typename A>
  871. H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
  872. auto size = a.size();
  873. return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
  874. }
  875. ABSL_NAMESPACE_END
  876. } // namespace absl
  877. #endif // ABSL_CONTAINER_INLINED_VECTOR_H_