adt: create split optional span view to be used for C-array types

This commit is contained in:
Francisco Paisana 2021-08-20 12:19:29 +02:00
parent d616e46936
commit e896ac49e8
3 changed files with 316 additions and 78 deletions

View File

@ -14,6 +14,7 @@
#define SRSRAN_OPTIONAL_ARRAY_H
#include "optional.h"
#include "span.h"
#include "srsran/common/srsran_assert.h"
#include <array>
@ -22,9 +23,9 @@ namespace srsran {
namespace detail {
template <typename Vec>
class base_optional_vector
class base_optional_span
{
using base_t = base_optional_vector<Vec>;
using base_t = base_optional_span<Vec>;
using T = typename Vec::value_type::value_type;
protected:
@ -67,7 +68,7 @@ protected:
bool operator==(const It& other) const { return idx == other.idx and parent == other.parent; }
bool operator!=(const It& other) const { return not(*this == other); }
protected:
private:
friend base_t;
base_t* parent = nullptr;
@ -78,24 +79,10 @@ protected:
Vec vec;
public:
using value_type = T;
using iterator = iterator_impl<T>;
using const_iterator = iterator_impl<const T>;
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;
}
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;
nof_elems = 0;
return *this;
}
// Find first position that is empty
size_t find_first_empty(size_t start_guess = 0)
{
@ -112,22 +99,6 @@ public:
bool contains(size_t idx) const { return idx < vec.size() and vec[idx].has_value(); }
void erase(size_t idx)
{
if (contains(idx)) {
nof_elems--;
vec[idx].reset();
}
}
void erase(iterator it) { erase(it.idx); }
void clear()
{
nof_elems = 0;
for (auto& e : *this) {
e.reset();
}
}
T& operator[](size_t idx) { return *vec[idx]; }
const T& operator[](size_t idx) const { return *vec[idx]; }
@ -138,6 +109,58 @@ public:
iterator end() { return iterator{this, vec.size()}; }
const_iterator begin() const { return const_iterator{this, 0}; }
const_iterator end() const { return const_iterator{this, vec.size()}; }
void clear()
{
this->nof_elems = 0;
for (auto& e : *this) {
e.reset();
}
}
void erase(size_t idx)
{
srsran_assert(idx < this->vec.size(), "Out-of-bounds access to array: %zd>=%zd", idx, this->vec.size());
if (this->contains(idx)) {
this->nof_elems--;
this->vec[idx].reset();
}
}
void erase(iterator it) { erase(it.idx); }
template <typename U>
void insert(size_t idx, U&& u)
{
srsran_assert(idx < this->vec.size(), "Out-of-bounds access to array: %zd>=%zd", idx, this->vec.size());
this->nof_elems += this->contains(idx) ? 0 : 1;
this->vec[idx] = std::forward<U>(u);
}
};
template <typename Vec>
class base_optional_vector : public base_optional_span<Vec>
{
using base_t = base_optional_span<Vec>;
public:
using value_type = typename base_optional_span<Vec>::value_type;
using iterator = typename base_optional_span<Vec>::iterator;
using const_iterator = typename base_optional_span<Vec>::const_iterator;
base_optional_vector() = default;
base_optional_vector(const base_optional_vector&) = default;
base_optional_vector(base_optional_vector&& other) noexcept : base_t::vec(std::move(other.vec)),
base_t::nof_elems(other.nof_elems)
{
other.nof_elems = 0;
}
base_optional_vector& operator=(const base_optional_vector&) = default;
base_optional_vector& operator =(base_optional_vector&& other) noexcept
{
this->vec = std::move(other.vec);
this->nof_elems = other.nof_elems;
this->nof_elems = 0;
return *this;
}
};
} // namespace detail
@ -151,17 +174,7 @@ public:
*/
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.
@ -178,14 +191,206 @@ public:
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()));
if (idx >= this->vec.size()) {
this->vec.resize(idx + 1);
}
this->vec[idx] = std::forward<U>(u);
base_t::insert(idx, std::forward<U>(u));
}
};
template <typename T>
class optional_span : public detail::base_optional_span<srsran::span<optional<T> > >
{
using base_t = detail::base_optional_span<srsran::span<optional<T> > >;
public:
template <size_t N>
optional_span(const optional_array<T, N>& ar) : base_t::vec(ar)
{}
optional_span(const optional_vector<T>& ar) : base_t::vec(ar) {}
};
namespace detail {
template <typename T>
class base_split_optional_span
{
protected:
using presence_type = typename std::conditional<std::is_const<T>::value, const bool, bool>::type;
T* ptr = nullptr;
presence_type* present_ptr = nullptr;
size_t len = 0;
template <typename Obj>
class iterator_impl
{
using It = iterator_impl<Obj>;
using Parent = typename std::
conditional<std::is_const<Obj>::value, const base_split_optional_span<T>, base_split_optional_span<T> >::type;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = Obj;
using difference_type = std::ptrdiff_t;
using pointer = Obj*;
using reference = Obj&;
iterator_impl() = default;
iterator_impl(Parent* parent_, size_t idx_) : parent(parent_), idx(idx_)
{
if (idx < parent->len and not parent->contains(idx)) {
++(*this);
}
}
It& operator++()
{
while (++idx < parent->len and not parent->contains(idx)) {
}
return *this;
}
It& operator--()
{
while (--idx < parent->len and not parent->contains(idx)) {
}
return *this;
}
reference operator*() { return parent->operator[](idx); }
pointer operator->() { return &parent->operator[](idx); }
bool operator==(const It& other) const { return idx == other.idx and parent == other.parent; }
bool operator!=(const It& other) const { return not(*this == other); }
size_t get_idx() const { return idx; }
private:
Parent* parent = nullptr;
size_t idx = std::numeric_limits<size_t>::max();
};
public:
using value_type = T;
using iterator = iterator_impl<T>;
using const_iterator = iterator_impl<const T>;
constexpr base_split_optional_span() = default;
template <std::size_t N>
constexpr base_split_optional_span(value_type (&arr)[N], presence_type (&present)[N]) noexcept : ptr(arr),
present_ptr(present),
len(N)
{}
constexpr base_split_optional_span(value_type* arr, presence_type* present, size_t N) :
ptr(arr), present_ptr(present), len(N)
{}
bool contains(size_t idx) const { return idx < len and present_ptr[idx]; }
bool empty() const
{
for (size_t i = 0; i < len; ++i) {
if (present_ptr[i]) {
return false;
}
}
return true;
}
size_t size() const
{
size_t c = 0;
for (size_t i = 0; i < len; ++i) {
c += present_ptr[i] ? 1 : 0;
}
return c;
}
size_t capacity() const { return len; }
const T& operator[](size_t idx) const { return ptr[idx]; }
T& operator[](size_t idx) { return ptr[idx]; }
const T& at(size_t idx) const
{
srsran_assert(contains(idx), "Access to inexistent element of index=%zd", idx);
return ptr[idx];
}
T& at(size_t idx)
{
srsran_assert(this->contains(idx), "Access to inexistent element of index=%zd", idx);
return this->ptr[idx];
}
const_iterator begin() const { return const_iterator(this, 0); }
const_iterator end() const { return const_iterator(this, len); }
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, this->len); }
// Find first position that is empty
size_t find_first_empty(size_t start_guess = 0) { return begin().get_idx(); }
};
} // namespace detail
template <typename T>
class split_optional_span : public detail::base_split_optional_span<T>
{
using base_t = detail::base_split_optional_span<T>;
public:
using value_type = T;
using const_iterator = typename base_t::const_iterator;
using iterator = typename base_t::iterator;
using base_t::base_t;
template <typename U>
void insert(size_t idx, U&& u)
{
srsran_assert(idx < this->len, "Out-of-bounds access to array: %zd>=%zd", idx, this->len);
this->present_ptr[idx] = true;
this->ptr[idx] = std::forward<U>(u);
}
void erase(size_t idx)
{
srsran_assert(idx < this->len, "Out-of-bounds access to array: %zd>=%zd", idx, this->len);
this->present_ptr[idx] = false;
}
void erase(iterator it) { erase(it.get_idx()); }
void clear()
{
for (size_t i = 0; i < this->len; ++i) {
this->present_ptr[i] = false;
}
}
};
template <typename U>
class split_optional_span<const U> : public detail::base_split_optional_span<const U>
{
using base_t = detail::base_split_optional_span<const U>;
using presence_type = typename base_t::presence_type;
public:
using value_type = const U;
using const_iterator = typename base_t::const_iterator;
using base_t::base_t;
};
template <typename T>
split_optional_span<T>
make_optional_span(T* array,
typename std::conditional<std::is_const<T>::value, const bool, bool>::type* present,
size_t N)
{
return split_optional_span<T>(array, present, N);
}
template <typename T, size_t N>
split_optional_span<T>
make_optional_span(T (&array)[N],
typename std::conditional<std::is_const<T>::value, const bool, bool>::type (&present)[N])
{
return split_optional_span<T>(array, present);
}
} // namespace srsran
#endif // SRSRAN_OPTIONAL_ARRAY_H

