From e896ac49e8513b23066e19fceb82d1a4aa8d1b1f Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 20 Aug 2021 12:19:29 +0200 Subject: [PATCH] adt: create split optional span view to be used for C-array types --- lib/include/srsran/adt/optional_array.h | 303 ++++++++++++++++++++---- lib/test/adt/optional_array_test.cc | 37 +++ srsenb/src/stack/mac/nr/sched_nr_cfg.cc | 54 ++--- 3 files changed, 316 insertions(+), 78 deletions(-) diff --git a/lib/include/srsran/adt/optional_array.h b/lib/include/srsran/adt/optional_array.h index cc107cb86..087705b32 100644 --- a/lib/include/srsran/adt/optional_array.h +++ b/lib/include/srsran/adt/optional_array.h @@ -14,6 +14,7 @@ #define SRSRAN_OPTIONAL_ARRAY_H #include "optional.h" +#include "span.h" #include "srsran/common/srsran_assert.h" #include @@ -22,9 +23,9 @@ namespace srsran { namespace detail { template -class base_optional_vector +class base_optional_span { - using base_t = base_optional_vector; + using base_t = base_optional_span; 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; using const_iterator = iterator_impl; - 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 + 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); + } +}; + +template +class base_optional_vector : public base_optional_span +{ + using base_t = base_optional_span; + +public: + using value_type = typename base_optional_span::value_type; + using iterator = typename base_optional_span::iterator; + using const_iterator = typename base_optional_span::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 class optional_array : public detail::base_optional_vector, N> > -{ - using base_t = detail::base_optional_vector, N> >; - -public: - template - void insert(size_t idx, U&& u) - { - this->nof_elems += this->contains(idx) ? 0 : 1; - this->vec[idx] = std::forward(u); - } -}; +{}; /** * Contrarily to optional_array, this class may allocate and cause pointer/reference/iterator invalidation. @@ -178,14 +191,206 @@ public: template 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); + base_t::insert(idx, std::forward(u)); } }; +template +class optional_span : public detail::base_optional_span > > +{ + using base_t = detail::base_optional_span > >; + +public: + template + optional_span(const optional_array& ar) : base_t::vec(ar) + {} + optional_span(const optional_vector& ar) : base_t::vec(ar) {} +}; + +namespace detail { + +template +class base_split_optional_span +{ +protected: + using presence_type = typename std::conditional::value, const bool, bool>::type; + + T* ptr = nullptr; + presence_type* present_ptr = nullptr; + size_t len = 0; + + template + class iterator_impl + { + using It = iterator_impl; + using Parent = typename std:: + conditional::value, const base_split_optional_span, base_split_optional_span >::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::max(); + }; + +public: + using value_type = T; + using iterator = iterator_impl; + using const_iterator = iterator_impl; + + constexpr base_split_optional_span() = default; + template + 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 +class split_optional_span : public detail::base_split_optional_span +{ + using base_t = detail::base_split_optional_span; + +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 + 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); + } + 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 +class split_optional_span : public detail::base_split_optional_span +{ + using base_t = detail::base_split_optional_span; + 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 +split_optional_span +make_optional_span(T* array, + typename std::conditional::value, const bool, bool>::type* present, + size_t N) +{ + return split_optional_span(array, present, N); +} +template +split_optional_span + make_optional_span(T (&array)[N], + typename std::conditional::value, const bool, bool>::type (&present)[N]) +{ + return split_optional_span(array, present); +} + } // namespace srsran #endif // SRSRAN_OPTIONAL_ARRAY_H diff --git a/lib/test/adt/optional_array_test.cc b/lib/test/adt/optional_array_test.cc index 4402146ab..7ddf21625 100644 --- a/lib/test/adt/optional_array_test.cc +++ b/lib/test/adt/optional_array_test.cc @@ -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 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; diff --git a/srsenb/src/stack/mac/nr/sched_nr_cfg.cc b/srsenb/src/stack/mac/nr/sched_nr_cfg.cc index b81b8743f..b5a156d02 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_cfg.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_cfg.cc @@ -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); } } }