diff options
Diffstat (limited to 'src/common/windows/variant.hpp')
| -rw-r--r-- | src/common/windows/variant.hpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/common/windows/variant.hpp b/src/common/windows/variant.hpp new file mode 100644 index 0000000..58e46b7 --- /dev/null +++ b/src/common/windows/variant.hpp @@ -0,0 +1,164 @@ +#include <oaidl.h> +#include <propidl.h> +#include <type_traits> +#include <utility> +#include <string_view> +#include <cassert> +#include <cstdint> + +template <typename TVariant> +struct FFBaseVariant : TVariant { + bool hasValue() { + return this->vt != VT_EMPTY; + } + + explicit operator bool() { + return this->hasValue(); + } + + template <typename T> + T get() { + // boolean + if constexpr (std::is_same_v<T, bool>) { + assert(this->vt == VT_BOOL); + return this->boolVal != VARIANT_FALSE; + } + + // signed + else if constexpr (std::is_same_v<T, int8_t>) { + assert(this->vt == VT_I1); + return this->cVal; + } else if constexpr (std::is_same_v<T, int16_t>) { + assert(this->vt == VT_I2); + return this->iVal; + } else if constexpr (std::is_same_v<T, int32_t>) { + assert(this->vt == VT_I4 || this->vt == VT_INT); + return this->intVal; + } else if constexpr (std::is_same_v<T, int64_t>) { + assert(this->vt == VT_I8); + return this->llVal; + } + + // unsigned + else if constexpr (std::is_same_v<T, uint8_t>) { + assert(this->vt == VT_UI1); + return this->bVal; + } else if constexpr (std::is_same_v<T, uint16_t>) { + assert(this->vt == VT_UI2); + return this->uiVal; + } else if constexpr (std::is_same_v<T, uint32_t>) { + assert(this->vt == VT_UI4 || this->vt == VT_UINT); + return this->uintVal; + } else if constexpr (std::is_same_v<T, uint64_t>) { + assert(this->vt == VT_UI8); + return this->ullVal; + } + + // decimal + else if constexpr (std::is_same_v<T, float>) { + assert(this->vt == VT_R4); + return this->fltVal; + } else if constexpr (std::is_same_v<T, double>) { + assert(this->vt == VT_R8); + return this->dblVal; + } + + // string + else if constexpr (std::is_same_v<T, std::string_view>) { + assert(this->vt == VT_LPSTR); + return this->pcVal; + } else if constexpr (std::is_same_v<T, std::wstring_view>) { + assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR); + if (this->vt == VT_LPWSTR) { + return this->bstrVal; + } else { + return { this->bstrVal, SysStringLen(this->bstrVal) }; + } + } + + // array signed + else if constexpr (std::is_same_v<T, std::pair<const int8_t*, uint32_t>>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_I1); + return std::make_pair((int8_t*) this->parray->pvData, this->parray->cDims); + } else if constexpr (std::is_same_v<T, std::pair<const int16_t*, uint32_t>>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_I2); + return std::make_pair((int16_t*) this->parray->pvData, this->parray->cDims); + } else if constexpr (std::is_same_v<T, std::pair<const int32_t*, uint32_t>>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_I4); + return std::make_pair((int32_t*) this->parray->pvData, this->parray->cDims); + } else if constexpr (std::is_same_v<T, std::pair<const int64_t*, uint32_t>>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_I8); + return std::make_pair((int64_t*) this->parray->pvData, this->parray->cDims); + } + + // array unsigned + else if constexpr (std::is_same_v<T, std::pair<const uint8_t*, uint32_t>>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_UI1); + return std::make_pair((uint8_t*) this->parray->pvData, this->parray->cDims); + } else if constexpr (std::is_same_v<T, std::pair<const uint16_t*, uint32_t>>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_UI2); + return std::make_pair((uint16_t*) this->parray->pvData, this->parray->cDims); + } else if constexpr (std::is_same_v<T, std::pair<const uint32_t*, uint32_t>>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_UI4); + return std::make_pair((uint32_t*) this->parray->pvData, this->parray->cDims); + } else if constexpr (std::is_same_v<T, std::pair<const uint64_t*, uint32_t>>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_UI8); + return std::make_pair((uint64_t*) this->parray->pvData, this->parray->cDims); + } else { + assert(false && "unsupported type"); + __builtin_unreachable(); + } + } +}; + +struct FFWmiVariant : FFBaseVariant<VARIANT> { + FFWmiVariant(const FFWmiVariant&) = delete; + FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization + explicit FFWmiVariant() { + VariantInit(this); + } + explicit FFWmiVariant(std::initializer_list<PCWSTR> strings); + ~FFWmiVariant() { + VariantClear(this); + } +}; +static_assert(sizeof(FFWmiVariant) == sizeof(VARIANT), ""); + +struct FFPropVariant : FFBaseVariant<PROPVARIANT> { + FFPropVariant(const FFPropVariant&) = delete; + FFPropVariant(FFPropVariant&&); // don't define it to enforce NRVO optimization + explicit FFPropVariant() { + PropVariantInit(this); + } + ~FFPropVariant() { + PropVariantClear(this); + } +}; +static_assert(sizeof(FFPropVariant) == sizeof(PROPVARIANT), ""); + +namespace { +// Provide our bstr_t to avoid libstdc++ dependency +struct bstr_t { + explicit bstr_t(const wchar_t* str) noexcept : _bstr(SysAllocString(str)) {} + ~bstr_t(void) noexcept { + SysFreeString(_bstr); + } + explicit operator const wchar_t*(void) const noexcept { + return _bstr; + } + operator BSTR(void) const noexcept { + return _bstr; + } + + private: + BSTR _bstr; +}; +} // namespace |