forked from Bananymous/banan-os
BAN: implement Variant<> for two types
This commit is contained in:
parent
afd4b7a184
commit
10b6d51522
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(__is_kernel)
|
||||||
|
#include <kernel/Panic.h>
|
||||||
|
#define ASSERT(cond) do { if (!(cond)) Kernel::panic("ASSERT("#cond") failed"); } while(false)
|
||||||
|
#else
|
||||||
|
#error "NOT IMPLEMENTED"
|
||||||
|
#endif
|
|
@ -0,0 +1,147 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Assert.h>
|
||||||
|
#include <BAN/Math.h>
|
||||||
|
#include <BAN/Move.h>
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
class Variant
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static_assert(!is_same_v<T1, T2>);
|
||||||
|
|
||||||
|
Variant() = default;
|
||||||
|
|
||||||
|
Variant(const T1& value) { set(value); }
|
||||||
|
Variant(T1&& value) { set(move(value)); }
|
||||||
|
Variant(const T2& value) { set(value); }
|
||||||
|
Variant(T2&& value) { set(move(value)); }
|
||||||
|
|
||||||
|
Variant(const Variant<T1, T2>& other) { *this = other; }
|
||||||
|
Variant(Variant<T1, T2>&& other) { *this = move(other); }
|
||||||
|
|
||||||
|
~Variant() { clear(); }
|
||||||
|
|
||||||
|
Variant<T1, T2>& operator=(const Variant<T1, T2>& other);
|
||||||
|
Variant<T1, T2>& operator=(Variant<T1, T2>&& other);
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
bool is() const;
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
void set(U&&);
|
||||||
|
template<typename U>
|
||||||
|
void set(const U& value) { set(move(U(value))); }
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
const U& get() const;
|
||||||
|
template<typename U>
|
||||||
|
U& get();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr uint32_t m_size = Math::max(sizeof(T1), sizeof(T2));
|
||||||
|
uint8_t m_storage[m_size] = {};
|
||||||
|
uint32_t m_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
Variant<T1, T2>& Variant<T1, T2>::operator=(const Variant<T1, T2>& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
if (other.is<T1>())
|
||||||
|
set(other.get<T1>());
|
||||||
|
if (other.is<T2>())
|
||||||
|
set(other.get<T2>());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
Variant<T1, T2>& Variant<T1, T2>::operator=(Variant<T1, T2>&& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
if (other.is<T1>())
|
||||||
|
set(move(other.get<T1>()));
|
||||||
|
if (other.is<T2>())
|
||||||
|
set(move(other.get<T2>()));
|
||||||
|
other.clear();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
template<typename U>
|
||||||
|
bool Variant<T1, T2>::is() const
|
||||||
|
{
|
||||||
|
if constexpr(is_same_v<T1, U>)
|
||||||
|
return m_index == 1;
|
||||||
|
if constexpr(is_same_v<T2, U>)
|
||||||
|
return m_index == 2;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
template<typename U>
|
||||||
|
void Variant<T1, T2>::set(U&& value)
|
||||||
|
{
|
||||||
|
static_assert(is_same_v<T1, U> || is_same_v<T2, U>);
|
||||||
|
clear();
|
||||||
|
if constexpr(is_same_v<T1, U>)
|
||||||
|
{
|
||||||
|
new (m_storage) T1(move(value));
|
||||||
|
m_index = 1;
|
||||||
|
}
|
||||||
|
if constexpr(is_same_v<T2, U>)
|
||||||
|
{
|
||||||
|
new (m_storage) T2(move(value));
|
||||||
|
m_index = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
template<typename U>
|
||||||
|
const U& Variant<T1, T2>::get() const
|
||||||
|
{
|
||||||
|
static_assert(is_same_v<T1, U> || is_same_v<T2, U>);
|
||||||
|
if constexpr(is_same_v<T1, U>)
|
||||||
|
{
|
||||||
|
ASSERT(m_index == 1);
|
||||||
|
return *(T1*)m_storage;
|
||||||
|
}
|
||||||
|
if constexpr(is_same_v<T2, U>)
|
||||||
|
{
|
||||||
|
ASSERT(m_index == 2);
|
||||||
|
return *(T2*)m_storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
template<typename U>
|
||||||
|
U& Variant<T1, T2>::get()
|
||||||
|
{
|
||||||
|
static_assert(is_same_v<T1, U> || is_same_v<T2, U>);
|
||||||
|
if constexpr(is_same_v<T1, U>)
|
||||||
|
{
|
||||||
|
ASSERT(m_index == 1);
|
||||||
|
return *(T1*)m_storage;
|
||||||
|
}
|
||||||
|
if constexpr(is_same_v<T2, U>)
|
||||||
|
{
|
||||||
|
ASSERT(m_index == 2);
|
||||||
|
return *(T2*)m_storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
void Variant<T1, T2>::clear()
|
||||||
|
{
|
||||||
|
if (is<T1>()) ((T1*)m_storage)->~T1();
|
||||||
|
if (is<T2>()) ((T2*)m_storage)->~T2();
|
||||||
|
m_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue