ResourceLimitedVector.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. // Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima).
  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. // http://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. * @file ResourceLimitedVector.hpp
  16. *
  17. */
  18. #ifndef FASTRTPS_UTILS_COLLECTIONS_RESOURCELIMITEDVECTOR_HPP_
  19. #define FASTRTPS_UTILS_COLLECTIONS_RESOURCELIMITEDVECTOR_HPP_
  20. #include "ResourceLimitedContainerConfig.hpp"
  21. #include <assert.h>
  22. #include <algorithm>
  23. #include <type_traits>
  24. #include <vector>
  25. namespace eprosima {
  26. namespace fastrtps {
  27. /**
  28. * Resource limited wrapper of std::vector.
  29. *
  30. * This template class holds an unordered collection of elements using a std::vector or a replacement.
  31. * It makes use of a \ref ResourceLimitedContainerConfig to setup the allocation behaviour regarding the number of
  32. * elements in the collection.
  33. *
  34. * It features linear increment of the capacity, initial preallocation, and maximum number of elements control.
  35. *
  36. * @tparam _Ty Element type.
  37. * @tparam _KeepOrderEnabler Indicates if element order should be kept when removing items,
  38. * defaults to std::false_type.
  39. * @tparam _LimitsConfig Type defining the resource limits configuration,
  40. * defaults to ResourceLimitedContainerConfig
  41. * @tparam _Alloc Allocator to use on the underlying collection type, defaults to std::allocator<_Ty>.
  42. * @tparam _Collection Type used to store the collection of items, defaults to std::vector<_Ty, _Alloc>.
  43. *
  44. * @ingroup UTILITIES_MODULE
  45. */
  46. template <
  47. typename _Ty,
  48. typename _KeepOrderEnabler = std::false_type,
  49. typename _LimitsConfig = ResourceLimitedContainerConfig,
  50. typename _Alloc = std::allocator<_Ty>,
  51. typename _Collection = std::vector<_Ty, _Alloc> >
  52. class ResourceLimitedVector
  53. {
  54. public:
  55. using configuration_type = _LimitsConfig;
  56. using collection_type = _Collection;
  57. using value_type = _Ty;
  58. using allocator_type = _Alloc;
  59. using pointer = typename collection_type::pointer;
  60. using const_pointer = typename collection_type::const_pointer;
  61. using reference = typename collection_type::reference;
  62. using const_reference = typename collection_type::const_reference;
  63. using size_type = typename collection_type::size_type;
  64. using difference_type = typename collection_type::difference_type;
  65. using iterator = typename collection_type::iterator;
  66. using const_iterator = typename collection_type::const_iterator;
  67. using reverse_iterator = typename collection_type::reverse_iterator;
  68. using const_reverse_iterator = typename collection_type::const_reverse_iterator;
  69. /**
  70. * Construct a ResourceLimitedVector.
  71. *
  72. * This constructor receives a \ref ResourceLimitedContainerConfig to setup the allocation behaviour regarding the
  73. * number of elements in the collection.
  74. *
  75. * The cfg parameter indicates the initial number to be reserved, the maximum number of items allowed,
  76. * and the capacity increment value.
  77. *
  78. * @param cfg Resource limits configuration to use.
  79. * @param alloc Allocator object. Forwarded to collection constructor.
  80. */
  81. ResourceLimitedVector(
  82. configuration_type cfg = configuration_type(),
  83. const allocator_type& alloc = allocator_type())
  84. : configuration_(cfg)
  85. , collection_(alloc)
  86. {
  87. collection_.reserve(cfg.initial);
  88. }
  89. ResourceLimitedVector(
  90. const ResourceLimitedVector& other)
  91. : configuration_(other.configuration_)
  92. , collection_(other.collection_.get_allocator())
  93. {
  94. collection_.reserve(other.collection_.capacity());
  95. collection_.assign(other.collection_.begin(), other.collection_.end());
  96. }
  97. virtual ~ResourceLimitedVector () = default;
  98. ResourceLimitedVector& operator = (
  99. const ResourceLimitedVector& other)
  100. {
  101. clear();
  102. for (const_reference item : other)
  103. {
  104. push_back(item);
  105. }
  106. assert(size() == other.size());
  107. return *this;
  108. }
  109. /**
  110. * Add element at the end.
  111. *
  112. * Adds a new element at the end of the vector, after its current last element.
  113. * The content of val is copied to the new element.
  114. *
  115. * @param val Value to be copied to the new element.
  116. *
  117. * @return pointer to the new element, nullptr if resource limit is reached.
  118. */
  119. pointer push_back(
  120. const value_type& val)
  121. {
  122. return emplace_back(val);
  123. }
  124. /**
  125. * Add element at the end.
  126. *
  127. * Adds a new element at the end of the vector, after its current last element.
  128. * The content of val is moved to the new element.
  129. *
  130. * @param val Value to be moved to the new element.
  131. *
  132. * @return pointer to the new element, nullptr if resource limit is reached.
  133. */
  134. pointer push_back(
  135. value_type&& val)
  136. {
  137. return emplace_back(std::move(val));
  138. }
  139. /**
  140. * Construct and insert element at the end.
  141. *
  142. * Inserts a new element at the end of the vector, right after its current last element.
  143. * This new element is constructed in place using args as the arguments for its constructor.
  144. *
  145. * @param args Arguments forwarded to construct the new element.
  146. *
  147. * @return pointer to the new element, nullptr if resource limit is reached.
  148. */
  149. template<typename ... Args>
  150. pointer emplace_back(
  151. Args&& ... args)
  152. {
  153. if (!ensure_capacity())
  154. {
  155. // Indicate error by returning null pointer
  156. return nullptr;
  157. }
  158. // Construct new element at the end of the collection
  159. collection_.emplace_back(args ...);
  160. // Return pointer to newly created element
  161. return &collection_.back();
  162. }
  163. /**
  164. * Remove element.
  165. *
  166. * Removes the first element in the vector that compares equal to val.
  167. * All iterators may become invalidated if this method returns true.
  168. *
  169. * @param val Value to be compared.
  170. *
  171. * @return true if an element was removed, false otherwise.
  172. */
  173. bool remove(
  174. const value_type& val)
  175. {
  176. iterator it = std::find(collection_.begin(), collection_.end(), val);
  177. if (it != collection_.end())
  178. {
  179. do_remove(it);
  180. return true;
  181. }
  182. return false;
  183. }
  184. /**
  185. * Remove element.
  186. *
  187. * Removes the first element in the vector for which pred returns true.
  188. * All iterators may become invalidated if this method returns true.
  189. *
  190. * @param pred Unary function that accepts an element in the range as argument and returns a value
  191. * convertible to bool.
  192. * The value returned indicates whether the element is considered a match in the context
  193. * of this function.
  194. * The function shall not modify its argument.
  195. * This can either be a function pointer or a function object.
  196. *
  197. * @return true if an element was removed, false otherwise.
  198. */
  199. template<class UnaryPredicate>
  200. bool remove_if(
  201. UnaryPredicate pred)
  202. {
  203. iterator it = std::find_if(collection_.begin(), collection_.end(), pred);
  204. if (it != collection_.end())
  205. {
  206. do_remove(it);
  207. return true;
  208. }
  209. return false;
  210. }
  211. /**
  212. * Assign vector content.
  213. *
  214. * Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly.
  215. *
  216. * @param first, last Input iterators to the initial and final positions in a sequence.
  217. * The range used is [first,last), which includes all the elements between first and last,
  218. * including the element pointed by first but not the element pointed by last.
  219. * The function template argument InputIterator shall be an input iterator type that points
  220. * to elements of a type from which value_type objects can be constructed.
  221. * If the size of this range is greater than the maximum number of elements allowed on the
  222. * resource limits configuration, the elements exceeding that maximum will be silently
  223. * discarded.
  224. */
  225. template <class InputIterator>
  226. void assign(
  227. InputIterator first,
  228. InputIterator last)
  229. {
  230. size_type n = std::distance(first, last);
  231. n = std::min(n, configuration_.maximum);
  232. collection_.assign(first, first + n);
  233. }
  234. /**
  235. * Assign vector content.
  236. *
  237. * Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly.
  238. *
  239. * @param n New size for the container.
  240. * Will be truncated if greater than the maximum allowed on the resource limits configuration.
  241. * @param val Value to fill the container with.
  242. * Each of the n elements in the container will be initialized to a copy of this value.
  243. */
  244. void assign(
  245. size_type n,
  246. const value_type& val)
  247. {
  248. n = std::min(n, configuration_.maximum);
  249. collection_.assign(n, val);
  250. }
  251. /**
  252. * Assign vector content.
  253. *
  254. * Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly.
  255. *
  256. * @param il An initializer_list object.
  257. * The compiler will automatically construct such objects from initializer list declarators.
  258. * Member type value_type is the type of the elements in the container.
  259. * If the size of this list is greater than the maximum number of elements allowed on the
  260. * resource limits configuration, the elements exceeding that maximum will be silently discarded.
  261. */
  262. void assign(
  263. std::initializer_list<value_type> il)
  264. {
  265. size_type n = std::min(il.size(), configuration_.maximum);
  266. collection_.assign(il.begin(), il.begin() + n);
  267. }
  268. /**
  269. * Wrappers to other basic vector methods.
  270. * Please refer to https://en.cppreference.com/w/cpp/container/vector
  271. */
  272. ///@{
  273. reference at(
  274. size_type pos)
  275. {
  276. return collection_.at(pos);
  277. }
  278. const_reference at(
  279. size_type pos) const
  280. {
  281. return collection_.at(pos);
  282. }
  283. reference operator [](
  284. size_type pos)
  285. {
  286. return collection_[pos];
  287. }
  288. const_reference operator [](
  289. size_type pos) const
  290. {
  291. return collection_[pos];
  292. }
  293. reference front()
  294. {
  295. return collection_.front();
  296. }
  297. const_reference front() const
  298. {
  299. return collection_.front();
  300. }
  301. reference back()
  302. {
  303. return collection_.back();
  304. }
  305. const_reference back() const
  306. {
  307. return collection_.back();
  308. }
  309. iterator begin() noexcept
  310. {
  311. return collection_.begin();
  312. }
  313. const_iterator begin() const noexcept
  314. {
  315. return collection_.begin();
  316. }
  317. const_iterator cbegin() const noexcept
  318. {
  319. return collection_.cbegin();
  320. }
  321. iterator end() noexcept
  322. {
  323. return collection_.end();
  324. }
  325. const_iterator end() const noexcept
  326. {
  327. return collection_.end();
  328. }
  329. const_iterator cend() const noexcept
  330. {
  331. return collection_.cend();
  332. }
  333. reverse_iterator rbegin() noexcept
  334. {
  335. return collection_.rbegin();
  336. }
  337. const_reverse_iterator rbegin() const noexcept
  338. {
  339. return collection_.rbegin();
  340. }
  341. const_reverse_iterator crbegin() const noexcept
  342. {
  343. return collection_.crbegin();
  344. }
  345. reverse_iterator rend() noexcept
  346. {
  347. return collection_.rend();
  348. }
  349. const_reverse_iterator rend() const noexcept
  350. {
  351. return collection_.rend();
  352. }
  353. const_reverse_iterator crend() const noexcept
  354. {
  355. return collection_.crend();
  356. }
  357. bool empty() const noexcept
  358. {
  359. return collection_.empty();
  360. }
  361. size_type size() const noexcept
  362. {
  363. return collection_.size();
  364. }
  365. size_type capacity() const noexcept
  366. {
  367. return collection_.capacity();
  368. }
  369. size_type max_size() const noexcept
  370. {
  371. return std::min(configuration_.maximum, collection_.max_size());
  372. }
  373. void clear()
  374. {
  375. collection_.clear();
  376. }
  377. iterator erase(
  378. const_iterator pos)
  379. {
  380. return collection_.erase(pos);
  381. }
  382. iterator erase(
  383. const_iterator first,
  384. const_iterator last)
  385. {
  386. return collection_.erase(first, last);
  387. }
  388. void pop_back()
  389. {
  390. collection_.pop_back();
  391. }
  392. value_type* data()
  393. {
  394. return collection_.data();
  395. }
  396. const value_type* data() const
  397. {
  398. return collection_.data();
  399. }
  400. ///@}
  401. /**
  402. * Const cast to underlying collection.
  403. *
  404. * Useful to easy integration on old APIs where a traditional container was used.
  405. *
  406. * @return const reference to the underlying collection.
  407. */
  408. operator const collection_type& () const noexcept { return collection_; }
  409. protected:
  410. configuration_type configuration_;
  411. collection_type collection_;
  412. /**
  413. * Make room for one item.
  414. *
  415. * Tries to ensure that a new item can be added to the container.
  416. *
  417. * @return true if there is room for a new item, false if resource limit is reached.
  418. */
  419. bool ensure_capacity()
  420. {
  421. size_type size = collection_.size();
  422. size_type cap = collection_.capacity();
  423. if (size == cap)
  424. {
  425. // collection is full, check resource limit
  426. if (cap < configuration_.maximum)
  427. {
  428. // increase collection capacity
  429. assert(configuration_.increment > 0);
  430. cap += configuration_.increment;
  431. cap = std::min(cap, configuration_.maximum);
  432. collection_.reserve(cap);
  433. }
  434. else
  435. {
  436. return false;
  437. }
  438. }
  439. return true;
  440. }
  441. /**
  442. * Remove element.
  443. *
  444. * Removes the element pointed to by it.
  445. * All iterators may become invalidated if this method returns true.
  446. * This version doesn't keep the order of insertion, optimizing the number of copies performed.
  447. *
  448. * @param it Iterator pointing to the item to be removed.
  449. */
  450. template <typename Enabler = _KeepOrderEnabler>
  451. typename std::enable_if<!Enabler::value, void>::type do_remove(
  452. iterator it)
  453. {
  454. // Copy last element into the element being removed
  455. if (it != --collection_.end())
  456. {
  457. *it = std::move(collection_.back());
  458. }
  459. // Then drop last element
  460. collection_.pop_back();
  461. }
  462. /**
  463. * Remove element.
  464. *
  465. * Removes the element pointed to by it.
  466. * All iterators may become invalidated if this method returns true.
  467. * This version keeps the order of insertion, so when removing an item different from the last one,
  468. * part of the collection will be copied.
  469. *
  470. * @param it Iterator pointing to the item to be removed.
  471. */
  472. template <typename Enabler = _KeepOrderEnabler>
  473. typename std::enable_if<Enabler::value, void>::type do_remove(
  474. iterator it)
  475. {
  476. collection_.erase(it);
  477. }
  478. };
  479. } // namespace fastrtps
  480. } // namespace eprosima
  481. #endif /* FASTRTPS_UTILS_COLLECTIONS_RESOURCELIMITEDVECTOR_HPP_ */