adt addition - implemented reusable circular map

master
Francisco 4 years ago committed by Francisco Paisana
parent 4523ee6087
commit 98d0637ded

@ -0,0 +1,169 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSLTE_ID_MAP_H
#define SRSLTE_ID_MAP_H
#include "expected.h"
#include <array>
#include <cassert>
template <typename K, typename T, size_t N>
class static_circular_map
{
static_assert(std::is_integral<K>::value, "Map key must be an integer");
using obj_t = std::pair<K, T>;
using obj_storage_t = typename std::aligned_storage<sizeof(obj_t), alignof(obj_t)>::type;
public:
bool has_key(K id)
{
size_t idx = id % N;
return present[idx] and get_obj_(idx).first == id;
}
bool insert(K id, const T& obj)
{
size_t idx = id % N;
if (present[idx]) {
return false;
}
new (&buffer[idx]) obj_t(id, obj);
present[idx] = true;
count++;
return true;
}
srslte::error_type<T> insert(K id, T&& obj)
{
size_t idx = id % N;
if (present[idx]) {
return srslte::error_type<T>(std::move(obj));
}
new (&buffer[idx]) obj_t(id, std::move(obj));
present[idx] = true;
count++;
return {};
}
bool erase(K id)
{
if (not has_key(id)) {
return false;
}
size_t idx = id % N;
get_obj_(idx).~obj_t();
present[idx] = false;
--count;
return true;
}
T& operator[](K id)
{
assert(has_key(id));
return get_obj_(id % N).second;
}
const T& operator[](K id) const
{
assert(has_key(id));
return get_obj_(id % N).second;
}
size_t size() const { return count; }
bool empty() const { return count == 0; }
bool full() const { return count == N; }
size_t capacity() const { return N; }
class iterator
{
public:
iterator() = default;
iterator(static_circular_map<K, T, N>* map, size_t idx_) : ptr(map), idx(idx_)
{
if (idx < ptr->capacity() and not ptr->present[idx]) {
++(*this);
}
}
iterator& operator++()
{
while (++idx < ptr->capacity() and not ptr->present[idx]) {
}
return *this;
}
obj_t& operator*() { return ptr->get_obj_(idx); }
obj_t* operator->() { return &ptr->get_obj_(idx); }
const obj_t* operator*() const { return ptr->buffer[idx]; }
const obj_t* operator->() const { return ptr->buffer[idx]; }
bool operator==(const iterator& other) const { return ptr == other.ptr and idx == other.idx; }
bool operator!=(const iterator& other) const { return not(*this == other); }
private:
static_circular_map<K, T, N>* ptr = nullptr;
size_t idx = 0;
};
class const_iterator
{
public:
const_iterator() = default;
const_iterator(static_circular_map<K, T, N>* map, size_t idx_) : ptr(map), idx(idx_) {}
const_iterator& operator++()
{
while (++idx < ptr->capacity() and not ptr->present[idx]) {
}
return *this;
}
const obj_t* operator*() const { return ptr->buffer[idx]; }
const obj_t* operator->() const { return ptr->buffer[idx]; }
bool operator==(const const_iterator& other) const { return ptr == other.ptr and idx == other.idx; }
bool operator!=(const const_iterator& other) const { return not(*this == other); }
private:
const static_circular_map<K, T, N>* ptr = nullptr;
size_t idx = 0;
};
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, N); }
const_iterator begin() const { return iterator(this, 0); }
const_iterator end() const { return iterator(this, N); }
iterator find(K id)
{
if (has_key(id)) {
return iterator(this, id % N);
}
return end();
}
const_iterator find(K id) const
{
if (has_key(id)) {
return iterator(this, id % N);
}
return end();
}
private:
obj_t& get_obj_(size_t idx) { return reinterpret_cast<obj_t&>(buffer[idx]); }
const obj_t& get_obj_(size_t idx) const { return reinterpret_cast<obj_t&>(buffer[idx]); }
std::array<obj_storage_t, N> buffer;
std::array<bool, N> present = {false};
size_t count = 0;
};
#endif // SRSLTE_ID_MAP_H

@ -45,3 +45,7 @@ add_test(mem_pool_test mem_pool_test)
add_executable(circular_buffer_test circular_buffer_test.cc) add_executable(circular_buffer_test circular_buffer_test.cc)
target_link_libraries(circular_buffer_test srsran_common) target_link_libraries(circular_buffer_test srsran_common)
add_test(circular_buffer_test circular_buffer_test) add_test(circular_buffer_test circular_buffer_test)
add_executable(circular_map_test circular_map_test.cc)
target_link_libraries(circular_map_test srslte_common)
add_test(circular_map_test circular_map_test)

@ -0,0 +1,70 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srslte/adt/circular_map.h"
#include "srslte/common/test_common.h"
namespace srslte {
int test_id_map()
{
static_circular_map<uint32_t, std::string, 16> myobj;
TESTASSERT(myobj.size() == 0 and myobj.empty() and not myobj.full());
TESTASSERT(myobj.begin() == myobj.end());
TESTASSERT(not myobj.has_key(0));
TESTASSERT(myobj.insert(0, "obj0"));
TESTASSERT(myobj.has_key(0) and myobj[0] == "obj0");
TESTASSERT(myobj.size() == 1 and not myobj.empty() and not myobj.full());
TESTASSERT(myobj.begin() != myobj.end());
TESTASSERT(not myobj.insert(0, "obj0"));
TESTASSERT(myobj.insert(1, "obj1"));
TESTASSERT(myobj.has_key(0) and myobj.has_key(1) and myobj[1] == "obj1");
TESTASSERT(myobj.size() == 2 and not myobj.empty() and not myobj.full());
TESTASSERT(myobj.find(1) != myobj.end());
TESTASSERT(myobj.find(1)->first == 1);
TESTASSERT(myobj.find(1)->second == "obj1");
// TEST: iteration
uint32_t count = 0;
for (std::pair<uint32_t, std::string>& obj : myobj) {
TESTASSERT(obj.second == "obj" + std::to_string(count++));
}
// TEST: const iteration
count = 0;
for (const std::pair<uint32_t, std::string>& obj : myobj) {
TESTASSERT(obj.second == "obj" + std::to_string(count++));
}
TESTASSERT(myobj.erase(0));
TESTASSERT(myobj.erase(1));
TESTASSERT(myobj.size() == 0 and myobj.empty());
return SRSLTE_SUCCESS;
}
} // namespace srslte
int main()
{
auto& test_log = srslog::fetch_basic_logger("TEST");
test_log.set_level(srslog::basic_levels::info);
// Start the log backend.
srslog::init();
TESTASSERT(srslte::test_id_map() == SRSLTE_SUCCESS);
return SRSLTE_SUCCESS;
}
Loading…
Cancel
Save