mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Refactor custom variant template.
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
all:
|
||||
clang++ -std=c++14 -I../../src main.cc
|
||||
clang++ -std=c++14 -I../../src tusdz-variant.cc
|
||||
|
||||
176
sandbox/simple_variant/tusdz-variant.cc
Normal file
176
sandbox/simple_variant/tusdz-variant.cc
Normal file
@@ -0,0 +1,176 @@
|
||||
#include <iostream>
|
||||
//#include <utility>
|
||||
//#include <typeinfo>
|
||||
//#include <type_traits>
|
||||
#include <string>
|
||||
|
||||
#include "value-type.hh"
|
||||
|
||||
namespace tinyusdz {
|
||||
|
||||
// Simpole variant template Based on
|
||||
// https://gist.github.com/tibordp/6909880#file-variant-cc-L148
|
||||
//
|
||||
// Modification:
|
||||
// - Use TypeTrait::type_id so only types which defines TypeTrait are
|
||||
// supported.
|
||||
// - Remove std::swap
|
||||
// https://gist.github.com/tibordp/6909880?permalink_comment_id=1831344#gistcomment-1831344
|
||||
|
||||
// Equivalent to std::aligned_storage
|
||||
template <unsigned int Len, unsigned int Align>
|
||||
struct aligned_storage {
|
||||
struct type {
|
||||
alignas(Align) unsigned char data[Len];
|
||||
};
|
||||
};
|
||||
|
||||
template <size_t arg1, size_t... others>
|
||||
struct static_max;
|
||||
|
||||
template <size_t arg>
|
||||
struct static_max<arg> {
|
||||
static const size_t value = arg;
|
||||
};
|
||||
|
||||
template <size_t arg1, size_t arg2, size_t... others>
|
||||
struct static_max<arg1, arg2, others...> {
|
||||
static const size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value
|
||||
: static_max<arg2, others...>::value;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct variant_helper;
|
||||
|
||||
template <typename F, typename... Ts>
|
||||
struct variant_helper<F, Ts...> {
|
||||
inline static void destroy(size_t id, void* data) {
|
||||
if (id == value::TypeTrait<F>::type_id)
|
||||
reinterpret_cast<F*>(data)->~F();
|
||||
else
|
||||
variant_helper<Ts...>::destroy(id, data);
|
||||
}
|
||||
|
||||
inline static void move(size_t old_t, void* old_v, void* new_v) {
|
||||
if (old_t == value::TypeTrait<F>::type_id)
|
||||
new (new_v) F(std::move(*reinterpret_cast<F*>(old_v)));
|
||||
else
|
||||
variant_helper<Ts...>::move(old_t, old_v, new_v);
|
||||
}
|
||||
|
||||
inline static void copy(size_t old_t, const void* old_v, void* new_v) {
|
||||
if (old_t == value::TypeTrait<F>::type_id)
|
||||
new (new_v) F(*reinterpret_cast<const F*>(old_v));
|
||||
else
|
||||
variant_helper<Ts...>::copy(old_t, old_v, new_v);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct variant_helper<> {
|
||||
inline static void destroy(size_t id, void* data) {}
|
||||
inline static void move(size_t old_t, void* old_v, void* new_v) {}
|
||||
inline static void copy(size_t old_t, const void* old_v, void* new_v) {}
|
||||
};
|
||||
|
||||
template <typename...>
|
||||
struct is_one_of {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <typename T, typename S, typename... Ts>
|
||||
struct is_one_of<T, S, Ts...> {
|
||||
static constexpr bool value =
|
||||
std::is_same<T, S>::value || is_one_of<T, Ts...>::value;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct variant {
|
||||
private:
|
||||
static const size_t data_size = static_max<sizeof(Ts)...>::value;
|
||||
static const size_t data_align = static_max<alignof(Ts)...>::value;
|
||||
|
||||
using data_t = typename std::aligned_storage<data_size, data_align>::type;
|
||||
|
||||
using helper_t = variant_helper<Ts...>;
|
||||
|
||||
static inline size_t invalid_type() {
|
||||
return value::TypeTrait<void>::type_id;
|
||||
}
|
||||
|
||||
size_t type_id;
|
||||
data_t data;
|
||||
|
||||
public:
|
||||
variant() : type_id(invalid_type()) {}
|
||||
|
||||
variant(const variant<Ts...>& old) : type_id(old.type_id) {
|
||||
helper_t::copy(old.type_id, &old.data, &data);
|
||||
}
|
||||
|
||||
variant(variant<Ts...>&& old) : type_id(old.type_id) {
|
||||
helper_t::move(old.type_id, &old.data, &data);
|
||||
}
|
||||
|
||||
// Serves as both the move and the copy asignment operator.
|
||||
variant<Ts...>& operator=(variant<Ts...>& rhs) {
|
||||
// std::swap + aligned_storage = undefined behavior with non-trivially
|
||||
// copyable types
|
||||
// https://gist.github.com/tibordp/6909880?permalink_comment_id=1831344#gistcomment-1831344
|
||||
// std::swap(type_id, old.type_id);
|
||||
// std::swap(data, old.data);
|
||||
|
||||
helper_t::destroy(type_id, &data);
|
||||
type_id = rhs.type_id;
|
||||
helper_t::copy(rhs.type_id, &rhs.data, &data);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void is() {
|
||||
return (type_id == value::TypeTrait<T>::type_id);
|
||||
}
|
||||
|
||||
bool valid() { return (type_id != invalid_type()); }
|
||||
|
||||
// template<typename T, typename... Args>
|
||||
template <typename T, typename... Args,
|
||||
typename =
|
||||
typename std::enable_if<is_one_of<T, Ts...>::value, void>::type>
|
||||
void set(Args&&... args) {
|
||||
// First we destroy the current contents
|
||||
helper_t::destroy(type_id, &data);
|
||||
new (&data) T(std::forward<Args>(args)...);
|
||||
type_id = value::TypeTrait<T>::type_id;
|
||||
}
|
||||
|
||||
// template<typename T>
|
||||
template <typename T, typename... Args,
|
||||
typename =
|
||||
typename std::enable_if<is_one_of<T, Ts...>::value, void>::type>
|
||||
T& get() {
|
||||
// It is a dynamic_cast-like behaviour
|
||||
if (type_id == value::TypeTrait<T>::type_id)
|
||||
return *reinterpret_cast<T*>(&data);
|
||||
else
|
||||
throw std::bad_cast();
|
||||
}
|
||||
|
||||
~variant() { helper_t::destroy(type_id, &data); }
|
||||
};
|
||||
|
||||
} // namespace tinyusdz
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
tinyusdz::variant<bool, std::string> a;
|
||||
a.set<bool>(true);
|
||||
a.set<std::string>("bora");
|
||||
|
||||
tinyusdz::variant<bool, std::string> b = a;
|
||||
|
||||
std::cout << a.get<std::string>() << "\n";
|
||||
std::cout << b.get<std::string>() << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -594,6 +594,9 @@ struct TypeTrait;
|
||||
} \
|
||||
}
|
||||
|
||||
// Invalid type
|
||||
DEFINE_TYPE_TRAIT(void, "void", TYPE_ID_ALL, 1);
|
||||
|
||||
DEFINE_TYPE_TRAIT(bool, kBool, TYPE_ID_BOOL, 1);
|
||||
DEFINE_TYPE_TRAIT(uint8_t, kUChar, TYPE_ID_UCHAR, 1);
|
||||
DEFINE_TYPE_TRAIT(half, kHalf, TYPE_ID_HALF, 1);
|
||||
|
||||
Reference in New Issue
Block a user