View File

@ -69,6 +69,42 @@ void test_optional_vector()
TESTASSERT(table1.size() == 1);
}
void test_split_optional_span()
{
constexpr size_t L = 7;
int some_list[L] = {};
bool some_list_presence[L] = {};
split_optional_span<int> view(some_list, some_list_presence, L);
TESTASSERT(view.size() == 0 and view.empty());
TESTASSERT(view.begin() == view.end());
TESTASSERT(not view.contains(0));
TESTASSERT(view.find_first_empty() == L);
view.insert(1, 1);
TESTASSERT(view.size() == 1 and not view.empty());
TESTASSERT(view.begin() != view.end() and *view.begin() == 1);
TESTASSERT(view.contains(1));
TESTASSERT(view[1] == 1);
TESTASSERT(view.find_first_empty() == 1);
view.insert(3, 3);
TESTASSERT(view[3] == 3);
size_t c = 0;
for (auto& e : view) {
TESTASSERT(c == 0 ? e == 1 : e == 3);
c++;
}
TESTASSERT(view.size() == 2);
view.erase(view.begin());
TESTASSERT(view.size() == 1);
TESTASSERT(not view.contains(1) and view.contains(3));
view.clear();
TESTASSERT(view.empty());
}
} // namespace srsran
int main(int argc, char** argv)
@ -80,6 +116,7 @@ int main(int argc, char** argv)
srsran::test_optional_array();
srsran::test_optional_vector();
srsran::test_split_optional_span();
printf("Success\n");
return SRSRAN_SUCCESS;

