Skip to content

Instantly share code, notes, and snippets.

@Rseding91
Created August 15, 2018 19:39
Show Gist options
  • Save Rseding91/b63189f13f538e4a26ed627f48fd0a45 to your computer and use it in GitHub Desktop.
Save Rseding91/b63189f13f538e4a26ed627f48fd0a45 to your computer and use it in GitHub Desktop.
MacroVariant
#include <MacroVariant.hpp>
bool MacroVariant::isCorrectDataTypeForAction(MacroVariantType action, const std::type_info& type)
{
switch (action)
{
#define ADD_CASE(ACTION, PREFIX, TYPE, VALUE) \
case MacroVariantType::ACTION: return typeid(std::remove_cv<PREFIX TYPE>) == type;
CALL_ON_EVERY_TYPE_WITH_DATA(ADD_CASE)
#undef ADD_CASE
default:
return false;
}
}
MacroVariant::MacroVariant(MacroVariantType type)
: type(type)
{
this->initValue();
}
MacroVariant::MacroVariant(MacroVariant&& other) noexcept
{
this->emplaceConstructFrom(std::move(other));
}
MacroVariant::MacroVariant(const MacroVariant& other)
{
this->emplaceConstructFrom(other);
}
MacroVariant::~MacroVariant()
{
this->destroyValue();
}
MacroVariant& MacroVariant::operator=(MacroVariant&& other) noexcept
{
this->destroyValue();
this->emplaceConstructFrom(std::move(other));
return *this;
}
MacroVariant& MacroVariant::operator=(const MacroVariant& other)
{
this->destroyValue();
this->emplaceConstructFrom(other);
return *this;
}
void MacroVariant::emplaceConstructFrom(const MacroVariant& other)
{
this->type = other.type;
switch (this->type)
{
#define CALL_CONSTRUCT(ACTION, PREFIX, TYPE, VALUE) \
case MacroVariantType::ACTION: new(&this->VALUE) PREFIX TYPE (other.VALUE); break;
CALL_ON_EVERY_TYPE_WITH_DATA(CALL_CONSTRUCT)
#undef CALL_CONSTRUCT
case MacroVariantType::Nothing:
break;
}
}
void MacroVariant::emplaceConstructFrom(MacroVariant&& other) noexcept
{
this->type = other.type;
switch (this->type)
{
#define CALL_CONSTRUCT(ACTION, PREFIX, TYPE, VALUE) \
case MacroVariantType::ACTION: new(&this->VALUE) PREFIX TYPE (std::move(other.VALUE)); break;
CALL_ON_EVERY_TYPE_WITH_DATA(CALL_CONSTRUCT)
#undef CALL_CONSTRUCT
case MacroVariantType::Nothing:
break;
}
}
void MacroVariant::clear()
{
this->destroyValue();
this->type = MacroVariantType::Nothing;
}
namespace MacroVariantHelper
{
template<class T>
void call_destructor(T& value)
{
value.~T();
}
}
void MacroVariant::destroyValue()
{
switch (this->type)
{
#define CALL_DESTRUCTOR(ACTION, PREFIX, TYPE, VALUE) \
case MacroVariantType::ACTION: MacroVariantHelper::call_destructor(this->VALUE); break;
CALL_ON_EVERY_TYPE_WITH_DATA(CALL_DESTRUCTOR)
#undef CALL_DESTRUCTOR
case MacroVariantType::Nothing:
break;
}
}
void MacroVariant::initValue()
{
switch (this->type)
{
#define CALL_CONSTRUCTOR(ACTION, PREFIX, TYPE, VALUE) \
case MacroVariantType::ACTION: new(&this->VALUE) PREFIX TYPE {}; break;
CALL_ON_EVERY_TYPE_WITH_DATA(CALL_CONSTRUCTOR)
#undef CALL_CONSTRUCTOR
case MacroVariantType::Nothing:
break;
}
}
#pragma once
#include <cassert>
#include <string>
#include <type_traits>
#define CALL_ON_EVERY_TYPE_WITH_NO_DATA(MACRO) \
MACRO(Nothing)
#define CALL_ON_EVERY_TYPE_WITH_DATA(MACRO) \
MACRO(Bool,, bool, boolValue) \
MACRO(String, std::, string, stringValue) \
MACRO(IntPointer, , int*, intPointer)
enum class MacroVariantType
{
#define CREATE_TYPE(NAME) \
NAME,
CALL_ON_EVERY_TYPE_WITH_NO_DATA(CREATE_TYPE)
#undef CREATE_TYPE
#define CREATE_TYPE(NAME, PREFIX, TYPE, VALUE) \
NAME,
CALL_ON_EVERY_TYPE_WITH_DATA(CREATE_TYPE)
#undef CREATE_TYPE
};
class MacroVariant
{
public:
#define CALL_ON_EVERY_DATA_TYPE(MACRO) \
MACRO(, bool,, boolValue) \
MACRO(std::, string,, stringValue) \
MACRO(, int, *, intPointer)
static bool isCorrectDataTypeForAction(MacroVariantType action, const std::type_info& type);
MacroVariant() : type(MacroVariantType::Nothing) {}
MacroVariant(MacroVariantType type);
MacroVariant(MacroVariant&& other) noexcept;
MacroVariant(const MacroVariant& other);
~MacroVariant();
#define CREATE_CONSTRUCTOR(PREFIX, TYPE, POINTER, NAME) \
MacroVariant(MacroVariantType type, PREFIX TYPE POINTER const& value) : type(type), NAME(value) \
{ \
assert(MacroVariant::isCorrectDataTypeForAction(type, typeid(std::remove_cv<PREFIX TYPE POINTER>))); \
} \
MacroVariant(MacroVariantType type, PREFIX TYPE POINTER&& value) : type(type), NAME(std::move(value)) \
{ \
assert(MacroVariant::isCorrectDataTypeForAction(type, typeid(std::remove_cv<PREFIX TYPE POINTER>))); \
}
CALL_ON_EVERY_DATA_TYPE(CREATE_CONSTRUCTOR)
#undef CREATE_CONSTRUCTOR
MacroVariantType getType() const { return this->type; }
#define CREATE_UNION_GETTER(PREFIX, TYPE, POINTER, NAME) \
PREFIX TYPE POINTER const& get ## TYPE() const \
{ \
assert(MacroVariant::isCorrectDataTypeForAction(this->type, typeid(std::remove_cv<PREFIX TYPE POINTER>))); \
return this->NAME; \
} \
PREFIX TYPE POINTER& get ## TYPE() \
{ \
assert(MacroVariant::isCorrectDataTypeForAction(this->type, typeid(std::remove_cv<PREFIX TYPE POINTER>))); \
return this->NAME; \
}
CALL_ON_EVERY_DATA_TYPE(CREATE_UNION_GETTER)
#undef CREATE_UNION_GETTER
bool empty() const { return this->type == MacroVariantType::Nothing; }
void clear();
MacroVariant& operator=(MacroVariant&& other) noexcept;
MacroVariant& operator=(const MacroVariant& other);
private:
void destroyValue();
void initValue();
void emplaceConstructFrom(const MacroVariant& other);
void emplaceConstructFrom(MacroVariant&& other) noexcept;
MacroVariantType type;
union
{
#define CREATE_UNION_DATA_TYPE(PREFIX, TYPE, POINTER, NAME) \
PREFIX TYPE POINTER NAME;
CALL_ON_EVERY_DATA_TYPE(CREATE_UNION_DATA_TYPE)
#undef CREATE_UNION_DATA_TYPE
};
};
static_assert(std::is_move_assignable<MacroVariant>::value);
static_assert(std::is_move_constructible<MacroVariant>::value);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment