TinyVector.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright (c)2019 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: 2023-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_TINYVECTOR_HPP
  14. #define ZT_TINYVECTOR_HPP
  15. #include "Constants.hpp"
  16. #include "Utils.hpp"
  17. #include <utility>
  18. #include <stdexcept>
  19. #include <algorithm>
  20. namespace ZeroTier {
  21. /**
  22. * Tiny vector with a static base capacity for allocation-free operation at small sizes
  23. *
  24. * This doesn't support all of std::vector, uses low-level memcpy to relocate things, and
  25. * lacks bounds checking. It's only intended for uses where a minimal subset of the vector
  26. * container is needed, the objects are primitive or safe to handle in this way, and the
  27. * number of items is typically less than or equal to some statically definable value.
  28. *
  29. * Examples of safe objects for this include primitive types, Str, SharedPtr, InetAddress,
  30. * Address, MAC, etc.
  31. *
  32. * @tparam T Type to encapsulate
  33. * @tparam BASE Base number of items to allocate storage inside the object itself (default: 4)
  34. */
  35. template<typename T,unsigned long BASE = 4>
  36. class TinyVector
  37. {
  38. public:
  39. typedef unsigned long size_t;
  40. typedef T * iterator;
  41. typedef const T * const_iterator;
  42. typedef T & reference;
  43. typedef const T & const_reference;
  44. ZT_ALWAYS_INLINE TinyVector() :
  45. _v((void *)_baseMem),
  46. _c(BASE),
  47. _l(0)
  48. {
  49. }
  50. ZT_ALWAYS_INLINE TinyVector(const TinyVector &vec) :
  51. _v((void *)_baseMem),
  52. _c(BASE),
  53. _l(0)
  54. {
  55. *this = vec;
  56. }
  57. ZT_ALWAYS_INLINE ~TinyVector()
  58. {
  59. clear();
  60. if (_v != (void *)_baseMem)
  61. free(_v);
  62. }
  63. ZT_ALWAYS_INLINE TinyVector &operator=(const TinyVector &vec)
  64. {
  65. unsigned long i = 0;
  66. if (_l < vec._l) {
  67. while (i < _l) {
  68. reinterpret_cast<T *>(_v)[i] = reinterpret_cast<const T *>(vec._v)[i];
  69. ++i;
  70. }
  71. if (vec._l > _c) {
  72. unsigned long nc = vec._c;
  73. void *nv;
  74. if (_v == (void *)_baseMem) {
  75. nv = malloc(nc);
  76. memcpy(nv,_v,sizeof(T) * _l);
  77. } else {
  78. nv = realloc(_v,nc);
  79. if (!nv)
  80. throw std::bad_alloc();
  81. }
  82. _v = nv;
  83. _c = nc;
  84. }
  85. while (i < vec._l) {
  86. new (reinterpret_cast<T *>(_v) + i) T(reinterpret_cast<const T *>(vec._v)[i]);
  87. ++i;
  88. }
  89. } else {
  90. while (i < vec._l) {
  91. reinterpret_cast<T *>(_v)[i] = reinterpret_cast<const T *>(vec._v)[i];
  92. ++i;
  93. }
  94. if (!Utils::isPrimitiveType<T>()) {
  95. while (i < _l)
  96. reinterpret_cast<T *>(_v)[i++]->~T();
  97. }
  98. }
  99. _l = vec._l;
  100. }
  101. ZT_ALWAYS_INLINE void clear()
  102. {
  103. if (!Utils::isPrimitiveType<T>()) {
  104. for (unsigned long i = 0; i < _l; ++i)
  105. reinterpret_cast<T *>(_v)[i]->~T();
  106. }
  107. _l = 0;
  108. }
  109. ZT_ALWAYS_INLINE void push_back(const T &v)
  110. {
  111. if (_l >= _c) {
  112. unsigned long nc = _c << 1U;
  113. void *nv;
  114. if (_v == (void *)_baseMem) {
  115. nv = malloc(sizeof(T) * nc);
  116. memcpy(nv,_v,sizeof(T) * _l);
  117. } else {
  118. nv = realloc(_v,sizeof(T) * nc);
  119. if (!nv)
  120. throw std::bad_alloc();
  121. }
  122. _v = nv;
  123. _c = nc;
  124. }
  125. new (reinterpret_cast<T *>(_v) + _l++) T(v);
  126. }
  127. ZT_ALWAYS_INLINE void pop_back()
  128. {
  129. if (!Utils::isPrimitiveType<T>())
  130. reinterpret_cast<T *>(_v)[_l]->~T();
  131. --_l;
  132. }
  133. ZT_ALWAYS_INLINE reference front() { reinterpret_cast<T *>(_v)[0]; }
  134. ZT_ALWAYS_INLINE const_reference front() const { reinterpret_cast<T *>(_v)[0]; }
  135. ZT_ALWAYS_INLINE reference back() { reinterpret_cast<T *>(_v)[_l - 1]; }
  136. ZT_ALWAYS_INLINE const_reference back() const { reinterpret_cast<T *>(_v)[_l - 1]; }
  137. ZT_ALWAYS_INLINE unsigned long size() const { return _l; }
  138. ZT_ALWAYS_INLINE bool empty() const { return (_l == 0); }
  139. ZT_ALWAYS_INLINE iterator begin() { return reinterpret_cast<T *>(_v); }
  140. ZT_ALWAYS_INLINE iterator end() { return (reinterpret_cast<T *>(_v) + _l); }
  141. ZT_ALWAYS_INLINE const_iterator begin() const { return reinterpret_cast<T *>(_v); }
  142. ZT_ALWAYS_INLINE const_iterator end() const { return (reinterpret_cast<T *>(_v) + _l); }
  143. ZT_ALWAYS_INLINE T *data() { return reinterpret_cast<T *>(_v); }
  144. ZT_ALWAYS_INLINE const T *data() const { return reinterpret_cast<T *>(_v); }
  145. ZT_ALWAYS_INLINE reference operator[](const unsigned long i) { return reinterpret_cast<T *>(_v)[i]; }
  146. ZT_ALWAYS_INLINE const_reference operator[](const unsigned long i) const { return reinterpret_cast<T *>(_v)[i]; }
  147. ZT_ALWAYS_INLINE reference at(const unsigned long i) { return reinterpret_cast<T *>(_v)[i]; }
  148. ZT_ALWAYS_INLINE const_reference at(const unsigned long i) const { return reinterpret_cast<T *>(_v)[i]; }
  149. private:
  150. uint8_t _baseMem[BASE * sizeof(T)];
  151. void *_v;
  152. unsigned long _c;
  153. unsigned long _l;
  154. };
  155. } // namespace ZeroTier
  156. #endif