FCV.hpp 6.6 KB

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