View File

@ -12,6 +12,7 @@
#include "srsenb/hdr/stack/mac/nr/sched_nr_cfg.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_helpers.h"
#include "srsran/adt/optional_array.h"
extern "C" {
#include "srsran/phy/phch/ra_ul_nr.h"
}
@ -94,45 +95,40 @@ bwp_ue_cfg::bwp_ue_cfg(uint16_t rnti_, const bwp_params& bwp_cfg_, const ue_cfg_
rnti(rnti_), cfg_(&uecfg_), bwp_cfg(&bwp_cfg_)
{
std::fill(ss_id_to_cce_idx.begin(), ss_id_to_cce_idx.end(), SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE);
const auto& pdcch = phy().pdcch;
for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ++i) {
if (pdcch.search_space_present[i]) {
const auto& ss = pdcch.search_space[i];
srsran_assert(pdcch.coreset_present[ss.coreset_id],
"Invalid mapping search space id=%d to coreset id=%d",
ss.id,
ss.coreset_id);
const auto& coreset = pdcch.coreset[ss.coreset_id];
cce_positions_list.emplace_back();
get_dci_locs(coreset, ss, rnti, cce_positions_list.back());
ss_id_to_cce_idx[ss.id] = cce_positions_list.size() - 1;
}
const auto& pdcch = phy().pdcch;
auto ss_view = srsran::make_optional_span(pdcch.search_space, pdcch.search_space_present);
auto coreset_view = srsran::make_optional_span(pdcch.coreset, pdcch.coreset_present);
for (const auto& ss : ss_view) {
srsran_assert(coreset_view.contains(ss.coreset_id),
"Invalid mapping search space id=%d to coreset id=%d",
ss.id,
ss.coreset_id);
cce_positions_list.emplace_back();
get_dci_locs(coreset_view[ss.coreset_id], ss, rnti, cce_positions_list.back());
ss_id_to_cce_idx[ss.id] = cce_positions_list.size() - 1;
}
}
ue_cfg_extended::ue_cfg_extended(uint16_t rnti_, const ue_cfg_t& uecfg) : ue_cfg_t(uecfg), rnti(rnti_)
{
auto ss_view = srsran::make_optional_span(phy_cfg.pdcch.search_space, phy_cfg.pdcch.search_space_present);
auto coreset_view = srsran::make_optional_span(phy_cfg.pdcch.coreset, phy_cfg.pdcch.coreset_present);
cc_params.resize(carriers.size());
for (uint32_t cc = 0; cc < cc_params.size(); ++cc) {
cc_params[cc].bwps.resize(1);
auto& bwp = cc_params[cc].bwps[0];
for (uint32_t ssid = 0; ssid < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ++ssid) {
if (phy_cfg.pdcch.search_space_present[ssid]) {
auto& ss = phy_cfg.pdcch.search_space[ssid];
bwp.ss_list[ss.id].emplace();
bwp.ss_list[ss.id]->cfg = &ss;
get_dci_locs(phy_cfg.pdcch.coreset[ss.coreset_id], ss, rnti, bwp.ss_list[ss.id]->cce_positions);
}
for (auto& ss : ss_view) {
bwp.ss_list[ss.id].emplace();
bwp.ss_list[ss.id]->cfg = &ss;
get_dci_locs(phy_cfg.pdcch.coreset[ss.coreset_id], ss, rnti, bwp.ss_list[ss.id]->cce_positions);
}
for (uint32_t idx = 0; idx < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; ++idx) {
if (phy_cfg.pdcch.coreset_present[idx]) {
bwp.coresets.emplace_back();
auto& coreset = bwp.coresets.back();
coreset.cfg = &phy_cfg.pdcch.coreset[idx];
for (auto& ss : bwp.ss_list) {
if (ss.has_value() and ss->cfg->coreset_id == coreset.cfg->id) {
coreset.ss_list.push_back(ss->cfg->id);
}
for (auto& coreset_cfg : coreset_view) {
bwp.coresets.emplace_back();
auto& coreset = bwp.coresets.back();
coreset.cfg = &coreset_cfg;
for (auto& ss : bwp.ss_list) {
if (ss.has_value() and ss->cfg->coreset_id == coreset.cfg->id) {
coreset.ss_list.push_back(ss->cfg->id);
}
}
}