Last active
August 19, 2021 20:03
-
-
Save KoKuToru/b7904b80a308ca81c4c60e930f3b5683 to your computer and use it in GitHub Desktop.
C++ Variant
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//#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