123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- /*
- * Copyright (c)2013-2020 ZeroTier, Inc.
- *
- * Use of this software is governed by the Business Source License included
- * in the LICENSE.TXT file in the project's root directory.
- *
- * Change Date: 2025-01-01
- *
- * On the date above, in accordance with the Business Source License, use
- * of this software will be governed by version 2.0 of the Apache License.
- */
- /****/
- #ifndef ZT_FCV_HPP
- #define ZT_FCV_HPP
- #include "Constants.hpp"
- #include <iterator>
- #include <algorithm>
- #include <memory>
- #include <stdexcept>
- namespace ZeroTier {
- /**
- * FCV is a Fixed Capacity Vector
- *
- * This doesn't implement everything in std::vector, just what we need. It
- * also adds a few special things for use in ZT core code.
- *
- * @tparam T Type to contain
- * @tparam C Maximum capacity of vector
- */
- template< typename T, unsigned int C >
- class FCV
- {
- public:
- typedef T *iterator;
- typedef const T *const_iterator;
- ZT_INLINE FCV() noexcept: _s(0)
- {}
- ZT_INLINE FCV(const FCV &v) : _s(0)
- { *this = v; }
- ZT_INLINE FCV(const T *const contents, const unsigned int len) :
- _s(len)
- {
- const unsigned int l = std::min(len, C);
- for (unsigned int i = 0; i < l; ++i)
- new(reinterpret_cast<T *>(_m) + i) T(contents[i]);
- }
- template< typename I >
- ZT_INLINE FCV(I i, I end) :
- _s(0)
- {
- while (i != end) {
- push_back(*i);
- ++i;
- }
- }
- ZT_INLINE ~FCV()
- { this->clear(); }
- ZT_INLINE FCV &operator=(const FCV &v)
- {
- if (likely(&v != this)) {
- this->clear();
- const unsigned int s = v._s;
- _s = s;
- for (unsigned int i = 0; i < s; ++i)
- new(reinterpret_cast<T *>(_m) + i) T(*(reinterpret_cast<const T *>(v._m) + i));
- }
- return *this;
- }
- /**
- * Clear this vector, destroying all content objects
- */
- ZT_INLINE void clear()
- {
- const unsigned int s = _s;
- _s = 0;
- for (unsigned int i = 0; i < s; ++i)
- (reinterpret_cast<T *>(_m) + i)->~T();
- }
- /**
- * Move contents from this vector to another and clear this vector.
- *
- * @param v Target vector
- */
- ZT_INLINE void unsafeMoveTo(FCV &v) noexcept
- {
- Utils::copy(v._m, _m, (v._s = _s) * sizeof(T));
- _s = 0;
- }
- ZT_INLINE iterator begin() noexcept
- { return reinterpret_cast<T *>(_m); }
- ZT_INLINE iterator end() noexcept
- { return reinterpret_cast<T *>(_m) + _s; }
- ZT_INLINE const_iterator begin() const noexcept
- { return reinterpret_cast<const T *>(_m); }
- ZT_INLINE const_iterator end() const noexcept
- { return reinterpret_cast<const T *>(_m) + _s; }
- ZT_INLINE T &operator[](const unsigned int i)
- {
- if (likely(i < _s))
- return reinterpret_cast<T *>(_m)[i];
- throw Utils::OutOfRangeException;
- }
- ZT_INLINE const T &operator[](const unsigned int i) const
- {
- if (likely(i < _s))
- return reinterpret_cast<const T *>(_m)[i];
- throw Utils::OutOfRangeException;
- }
- static constexpr unsigned int capacity() noexcept
- { return C; }
- ZT_INLINE unsigned int size() const noexcept
- { return _s; }
- ZT_INLINE bool empty() const noexcept
- { return (_s == 0); }
- ZT_INLINE T *data() noexcept
- { return reinterpret_cast<T *>(_m); }
- ZT_INLINE const T *data() const noexcept
- { return reinterpret_cast<const T *>(_m); }
- /**
- * Push a value onto the back of this vector
- *
- * If the vector is at capacity this silently fails.
- *
- * @param v Value to push
- */
- ZT_INLINE void push_back(const T &v)
- {
- if (likely(_s < C))
- new(reinterpret_cast<T *>(_m) + _s++) T(v);
- else throw Utils::OutOfRangeException;
- }
- /**
- * Push new default value or return last in vector if full.
- *
- * @return Reference to new item
- */
- ZT_INLINE T &push()
- {
- if (likely(_s < C)) {
- return *(new(reinterpret_cast<T *>(_m) + _s++) T());
- } else {
- return *(reinterpret_cast<T *>(_m) + (C - 1));
- }
- }
- /**
- * Push new default value or replace and return last in vector if full.
- *
- * @return Reference to new item
- */
- ZT_INLINE T &push(const T &v)
- {
- if (likely(_s < C)) {
- return *(new(reinterpret_cast<T *>(_m) + _s++) T(v));
- } else {
- T &tmp = *(reinterpret_cast<T *>(_m) + (C - 1));
- tmp = v;
- return tmp;
- }
- }
- /**
- * Remove the last element if this vector is not empty
- */
- ZT_INLINE void pop_back()
- {
- if (likely(_s != 0))
- (reinterpret_cast<T *>(_m) + --_s)->~T();
- }
- /**
- * Resize vector
- *
- * @param ns New size (clipped to C if larger than capacity)
- */
- ZT_INLINE void resize(unsigned int ns)
- {
- if (unlikely(ns > C))
- throw Utils::OutOfRangeException;
- unsigned int s = _s;
- while (s < ns)
- new(reinterpret_cast<T *>(_m) + s++) T();
- while (s > ns)
- (reinterpret_cast<T *>(_m) + --s)->~T();
- _s = s;
- }
- /**
- * Set the size of this vector without otherwise changing anything
- *
- * @param ns New size
- */
- ZT_INLINE void unsafeSetSize(unsigned int ns)
- { _s = ns; }
- /**
- * This is a bounds checked auto-resizing variant of the [] operator
- *
- * If 'i' is out of bounds vs the current size of the vector, the vector is
- * resized. If that size would exceed C (capacity), 'i' is clipped to C-1.
- *
- * @param i Index to obtain as a reference, resizing if needed
- * @return Reference to value at this index
- */
- ZT_INLINE T &at(unsigned int i)
- {
- if (i >= _s) {
- if (unlikely(i >= C))
- i = C - 1;
- do {
- new(reinterpret_cast<T *>(_m) + _s++) T();
- } while (i >= _s);
- }
- return *(reinterpret_cast<T *>(_m) + i);
- }
- /**
- * Assign this vector's contents from a range of pointers or iterators
- *
- * If the range is larger than C it is truncated at C.
- *
- * @tparam X Inferred type of interators or pointers
- * @param start Starting iterator
- * @param end Ending iterator (must be greater than start)
- */
- template< typename X >
- ZT_INLINE void assign(X start, const X &end)
- {
- const int l = std::min((int)std::distance(start, end), (int)C);
- if (l > 0) {
- this->resize((unsigned int)l);
- for (int i = 0; i < l; ++i)
- reinterpret_cast<T *>(_m)[i] = *(start++);
- } else {
- this->clear();
- }
- }
- ZT_INLINE bool operator==(const FCV &v) const noexcept
- {
- if (_s == v._s) {
- for (unsigned int i = 0; i < _s; ++i) {
- if (!(*(reinterpret_cast<const T *>(_m) + i) == *(reinterpret_cast<const T *>(v._m) + i)))
- return false;
- }
- return true;
- }
- return false;
- }
- ZT_INLINE bool operator!=(const FCV &v) const noexcept
- { return (!(*this == v)); }
- ZT_INLINE bool operator<(const FCV &v) const noexcept
- { return std::lexicographical_compare(begin(), end(), v.begin(), v.end()); }
- ZT_INLINE bool operator>(const FCV &v) const noexcept
- { return (v < *this); }
- ZT_INLINE bool operator<=(const FCV &v) const noexcept
- { return !(v < *this); }
- ZT_INLINE bool operator>=(const FCV &v) const noexcept
- { return !(*this < v); }
- private:
- #ifdef _MSC_VER
- uint8_t _m[sizeof(T) * C];
- #else
- __attribute__((aligned(16))) uint8_t _m[sizeof(T) * C];
- #endif
- unsigned int _s;
- };
- } // namespace ZeroTier
- #endif
|