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.

small_vector.h 29 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. //===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file defines the SmallVector class.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. /**
  14. * \file include/megdnn/thin/small_vector.h
  15. *
  16. * This file is part of MegDNN, a deep neural network run-time library
  17. * developed by Megvii.
  18. *
  19. * \brief thin megdnn function
  20. *
  21. * \copyright Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
  22. */
  23. #pragma once
  24. #include "megdnn/arch.h"
  25. #include <algorithm>
  26. #include <cstdlib>
  27. #include <cstring>
  28. #include <iterator>
  29. #include <limits>
  30. #include <memory>
  31. #include <type_traits>
  32. #include "megdnn/internal/visibility_prologue.h"
  33. namespace megdnn {
  34. class SmallVectorBase {
  35. protected:
  36. void *m_begin_ptr, *m_end_ptr, *m_capacity_ptr;
  37. MGE_WIN_DECLSPEC_FUC MEGDNN_NORETURN static void on_invalid_at(
  38. size_t idx, size_t size);
  39. protected:
  40. SmallVectorBase(void* first_elm, size_t size)
  41. : m_begin_ptr(first_elm),
  42. m_end_ptr(first_elm),
  43. m_capacity_ptr(static_cast<char*>(first_elm) + size) {}
  44. MGE_WIN_DECLSPEC_FUC void grow_pod(
  45. void* first_elm_ptr, size_t min_sz_in_bytes, size_t type_size);
  46. public:
  47. size_t size_in_bytes() const {
  48. return size_t(static_cast<char*>(m_end_ptr) - static_cast<char*>(m_begin_ptr));
  49. }
  50. size_t capacity_in_bytes() const {
  51. return size_t(
  52. static_cast<char*>(m_capacity_ptr) - static_cast<char*>(m_begin_ptr));
  53. }
  54. bool empty() const { return m_begin_ptr == m_end_ptr; }
  55. };
  56. template <typename T, typename = void>
  57. class SmallVectorTemplateCommon : public SmallVectorBase {
  58. private:
  59. template <typename, unsigned>
  60. friend struct SmallVectorStorage;
  61. using U = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
  62. U m_first_elm;
  63. protected:
  64. SmallVectorTemplateCommon(size_t size) : SmallVectorBase(&m_first_elm, size) {}
  65. void grow_pod(size_t min_sz_in_bytes, size_t type_size) {
  66. SmallVectorBase::grow_pod(&m_first_elm, min_sz_in_bytes, type_size);
  67. }
  68. bool is_small() { return m_begin_ptr == static_cast<const void*>(&m_first_elm); }
  69. void reset_to_small() { m_begin_ptr = m_end_ptr = m_capacity_ptr = &m_first_elm; }
  70. void set_end(T* p) { m_end_ptr = p; }
  71. public:
  72. using size_type = size_t;
  73. using difference_type = std::ptrdiff_t;
  74. using value_type = T;
  75. using iterator = T*;
  76. using const_iterator = const T*;
  77. using reverse_iterator = std::reverse_iterator<iterator>;
  78. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  79. using reference = T&;
  80. using const_reference = const T&;
  81. using pointer = T*;
  82. using const_pointer = const T*;
  83. size_t capacity() const { return capacity_ptr() - begin(); }
  84. protected:
  85. iterator capacity_ptr() { return static_cast<iterator>(m_capacity_ptr); }
  86. const_iterator capacity_ptr() const {
  87. return static_cast<const_iterator>(m_capacity_ptr);
  88. }
  89. public:
  90. // forwarding iterator creation
  91. iterator begin() { return static_cast<iterator>(m_begin_ptr); }
  92. const_iterator begin() const { return static_cast<const_iterator>(m_begin_ptr); }
  93. const_iterator cbegin() const { return static_cast<const_iterator>(m_begin_ptr); }
  94. iterator end() { return static_cast<iterator>(m_end_ptr); }
  95. const_iterator end() const { return static_cast<const_iterator>(m_end_ptr); }
  96. const_iterator cend() const { return static_cast<const_iterator>(m_end_ptr); }
  97. reference at(size_type idx) {
  98. if (idx >= size()) {
  99. on_invalid_at(idx, size());
  100. }
  101. return begin()[idx];
  102. }
  103. const_reference at(size_type idx) const {
  104. if (idx >= size()) {
  105. on_invalid_at(idx, size());
  106. }
  107. return begin()[idx];
  108. }
  109. reference operator[](size_type idx) { return begin()[idx]; }
  110. const_reference operator[](size_type idx) const { return begin()[idx]; }
  111. reference front() { return begin()[0]; }
  112. const_reference front() const { return begin()[0]; }
  113. reference back() { return rbegin()[0]; }
  114. const_reference back() const { return rbegin()[0]; }
  115. // reverse iterator creation method.
  116. reverse_iterator rbegin() { return reverse_iterator(end()); }
  117. const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
  118. reverse_iterator rend() { return reverse_iterator(begin()); }
  119. const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
  120. pointer data() { return pointer(begin()); }
  121. const_pointer data() const { return const_pointer(begin()); }
  122. size_type size() const { return end() - begin(); }
  123. size_type max_size() const {
  124. return std::numeric_limits<size_type>::max() / sizeof(T);
  125. }
  126. template <typename in_iter>
  127. in_iter find(in_iter first, in_iter last, const T& value) const {
  128. while (first != last) {
  129. if (*first == value)
  130. return first;
  131. ++first;
  132. }
  133. return last;
  134. }
  135. };
  136. template <typename T, bool is_pod>
  137. class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
  138. protected:
  139. SmallVectorTemplateBase(size_t size) : SmallVectorTemplateCommon<T>(size) {}
  140. static void destroy_range(T* start, T* end) {
  141. while (start != end) {
  142. --end;
  143. end->~T();
  144. }
  145. }
  146. template <typename It1, typename It2>
  147. static void uninitialized_move(It1 first, It1 last, It2 dest) {
  148. std::uninitialized_copy(
  149. std::make_move_iterator(first), std::make_move_iterator(last), dest);
  150. }
  151. template <typename It1, typename It2>
  152. static void uninitialized_copy(It1 first, It1 last, It2 dest) {
  153. std::uninitialized_copy(first, last, dest);
  154. }
  155. void grow(size_t min_sz = 0);
  156. public:
  157. void push_back(const T& _elm) {
  158. if (megdnn_unlikely(this->m_end_ptr >= this->m_capacity_ptr)) {
  159. T elm = _elm;
  160. this->grow();
  161. new (static_cast<void*>(this->end())) T(std::move(elm));
  162. } else {
  163. new (static_cast<void*>(this->end())) T(_elm);
  164. }
  165. this->set_end(this->end() + 1);
  166. }
  167. void push_back(T&& elm) {
  168. if (megdnn_unlikely(this->m_end_ptr >= this->m_capacity_ptr)) {
  169. this->grow();
  170. }
  171. new (static_cast<void*>(this->end())) T(std::move(elm));
  172. this->set_end(this->end() + 1);
  173. }
  174. void pop_back() {
  175. this->set_end(this->end() - 1);
  176. this->end()->~T();
  177. }
  178. };
  179. template <typename T, bool is_pod>
  180. void SmallVectorTemplateBase<T, is_pod>::grow(size_t min_sz) {
  181. size_t cur_capacity = this->capacity();
  182. size_t cur_sz = this->size();
  183. size_t new_capacity = (cur_capacity + 2) * 2;
  184. if (new_capacity < min_sz) {
  185. new_capacity = min_sz;
  186. }
  187. T* elms = static_cast<T*>(malloc(new_capacity * sizeof(T)));
  188. this->uninitialized_move(this->begin(), this->end(), elms);
  189. this->destroy_range(this->begin(), this->end());
  190. if (!this->is_small()) {
  191. free(this->begin());
  192. }
  193. this->m_begin_ptr = elms;
  194. this->set_end(elms + cur_sz);
  195. this->m_capacity_ptr = this->begin() + new_capacity;
  196. }
  197. template <typename T>
  198. class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
  199. protected:
  200. SmallVectorTemplateBase(size_t size) : SmallVectorTemplateCommon<T>(size) {}
  201. static void destroy_range(T*, T*) {}
  202. template <typename It1, typename It2>
  203. static void uninitialized_move(It1 first, It1 last, It2 dest) {
  204. uninitialized_copy(first, last, dest);
  205. }
  206. template <typename It1, typename It2>
  207. static void uninitialized_copy(It1 first, It1 last, It2 dest) {
  208. std::uninitialized_copy(first, last, dest);
  209. }
  210. template <typename T1, typename T2>
  211. static void uninitialized_copy(
  212. T1* first, T1* last, T2* dest,
  213. typename std::enable_if<std::is_same<
  214. typename std::remove_const<T1>::type, T2>::value>::type* =
  215. nullptr) {
  216. if (first != last)
  217. memcpy(dest, first, (last - first) * sizeof(T));
  218. }
  219. void grow(size_t min_sz = 0) { this->grow_pod(min_sz * sizeof(T), sizeof(T)); }
  220. public:
  221. void push_back(const T& _elm) {
  222. if (megdnn_unlikely(this->m_end_ptr >= this->m_capacity_ptr)) {
  223. T elm = _elm;
  224. this->grow();
  225. memcpy(this->end(), &elm, sizeof(T));
  226. } else {
  227. memcpy(this->end(), &_elm, sizeof(T));
  228. }
  229. this->set_end(this->end() + 1);
  230. }
  231. void pop_back() { this->set_end(this->end() - 1); }
  232. };
  233. /*!
  234. * \brief the implementation class of SmallVector
  235. *
  236. * SmallVector<T, N> can be converted to SmallVectorImpl<T> to erase N
  237. */
  238. template <typename T>
  239. class SmallVectorImpl : public SmallVectorTemplateBase<T, std::is_pod<T>::value> {
  240. using SuperClass = SmallVectorTemplateBase<T, std::is_pod<T>::value>;
  241. public:
  242. using iterator = typename SuperClass::iterator;
  243. using const_iterator = typename SuperClass::const_iterator;
  244. using size_type = typename SuperClass::size_type;
  245. protected:
  246. explicit SmallVectorImpl(unsigned n)
  247. : SmallVectorTemplateBase<T, std::is_pod<T>::value>(n * sizeof(T)) {}
  248. public:
  249. SmallVectorImpl(const SmallVectorImpl&) = delete;
  250. ~SmallVectorImpl() {
  251. this->destroy_range(this->begin(), this->end());
  252. if (!this->is_small())
  253. free(this->begin());
  254. }
  255. void clear() {
  256. this->destroy_range(this->begin(), this->end());
  257. this->m_end_ptr = this->m_begin_ptr;
  258. }
  259. void resize(size_type n) {
  260. if (n < this->size()) {
  261. this->destroy_range(this->begin() + n, this->end());
  262. this->set_end(this->begin() + n);
  263. } else if (n > this->size()) {
  264. if (this->capacity() < n)
  265. this->grow(n);
  266. for (iterator it = this->end(), end = this->begin() + n; it != end; ++it)
  267. new (&*it) T();
  268. this->set_end(this->begin() + n);
  269. }
  270. }
  271. void resize(size_type n, const T& _nv) {
  272. T nv = _nv;
  273. if (n < this->size()) {
  274. this->destroy_range(this->begin() + n, this->end());
  275. this->set_end(this->begin() + n);
  276. } else if (n > this->size()) {
  277. if (this->capacity() < n)
  278. this->grow(n);
  279. std::uninitialized_fill(this->end(), this->begin() + n, nv);
  280. this->set_end(this->begin() + n);
  281. }
  282. }
  283. void reserve(size_type n) {
  284. if (this->capacity() < n) {
  285. this->grow(n);
  286. }
  287. }
  288. T pop_back_val() {
  289. T result = std::move(this->back());
  290. this->pop_back();
  291. return result;
  292. }
  293. void swap(SmallVectorImpl<T>& rhs);
  294. /// Add the specified range to the end of the SmallVector.
  295. template <
  296. typename in_iter,
  297. typename = typename std::enable_if<std::is_convertible<
  298. typename std::iterator_traits<in_iter>::iterator_category,
  299. std::input_iterator_tag>::value>::type>
  300. void append(in_iter in_start, in_iter in_end) {
  301. size_type num_inputs = std::distance(in_start, in_end);
  302. // Grow allocated space if needed.
  303. if (num_inputs > size_type(this->capacity_ptr() - this->end()))
  304. this->grow(this->size() + num_inputs);
  305. // Copy the new elements over.
  306. this->uninitialized_copy(in_start, in_end, this->end());
  307. this->set_end(this->end() + num_inputs);
  308. }
  309. /// Add the specified range to the end of the SmallVector.
  310. void append(size_type num_inputs, const T& _elm) {
  311. T elm = _elm;
  312. // Grow allocated space if needed.
  313. if (num_inputs > size_type(this->capacity_ptr() - this->end()))
  314. this->grow(this->size() + num_inputs);
  315. // Copy the new elements over.
  316. std::uninitialized_fill_n(this->end(), num_inputs, elm);
  317. this->set_end(this->end() + num_inputs);
  318. }
  319. void append(std::initializer_list<T> init_list) {
  320. append(init_list.begin(), init_list.end());
  321. }
  322. // FIXME: Consider assigning over existing elements, rather than clearing &
  323. // re-initializing them - for all assign(...) variants.
  324. void assign(size_type num_elms, const T& _elm) {
  325. T elm = _elm;
  326. clear();
  327. if (this->capacity() < num_elms)
  328. this->grow(num_elms);
  329. this->set_end(this->begin() + num_elms);
  330. std::uninitialized_fill(this->begin(), this->end(), elm);
  331. }
  332. template <
  333. typename in_iter,
  334. typename = typename std::enable_if<std::is_convertible<
  335. typename std::iterator_traits<in_iter>::iterator_category,
  336. std::input_iterator_tag>::value>::type>
  337. void assign(in_iter in_start, in_iter in_end) {
  338. clear();
  339. append(in_start, in_end);
  340. }
  341. void assign(std::initializer_list<T> init_list) {
  342. clear();
  343. append(init_list);
  344. }
  345. iterator erase(const_iterator cit) {
  346. // Just cast away constness because this is a non-const member function.
  347. iterator it = const_cast<iterator>(cit);
  348. iterator n = it;
  349. // Shift all elms down one.
  350. std::move(it + 1, this->end(), it);
  351. // Drop the last elm.
  352. this->pop_back();
  353. return (n);
  354. }
  355. iterator erase(const_iterator c_first, const_iterator c_last) {
  356. // Just cast away constness because this is a non-const member function.
  357. iterator first = const_cast<iterator>(c_first);
  358. iterator last = const_cast<iterator>(c_last);
  359. iterator n = first;
  360. // Shift all elms down.
  361. iterator it = std::move(last, this->end(), first);
  362. // Drop the last elms.
  363. this->destroy_range(it, this->end());
  364. this->set_end(it);
  365. return (n);
  366. }
  367. iterator insert(iterator it, T&& elm) {
  368. if (it == this->end()) { // Important special case for empty vector.
  369. this->push_back(std::move(elm));
  370. return this->end() - 1;
  371. }
  372. if (this->m_end_ptr >= this->m_capacity_ptr) {
  373. size_t elm_idx = it - this->begin();
  374. this->grow();
  375. it = this->begin() + elm_idx;
  376. }
  377. new (static_cast<void*>(this->end())) T(std::move(this->back()));
  378. // Push everything else over.
  379. std::move_backward(it, this->end() - 1, this->end());
  380. this->set_end(this->end() + 1);
  381. // If we just moved the element we're inserting, be sure to update
  382. // the reference.
  383. T* elm_ptr = &elm;
  384. if (it <= elm_ptr && elm_ptr < this->m_end_ptr)
  385. ++elm_ptr;
  386. *it = std::move(*elm_ptr);
  387. return it;
  388. }
  389. iterator insert(iterator it, const T& _elm) {
  390. if (it == this->end()) { // Important special case for empty vector.
  391. this->push_back(_elm);
  392. return this->end() - 1;
  393. }
  394. T elm = _elm;
  395. if (this->m_end_ptr >= this->m_capacity_ptr) {
  396. size_t elm_idx = it - this->begin();
  397. this->grow();
  398. it = this->begin() + elm_idx;
  399. }
  400. new (static_cast<void*>(this->end())) T(std::move(this->back()));
  401. // Push everything else over.
  402. std::move_backward(it, this->end() - 1, this->end());
  403. this->set_end(this->end() + 1);
  404. // If we just moved the element we're inserting, be sure to update
  405. // the reference.
  406. const T* elm_ptr = &elm;
  407. if (it <= elm_ptr && elm_ptr < this->m_end_ptr)
  408. ++elm_ptr;
  409. *it = *elm_ptr;
  410. return it;
  411. }
  412. iterator insert(iterator it, size_type num_to_insert, const T& _elm) {
  413. // Convert iterator to elm# to avoid invalidating iterator
  414. // when we reserve()
  415. size_t elm_idx = it - this->begin();
  416. if (it == this->end()) { // Important special case for empty vector.
  417. append(num_to_insert, _elm);
  418. return this->begin() + elm_idx;
  419. }
  420. T elm = _elm;
  421. // Ensure there is enough space.
  422. reserve(this->size() + num_to_insert);
  423. // Uninvalidate the iterator.
  424. it = this->begin() + elm_idx;
  425. // If there are more elements between the insertion point and
  426. // the end of the range than there are being inserted,
  427. // we can use a simple approach to insertion.
  428. // Since we already reserved space, we know that this won't
  429. // reallocate the vector.
  430. if (size_t(this->end() - it) >= num_to_insert) {
  431. T* old_end = this->end();
  432. append(std::move_iterator<iterator>(this->end() - num_to_insert),
  433. std::move_iterator<iterator>(this->end()));
  434. // Copy the existing elements that get replaced.
  435. std::move_backward(it, old_end - num_to_insert, old_end);
  436. std::fill_n(it, num_to_insert, elm);
  437. return it;
  438. }
  439. // Otherwise, we're inserting more elements than exist already,
  440. // and we're not inserting at the end.
  441. // Move over the elements that we're about to overwrite.
  442. T* old_end = this->end();
  443. this->set_end(this->end() + num_to_insert);
  444. size_t num_overwritten = old_end - it;
  445. this->uninitialized_move(it, old_end, this->end() - num_overwritten);
  446. // Replace the overwritten part.
  447. std::fill_n(it, num_overwritten, elm);
  448. // Insert the non-overwritten middle part.
  449. std::uninitialized_fill_n(old_end, num_to_insert - num_overwritten, elm);
  450. return it;
  451. }
  452. template <
  453. typename IterType,
  454. typename = typename std::enable_if<std::is_convertible<
  455. typename std::iterator_traits<IterType>::iterator_category,
  456. std::input_iterator_tag>::value>::type>
  457. iterator insert(iterator it, IterType from, IterType to) {
  458. // Convert iterator to elm# to avoid invalidating iterator
  459. // when we reserve()
  460. size_t elm_idx = it - this->begin();
  461. if (it == this->end()) { // Important special case for empty vector.
  462. append(from, to);
  463. return this->begin() + elm_idx;
  464. }
  465. size_t num_to_insert = std::distance(from, to);
  466. // Ensure there is enough space.
  467. reserve(this->size() + num_to_insert);
  468. // Uninvalidate the iterator.
  469. it = this->begin() + elm_idx;
  470. // If there are more elements between the insertion point and
  471. // the end of the range than there are being inserted,
  472. // we can use a simple approach to insertion.
  473. // Since we already reserved space, we know that this won't
  474. // reallocate the vector.
  475. if (size_t(this->end() - it) >= num_to_insert) {
  476. T* old_end = this->end();
  477. append(std::move_iterator<iterator>(this->end() - num_to_insert),
  478. std::move_iterator<iterator>(this->end()));
  479. // Copy the existing elements that get replaced.
  480. std::move_backward(it, old_end - num_to_insert, old_end);
  481. std::copy(from, to, it);
  482. return it;
  483. }
  484. // Otherwise, we're inserting more elements than exist already,
  485. // and we're not inserting at the end.
  486. // Move over the elements that we're about to overwrite.
  487. T* old_end = this->end();
  488. this->set_end(this->end() + num_to_insert);
  489. size_t num_overwritten = old_end - it;
  490. this->uninitialized_move(it, old_end, this->end() - num_overwritten);
  491. // Replace the overwritten part.
  492. for (T* iter = it; num_overwritten > 0; --num_overwritten) {
  493. *iter = *from;
  494. ++iter;
  495. ++from;
  496. }
  497. // Insert the non-overwritten middle part.
  498. this->uninitialized_copy(from, to, old_end);
  499. return it;
  500. }
  501. void insert(iterator it, std::initializer_list<T> init_list) {
  502. insert(it, init_list.begin(), init_list.end());
  503. }
  504. template <typename... ArgTypes>
  505. void emplace_back(ArgTypes&&... args) {
  506. if (megdnn_unlikely(this->m_end_ptr >= this->m_capacity_ptr)) {
  507. this->grow();
  508. }
  509. new (static_cast<void*>(this->end())) T(std::forward<ArgTypes>(args)...);
  510. this->set_end(this->end() + 1);
  511. }
  512. SmallVectorImpl& operator=(const SmallVectorImpl& rhs);
  513. SmallVectorImpl& operator=(SmallVectorImpl&& rhs);
  514. bool operator==(const SmallVectorImpl<T>& rhs) const {
  515. if (this->size() != rhs.size())
  516. return false;
  517. return std::equal(this->begin(), this->end(), rhs.begin());
  518. }
  519. bool operator!=(const SmallVectorImpl<T>& rhs) const { return !(*this == rhs); }
  520. bool operator<(const SmallVectorImpl<T>& rhs) const {
  521. return std::lexicographical_compare(
  522. this->begin(), this->end(), rhs.begin(), rhs.end());
  523. }
  524. };
  525. template <typename T>
  526. void SmallVectorImpl<T>::swap(SmallVectorImpl<T>& rhs) {
  527. if (this == &rhs)
  528. return;
  529. // We can only avoid copying elements if neither vector is small.
  530. if (!this->is_small() && !rhs.is_small()) {
  531. std::swap(this->m_begin_ptr, rhs.m_begin_ptr);
  532. std::swap(this->m_end_ptr, rhs.m_end_ptr);
  533. std::swap(this->m_capacity_ptr, rhs.m_capacity_ptr);
  534. return;
  535. }
  536. if (rhs.size() > this->capacity())
  537. this->grow(rhs.size());
  538. if (this->size() > rhs.capacity())
  539. rhs.grow(this->size());
  540. // Swap the shared elements.
  541. size_t num_shared = this->size();
  542. if (num_shared > rhs.size())
  543. num_shared = rhs.size();
  544. for (size_type i = 0; i != num_shared; ++i)
  545. std::swap((*this)[i], rhs[i]);
  546. // Copy over the extra elms.
  547. if (this->size() > rhs.size()) {
  548. size_t elm_diff = this->size() - rhs.size();
  549. this->uninitialized_move(this->begin() + num_shared, this->end(), rhs.end());
  550. rhs.set_end(rhs.end() + elm_diff);
  551. this->destroy_range(this->begin() + num_shared, this->end());
  552. this->set_end(this->begin() + num_shared);
  553. } else if (rhs.size() > this->size()) {
  554. size_t elm_diff = rhs.size() - this->size();
  555. this->uninitialized_move(rhs.begin() + num_shared, rhs.end(), this->end());
  556. this->set_end(this->end() + elm_diff);
  557. this->destroy_range(rhs.begin() + num_shared, rhs.end());
  558. rhs.set_end(rhs.begin() + num_shared);
  559. }
  560. }
  561. template <typename T>
  562. SmallVectorImpl<T>& SmallVectorImpl<T>::operator=(const SmallVectorImpl<T>& rhs) {
  563. if (this == &rhs)
  564. return *this;
  565. size_t rhs_sz = rhs.size();
  566. size_t cur_sz = this->size();
  567. if (cur_sz >= rhs_sz) {
  568. iterator new_end;
  569. if (rhs_sz) {
  570. new_end = std::copy(rhs.begin(), rhs.end(), this->begin());
  571. } else {
  572. new_end = this->begin();
  573. }
  574. this->destroy_range(new_end, this->end());
  575. this->set_end(new_end);
  576. return *this;
  577. }
  578. if (this->capacity() < rhs_sz) {
  579. // save time for no copy when growing
  580. this->destroy_range(this->begin(), this->end());
  581. this->set_end(this->begin());
  582. cur_sz = 0;
  583. this->grow(rhs_sz);
  584. } else if (cur_sz) {
  585. std::copy(rhs.begin(), rhs.begin() + cur_sz, this->begin());
  586. }
  587. std::uninitialized_copy(rhs.begin() + cur_sz, rhs.end(), this->begin() + cur_sz);
  588. this->set_end(this->begin() + rhs_sz);
  589. return *this;
  590. }
  591. template <typename T>
  592. SmallVectorImpl<T>& SmallVectorImpl<T>::operator=(SmallVectorImpl<T>&& rhs) {
  593. // avoid self assignment
  594. if (this == &rhs)
  595. return *this;
  596. // copy ptr when rhs is small
  597. if (!rhs.is_small()) {
  598. this->destroy_range(this->begin(), this->end());
  599. if (!this->is_small())
  600. free(this->begin());
  601. this->m_begin_ptr = rhs.m_begin_ptr;
  602. this->m_end_ptr = rhs.m_end_ptr;
  603. this->m_capacity_ptr = rhs.m_capacity_ptr;
  604. rhs.reset_to_small();
  605. return *this;
  606. }
  607. size_t rhs_sz = rhs.size();
  608. size_t cur_sz = this->size();
  609. if (cur_sz >= rhs_sz) {
  610. iterator new_end = this->begin();
  611. if (rhs_sz) {
  612. new_end = std::move(rhs.begin(), rhs.end(), new_end);
  613. }
  614. this->destroy_range(new_end, this->end());
  615. this->set_end(new_end);
  616. rhs.clear();
  617. return *this;
  618. }
  619. if (this->capacity() < rhs_sz) {
  620. this->destroy_range(this->begin(), this->end());
  621. this->set_end(this->begin());
  622. cur_sz = 0;
  623. this->grow(rhs_sz);
  624. } else if (cur_sz) {
  625. std::move(rhs.begin(), rhs.begin() + cur_sz, this->begin());
  626. }
  627. this->uninitialized_move(rhs.begin() + cur_sz, rhs.end(), this->begin() + cur_sz);
  628. this->set_end(this->begin() + rhs_sz);
  629. rhs.clear();
  630. return *this;
  631. }
  632. template <typename T, unsigned N>
  633. struct SmallVectorStorage {
  634. typename SmallVectorTemplateCommon<T>::U inline_elms[N - 1];
  635. };
  636. template <typename T>
  637. struct SmallVectorStorage<T, 1> {};
  638. template <typename T>
  639. struct SmallVectorStorage<T, 0> {};
  640. /*!
  641. * \brief This is a 'vector' (really, a variable-sized array), optimized for the
  642. * case when the array is small.
  643. *
  644. * It contains some number of elements in-place,
  645. * which allows it to avoid heap allocation when the actual number of elements
  646. * is below that threshold. This allows normal "small" cases to be fast without
  647. * losing generality for large inputs.
  648. *
  649. * Note that this does not attempt to be exception safe.
  650. *
  651. * SmallVector<T, N>& can be converted to SmallVectorImpl<T>& to erase the
  652. * template param \p N; this is useful for function params.
  653. *
  654. * \tparam T emelment type
  655. * \tparam N number of elements to be stored in the class object
  656. */
  657. template <typename T, unsigned N = 4>
  658. class SmallVector : public SmallVectorImpl<T> {
  659. SmallVectorStorage<T, N> m_storage;
  660. public:
  661. SmallVector() : SmallVectorImpl<T>(N) {}
  662. explicit SmallVector(size_t size, const T& value = T()) : SmallVectorImpl<T>(N) {
  663. this->assign(size, value);
  664. }
  665. template <
  666. typename IterType,
  667. typename = typename std::enable_if<std::is_convertible<
  668. typename std::iterator_traits<IterType>::iterator_category,
  669. std::input_iterator_tag>::value>::type>
  670. SmallVector(IterType first, IterType last) : SmallVectorImpl<T>(N) {
  671. this->append(first, last);
  672. }
  673. SmallVector(std::initializer_list<T> init_list) : SmallVectorImpl<T>(N) {
  674. this->assign(init_list);
  675. }
  676. SmallVector(const SmallVector& rhs) : SmallVectorImpl<T>(N) {
  677. if (!rhs.empty())
  678. SmallVectorImpl<T>::operator=(rhs);
  679. }
  680. ~SmallVector() {}
  681. const SmallVector& operator=(const SmallVector& rhs) {
  682. SmallVectorImpl<T>::operator=(rhs);
  683. return *this;
  684. }
  685. SmallVector(SmallVector&& rhs) : SmallVectorImpl<T>(N) {
  686. if (!rhs.empty())
  687. SmallVectorImpl<T>::operator=(std::move(rhs));
  688. }
  689. SmallVector(SmallVectorImpl<T>&& rhs) : SmallVectorImpl<T>(N) {
  690. if (!rhs.empty())
  691. SmallVectorImpl<T>::operator=(std::move(rhs));
  692. }
  693. const SmallVector& operator=(SmallVector&& rhs) {
  694. SmallVectorImpl<T>::operator=(std::move(rhs));
  695. return *this;
  696. }
  697. const SmallVector& operator=(SmallVectorImpl<T>&& rhs) {
  698. SmallVectorImpl<T>::operator=(std::move(rhs));
  699. return *this;
  700. }
  701. const SmallVector& operator=(std::initializer_list<T> init_list) {
  702. this->assign(init_list);
  703. return *this;
  704. }
  705. };
  706. template <typename T, unsigned n>
  707. static inline size_t capacity_in_bytes(const SmallVector<T, n>& vec) {
  708. return vec.capacity_in_bytes();
  709. }
  710. template <typename T>
  711. inline typename SmallVectorImpl<T>::const_iterator find(
  712. const SmallVectorImpl<T>& vec, const T& value) {
  713. return vec.find(vec.begin(), vec.end(), value);
  714. }
  715. } // end namespace megdnn
  716. #include "megdnn/internal/visibility_epilogue.h"
  717. namespace std {
  718. /// Implement std::swap in terms of SmallVector swap.
  719. template <typename T>
  720. inline void swap(megdnn::SmallVectorImpl<T>& lhs, megdnn::SmallVectorImpl<T>& rhs) {
  721. lhs.swap(rhs);
  722. }
  723. /// Implement std::swap in terms of SmallVector swap.
  724. template <typename T, unsigned N>
  725. inline void swap(megdnn::SmallVector<T, N>& lhs, megdnn::SmallVector<T, N>& rhs) {
  726. lhs.swap(rhs);
  727. }
  728. } // end namespace std
  729. // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}