From: Jacob Lifshay Date: Sun, 28 May 2017 10:12:29 +0000 (-0700) Subject: working on implementing util::variant X-Git-Tag: gsoc-2017~122 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=be8d0265f0ef847415577cf82aafef75d8183c21;p=kazan.git working on implementing util::variant --- diff --git a/src/util/variant.h b/src/util/variant.h new file mode 100644 index 0000000..13b8186 --- /dev/null +++ b/src/util/variant.h @@ -0,0 +1,366 @@ +/* + * Copyright 2017 Jacob Lifshay + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef SOURCE_UTIL_VARIANT_H_ +#define SOURCE_UTIL_VARIANT_H_ + +#include +#include +#include +#include +#include +#include +#include "in_place.h" + +namespace vulkan_cpu +{ +namespace util +{ +class bad_variant_access : public std::exception +{ + bad_variant_access() noexcept = default; + virtual const char *what() const noexcept override + { + return "bad_variant_access"; + } +}; + +struct monostate +{ +}; + +constexpr bool operator==(monostate, monostate) noexcept +{ + return true; +} + +constexpr bool operator!=(monostate, monostate) noexcept +{ + return false; +} + +constexpr bool operator<=(monostate, monostate) noexcept +{ + return true; +} + +constexpr bool operator>=(monostate, monostate) noexcept +{ + return true; +} + +constexpr bool operator<(monostate, monostate) noexcept +{ + return false; +} + +constexpr bool operator>(monostate, monostate) noexcept +{ + return false; +} + +constexpr std::size_t variant_npos = -1; + +template +class variant; + +template +struct variant_size; + +template +struct variant_size> + : public std::integral_constant +{ +}; + +template +struct variant_size : public variant_size +{ +}; + +template +struct variant_size : public variant_size +{ +}; + +template +struct variant_size : public variant_size +{ +}; + +template +constexpr std::size_t variant_size_v = variant_size::value; + +template +struct variant_alternative; + +template +struct variant_alternative +{ + typedef const typename variant_alternative::type type; +}; + +template +struct variant_alternative +{ + typedef const typename variant_alternative::type type; +}; + +template +struct variant_alternative +{ + typedef const volatile typename variant_alternative::type type; +}; + +template +struct variant_alternative> +{ + typedef typename variant_alternative>::type type; +}; + +template +struct variant_alternative<0, variant> +{ + typedef T type; +}; + +template +using variant_alternative_t = typename variant_alternative::type; + +namespace detail +{ +template +union variant_values +{ + char value; + static constexpr bool is_copy_constructible = true; + static constexpr bool is_move_constructible = true; + static constexpr bool is_nothrow_copy_constructible = true; + static constexpr bool is_nothrow_move_constructible = true; + variant_values() = delete; + template + constexpr variant_values(in_place_index_t) noexcept : value() + { + } + template + static constexpr std::size_t index_from_type() noexcept + { + return variant_npos; + } + void copy_construct(const variant_values &rt, std::size_t index) noexcept + { + } + void move_construct(variant_values &&rt, std::size_t index) noexcept + { + } +}; + +template +union variant_values +{ + typedef T type_0; + static_assert(!std::is_void::value, "invalid variant member type"); + static_assert(!std::is_reference::value, "invalid variant member type"); + static_assert(!std::is_array::value, "invalid variant member type"); + T current_value; + variant_values other_values; + static constexpr bool is_copy_constructible = + std::is_copy_constructible::value && variant_values::is_copy_constructible; + static constexpr bool is_move_constructible = + std::is_move_constructible::value && variant_values::is_move_constructible; + static constexpr bool is_nothrow_copy_constructible = + std::is_nothrow_copy_constructible::value + && variant_values::is_nothrow_copy_constructible; + static constexpr bool is_nothrow_move_constructible = + std::is_nothrow_move_constructible::value + && variant_values::is_nothrow_move_constructible; + template ::value>::type> + constexpr variant_values() noexcept(std::is_nothrow_default_constructible::value) + : current_value() + { + } + template ::value>::type> + constexpr variant_values(in_place_index_t<0>, Args &&... args) noexcept( + std::is_nothrow_constructible::value) + : current_value(std::forward(args)...) + { + } + template , + in_place_index_t, + Args...>::value>::type> + constexpr variant_values(in_place_index_t, Args &&... args) noexcept( + std::is_nothrow_constructible, + in_place_index_t, + Args...>::value) + : other_values(in_place_index, std::forward(args)...) + { + } + template + static constexpr std::size_t index_from_type() noexcept + { + std::size_t next = variant_values::index_from_type(); + if(std::is_same::value && next == variant_npos) + return 0; + if(next == variant_npos) + return variant_npos; + return next + 1; + } + void copy_construct(const variant_values &rt, std::size_t index) noexcept + { + if(index == 0) + new(const_cast(std::addressof(current_value))) T(rt.current_value); + else + other_values.copy_construct(rt.other_values, index - 1); + } + void move_construct(variant_values &&rt, std::size_t index) noexcept + { + if(index == 0) + new(const_cast(std::addressof(current_value))) T(std::move(rt.current_value)); + else + other_values.move_construct(std::move(rt.other_values), index - 1); + } +}; + +template +struct variant_index_type +{ + static constexpr std::size_t total_state_count = + Type_Count + 1; // for valueless-by-exception state + static constexpr bool is_unsigned_char_good = + total_state_count <= std::numeric_limits::max(); + static constexpr bool is_unsigned_short_good = + total_state_count <= std::numeric_limits::max(); + static constexpr bool is_unsigned_good = + total_state_count <= std::numeric_limits::max(); + static constexpr bool is_unsigned_long_good = + total_state_count <= std::numeric_limits::max(); + static constexpr bool is_unsigned_long_long_good = + total_state_count <= std::numeric_limits::max(); + typedef + typename std::conditional::type + unsigned_long_long_or_larger; + typedef typename std::conditional::type unsigned_long_or_larger; + typedef typename std::conditional::type + unsigned_or_larger; + typedef + typename std::conditional::type + unsigned_short_or_larger; + typedef typename std::conditional::type type; + static constexpr type npos = variant_npos; + type index_value; + constexpr variant_index_type() = delete; + constexpr explicit variant_index_type(std::size_t index_value) noexcept + : index_value(index_value) + { + } + constexpr std::size_t get() const noexcept + { + return index_value == npos ? variant_npos : index_value; + } + constexpr void set(std::size_t new_value) noexcept + { + index_value = new_value; + } +}; +} + +template +class variant +{ + static_assert(sizeof...(Types) > 0, "empty variant is not permitted"); + +private: + typedef typename detail::variant_values::type_0 type_0; + +private: + detail::variant_values values; + detail::variant_index_type index_value; + +public: + template < + typename = typename std::enable_if::value>::value> + constexpr variant() noexcept(std::is_nothrow_default_constructible::value) + : values(), index_value(0) + { + } + template < + typename = + typename std::enable_if::is_copy_constructible>::type> + variant(const variant &rt) noexcept( + detail::variant_values::is_nothrow_copy_constructible) + : values(in_place_index()), index_value(variant_npos) + { + values.copy_construct(rt.values, rt.index_value.get()); + index_value = rt.index_value; + } + template < + typename = + typename std::enable_if::is_move_constructible>::type> + variant(variant &&rt) noexcept(detail::variant_values::is_nothrow_move_constructible) + : values(in_place_index()), index_value(variant_npos) + { + values.move_construct(std::move(rt.values), rt.index_value.get()); + index_value = rt.index_value; + } + template >, + Args...>::value>::type> + constexpr explicit variant(in_place_index_t, Args &&... args) noexcept( + std::is_nothrow_constructible>, + Args...>::value) + : values(in_place_index, std::forward(args)...), index_value(index) + { + } +#error finish + constexpr std::size_t index() const noexcept + { + return index_value.get(); + } +}; +} +} + +namespace std +{ +template <> +struct hash +{ + constexpr std::size_t operator()(vulkan_cpu::util::monostate) const noexcept + { + return 5546275UL; + } +}; +} + +#endif /* SOURCE_UTIL_VARIANT_H_ */