From d86afd024d8bb01723794a5bf4aadb13e0ca393d Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 31 May 2017 17:57:43 -0700 Subject: [PATCH] finished members of util::variant; need to finish the rest of variant.h --- src/util/CMakeLists.txt | 3 +- src/util/copy_cv_ref.cpp | 23 +++ src/util/copy_cv_ref.h | 102 +++++++++++ src/util/is_swappable.h | 12 ++ src/util/variant.h | 374 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 504 insertions(+), 10 deletions(-) create mode 100644 src/util/copy_cv_ref.cpp create mode 100644 src/util/copy_cv_ref.h diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index ffe89a1..a775745 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -19,7 +19,8 @@ # SOFTWARE. # cmake_minimum_required(VERSION 3.1 FATAL_ERROR) -set(sources in_place.cpp +set(sources copy_cv_ref.cpp + in_place.cpp is_referenceable.cpp is_swappable.cpp optional.cpp diff --git a/src/util/copy_cv_ref.cpp b/src/util/copy_cv_ref.cpp new file mode 100644 index 0000000..7f5606a --- /dev/null +++ b/src/util/copy_cv_ref.cpp @@ -0,0 +1,23 @@ +/* + * 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. + * + */ +#include "copy_cv_ref.h" diff --git a/src/util/copy_cv_ref.h b/src/util/copy_cv_ref.h new file mode 100644 index 0000000..ce68ca6 --- /dev/null +++ b/src/util/copy_cv_ref.h @@ -0,0 +1,102 @@ +/* + * 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_COPY_CV_REF_H_ +#define SOURCE_UTIL_COPY_CV_REF_H_ + +namespace vulkan_cpu +{ +namespace util +{ +template +struct copy_const +{ + typedef Dest type; +}; + +template +struct copy_const +{ + typedef const Dest type; +}; + +template +using copy_const_t = typename copy_const::type; + +template +struct copy_volatile +{ + typedef Dest type; +}; + +template +struct copy_volatile +{ + typedef volatile Dest type; +}; + +template +using copy_volatile_t = typename copy_volatile::type; + +template +struct copy_cv +{ + typedef copy_const_t> type; +}; + +template +using copy_cv_t = typename copy_cv::type; + +template +struct copy_ref +{ + typedef Dest type; +}; + +template +struct copy_ref +{ + typedef Dest &type; +}; + +template +struct copy_ref +{ + typedef Dest &&type; +}; + +template +using copy_ref_t = typename copy_ref::type; + +template +struct copy_cv_ref +{ + typedef copy_cv_t> type; +}; + +template +using copy_cv_ref_t = typename copy_cv_ref::type; +} +} + +#endif /* SOURCE_UTIL_COPY_CV_REF_H_ */ diff --git a/src/util/is_swappable.h b/src/util/is_swappable.h index b744200..483fb33 100644 --- a/src/util/is_swappable.h +++ b/src/util/is_swappable.h @@ -80,6 +80,9 @@ struct is_swappable_with { }; +template +constexpr bool is_swappable_with_v = is_swappable_with::value; + template struct is_nothrow_swappable_with : public std::integral_constant +constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with::value; + namespace detail { template ::value> @@ -120,11 +126,17 @@ struct is_swappable : public std::integral_constant +constexpr bool is_swappable_v = is_swappable::value; + template struct is_nothrow_swappable : public std::integral_constant::value> { }; + +template +constexpr bool is_nothrow_swappable_v = is_nothrow_swappable::value; } } diff --git a/src/util/variant.h b/src/util/variant.h index 8a0d03d..19ef314 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -32,6 +32,8 @@ #include #include "in_place.h" #include "void_t.h" +#include "copy_cv_ref.h" +#include "is_swappable.h" namespace vulkan_cpu { @@ -186,6 +188,8 @@ union variant_values static constexpr bool is_nothrow_copy_assignable = true; static constexpr bool is_nothrow_move_assignable = true; static constexpr bool is_trivially_destructible = true; + static constexpr bool is_swappable = true; + static constexpr bool is_nothrow_swappable = true; variant_values() = delete; template constexpr variant_values(in_place_index_t) noexcept : value() @@ -211,6 +215,9 @@ union variant_values void destroy(std::size_t index) noexcept { } + void swap(variant_values &rt, std::size_t index) noexcept + { + } }; template @@ -232,19 +239,28 @@ union variant_values static constexpr bool is_nothrow_move_constructible = std::is_nothrow_move_constructible::value && variant_values::is_nothrow_move_constructible; - static constexpr bool is_copy_assignable = - std::is_copy_assignable::value && variant_values::is_copy_assignable; - static constexpr bool is_move_assignable = - std::is_move_assignable::value && variant_values::is_move_assignable; + static constexpr bool is_copy_assignable = std::is_copy_assignable::value + && std::is_copy_constructible::value + && variant_values::is_copy_assignable; + static constexpr bool is_move_assignable = std::is_move_assignable::value + && std::is_move_constructible::value + && variant_values::is_move_assignable; static constexpr bool is_nothrow_copy_assignable = - std::is_nothrow_copy_assignable::value + std::is_nothrow_copy_assignable::value && std::is_nothrow_copy_constructible::value && variant_values::is_nothrow_copy_assignable; static constexpr bool is_nothrow_move_assignable = - std::is_nothrow_move_assignable::value + std::is_nothrow_move_assignable::value && std::is_nothrow_move_constructible::value && variant_values::is_nothrow_move_assignable; static constexpr bool is_trivially_destructible = std::is_trivially_destructible::value && variant_values::is_trivially_destructible; + static constexpr bool is_swappable = + is_swappable_v && std::is_move_constructible && variant_values:: + is_swappable; + static constexpr bool is_nothrow_swappable = + is_nothrow_swappable_v && std:: + is_nothrow_move_constructible && variant_values:: + is_nothrow_swappable; template ::value>::type> constexpr variant_values() noexcept(std::is_nothrow_default_constructible::value) @@ -333,8 +349,170 @@ union variant_values else other_values.destruct(index - 1); } + void swap(variant_values &rt, std::size_t index) noexcept(is_nothrow_swappable) + { + using std::swap; + if(index == 0) + swap(current_value, rt.current_value); + else + other_values.swap(rt.other_values, index - 1); + } +}; + +template +struct variant_get; + +template +struct variant_get +{ + static constexpr auto get(const variant_values &values) noexcept + -> decltype(variant_get::get(values.other_values)) + { + return variant_get::get(values.other_values); + } + static constexpr auto get(variant_values &values) noexcept + -> decltype(variant_get::get(values.other_values)) + { + return variant_get::get(values.other_values); + } + static constexpr auto get(const variant_values &&values) noexcept + -> decltype(variant_get::get(std::move(values.other_values))) + { + return variant_get::get(std::move(values.other_values)); + } + static constexpr auto get(variant_values &&values) noexcept + -> decltype(variant_get::get(std::move(values.other_values))) + { + return variant_get::get(std::move(values.other_values)); + } +}; + +template +struct variant_get<0, T, Types...> +{ + static constexpr const T &get(const variant_values &values) noexcept + { + return values.current_value; + } + static constexpr T &get(variant_values &values) noexcept + { + return values.current_value; + } + static constexpr const T &&get(const variant_values &&values) noexcept + { + return std::move(values.current_value); + } + static constexpr T &&get(variant_values &&values) noexcept + { + return std::move(values.current_value); + } }; +#define VULKAN_CPU_UTIL_VARIANT_DISPATCH(Const, Ref) \ + template ()( \ + std::declval(), std::declval()...))...>::type> \ + constexpr Return_Type variant_dispatch_helper(Fn &&fn, \ + Const variant_values Ref values, \ + std::size_t index, \ + std::index_sequence, \ + Args &&... args) \ + { \ + typedef Return_Type (*Dispatch_Function)( \ + Fn && fn, Const variant_values & values, Args && ... args); \ + static const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \ + static_cast( \ + [](Fn &&fn, Const variant_values &values, Args &&... args) \ + -> Return_Type \ + { \ + return std::forward(fn)( \ + variant_get::get( \ + std::forward Ref>(values)), \ + std::forward(args)...); \ + })..., \ + }; \ + if(index < sizeof...(Types)) \ + return dispatch_functions[index]( \ + std::forward(fn), values, std::forward(args)...); \ + throw bad_variant_access(); \ + } \ + \ + template \ + constexpr auto variant_dispatch( \ + Fn &&fn, Const variant_values Ref values, std::size_t index, Args &&... args) \ + ->decltype( \ + variant_dispatch_helper(std::forward(fn), \ + std::forward Ref>(values), \ + index, \ + std::index_sequence_for{}, \ + std::forward(args)...)) \ + { \ + return variant_dispatch_helper(std::forward(fn), \ + std::forward Ref>(values), \ + index, \ + std::index_sequence_for{}, \ + std::forward(args)...); \ + } \ + \ + template ()( \ + std::declval(), std::declval()...))...>::type> \ + constexpr Return_Type variant_dispatch_helper_nothrow( \ + Fn &&fn, \ + Const variant_values Ref values, \ + std::size_t index, \ + std::index_sequence, \ + Args &&... args) \ + { \ + typedef Return_Type (*Dispatch_Function)( \ + Fn && fn, Const variant_values & values, Args && ... args); \ + static const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \ + static_cast( \ + [](Fn &&fn, Const variant_values &values, Args &&... args) \ + -> Return_Type \ + { \ + return std::forward(fn)( \ + variant_get::get( \ + std::forward Ref>(values)), \ + std::forward(args)...); \ + })..., \ + }; \ + if(index < sizeof...(Types)) \ + return dispatch_functions[index]( \ + std::forward(fn), values, std::forward(args)...); \ + return {}; \ + } \ + \ + template \ + constexpr auto variant_dispatch_nothrow( \ + Fn &&fn, Const variant_values Ref values, std::size_t index, Args &&... args) \ + ->decltype(variant_dispatch_helper_nothrow( \ + std::forward(fn), \ + std::forward Ref>(values), \ + index, \ + std::index_sequence_for{}, \ + std::forward(args)...)) \ + { \ + return variant_dispatch_helper_nothrow( \ + std::forward(fn), \ + std::forward Ref>(values), \ + index, \ + std::index_sequence_for{}, \ + std::forward(args)...); \ + } + +VULKAN_CPU_UTIL_VARIANT_DISPATCH(, &) +VULKAN_CPU_UTIL_VARIANT_DISPATCH(const, &) +VULKAN_CPU_UTIL_VARIANT_DISPATCH(, &&) +VULKAN_CPU_UTIL_VARIANT_DISPATCH(const, &&) +#undef VULKAN_CPU_UTIL_VARIANT_DISPATCH + template ::type, variant>::value && !detail::variant_is_in_place_index::type>::value - && !detail::variant_is_in_place_type::type>::value>:: - type> + && !detail::variant_is_in_place_type::type>::value + && std::is_constructible>, + T>::value>::type> constexpr variant(T &&value) noexcept( std::is_nothrow_constructible>, T>::value) : base(Index, in_place_index, std::forward(value)) { } + template ::index_from_type(), + typename = typename std::enable_if<(Index < sizeof...(Types)) + && std::is_constructible::value>::type> + constexpr explicit variant(in_place_type_t, Args &&... args) noexcept( + std::is_nothrow_constructible::value) + : base(Index, in_place_index, std::forward(args)...) + { + } + template < + typename T, + typename U, + typename... Args, + std::size_t Index = detail::variant_values::index_from_type(), + typename = typename std:: + enable_if<(Index < sizeof...(Types)) + && std::is_constructible, Args...>::value>::type> + constexpr explicit variant( + in_place_type_t, + std::initializer_list il, + Args &&... args) noexcept(std::is_nothrow_constructible, + Args...>::value) + : base(Index, in_place_index, il, std::forward(args)...) + { + } template , il, std::forward(args)...) { } -#error finish + template < + typename = + typename std::enable_if::is_copy_assignable>::type> + variant &operator=(const variant &rt) noexcept( + detail::variant_values::is_nothrow_copy_assignable) + { + if(index_value.get() == rt.index_value.get()) + { + values.copy_assign(rt.values, index_value.get()); + } + else + { + values.destruct(index_value.get()); + index_value.set(variant_npos); // in case copy_construct throws + values.copy_construct(rt, rt.index_value.get()); + index_value = rt.index_value; + } + return *this; + } + template < + typename = + typename std::enable_if::is_move_assignable>::type> + variant &operator=(variant &&rt) noexcept( + detail::variant_values::is_nothrow_move_assignable) + { + if(index_value.get() == rt.index_value.get()) + { + values.move_assign(std::move(rt.values), index_value.get()); + } + else + { + values.destruct(index_value.get()); + index_value.set(variant_npos); // in case move_construct throws + values.move_construct(std::move(rt), rt.index_value.get()); + index_value = rt.index_value; + } + return *this; + } + template < + typename T, + std::size_t Index = detail::variant_conversion_deduce_index(), + typename = typename std:: + enable_if::type, variant>::value + && !detail::variant_is_in_place_index::type>::value + && !detail::variant_is_in_place_type::type>::value + && std::is_constructible>, + T>::value + && std::is_assignable>, + T>::value>::type> + variant &operator=(T &&new_value) noexcept( + std::is_nothrow_constructible>, T>::value + &&std::is_nothrow_assignable>, T>::value) + { + if(index_value.get() == Index) + { + detail::variant_get::get(values) = std::forward(new_value); + } + else + { + values.destruct(index_value.get()); + index_value.set(variant_npos); // in case construction throws + auto &value = detail::variant_get::get(values); + new(const_cast(std::addressof(value))) + variant_alternative_t>(std::forward(new_value)); + index_value.set(Index); + } + return *this; + } + template ::index_from_type(), + typename = typename std::enable_if<(Index < sizeof...(Types)) + && std::is_constructible::value>::type> + void emplace(Args &&... args) + { + emplace(std::forward(args)...); + } + template < + typename T, + typename U, + typename... Args, + std::size_t Index = detail::variant_values::index_from_type(), + typename = typename std:: + enable_if<(Index < sizeof...(Types)) + && std::is_constructible, Args...>::value>::type> + void emplace(std::initializer_list il, Args &&... args) + { + emplace(il, std::forward(args)...); + } + template >, + Args...>::value>::type> + void emplace(Args &&... args) + { + values.destruct(index_value.get()); + index_value.set(variant_npos); // in case construction throws + auto &value = detail::variant_get::get(values); + new(const_cast(std::addressof(value))) + variant_alternative_t>(std::forward(args)...); + index_value.set(Index); + } + template >, + std::initializer_list, + Args...>::value>::type> + void emplace(std::initializer_list il, Args &&... args) + { + values.destruct(index_value.get()); + index_value.set(variant_npos); // in case construction throws + auto &value = detail::variant_get::get(values); + new(const_cast(std::addressof(value))) + variant_alternative_t>(il, std::forward(args)...); + index_value.set(Index); + } + constexpr bool valueless_by_exception() const noexcept + { + return index_value.get() == variant_npos; + } constexpr std::size_t index() const noexcept { return index_value.get(); } + template < + typename = typename std::enable_if::is_swappable>::type> + void swap(variant &rt) noexcept(detail::variant_values::is_nothrow_swappable) + { + if(index_value.get() == rt.index_value.get()) + values.swap(rt.values, index_value.get()); + else + { + variant temp = std::move(rt); + rt = std::move(*this); + *this = std::move(temp); + } + } }; +#error finish } } @@ -555,6 +901,16 @@ struct hash return 5546275UL; } }; + +template ::is_swappable>::type> +inline void + swap(vulkan_cpu::util::variant &l, vulkan_cpu::util::variant &r) noexcept( + vulkan_cpu::util::detail::variant_values::is_nothrow_swappable) +{ + l.swap(r); +} } #endif /* SOURCE_UTIL_VARIANT_H_ */ -- 2.30.2