mirror of https://github.com/PentHertz/srsLTE.git
237 lines
6.2 KiB
C++
237 lines
6.2 KiB
C++
/**
|
|
*
|
|
* \section COPYRIGHT
|
|
*
|
|
* Copyright 2013-2021 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 "srsran/adt/detail/type_utils.h"
|
|
|
|
#ifndef SRSRAN_CHOICE_TYPE_H
|
|
#define SRSRAN_CHOICE_TYPE_H
|
|
|
|
namespace srsran {
|
|
|
|
//! Compute maximum at compile time
|
|
template <std::size_t arg1, std::size_t... others>
|
|
struct static_max;
|
|
template <std::size_t arg>
|
|
struct static_max<arg> {
|
|
static const std::size_t value = arg;
|
|
};
|
|
template <std::size_t arg1, std::size_t arg2, std::size_t... others>
|
|
struct static_max<arg1, arg2, others...> {
|
|
static const std::size_t value =
|
|
arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
|
|
};
|
|
|
|
namespace choice_details {
|
|
|
|
//! Holds one of the Args types
|
|
template <std::size_t MaxSize, std::size_t MaxAlign>
|
|
struct choice_storage_t {
|
|
static const std::size_t max_size = MaxSize;
|
|
static const std::size_t max_align = MaxAlign;
|
|
using buffer_t = typename std::aligned_storage<max_size, max_align>::type;
|
|
buffer_t buffer;
|
|
|
|
void* get_buffer() { return &buffer; }
|
|
|
|
template <typename T>
|
|
T& get_unchecked()
|
|
{
|
|
return *reinterpret_cast<T*>(&buffer);
|
|
}
|
|
|
|
template <typename T>
|
|
const T& get_unchecked() const
|
|
{
|
|
return *reinterpret_cast<const T*>(&buffer);
|
|
}
|
|
|
|
template <typename U>
|
|
void destroy_unchecked()
|
|
{
|
|
get_unchecked<U>().~U();
|
|
};
|
|
};
|
|
|
|
/*************************
|
|
* Tagged Union Helpers
|
|
************************/
|
|
|
|
template <typename C>
|
|
struct CopyCtorVisitor {
|
|
explicit CopyCtorVisitor(C* c_) : c(c_) {}
|
|
template <typename T>
|
|
void operator()(const T& t)
|
|
{
|
|
c->construct_unchecked(t);
|
|
}
|
|
C* c;
|
|
};
|
|
|
|
template <typename C>
|
|
struct MoveCtorVisitor {
|
|
explicit MoveCtorVisitor(C* c_) : c(c_) {}
|
|
template <typename T>
|
|
void operator()(T&& t)
|
|
{
|
|
c->construct_unchecked(std::move(t));
|
|
}
|
|
C* c;
|
|
};
|
|
|
|
template <typename C>
|
|
struct DtorUncheckVisitor {
|
|
explicit DtorUncheckVisitor(C* c_) : c(c_) {}
|
|
template <typename T>
|
|
void operator()(T& t)
|
|
{
|
|
c->template destroy_unchecked<T>();
|
|
}
|
|
C* c;
|
|
};
|
|
|
|
template <typename... Args>
|
|
struct tagged_union_t;
|
|
|
|
template <typename... Args>
|
|
struct tagged_union_t
|
|
: private choice_storage_t<static_max<sizeof(Args)...>::value, static_max<alignof(Args)...>::value> {
|
|
using base_t = choice_storage_t<static_max<sizeof(Args)...>::value, static_max<alignof(Args)...>::value>;
|
|
using buffer_t = typename base_t::buffer_t;
|
|
using this_type = tagged_union_t<Args...>;
|
|
|
|
std::size_t type_id;
|
|
|
|
using base_t::destroy_unchecked;
|
|
using base_t::get_buffer;
|
|
using base_t::get_unchecked;
|
|
|
|
template <typename U, typename... Args2>
|
|
void construct_emplace_unchecked(Args2&&... args)
|
|
{
|
|
using U2 = typename std::decay<U>::type;
|
|
static_assert(type_list_contains<U2, Args...>(),
|
|
"The provided type to ctor is not part of the list of possible types");
|
|
type_id = get_type_index<U2, Args...>();
|
|
new (get_buffer()) U2(std::forward<Args2>(args)...);
|
|
}
|
|
|
|
template <typename U>
|
|
void construct_unchecked(U&& u)
|
|
{
|
|
using U2 = typename std::decay<U>::type;
|
|
static_assert(type_list_contains<U2, Args...>(),
|
|
"The provided type to ctor is not part of the list of possible types");
|
|
type_id = get_type_index<U2, Args...>();
|
|
new (get_buffer()) U2(std::forward<U>(u));
|
|
}
|
|
|
|
void copy_unchecked(const this_type& other) { visit(CopyCtorVisitor<this_type>{this}, other); }
|
|
|
|
void move_unchecked(this_type&& other) { visit(MoveCtorVisitor<this_type>{this}, other); }
|
|
|
|
void dtor_unchecked() { visit(choice_details::DtorUncheckVisitor<base_t>{this}, *this); }
|
|
|
|
size_t get_type_idx() const { return type_id; }
|
|
|
|
template <typename T>
|
|
bool is() const
|
|
{
|
|
return get_type_index<T, Args...>() == type_id;
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr static bool can_hold_type()
|
|
{
|
|
return type_list_contains<T, Args...>();
|
|
}
|
|
};
|
|
|
|
} // namespace choice_details
|
|
|
|
template <typename... Args>
|
|
class choice_t : private choice_details::tagged_union_t<Args...>
|
|
{
|
|
using base_t = choice_details::tagged_union_t<Args...>;
|
|
|
|
public:
|
|
using default_type = typename get_index_type<0, Args...>::type;
|
|
//! Useful metafunction
|
|
template <typename T>
|
|
using enable_if_can_hold =
|
|
typename std::enable_if<base_t::template can_hold_type<typename std::decay<T>::type>()>::type;
|
|
template <typename T>
|
|
using disable_if_can_hold =
|
|
typename std::enable_if<not base_t::template can_hold_type<typename std::decay<T>::type>()>::type;
|
|
|
|
using base_t::can_hold_type;
|
|
using base_t::get_unchecked;
|
|
using base_t::is;
|
|
|
|
template <typename... Args2,
|
|
typename = typename std::enable_if<std::is_constructible<default_type, Args2...>::value>::type>
|
|
explicit choice_t(Args2&&... args) noexcept
|
|
{
|
|
base_t::template construct_emplace_unchecked<default_type>(std::forward<Args2>(args)...);
|
|
}
|
|
|
|
choice_t(const choice_t<Args...>& other) noexcept { base_t::copy_unchecked(other); }
|
|
|
|
choice_t(choice_t<Args...>&& other) noexcept { base_t::move_unchecked(std::move(other)); }
|
|
|
|
template <typename U, typename = enable_if_can_hold<U> >
|
|
choice_t(U&& u) noexcept
|
|
{
|
|
base_t::construct_unchecked(std::forward<U>(u));
|
|
}
|
|
|
|
~choice_t() { base_t::dtor_unchecked(); }
|
|
|
|
template <typename U, typename = enable_if_can_hold<U> >
|
|
choice_t& operator=(U&& u) noexcept
|
|
{
|
|
if (not base_t::template is<U>()) {
|
|
base_t::dtor_unchecked();
|
|
}
|
|
base_t::construct_unchecked(std::forward<U>(u));
|
|
return *this;
|
|
}
|
|
|
|
template <typename U, typename... Args2>
|
|
void emplace(Args2&&... args) noexcept
|
|
{
|
|
base_t::dtor_unchecked();
|
|
base_t::template construct_emplace_unchecked<U>(std::forward<Args2>(args)...);
|
|
}
|
|
|
|
choice_t& operator=(const choice_t& other) noexcept
|
|
{
|
|
if (this != &other) {
|
|
base_t::dtor_unchecked();
|
|
base_t::copy_unchecked(other);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
choice_t& operator=(choice_t&& other) noexcept
|
|
{
|
|
base_t::dtor_unchecked();
|
|
base_t::move_unchecked(std::move(other));
|
|
return *this;
|
|
}
|
|
|
|
bool holds_same_type(const choice_t& other) noexcept { return base_t::type_id == other.type_id; }
|
|
};
|
|
|
|
} // namespace srsran
|
|
|
|
#endif // SRSRAN_CHOICE_TYPE_H
|