FCV.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2024-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #ifndef ZT_FCV_HPP
  14. #define ZT_FCV_HPP
  15. #include "Constants.hpp"
  16. #include <iterator>
  17. #include <algorithm>
  18. #include <memory>
  19. namespace ZeroTier {
  20. /**
  21. * FCV is a Fixed Capacity Vector
  22. *
  23. * This doesn't implement everything in std::vector, just what we need. It
  24. * also adds a few special things for use in ZT core code.
  25. *
  26. * @tparam T Type to contain
  27. * @tparam C Maximum capacity of vector
  28. */
  29. template<typename T, unsigned int C>
  30. class FCV
  31. {
  32. public:
  33. typedef T *iterator;
  34. typedef const T *const_iterator;
  35. ZT_INLINE FCV() noexcept: _s(0)
  36. {}
  37. ZT_INLINE FCV(const FCV &v) : _s(0)
  38. { *this = v; }
  39. ZT_INLINE FCV(const T *const contents, const unsigned int len) :
  40. _s(0)
  41. {
  42. for (unsigned int i = 0;i < len;++i)
  43. push_back(contents[i]);
  44. }
  45. template<typename I>
  46. ZT_INLINE FCV(I i, I end) :
  47. _s(0)
  48. {
  49. while (i != end) {
  50. push_back(*i);
  51. ++i;
  52. }
  53. }
  54. ZT_INLINE ~FCV()
  55. { this->clear(); }
  56. ZT_INLINE FCV &operator=(const FCV &v)
  57. {
  58. if (likely(&v != this)) {
  59. this->clear();
  60. const unsigned int s = v._s;
  61. _s = s;
  62. for (unsigned int i = 0;i < s;++i)
  63. new(reinterpret_cast<T *>(_m) + i) T(*(reinterpret_cast<const T *>(v._m) + i));
  64. }
  65. return *this;
  66. }
  67. /**
  68. * Clear this vector, destroying all content objects
  69. */
  70. ZT_INLINE void clear()
  71. {
  72. const unsigned int s = _s;
  73. _s = 0;
  74. for (unsigned int i = 0;i < s;++i)
  75. (reinterpret_cast<T *>(_m) + i)->~T();
  76. }
  77. /**
  78. * Move contents from this vector to another and clear this vector.
  79. *
  80. * @param v Target vector
  81. */
  82. ZT_INLINE void unsafeMoveTo(FCV &v) noexcept
  83. {
  84. Utils::copy(v._m, _m, (v._s = _s) * sizeof(T));
  85. _s = 0;
  86. }
  87. ZT_INLINE iterator begin() noexcept
  88. { return reinterpret_cast<T *>(_m); }
  89. ZT_INLINE iterator end() noexcept
  90. { return reinterpret_cast<T *>(_m) + _s; }
  91. ZT_INLINE const_iterator begin() const noexcept
  92. { return reinterpret_cast<const T *>(_m); }
  93. ZT_INLINE const_iterator end() const noexcept
  94. { return reinterpret_cast<const T *>(_m) + _s; }
  95. ZT_INLINE T &operator[](const unsigned int i)
  96. {
  97. if (likely(i < _s))
  98. return reinterpret_cast<T *>(_m)[i];
  99. throw std::out_of_range("i > capacity");
  100. }
  101. ZT_INLINE const T &operator[](const unsigned int i) const
  102. {
  103. if (likely(i < _s))
  104. return reinterpret_cast<const T *>(_m)[i];
  105. throw std::out_of_range("i > capacity");
  106. }
  107. static constexpr unsigned int capacity() noexcept
  108. { return C; }
  109. ZT_INLINE unsigned int size() const noexcept
  110. { return _s; }
  111. ZT_INLINE bool empty() const noexcept
  112. { return (_s == 0); }
  113. ZT_INLINE T *data() noexcept
  114. { return reinterpret_cast<T *>(_m); }
  115. ZT_INLINE const T *data() const noexcept
  116. { return reinterpret_cast<const T *>(_m); }
  117. /**
  118. * Push a value onto the back of this vector
  119. *
  120. * If the vector is at capacity this silently fails.
  121. *
  122. * @param v Value to push
  123. */
  124. ZT_INLINE void push_back(const T &v)
  125. {
  126. if (likely(_s < C))
  127. new(reinterpret_cast<T *>(_m) + _s++) T(v);
  128. else throw std::out_of_range("capacity exceeded");
  129. }
  130. /**
  131. * Push new default value or return last in vector if full.
  132. *
  133. * @return Reference to new item
  134. */
  135. ZT_INLINE T &push()
  136. {
  137. if (likely(_s < C)) {
  138. return *(new(reinterpret_cast<T *>(_m) + _s++) T());
  139. } else {
  140. return *(reinterpret_cast<T *>(_m) + (C - 1));
  141. }
  142. }
  143. /**
  144. * Push new default value or replace and return last in vector if full.
  145. *
  146. * @return Reference to new item
  147. */
  148. ZT_INLINE T &push(const T &v)
  149. {
  150. if (likely(_s < C)) {
  151. return *(new(reinterpret_cast<T *>(_m) + _s++) T(v));
  152. } else {
  153. T &tmp = *(reinterpret_cast<T *>(_m) + (C - 1));
  154. tmp = v;
  155. return tmp;
  156. }
  157. }
  158. /**
  159. * Remove the last element if this vector is not empty
  160. */
  161. ZT_INLINE void pop_back()
  162. {
  163. if (likely(_s != 0))
  164. (reinterpret_cast<T *>(_m) + --_s)->~T();
  165. }
  166. /**
  167. * Resize vector
  168. *
  169. * @param ns New size (clipped to C if larger than capacity)
  170. */
  171. ZT_INLINE void resize(unsigned int ns)
  172. {
  173. if (unlikely(ns > C))
  174. throw std::out_of_range("capacity exceeded");
  175. unsigned int s = _s;
  176. while (s < ns)
  177. new(reinterpret_cast<T *>(_m) + s++) T();
  178. while (s > ns)
  179. (reinterpret_cast<T *>(_m) + --s)->~T();
  180. _s = s;
  181. }
  182. /**
  183. * Set the size of this vector without otherwise changing anything
  184. *
  185. * @param ns New size
  186. */
  187. ZT_INLINE void unsafeSetSize(unsigned int ns)
  188. { _s = ns; }
  189. /**
  190. * This is a bounds checked auto-resizing variant of the [] operator
  191. *
  192. * If 'i' is out of bounds vs the current size of the vector, the vector is
  193. * resized. If that size would exceed C (capacity), 'i' is clipped to C-1.
  194. *
  195. * @param i Index to obtain as a reference, resizing if needed
  196. * @return Reference to value at this index
  197. */
  198. ZT_INLINE T &at(unsigned int i)
  199. {
  200. if (i >= _s) {
  201. if (unlikely(i >= C))
  202. i = C - 1;
  203. do {
  204. new(reinterpret_cast<T *>(_m) + _s++) T();
  205. } while (i >= _s);
  206. }
  207. return *(reinterpret_cast<T *>(_m) + i);
  208. }
  209. /**
  210. * Assign this vector's contents from a range of pointers or iterators
  211. *
  212. * If the range is larger than C it is truncated at C.
  213. *
  214. * @tparam X Inferred type of interators or pointers
  215. * @param start Starting iterator
  216. * @param end Ending iterator (must be greater than start)
  217. */
  218. template<typename X>
  219. ZT_INLINE void assign(X start, const X &end)
  220. {
  221. const int l = std::min((int) std::distance(start, end), (int) C);
  222. if (l > 0) {
  223. this->resize((unsigned int) l);
  224. for (int i = 0;i < l;++i)
  225. reinterpret_cast<T *>(_m)[i] = *(start++);
  226. } else {
  227. this->clear();
  228. }
  229. }
  230. ZT_INLINE bool operator==(const FCV &v) const noexcept
  231. {
  232. if (_s == v._s) {
  233. for (unsigned int i = 0;i < _s;++i) {
  234. if (!(*(reinterpret_cast<const T *>(_m) + i) == *(reinterpret_cast<const T *>(v._m) + i)))
  235. return false;
  236. }
  237. return true;
  238. }
  239. return false;
  240. }
  241. ZT_INLINE bool operator!=(const FCV &v) const noexcept
  242. { return (!(*this == v)); }
  243. ZT_INLINE bool operator<(const FCV &v) const noexcept
  244. { return std::lexicographical_compare(begin(), end(), v.begin(), v.end()); }
  245. ZT_INLINE bool operator>(const FCV &v) const noexcept
  246. { return (v < *this); }
  247. ZT_INLINE bool operator<=(const FCV &v) const noexcept
  248. { return !(v < *this); }
  249. ZT_INLINE bool operator>=(const FCV &v) const noexcept
  250. { return !(*this < v); }
  251. private:
  252. #ifdef _MSC_VER
  253. uint8_t _m[sizeof(T) * C];
  254. #else
  255. __attribute__((aligned(16))) uint8_t _m[sizeof(T) * C];
  256. #endif
  257. unsigned int _s;
  258. };
  259. } // namespace ZeroTier
  260. #endif