inlined_vector.h 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  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 <cassert>
  38. #include <cstddef>
  39. #include <cstdlib>
  40. #include <cstring>
  41. #include <initializer_list>
  42. #include <iterator>
  43. #include <memory>
  44. #include <type_traits>
  45. #include <utility>
  46. #include "absl/algorithm/algorithm.h"
  47. #include "absl/base/internal/throw_delegate.h"
  48. #include "absl/base/macros.h"
  49. #include "absl/base/optimization.h"
  50. #include "absl/base/port.h"
  51. #include "absl/container/internal/inlined_vector.h"
  52. #include "absl/memory/memory.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 IsMemcpyOk = inlined_vector_internal::IsMemcpyOk<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. public:
  90. using allocator_type = A;
  91. using value_type = inlined_vector_internal::ValueType<A>;
  92. using pointer = inlined_vector_internal::Pointer<A>;
  93. using const_pointer = inlined_vector_internal::ConstPointer<A>;
  94. using size_type = inlined_vector_internal::SizeType<A>;
  95. using difference_type = inlined_vector_internal::DifferenceType<A>;
  96. using reference = inlined_vector_internal::Reference<A>;
  97. using const_reference = inlined_vector_internal::ConstReference<A>;
  98. using iterator = inlined_vector_internal::Iterator<A>;
  99. using const_iterator = inlined_vector_internal::ConstIterator<A>;
  100. using reverse_iterator = inlined_vector_internal::ReverseIterator<A>;
  101. using const_reverse_iterator =
  102. inlined_vector_internal::ConstReverseIterator<A>;
  103. // ---------------------------------------------------------------------------
  104. // InlinedVector Constructors and Destructor
  105. // ---------------------------------------------------------------------------
  106. // Creates an empty inlined vector with a value-initialized allocator.
  107. InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {}
  108. // Creates an empty inlined vector with a copy of `allocator`.
  109. explicit InlinedVector(const allocator_type& allocator) noexcept
  110. : storage_(allocator) {}
  111. // Creates an inlined vector with `n` copies of `value_type()`.
  112. explicit InlinedVector(size_type n,
  113. const allocator_type& allocator = allocator_type())
  114. : storage_(allocator) {
  115. storage_.Initialize(DefaultValueAdapter<A>(), n);
  116. }
  117. // Creates an inlined vector with `n` copies of `v`.
  118. InlinedVector(size_type n, const_reference v,
  119. const allocator_type& allocator = allocator_type())
  120. : storage_(allocator) {
  121. storage_.Initialize(CopyValueAdapter<A>(std::addressof(v)), n);
  122. }
  123. // Creates an inlined vector with copies of the elements of `list`.
  124. InlinedVector(std::initializer_list<value_type> list,
  125. const allocator_type& allocator = allocator_type())
  126. : InlinedVector(list.begin(), list.end(), allocator) {}
  127. // Creates an inlined vector with elements constructed from the provided
  128. // forward iterator range [`first`, `last`).
  129. //
  130. // NOTE: the `enable_if` prevents ambiguous interpretation between a call to
  131. // this constructor with two integral arguments and a call to the above
  132. // `InlinedVector(size_type, const_reference)` constructor.
  133. template <typename ForwardIterator,
  134. EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
  135. InlinedVector(ForwardIterator first, ForwardIterator last,
  136. const allocator_type& allocator = allocator_type())
  137. : storage_(allocator) {
  138. storage_.Initialize(IteratorValueAdapter<A, ForwardIterator>(first),
  139. std::distance(first, last));
  140. }
  141. // Creates an inlined vector with elements constructed from the provided input
  142. // iterator range [`first`, `last`).
  143. template <typename InputIterator,
  144. DisableIfAtLeastForwardIterator<InputIterator> = 0>
  145. InlinedVector(InputIterator first, InputIterator last,
  146. const allocator_type& allocator = allocator_type())
  147. : storage_(allocator) {
  148. std::copy(first, last, std::back_inserter(*this));
  149. }
  150. // Creates an inlined vector by copying the contents of `other` using
  151. // `other`'s allocator.
  152. InlinedVector(const InlinedVector& other)
  153. : InlinedVector(other, other.storage_.GetAllocator()) {}
  154. // Creates an inlined vector by copying the contents of `other` using the
  155. // provided `allocator`.
  156. InlinedVector(const InlinedVector& other, const allocator_type& allocator)
  157. : storage_(allocator) {
  158. if (other.empty()) {
  159. // Empty; nothing to do.
  160. } else if (IsMemcpyOk<A>::value && !other.storage_.GetIsAllocated()) {
  161. // Memcpy-able and do not need allocation.
  162. storage_.MemcpyFrom(other.storage_);
  163. } else {
  164. storage_.InitFrom(other.storage_);
  165. }
  166. }
  167. // Creates an inlined vector by moving in the contents of `other` without
  168. // allocating. If `other` contains allocated memory, the newly-created inlined
  169. // vector will take ownership of that memory. However, if `other` does not
  170. // contain allocated memory, the newly-created inlined vector will perform
  171. // element-wise move construction of the contents of `other`.
  172. //
  173. // NOTE: since no allocation is performed for the inlined vector in either
  174. // case, the `noexcept(...)` specification depends on whether moving the
  175. // underlying objects can throw. It is assumed assumed that...
  176. // a) move constructors should only throw due to allocation failure.
  177. // b) if `value_type`'s move constructor allocates, it uses the same
  178. // allocation function as the inlined vector's allocator.
  179. // Thus, the move constructor is non-throwing if the allocator is non-throwing
  180. // or `value_type`'s move constructor is specified as `noexcept`.
  181. InlinedVector(InlinedVector&& other) noexcept(
  182. absl::allocator_is_nothrow<allocator_type>::value ||
  183. std::is_nothrow_move_constructible<value_type>::value)
  184. : storage_(other.storage_.GetAllocator()) {
  185. if (IsMemcpyOk<A>::value) {
  186. storage_.MemcpyFrom(other.storage_);
  187. other.storage_.SetInlinedSize(0);
  188. } else if (other.storage_.GetIsAllocated()) {
  189. storage_.SetAllocation({other.storage_.GetAllocatedData(),
  190. other.storage_.GetAllocatedCapacity()});
  191. storage_.SetAllocatedSize(other.storage_.GetSize());
  192. other.storage_.SetInlinedSize(0);
  193. } else {
  194. IteratorValueAdapter<A, MoveIterator<A>> other_values(
  195. MoveIterator<A>(other.storage_.GetInlinedData()));
  196. inlined_vector_internal::ConstructElements<A>(
  197. storage_.GetAllocator(), storage_.GetInlinedData(), other_values,
  198. other.storage_.GetSize());
  199. storage_.SetInlinedSize(other.storage_.GetSize());
  200. }
  201. }
  202. // Creates an inlined vector by moving in the contents of `other` with a copy
  203. // of `allocator`.
  204. //
  205. // NOTE: if `other`'s allocator is not equal to `allocator`, even if `other`
  206. // contains allocated memory, this move constructor will still allocate. Since
  207. // allocation is performed, this constructor can only be `noexcept` if the
  208. // specified allocator is also `noexcept`.
  209. InlinedVector(
  210. InlinedVector&& other,
  211. const allocator_type& allocator)
  212. noexcept(absl::allocator_is_nothrow<allocator_type>::value)
  213. : storage_(allocator) {
  214. if (IsMemcpyOk<A>::value) {
  215. storage_.MemcpyFrom(other.storage_);
  216. other.storage_.SetInlinedSize(0);
  217. } else if ((storage_.GetAllocator() == other.storage_.GetAllocator()) &&
  218. other.storage_.GetIsAllocated()) {
  219. storage_.SetAllocation({other.storage_.GetAllocatedData(),
  220. other.storage_.GetAllocatedCapacity()});
  221. storage_.SetAllocatedSize(other.storage_.GetSize());
  222. other.storage_.SetInlinedSize(0);
  223. } else {
  224. storage_.Initialize(IteratorValueAdapter<A, MoveIterator<A>>(
  225. MoveIterator<A>(other.data())),
  226. other.size());
  227. }
  228. }
  229. ~InlinedVector() {}
  230. // ---------------------------------------------------------------------------
  231. // InlinedVector Member Accessors
  232. // ---------------------------------------------------------------------------
  233. // `InlinedVector::empty()`
  234. //
  235. // Returns whether the inlined vector contains no elements.
  236. bool empty() const noexcept { return !size(); }
  237. // `InlinedVector::size()`
  238. //
  239. // Returns the number of elements in the inlined vector.
  240. size_type size() const noexcept { return storage_.GetSize(); }
  241. // `InlinedVector::max_size()`
  242. //
  243. // Returns the maximum number of elements the inlined vector can hold.
  244. size_type max_size() const noexcept {
  245. // One bit of the size storage is used to indicate whether the inlined
  246. // vector contains allocated memory. As a result, the maximum size that the
  247. // inlined vector can express is half of the max for `size_type`.
  248. return (std::numeric_limits<size_type>::max)() / 2;
  249. }
  250. // `InlinedVector::capacity()`
  251. //
  252. // Returns the number of elements that could be stored in the inlined vector
  253. // without requiring a reallocation.
  254. //
  255. // NOTE: for most inlined vectors, `capacity()` should be equal to the
  256. // template parameter `N`. For inlined vectors which exceed this capacity,
  257. // they will no longer be inlined and `capacity()` will equal the capactity of
  258. // the allocated memory.
  259. size_type capacity() const noexcept {
  260. return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity()
  261. : storage_.GetInlinedCapacity();
  262. }
  263. // `InlinedVector::data()`
  264. //
  265. // Returns a `pointer` to the elements of the inlined vector. This pointer
  266. // can be used to access and modify the contained elements.
  267. //
  268. // NOTE: only elements within [`data()`, `data() + size()`) are valid.
  269. pointer data() noexcept {
  270. return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
  271. : storage_.GetInlinedData();
  272. }
  273. // Overload of `InlinedVector::data()` that returns a `const_pointer` to the
  274. // elements of the inlined vector. This pointer can be used to access but not
  275. // modify the contained elements.
  276. //
  277. // NOTE: only elements within [`data()`, `data() + size()`) are valid.
  278. const_pointer data() const noexcept {
  279. return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
  280. : storage_.GetInlinedData();
  281. }
  282. // `InlinedVector::operator[](...)`
  283. //
  284. // Returns a `reference` to the `i`th element of the inlined vector.
  285. reference operator[](size_type i) {
  286. ABSL_HARDENING_ASSERT(i < size());
  287. return data()[i];
  288. }
  289. // Overload of `InlinedVector::operator[](...)` that returns a
  290. // `const_reference` to the `i`th element of the inlined vector.
  291. const_reference operator[](size_type i) const {
  292. ABSL_HARDENING_ASSERT(i < size());
  293. return data()[i];
  294. }
  295. // `InlinedVector::at(...)`
  296. //
  297. // Returns a `reference` to the `i`th element of the inlined vector.
  298. //
  299. // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
  300. // in both debug and non-debug builds, `std::out_of_range` will be thrown.
  301. reference at(size_type i) {
  302. if (ABSL_PREDICT_FALSE(i >= size())) {
  303. base_internal::ThrowStdOutOfRange(
  304. "`InlinedVector::at(size_type)` failed bounds check");
  305. }
  306. return data()[i];
  307. }
  308. // Overload of `InlinedVector::at(...)` that returns a `const_reference` to
  309. // the `i`th element of the inlined vector.
  310. //
  311. // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
  312. // in both debug and non-debug builds, `std::out_of_range` will be thrown.
  313. const_reference at(size_type i) const {
  314. if (ABSL_PREDICT_FALSE(i >= size())) {
  315. base_internal::ThrowStdOutOfRange(
  316. "`InlinedVector::at(size_type) const` failed bounds check");
  317. }
  318. return data()[i];
  319. }
  320. // `InlinedVector::front()`
  321. //
  322. // Returns a `reference` to the first element of the inlined vector.
  323. reference front() {
  324. ABSL_HARDENING_ASSERT(!empty());
  325. return data()[0];
  326. }
  327. // Overload of `InlinedVector::front()` that returns a `const_reference` to
  328. // the first element of the inlined vector.
  329. const_reference front() const {
  330. ABSL_HARDENING_ASSERT(!empty());
  331. return data()[0];
  332. }
  333. // `InlinedVector::back()`
  334. //
  335. // Returns a `reference` to the last element of the inlined vector.
  336. reference back() {
  337. ABSL_HARDENING_ASSERT(!empty());
  338. return data()[size() - 1];
  339. }
  340. // Overload of `InlinedVector::back()` that returns a `const_reference` to the
  341. // last element of the inlined vector.
  342. const_reference back() const {
  343. ABSL_HARDENING_ASSERT(!empty());
  344. return data()[size() - 1];
  345. }
  346. // `InlinedVector::begin()`
  347. //
  348. // Returns an `iterator` to the beginning of the inlined vector.
  349. iterator begin() noexcept { return data(); }
  350. // Overload of `InlinedVector::begin()` that returns a `const_iterator` to
  351. // the beginning of the inlined vector.
  352. const_iterator begin() const noexcept { return data(); }
  353. // `InlinedVector::end()`
  354. //
  355. // Returns an `iterator` to the end of the inlined vector.
  356. iterator end() noexcept { return data() + size(); }
  357. // Overload of `InlinedVector::end()` that returns a `const_iterator` to the
  358. // end of the inlined vector.
  359. const_iterator end() const noexcept { return data() + size(); }
  360. // `InlinedVector::cbegin()`
  361. //
  362. // Returns a `const_iterator` to the beginning of the inlined vector.
  363. const_iterator cbegin() const noexcept { return begin(); }
  364. // `InlinedVector::cend()`
  365. //
  366. // Returns a `const_iterator` to the end of the inlined vector.
  367. const_iterator cend() const noexcept { return end(); }
  368. // `InlinedVector::rbegin()`
  369. //
  370. // Returns a `reverse_iterator` from the end of the inlined vector.
  371. reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
  372. // Overload of `InlinedVector::rbegin()` that returns a
  373. // `const_reverse_iterator` from the end of the inlined vector.
  374. const_reverse_iterator rbegin() const noexcept {
  375. return const_reverse_iterator(end());
  376. }
  377. // `InlinedVector::rend()`
  378. //
  379. // Returns a `reverse_iterator` from the beginning of the inlined vector.
  380. reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
  381. // Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator`
  382. // from the beginning of the inlined vector.
  383. const_reverse_iterator rend() const noexcept {
  384. return const_reverse_iterator(begin());
  385. }
  386. // `InlinedVector::crbegin()`
  387. //
  388. // Returns a `const_reverse_iterator` from the end of the inlined vector.
  389. const_reverse_iterator crbegin() const noexcept { return rbegin(); }
  390. // `InlinedVector::crend()`
  391. //
  392. // Returns a `const_reverse_iterator` from the beginning of the inlined
  393. // vector.
  394. const_reverse_iterator crend() const noexcept { return rend(); }
  395. // `InlinedVector::get_allocator()`
  396. //
  397. // Returns a copy of the inlined vector's allocator.
  398. allocator_type get_allocator() const { return storage_.GetAllocator(); }
  399. // ---------------------------------------------------------------------------
  400. // InlinedVector Member Mutators
  401. // ---------------------------------------------------------------------------
  402. // `InlinedVector::operator=(...)`
  403. //
  404. // Replaces the elements of the inlined vector with copies of the elements of
  405. // `list`.
  406. InlinedVector& operator=(std::initializer_list<value_type> list) {
  407. assign(list.begin(), list.end());
  408. return *this;
  409. }
  410. // Overload of `InlinedVector::operator=(...)` that replaces the elements of
  411. // the inlined vector with copies of the elements of `other`.
  412. InlinedVector& operator=(const InlinedVector& other) {
  413. if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
  414. const_pointer other_data = other.data();
  415. assign(other_data, other_data + other.size());
  416. }
  417. return *this;
  418. }
  419. // Overload of `InlinedVector::operator=(...)` that moves the elements of
  420. // `other` into the inlined vector.
  421. //
  422. // NOTE: as a result of calling this overload, `other` is left in a valid but
  423. // unspecified state.
  424. InlinedVector& operator=(InlinedVector&& other) {
  425. if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
  426. if (IsMemcpyOk<A>::value || other.storage_.GetIsAllocated()) {
  427. inlined_vector_internal::DestroyElements<A>(storage_.GetAllocator(),
  428. data(), size());
  429. storage_.DeallocateIfAllocated();
  430. storage_.MemcpyFrom(other.storage_);
  431. other.storage_.SetInlinedSize(0);
  432. } else {
  433. storage_.Assign(IteratorValueAdapter<A, MoveIterator<A>>(
  434. MoveIterator<A>(other.storage_.GetInlinedData())),
  435. other.size());
  436. }
  437. }
  438. return *this;
  439. }
  440. // `InlinedVector::assign(...)`
  441. //
  442. // Replaces the contents of the inlined vector with `n` copies of `v`.
  443. void assign(size_type n, const_reference v) {
  444. storage_.Assign(CopyValueAdapter<A>(std::addressof(v)), n);
  445. }
  446. // Overload of `InlinedVector::assign(...)` that replaces the contents of the
  447. // inlined vector with copies of the elements of `list`.
  448. void assign(std::initializer_list<value_type> list) {
  449. assign(list.begin(), list.end());
  450. }
  451. // Overload of `InlinedVector::assign(...)` to replace the contents of the
  452. // inlined vector with the range [`first`, `last`).
  453. //
  454. // NOTE: this overload is for iterators that are "forward" category or better.
  455. template <typename ForwardIterator,
  456. EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
  457. void assign(ForwardIterator first, ForwardIterator last) {
  458. storage_.Assign(IteratorValueAdapter<A, ForwardIterator>(first),
  459. std::distance(first, last));
  460. }
  461. // Overload of `InlinedVector::assign(...)` to replace the contents of the
  462. // inlined vector with the range [`first`, `last`).
  463. //
  464. // NOTE: this overload is for iterators that are "input" category.
  465. template <typename InputIterator,
  466. DisableIfAtLeastForwardIterator<InputIterator> = 0>
  467. void assign(InputIterator first, InputIterator last) {
  468. size_type i = 0;
  469. for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
  470. data()[i] = *first;
  471. }
  472. erase(data() + i, data() + size());
  473. std::copy(first, last, std::back_inserter(*this));
  474. }
  475. // `InlinedVector::resize(...)`
  476. //
  477. // Resizes the inlined vector to contain `n` elements.
  478. //
  479. // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
  480. // is larger than `size()`, new elements are value-initialized.
  481. void resize(size_type n) {
  482. ABSL_HARDENING_ASSERT(n <= max_size());
  483. storage_.Resize(DefaultValueAdapter<A>(), n);
  484. }
  485. // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
  486. // contain `n` elements.
  487. //
  488. // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
  489. // is larger than `size()`, new elements are copied-constructed from `v`.
  490. void resize(size_type n, const_reference v) {
  491. ABSL_HARDENING_ASSERT(n <= max_size());
  492. storage_.Resize(CopyValueAdapter<A>(std::addressof(v)), n);
  493. }
  494. // `InlinedVector::insert(...)`
  495. //
  496. // Inserts a copy of `v` at `pos`, returning an `iterator` to the newly
  497. // inserted element.
  498. iterator insert(const_iterator pos, const_reference v) {
  499. return emplace(pos, v);
  500. }
  501. // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
  502. // move semantics, returning an `iterator` to the newly inserted element.
  503. iterator insert(const_iterator pos, value_type&& v) {
  504. return emplace(pos, std::move(v));
  505. }
  506. // Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies
  507. // of `v` starting at `pos`, returning an `iterator` pointing to the first of
  508. // the newly inserted elements.
  509. iterator insert(const_iterator pos, size_type n, const_reference v) {
  510. ABSL_HARDENING_ASSERT(pos >= begin());
  511. ABSL_HARDENING_ASSERT(pos <= end());
  512. if (ABSL_PREDICT_TRUE(n != 0)) {
  513. value_type dealias = v;
  514. return storage_.Insert(pos, CopyValueAdapter<A>(std::addressof(dealias)),
  515. n);
  516. } else {
  517. return const_cast<iterator>(pos);
  518. }
  519. }
  520. // Overload of `InlinedVector::insert(...)` that inserts copies of the
  521. // elements of `list` starting at `pos`, returning an `iterator` pointing to
  522. // the first of the newly inserted elements.
  523. iterator insert(const_iterator pos, std::initializer_list<value_type> list) {
  524. return insert(pos, list.begin(), list.end());
  525. }
  526. // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
  527. // `last`) starting at `pos`, returning an `iterator` pointing to the first
  528. // of the newly inserted elements.
  529. //
  530. // NOTE: this overload is for iterators that are "forward" category or better.
  531. template <typename ForwardIterator,
  532. EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
  533. iterator insert(const_iterator pos, ForwardIterator first,
  534. ForwardIterator last) {
  535. ABSL_HARDENING_ASSERT(pos >= begin());
  536. ABSL_HARDENING_ASSERT(pos <= end());
  537. if (ABSL_PREDICT_TRUE(first != last)) {
  538. return storage_.Insert(pos,
  539. IteratorValueAdapter<A, ForwardIterator>(first),
  540. std::distance(first, last));
  541. } else {
  542. return const_cast<iterator>(pos);
  543. }
  544. }
  545. // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
  546. // `last`) starting at `pos`, returning an `iterator` pointing to the first
  547. // of the newly inserted elements.
  548. //
  549. // NOTE: this overload is for iterators that are "input" category.
  550. template <typename InputIterator,
  551. DisableIfAtLeastForwardIterator<InputIterator> = 0>
  552. iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
  553. ABSL_HARDENING_ASSERT(pos >= begin());
  554. ABSL_HARDENING_ASSERT(pos <= end());
  555. size_type index = std::distance(cbegin(), pos);
  556. for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
  557. insert(data() + i, *first);
  558. }
  559. return iterator(data() + index);
  560. }
  561. // `InlinedVector::emplace(...)`
  562. //
  563. // Constructs and inserts an element using `args...` in the inlined vector at
  564. // `pos`, returning an `iterator` pointing to the newly emplaced element.
  565. template <typename... Args>
  566. iterator emplace(const_iterator pos, Args&&... args) {
  567. ABSL_HARDENING_ASSERT(pos >= begin());
  568. ABSL_HARDENING_ASSERT(pos <= end());
  569. value_type dealias(std::forward<Args>(args)...);
  570. return storage_.Insert(pos,
  571. IteratorValueAdapter<A, MoveIterator<A>>(
  572. MoveIterator<A>(std::addressof(dealias))),
  573. 1);
  574. }
  575. // `InlinedVector::emplace_back(...)`
  576. //
  577. // Constructs and inserts an element using `args...` in the inlined vector at
  578. // `end()`, returning a `reference` to the newly emplaced element.
  579. template <typename... Args>
  580. reference emplace_back(Args&&... args) {
  581. return storage_.EmplaceBack(std::forward<Args>(args)...);
  582. }
  583. // `InlinedVector::push_back(...)`
  584. //
  585. // Inserts a copy of `v` in the inlined vector at `end()`.
  586. void push_back(const_reference v) { static_cast<void>(emplace_back(v)); }
  587. // Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
  588. // using move semantics.
  589. void push_back(value_type&& v) {
  590. static_cast<void>(emplace_back(std::move(v)));
  591. }
  592. // `InlinedVector::pop_back()`
  593. //
  594. // Destroys the element at `back()`, reducing the size by `1`.
  595. void pop_back() noexcept {
  596. ABSL_HARDENING_ASSERT(!empty());
  597. AllocatorTraits<A>::destroy(storage_.GetAllocator(), data() + (size() - 1));
  598. storage_.SubtractSize(1);
  599. }
  600. // `InlinedVector::erase(...)`
  601. //
  602. // Erases the element at `pos`, returning an `iterator` pointing to where the
  603. // erased element was located.
  604. //
  605. // NOTE: may return `end()`, which is not dereferencable.
  606. iterator erase(const_iterator pos) {
  607. ABSL_HARDENING_ASSERT(pos >= begin());
  608. ABSL_HARDENING_ASSERT(pos < end());
  609. return storage_.Erase(pos, pos + 1);
  610. }
  611. // Overload of `InlinedVector::erase(...)` that erases every element in the
  612. // range [`from`, `to`), returning an `iterator` pointing to where the first
  613. // erased element was located.
  614. //
  615. // NOTE: may return `end()`, which is not dereferencable.
  616. iterator erase(const_iterator from, const_iterator to) {
  617. ABSL_HARDENING_ASSERT(from >= begin());
  618. ABSL_HARDENING_ASSERT(from <= to);
  619. ABSL_HARDENING_ASSERT(to <= end());
  620. if (ABSL_PREDICT_TRUE(from != to)) {
  621. return storage_.Erase(from, to);
  622. } else {
  623. return const_cast<iterator>(from);
  624. }
  625. }
  626. // `InlinedVector::clear()`
  627. //
  628. // Destroys all elements in the inlined vector, setting the size to `0` and
  629. // deallocating any held memory.
  630. void clear() noexcept {
  631. inlined_vector_internal::DestroyElements<A>(storage_.GetAllocator(), data(),
  632. size());
  633. storage_.DeallocateIfAllocated();
  634. storage_.SetInlinedSize(0);
  635. }
  636. // `InlinedVector::reserve(...)`
  637. //
  638. // Ensures that there is enough room for at least `n` elements.
  639. void reserve(size_type n) { storage_.Reserve(n); }
  640. // `InlinedVector::shrink_to_fit()`
  641. //
  642. // Attempts to reduce memory usage by moving elements to (or keeping elements
  643. // in) the smallest available buffer sufficient for containing `size()`
  644. // elements.
  645. //
  646. // If `size()` is sufficiently small, the elements will be moved into (or kept
  647. // in) the inlined space.
  648. void shrink_to_fit() {
  649. if (storage_.GetIsAllocated()) {
  650. storage_.ShrinkToFit();
  651. }
  652. }
  653. // `InlinedVector::swap(...)`
  654. //
  655. // Swaps the contents of the inlined vector with `other`.
  656. void swap(InlinedVector& other) {
  657. if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
  658. storage_.Swap(std::addressof(other.storage_));
  659. }
  660. }
  661. private:
  662. template <typename H, typename TheT, size_t TheN, typename TheA>
  663. friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
  664. Storage storage_;
  665. };
  666. // -----------------------------------------------------------------------------
  667. // InlinedVector Non-Member Functions
  668. // -----------------------------------------------------------------------------
  669. // `swap(...)`
  670. //
  671. // Swaps the contents of two inlined vectors.
  672. template <typename T, size_t N, typename A>
  673. void swap(absl::InlinedVector<T, N, A>& a,
  674. absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
  675. a.swap(b);
  676. }
  677. // `operator==(...)`
  678. //
  679. // Tests for value-equality of two inlined vectors.
  680. template <typename T, size_t N, typename A>
  681. bool operator==(const absl::InlinedVector<T, N, A>& a,
  682. const absl::InlinedVector<T, N, A>& b) {
  683. auto a_data = a.data();
  684. auto b_data = b.data();
  685. return absl::equal(a_data, a_data + a.size(), b_data, b_data + b.size());
  686. }
  687. // `operator!=(...)`
  688. //
  689. // Tests for value-inequality of two inlined vectors.
  690. template <typename T, size_t N, typename A>
  691. bool operator!=(const absl::InlinedVector<T, N, A>& a,
  692. const absl::InlinedVector<T, N, A>& b) {
  693. return !(a == b);
  694. }
  695. // `operator<(...)`
  696. //
  697. // Tests whether the value of an inlined vector is less than the value of
  698. // another inlined vector using a lexicographical comparison algorithm.
  699. template <typename T, size_t N, typename A>
  700. bool operator<(const absl::InlinedVector<T, N, A>& a,
  701. const absl::InlinedVector<T, N, A>& b) {
  702. auto a_data = a.data();
  703. auto b_data = b.data();
  704. return std::lexicographical_compare(a_data, a_data + a.size(), b_data,
  705. b_data + b.size());
  706. }
  707. // `operator>(...)`
  708. //
  709. // Tests whether the value of an inlined vector is greater than the value of
  710. // another inlined vector using a lexicographical comparison algorithm.
  711. template <typename T, size_t N, typename A>
  712. bool operator>(const absl::InlinedVector<T, N, A>& a,
  713. const absl::InlinedVector<T, N, A>& b) {
  714. return b < a;
  715. }
  716. // `operator<=(...)`
  717. //
  718. // Tests whether the value of an inlined vector is less than or equal to the
  719. // value of another inlined vector using a lexicographical comparison algorithm.
  720. template <typename T, size_t N, typename A>
  721. bool operator<=(const absl::InlinedVector<T, N, A>& a,
  722. const absl::InlinedVector<T, N, A>& b) {
  723. return !(b < a);
  724. }
  725. // `operator>=(...)`
  726. //
  727. // Tests whether the value of an inlined vector is greater than or equal to the
  728. // value of another inlined vector using a lexicographical comparison algorithm.
  729. template <typename T, size_t N, typename A>
  730. bool operator>=(const absl::InlinedVector<T, N, A>& a,
  731. const absl::InlinedVector<T, N, A>& b) {
  732. return !(a < b);
  733. }
  734. // `AbslHashValue(...)`
  735. //
  736. // Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to
  737. // call this directly.
  738. template <typename H, typename T, size_t N, typename A>
  739. H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
  740. auto size = a.size();
  741. return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
  742. }
  743. ABSL_NAMESPACE_END
  744. } // namespace absl
  745. #endif // ABSL_CONTAINER_INLINED_VECTOR_H_