]> git.tdb.fi Git - libs/core.git/commitdiff
Refactor Variant's internals to be compatible with older MSVC versions
authorMikko Rasa <tdb@tdb.fi>
Mon, 11 Sep 2023 08:00:25 +0000 (11:00 +0300)
committerMikko Rasa <tdb@tdb.fi>
Mon, 11 Sep 2023 18:58:01 +0000 (21:58 +0300)
source/core/variant.h

index b00f5616f7e83e2e39fe67889141153d539b4f60..f566e5ea1197b83b955133cd440a68b7f088e0bf 100644 (file)
@@ -31,6 +31,9 @@ public:
        };
 
 private:
+       template<typename T, bool small = (sizeof(T)<=INTERNAL_SIZE && alignof(T)<=alignof(void *))>
+       struct FunctionsImpl;
+
        template<typename T>
        using EnableNotVariant = typename std::enable_if<!std::is_same<typename std::remove_cv<typename std::remove_reference<T>::type>::type, Variant>::value>::type;
 
@@ -90,63 +93,59 @@ public:
 private:
        static bool type_equals(const Functions *, const Functions *);
 
-       template<typename T>
-       static constexpr bool is_small() { return (sizeof(T)<=INTERNAL_SIZE && alignof(T)<=alignof(void *)); }
-
-       template<typename T, typename U>
-       using EnableSmall = typename std::enable_if<is_small<T>(), U>::type;
-
-       template<typename T, typename U>
-       using EnableLarge = typename std::enable_if<!is_small<T>(), U>::type;
-
        template<typename T>
        static const Functions *get_functions();
 
        template<typename T>
        static const std::type_info &get_type() { return typeid(T); }
 
-       template<typename T>
-       static EnableSmall<T, void> create(char *s, T &&v)
-       { new(s) typename std::remove_reference<T>::type(std::forward<T>(v)); }
+       /* The extra function parameter is needed to avoid duplicate definition error
+       from MSVC 19.29 (VS 2019) */
+       template<typename T, typename = typename std::enable_if<!IsEqualityComparable<T>::value>::type>
+       static bool compare(const T &, const T &, int = 0)
+       { return false; }
 
-       template<typename T>
-       static EnableLarge<T, void> create(char *s, T &&v)
-       { using V = typename std::remove_reference<T>::type; *reinterpret_cast<V **>(s) = new V(std::forward<T>(v)); }
+       template<typename T, typename = typename std::enable_if<IsEqualityComparable<T>::value>::type>
+       static bool compare(const T &v1, const T &v2)
+       { return v1==v2; }
+};
 
-       template<typename T>
-       static typename std::enable_if<!IsEqualityComparable<T>::value, bool>::type compare(const char *, const char *)
-       { return false; }
 
-       template<typename T>
-       static typename std::enable_if<IsEqualityComparable<T>::value, EnableSmall<T, bool>>::type compare(const char *s1, const char *s2)
-       { return *reinterpret_cast<const T *>(s1)==*reinterpret_cast<const T *>(s2); }
+template<typename T>
+struct Variant::FunctionsImpl<T, true>
+{
+       static void create(char *s, T &&v)
+       { new(s) typename std::remove_reference<T>::type(std::forward<T>(v)); }
 
-       template<typename T>
-       static typename std::enable_if<IsEqualityComparable<T>::value, EnableLarge<T, bool>>::type compare(const char *s1, const char *s2)
-       { return **reinterpret_cast<const T *const *>(s1)==**reinterpret_cast<const T *const *>(s2); }
+       static bool compare(const char *s1, const char *s2)
+       { return Variant::compare<T>(*reinterpret_cast<const T *>(s1), *reinterpret_cast<const T *>(s2)); }
 
-       template<typename T>
-       static EnableSmall<T, void> clone(char *s, const char *v)
+       static void clone(char *s, const char *v)
        { new(s) T(*reinterpret_cast<const T *>(v)); }
 
-       template<typename T>
-       static EnableLarge<T, void> clone(char *s, const char *v)
-       { *reinterpret_cast<T **>(s) = new T(**reinterpret_cast<const T *const *>(v)); }
-
-       template<typename T>
-       static EnableSmall<T, void> move(char *s, char *v)
+       static void move(char *s, char *v)
        { new(s) T(std::move(*reinterpret_cast<T *>(v))); }
 
-       template<typename T>
-       static EnableLarge<T, void> move(char *s, char *v)
-       { T *&p = *reinterpret_cast<T **>(v); *reinterpret_cast<T **>(s) = p; p = nullptr; }
-
-       template<typename T>
-       static EnableSmall<T, void> destroy(char *s)
+       static void destroy(char *s)
        { reinterpret_cast<T *>(s)->~T(); }
+};
 
-       template<typename T>
-       static EnableLarge<T, void> destroy(char *s)
+template<typename T>
+struct Variant::FunctionsImpl<T, false>
+{
+       static void create(char *s, T &&v)
+       { using V = typename std::remove_reference<T>::type; *reinterpret_cast<V **>(s) = new V(std::forward<T>(v)); }
+
+       static bool compare(const char *s1, const char *s2)
+       { return Variant::compare<T>(**reinterpret_cast<const T *const *>(s1), **reinterpret_cast<const T *const *>(s2)); }
+
+       static void clone(char *s, const char *v)
+       { *reinterpret_cast<T **>(s) = new T(**reinterpret_cast<const T *const *>(v)); }
+
+       static void move(char *s, char *v)
+       { T *&p = *reinterpret_cast<T **>(v); *reinterpret_cast<T **>(s) = p; p = nullptr; }
+
+       static void destroy(char *s)
        { delete *reinterpret_cast<T **>(s); }
 };
 
@@ -163,7 +162,7 @@ inline void Variant::assign(T &&v)
 {
        clear();
        funcs = get_functions<typename std::remove_cv<typename std::remove_reference<T>::type>::type>();
-       create(storage, std::forward<T>(v));
+       FunctionsImpl<T>::create(storage, std::forward<T>(v));
 }
 
 inline void Variant::copy_from(const Variant &v)
@@ -216,13 +215,14 @@ inline bool Variant::type_equals(const Functions *funcs1, const Functions *funcs
 template<typename T>
 inline const Variant::Functions *Variant::get_functions()
 {
+       using Impl = FunctionsImpl<T>;
        static Functions funcs =
        {
                &get_type<T>,
-               &compare<T>,
-               &clone<T>,
-               &move<T>,
-               &destroy<T>
+               &Impl::compare,
+               &Impl::clone,
+               &Impl::move,
+               &Impl::destroy
        };
        return &funcs;
 }