Skip to content

Instantly share code, notes, and snippets.

@KoKuToru
Last active August 19, 2021 20:03
Show Gist options
  • Save KoKuToru/b7904b80a308ca81c4c60e930f3b5683 to your computer and use it in GitHub Desktop.
Save KoKuToru/b7904b80a308ca81c4c60e930f3b5683 to your computer and use it in GitHub Desktop.
C++ Variant
//#include <iostream>
#include <type_traits>
#include <string>
#include <stdexcept>
#define FLATTEN __attribute__((flatten))
#define INLINE __attribute__((always_inline))
#define INLINE_FLATTEN __attribute__((always_inline, flatten))
using size_t = std::size_t;
template<typename T>
constexpr size_t GetTypeId() {
throw std::runtime_error("GetTypeId failed");
return 0;
}
template<> constexpr size_t GetTypeId<long long>() { return 1; }
template<> constexpr size_t GetTypeId<int>() { return 2; }
template<> constexpr size_t GetTypeId<short>() { return 3; }
template<> constexpr size_t GetTypeId<unsigned char>() { return 4; }
template<> constexpr size_t GetTypeId<char>() { return 5; }
template<> constexpr size_t GetTypeId<double>() { return 6; }
template<> constexpr size_t GetTypeId<float>() { return 7; }
template<> constexpr size_t GetTypeId<std::string>() { return 8; }
class Variant {
public:
template<typename T>
using supported_value_type = std::enable_if_t<
std::is_same_v<std::remove_cvref_t<T>, long long> ||
std::is_same_v<std::remove_cvref_t<T>, int> ||
std::is_same_v<std::remove_cvref_t<T>, short> ||
std::is_same_v<std::remove_cvref_t<T>, unsigned char> ||
std::is_same_v<std::remove_cvref_t<T>, char> ||
std::is_same_v<std::remove_cvref_t<T>, double> ||
std::is_same_v<std::remove_cvref_t<T>, float>
, bool>;
private:
std::size_t type = 0;
union {
long long s_long_long;
int s_int;
short s_short;
unsigned char s_unsigned_char;
char s_char;
double s_double;
float s_float;
std::string s_string;
};
#define SET(T, N, V)\
case GetTypeId<std::remove_cvref_t<T>>(): {\
type = GetTypeId<std::remove_cvref_t<T>>(); \
N = V;\
return;\
}
#define SET_ALL(V, S)\
switch (GetTypeId<std::remove_cvref_t<decltype(V)>>()) {\
SET(long long, s_long_long, V)\
SET(int, s_int, V)\
SET(short, s_short, V)\
SET(unsigned char, s_unsigned_char, V)\
SET(char, s_char, V)\
SET(double, s_double, V)\
SET(float, s_float, V)\
SET(std::string, s_string, V)\
}
#define GET(M, T, N, S)\
case GetTypeId<std::remove_cvref_t<T>>(): {\
return S((M).N);\
}
#define GET_ALL(M, S)\
switch ((M).type) {\
GET(M, long long, s_long_long, S)\
GET(M, int, s_int, S)\
GET(M, short, s_short, S)\
GET(M, unsigned char, s_unsigned_char, S)\
GET(M, char, s_char, S)\
GET(M, double, s_double, S)\
GET(M, float, s_float, S)\
GET(M, std::string, s_string, S)\
}
// without std::string
#define GET_ALL_V(M, S)\
switch ((M).type) {\
GET(M, long long, s_long_long, S)\
GET(M, int, s_int, S)\
GET(M, short, s_short, S)\
GET(M, unsigned char, s_unsigned_char, S)\
GET(M, char, s_char, S)\
GET(M, double, s_double, S)\
GET(M, float, s_float, S)\
}
template<typename T, supported_value_type<T> = true>
INLINE_FLATTEN void SetValue(T value) {
SET_ALL(value, S)
throw std::runtime_error(__FUNCTION__);
}
INLINE void SetValue(const std::string& value) {
type = GetTypeId<std::string>();
new (&s_string) decltype(s_string)(value);
}
INLINE void Delete() {
if (type == GetTypeId<std::string>()) {
s_string.~basic_string();
}
type = 0;
}
public:
INLINE_FLATTEN Variant() {
SetValue(0);
}
//template<>
INLINE_FLATTEN Variant(Variant&& other) {
[&]() {
GET_ALL(other, ([&](auto& v) {
SetValue(v);
return nullptr;
}))
throw std::runtime_error(__FUNCTION__);
}();
}
template<typename T, supported_value_type<T> = true>
INLINE_FLATTEN Variant(T value) {
SetValue(value);
}
INLINE Variant(std::string&& value) {
SetValue(value);
}
template<typename T, supported_value_type<T> = true>
INLINE_FLATTEN Variant& operator=(T value) {
Delete();
SetValue(value);
return *this;
}
INLINE Variant& operator=(const std::string& value) {
Delete();
SetValue(value);
return *this;
}
INLINE_FLATTEN Variant& operator=(const Variant& other) {
Delete();
[&]() {
GET_ALL(other, ([&](auto& v) {
SetValue(v);
return nullptr;
}))
throw std::runtime_error(__FUNCTION__);
}();
return *this;
}
INLINE ~Variant() {
Delete();
}
INLINE_FLATTEN Variant operator+(const Variant& other) const {
GET_ALL_V(*this, ([&](auto& a) {
GET_ALL_V(other, ([&](auto& b) {
return Variant(a + b);
}))
throw std::runtime_error(__FUNCTION__);
}))
throw std::runtime_error(__FUNCTION__);
}
template<typename T, supported_value_type<T> = true>
INLINE_FLATTEN Variant operator+(T other) const {
GET_ALL_V(*this, ([&](auto& a) {
return Variant(a + other);
}))
throw std::runtime_error(__FUNCTION__);
}
INLINE_FLATTEN Variant operator-(const Variant& other) const {
GET_ALL_V(*this, ([&](auto& a) {
GET_ALL_V(other, ([&](auto& b) {
return Variant(a - b);
}))
throw std::runtime_error(__FUNCTION__);
}))
throw std::runtime_error(__FUNCTION__);
}
template<typename T, supported_value_type<T> = true>
INLINE_FLATTEN Variant operator-(T other) const {
GET_ALL_V(*this, ([&](auto& a) {
return Variant(a - other);
}))
throw std::runtime_error(__FUNCTION__);
}
INLINE_FLATTEN Variant operator/(const Variant& other) const {
GET_ALL_V(*this, ([&](auto& a) {
GET_ALL_V(other, ([&](auto& b) {
return Variant(a / b);
}))
throw std::runtime_error(__FUNCTION__);
}))
throw std::runtime_error(__FUNCTION__);
}
template<typename T, supported_value_type<T> = true>
INLINE_FLATTEN Variant operator/(T other) const {
GET_ALL_V(*this, ([&](auto& a) {
return Variant(a / other);
}))
throw std::runtime_error(__FUNCTION__);
}
INLINE_FLATTEN Variant operator*(const Variant& other) const {
GET_ALL_V(*this, ([&](auto& a) {
GET_ALL_V(other, ([&](auto& b) {
return Variant(a * b);
}))
throw std::runtime_error(__FUNCTION__);
}))
throw std::runtime_error(__FUNCTION__);
}
template<typename T, supported_value_type<T> = true>
INLINE_FLATTEN Variant operator*(T other) const {
GET_ALL_V(*this, ([&](auto& a) {
return Variant(a * other);
}))
throw std::runtime_error(__FUNCTION__);
}
template<typename T, supported_value_type<T> = true>
INLINE_FLATTEN operator T() const {
GET_ALL_V(*this, ([&](auto& v) {
return T(v);
}))
throw std::runtime_error(__FUNCTION__);
}
INLINE operator std::string() const {
switch (type) {
case GetTypeId<std::string>():
return s_string;
}
throw std::runtime_error(__FUNCTION__);
}
};
template<typename T, Variant::supported_value_type<T> = true>
FLATTEN Variant operator+(T a, const Variant& b) {
return Variant(a) + b;
}
template<typename T, Variant::supported_value_type<T> = true>
FLATTEN Variant operator-(T a, const Variant& b) {
return Variant(a) - b;
}
template<typename T, Variant::supported_value_type<T> = true>
FLATTEN Variant operator/(T a, const Variant& b) {
return Variant(a) / b;
}
template<typename T, Variant::supported_value_type<T> = true>
FLATTEN Variant operator*(T a, const Variant& b) {
return Variant(a) * b;
}
int main(int argc, char** argv) {
Variant x;
x = std::string("muh");
std::cout << "hi " << std::string(x) << std::endl;
x = 42;
x = 10.1;
for (auto i = 0; i < argc; ++i) {
x = (x + 11.5) * 10;
x = 2 + x;
}
std::cout << "res(" << argc << ") " << double(x) << std::endl;
return x;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment