You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

inlined_vector.h 33 kB

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