|
|
|
@ -19,16 +19,15 @@
|
|
|
|
|
|
|
|
|
|
namespace srsran {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Array of optional items. The iteration is in order of indexes and correctly skips non-present items
|
|
|
|
|
* Pointer/References/Iterators remain valid throughout the object lifetime
|
|
|
|
|
* NOTE: The sorted iteration and pointer validation guarantees add some overhead if the array is very fragmented
|
|
|
|
|
* @tparam T type of objects
|
|
|
|
|
* @tparam N static size of max nof items
|
|
|
|
|
*/
|
|
|
|
|
template <typename T, size_t N>
|
|
|
|
|
class optional_array
|
|
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
|
|
template <typename Vec>
|
|
|
|
|
class base_optional_vector
|
|
|
|
|
{
|
|
|
|
|
using base_t = base_optional_vector<Vec>;
|
|
|
|
|
using T = typename Vec::value_type::value_type;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
template <typename Obj>
|
|
|
|
|
class iterator_impl
|
|
|
|
|
{
|
|
|
|
@ -42,22 +41,22 @@ class optional_array
|
|
|
|
|
using reference = Obj&;
|
|
|
|
|
|
|
|
|
|
iterator_impl() = default;
|
|
|
|
|
iterator_impl(optional_array<T, N>* parent_, size_t idx_) : parent(parent_), idx(idx_)
|
|
|
|
|
iterator_impl(base_t* parent_, size_t idx_) : parent(parent_), idx(idx_)
|
|
|
|
|
{
|
|
|
|
|
if (idx < parent->capacity() and not parent->contains(idx)) {
|
|
|
|
|
if (idx < parent->vec.size() and not parent->contains(idx)) {
|
|
|
|
|
++(*this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It& operator++()
|
|
|
|
|
{
|
|
|
|
|
while (++idx < parent->capacity() and not parent->contains(idx)) {
|
|
|
|
|
while (++idx < parent->vec.size() and not parent->contains(idx)) {
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
It& operator--()
|
|
|
|
|
{
|
|
|
|
|
while (--idx < parent->capacity() and not parent->contains(idx)) {
|
|
|
|
|
while (--idx < parent->vec.size() and not parent->contains(idx)) {
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
@ -69,24 +68,27 @@ class optional_array
|
|
|
|
|
bool operator!=(const It& other) const { return not(*this == other); }
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
friend class optional_array<T, N>;
|
|
|
|
|
friend base_t;
|
|
|
|
|
|
|
|
|
|
optional_array<T, N>* parent = nullptr;
|
|
|
|
|
size_t idx = N;
|
|
|
|
|
base_t* parent = nullptr;
|
|
|
|
|
size_t idx = std::numeric_limits<size_t>::max();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
size_t nof_elems = 0;
|
|
|
|
|
Vec vec;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
using iterator = iterator_impl<T>;
|
|
|
|
|
using const_iterator = iterator_impl<const T>;
|
|
|
|
|
|
|
|
|
|
optional_array() = default;
|
|
|
|
|
optional_array(const optional_array&) = default;
|
|
|
|
|
optional_array(optional_array&& other) noexcept : vec(std::move(other.vec)), nof_elems(other.nof_elems)
|
|
|
|
|
base_optional_vector() = default;
|
|
|
|
|
base_optional_vector(const base_optional_vector&) = default;
|
|
|
|
|
base_optional_vector(base_optional_vector&& other) noexcept : vec(std::move(other.vec)), nof_elems(other.nof_elems)
|
|
|
|
|
{
|
|
|
|
|
other.nof_elems = 0;
|
|
|
|
|
}
|
|
|
|
|
optional_array& operator=(const optional_array&) = default;
|
|
|
|
|
optional_array& operator =(optional_array&& other) noexcept
|
|
|
|
|
base_optional_vector& operator=(const base_optional_vector&) = default;
|
|
|
|
|
base_optional_vector& operator =(base_optional_vector&& other) noexcept
|
|
|
|
|
{
|
|
|
|
|
vec = std::move(other.vec);
|
|
|
|
|
nof_elems = other.nof_elems;
|
|
|
|
@ -97,22 +99,19 @@ public:
|
|
|
|
|
// Find first position that is empty
|
|
|
|
|
size_t find_first_empty(size_t start_guess = 0)
|
|
|
|
|
{
|
|
|
|
|
if (nof_elems == capacity()) {
|
|
|
|
|
return N;
|
|
|
|
|
if (nof_elems == vec.size()) {
|
|
|
|
|
return vec.size();
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = start_guess; i < N; ++i) {
|
|
|
|
|
for (size_t i = start_guess; i < vec.size(); ++i) {
|
|
|
|
|
if (not vec[i].has_value()) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return N;
|
|
|
|
|
}
|
|
|
|
|
template <typename U>
|
|
|
|
|
void insert(size_t idx, U&& u)
|
|
|
|
|
{
|
|
|
|
|
nof_elems += contains(idx) ? 0 : 1;
|
|
|
|
|
vec[idx] = std::forward<U>(u);
|
|
|
|
|
return vec.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool contains(size_t idx) const { return idx < vec.size() and vec[idx].has_value(); }
|
|
|
|
|
|
|
|
|
|
void erase(size_t idx)
|
|
|
|
|
{
|
|
|
|
|
if (contains(idx)) {
|
|
|
|
@ -129,23 +128,62 @@ public:
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool contains(size_t idx) const { return idx < N and vec[idx].has_value(); }
|
|
|
|
|
|
|
|
|
|
T& operator[](size_t idx) { return *vec[idx]; }
|
|
|
|
|
const T& operator[](size_t idx) const { return *vec[idx]; }
|
|
|
|
|
|
|
|
|
|
bool empty() const { return nof_elems == 0; }
|
|
|
|
|
size_t size() const { return nof_elems; }
|
|
|
|
|
static size_t capacity() { return N; }
|
|
|
|
|
bool empty() const { return nof_elems == 0; }
|
|
|
|
|
size_t size() const { return nof_elems; }
|
|
|
|
|
|
|
|
|
|
iterator begin() { return iterator{this, 0}; }
|
|
|
|
|
iterator end() { return iterator{this, N}; }
|
|
|
|
|
iterator end() { return iterator{this, vec.size()}; }
|
|
|
|
|
const_iterator begin() const { return const_iterator{this, 0}; }
|
|
|
|
|
const_iterator end() const { return const_iterator{this, N}; }
|
|
|
|
|
const_iterator end() const { return const_iterator{this, vec.size()}; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
size_t nof_elems = 0;
|
|
|
|
|
std::array<optional<T>, N> vec;
|
|
|
|
|
/**
|
|
|
|
|
* Array of optional items. The iteration is in order of indexes and correctly skips non-present items
|
|
|
|
|
* Pointer/References/Iterators remain valid throughout the object lifetime
|
|
|
|
|
* NOTE: The sorted iteration and pointer validation guarantees add some overhead if the array is very fragmented
|
|
|
|
|
* @tparam T type of objects
|
|
|
|
|
* @tparam N static size of max nof items
|
|
|
|
|
*/
|
|
|
|
|
template <typename T, size_t N>
|
|
|
|
|
class optional_array : public detail::base_optional_vector<std::array<optional<T>, N> >
|
|
|
|
|
{
|
|
|
|
|
using base_t = detail::base_optional_vector<std::array<optional<T>, N> >;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
template <typename U>
|
|
|
|
|
void insert(size_t idx, U&& u)
|
|
|
|
|
{
|
|
|
|
|
this->nof_elems += this->contains(idx) ? 0 : 1;
|
|
|
|
|
this->vec[idx] = std::forward<U>(u);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Contrarily to optional_array, this class may allocate and cause pointer/reference/iterator invalidation.
|
|
|
|
|
* However, the indexes will remain valid.
|
|
|
|
|
* @tparam T
|
|
|
|
|
*/
|
|
|
|
|
template <typename T>
|
|
|
|
|
class optional_vector : public detail::base_optional_vector<std::vector<optional<T> > >
|
|
|
|
|
{
|
|
|
|
|
using base_t = detail::base_optional_vector<std::vector<optional<T> > >;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/// May allocate and cause pointer invalidation
|
|
|
|
|
template <typename U>
|
|
|
|
|
void insert(size_t idx, U&& u)
|
|
|
|
|
{
|
|
|
|
|
if (not this->contains(idx)) {
|
|
|
|
|
this->nof_elems++;
|
|
|
|
|
this->vec.resize(std::max(idx + 1, this->vec.size()));
|
|
|
|
|
}
|
|
|
|
|
this->vec[idx] = std::forward<U>(u);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace srsran
|
|
|
|
|