Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- namespace detail
- {
- class VariantHelper
- {
- public:
- typedef void(*DestructFunc)(void*);
- typedef void(*CopyFunc)(const void*, void*);
- typedef void(*MoveFunc)(void*, void*);
- typedef std::wstring(*ToStringFunc)(const void*);
- struct FuncPointers
- {
- FuncPointers(DestructFunc destruct, CopyFunc copy, MoveFunc move, ToStringFunc toString)
- : Destruct(destruct)
- , Copy(copy)
- , Move(move)
- , ToString(toString)
- {
- }
- DestructFunc Destruct;
- CopyFunc Copy;
- MoveFunc Move;
- ToStringFunc ToString;
- };
- template <typename T>
- static const FuncPointers * GetFuncPointers()
- {
- static FuncPointers funcPointers(
- GetDestructFunc<T>(),
- GetCopyFunc<T>(),
- GetMoveFunc<T>(),
- GetToStringFunc<T>());
- return &funcPointers;
- }
- private:
- template <typename T>
- static DestructFunc GetDestructFunc()
- {
- static auto destruct = [](void* storage)
- {
- reinterpret_cast<T*>(storage)->~T();
- };
- return destruct;
- }
- template <typename T>
- static CopyFunc GetCopyFunc()
- {
- static auto copy = [](const void* oldStorage, void* newStorage)
- {
- new (newStorage) T(*reinterpret_cast<const T*>(oldStorage));
- };
- return copy;
- }
- template <typename T>
- static MoveFunc GetMoveFunc()
- {
- static auto move = [](void* oldStorage, void* newStorage)
- {
- new (newStorage) T(std::move(*reinterpret_cast<T*>(oldStorage)));
- };
- return move;
- }
- template <typename T>
- static ToStringFunc GetToStringFunc()
- {
- static auto toString = [](const void* storage)
- {
- std::wstring str;
- // Write (*reinterpret_cast<const T*>(storage)) in a string representation
- return str;
- };
- return toString;
- }
- };
- }
- /// <summary>
- /// Variant implementation.
- /// </summary>
- template <typename ...Types>
- class VariantValue
- {
- public:
- VariantValue()
- : helperFuncs_(nullptr)
- {
- }
- VariantValue(VariantValue const& other)
- : helperFuncs_(other.helperFuncs_)
- {
- if (IsValid())
- {
- helperFuncs_->Copy(&other.storage_, &storage_);
- }
- }
- VariantValue(VariantValue&& other)
- : helperFuncs_(other.helperFuncs_)
- {
- if (IsValid())
- {
- helperFuncs_->Move(&other.storage_, &storage_);
- }
- }
- VariantValue& operator=(VariantValue const& other)
- {
- if (IsValid())
- {
- helperFuncs_->Destruct(&storage_);
- }
- helperFuncs_ = other.helperFuncs_;
- if (IsValid())
- {
- helperFuncs_->Copy(&other.storage_, &storage_);
- }
- return *this;
- }
- ~VariantValue()
- {
- if (IsValid())
- {
- helperFuncs_->Destruct(&storage_);
- }
- }
- /// <summary>
- /// Sets the value in the variant.
- /// </summary>
- template <class FieldT>
- void Set(FieldT&& value)
- {
- InPlace(std::forward<FieldT>(value));
- SetInternal<FieldT>();
- }
- /// <summary>
- /// Sets the value in the variant.
- /// </summary>
- template <class FieldT>
- void Set(FieldT const& value)
- {
- InPlace(value);
- SetInternal<FieldT>();
- }
- /// <summary>
- /// Gets the value from the variant.
- /// </summary>
- template <class FieldT>
- FieldT const& Get() const
- {
- if (!IsValid())
- {
- throw std::bad_cast();
- }
- return *reinterpret_cast<const FieldT*>(&storage_);
- }
- /// <summary>
- /// Gets the value from the variant as a string.
- /// </summary>
- std::wstring ToString() const
- {
- if (!IsValid())
- {
- throw std::bad_cast();
- }
- return helperFuncs_->ToString(&storage_);
- }
- private:
- bool IsValid() const
- {
- return helperFuncs_;
- }
- template <typename FieldT>
- void InPlace(FieldT&& value)
- {
- if (IsValid())
- {
- helperFuncs_->Destruct(&storage_);
- }
- ::new (&storage_) FieldT(value);
- }
- template <typename FieldT>
- void InPlace(FieldT const& value)
- {
- if (IsValid())
- {
- helperFuncs_->Destruct(&storage_);
- }
- ::new (&storage_) FieldT(value);
- }
- template <class FieldT>
- void SetInternal()
- {
- helperFuncs_ = detail::VariantHelper::GetFuncPointers<FieldT>();
- }
- using Storage = typename std::aligned_union<0, Types...>::type;
- Storage storage_;
- const detail::VariantHelper::FuncPointers* helperFuncs_;
- };
Add Comment
Please, Sign In to add comment