cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
add_subdirectory(spirv)
add_subdirectory(demo)
+add_subdirectory(json)
add_subdirectory(util)
\ No newline at end of file
--- /dev/null
+# 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.
+#
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+set(sources json.cpp)
+add_library(json STATIC ${sources})
+target_link_libraries(json util)
\ No newline at end of file
--- /dev/null
+/*
+ * 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 "json.h"
+#include <istream>
+#include <ostream>
+#include <cmath>
+#include <cstdint>
+#include <cassert>
+#include <tuple>
+#include "../util/soft_float.h"
+
+namespace vulkan_cpu
+{
+namespace json
+{
+namespace ast
+{
+namespace soft_float = util::soft_float;
+
+void null_value::write(std::ostream &os) const
+{
+ os << "null";
+}
+
+void boolean_value::write(std::ostream &os) const
+{
+ os << (value ? "true" : "false");
+}
+
+namespace
+{
+constexpr char get_digit_char(unsigned digit, bool uppercase) noexcept
+{
+ if(digit < 10)
+ return '0' + digit;
+ if(uppercase)
+ return digit - 10 + 'A';
+ return digit - 10 + 'a';
+}
+}
+
+void string_value::write(std::ostream &os, const std::string &value)
+{
+ os << '\"';
+ for(unsigned char ch : value)
+ {
+ switch(ch)
+ {
+ case '\\':
+ case '\"':
+ os << '\\' << ch;
+ break;
+ case '\b':
+ os << "\\b";
+ break;
+ case '\f':
+ os << "\\f";
+ break;
+ case '\n':
+ os << "\\n";
+ break;
+ case '\r':
+ os << "\\r";
+ break;
+ case '\t':
+ os << "\\t";
+ break;
+ default:
+ if(ch < 0x20U)
+ os << "\\u00" << get_digit_char(ch >> 4, true) << get_digit_char(ch & 0xFU, true);
+ else
+ os << ch;
+ }
+ }
+ os << '\"';
+}
+
+namespace
+{
+template <typename Write_Char>
+void write_string(Write_Char write_char, const char *str) noexcept(noexcept(write_char('0')))
+{
+ while(*str)
+ write_char(*str++);
+}
+
+template <typename Write_Char>
+void write_array(Write_Char write_char,
+ const char *array,
+ std::size_t size) noexcept(noexcept(write_char('0')))
+{
+ for(std::size_t i = 0; i < size; i++)
+ write_char(array[i]);
+}
+
+constexpr std::array<soft_float::ExtendedFloat, 37> make_base_2_logs() noexcept
+{
+ return std::array<soft_float::ExtendedFloat, 37>{{
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(0))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(1))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(2))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(3))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(4))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(5))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(6))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(7))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(8))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(9))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(10))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(11))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(12))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(13))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(14))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(15))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(16))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(17))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(18))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(19))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(20))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(21))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(22))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(23))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(24))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(25))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(26))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(27))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(28))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(29))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(30))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(31))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(32))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(33))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(34))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(35))),
+ log2(soft_float::ExtendedFloat(static_cast<std::uint64_t>(36))),
+ }};
+}
+
+constexpr std::size_t max_integer_buffer_size = 64; // max number of digits is base 2 with 64 digits
+
+template <typename Write_Char>
+void write_unsigned_integer(Write_Char write_char,
+ std::uint64_t value,
+ unsigned base) noexcept(noexcept(write_char('0')))
+{
+ assert(base >= number_value::min_base && base <= number_value::max_base);
+ char buffer[max_integer_buffer_size]{};
+ std::size_t buffer_used = 0;
+ do
+ {
+ assert(buffer_used < max_integer_buffer_size);
+ buffer[buffer_used++] = get_digit_char(value % base, false);
+ value /= base;
+ } while(value != 0);
+ for(std::size_t i = 0, j = buffer_used - 1; i < buffer_used; i++, j--)
+ write_char(buffer[j]);
+}
+
+template <typename Write_Char>
+void write_signed_integer(Write_Char write_char,
+ std::int64_t value,
+ unsigned base) noexcept(noexcept(write_char('0')))
+{
+ if(value < 0)
+ {
+ write_char('-');
+ write_unsigned_integer(write_char,
+ -static_cast<std::uint64_t>(value),
+ base); // cast to unsigned first to handle minimum value
+ }
+ else
+ {
+ write_unsigned_integer(write_char, static_cast<std::uint64_t>(value), base);
+ }
+}
+
+template <typename Write_Char>
+void write_number(Write_Char write_char,
+ double valueIn,
+ unsigned base) noexcept(noexcept(write_char('0')))
+{
+ // code modified from
+ // https://github.com/programmerjake/javascript-tasklets/blob/master/javascript_tasklets/value.cpp
+ // based on the ECMAScript ToString algorithm for numbers
+ assert(base >= number_value::min_base && base <= number_value::max_base);
+ const char exponent_char = base == 10 ? 'e' : base == 16 ? 'h' : base == 8 ? 'o' : 'E';
+ soft_float::ExtendedFloat value(valueIn), base_f(static_cast<std::uint64_t>(base));
+ auto inv_base_f = soft_float::ExtendedFloat::One() / base_f;
+ static constexpr auto base_2_logs = make_base_2_logs();
+ auto limit_21 =
+ static_cast<std::int64_t>(round(soft_float::ExtendedFloat(static_cast<std::uint64_t>(21))
+ * (base_2_logs[10] / base_2_logs[base])));
+ assert(limit_21 > 0);
+ auto limit_6 =
+ static_cast<std::int64_t>(round(soft_float::ExtendedFloat(static_cast<std::uint64_t>(6))
+ * (base_2_logs[10] / base_2_logs[base])));
+ assert(limit_6 > 0);
+ if(value.isNaN())
+ {
+ write_string(write_char, "NaN");
+ return;
+ }
+ if(value.isZero())
+ {
+ write_char('0');
+ return;
+ }
+ if(value.isInfinite())
+ {
+ if(value.signBit())
+ write_string(write_char, "-Infinity");
+ else
+ write_string(write_char, "Infinity");
+ return;
+ }
+ if(value.signBit())
+ {
+ write_char('-');
+ value = -value;
+ valueIn = -valueIn;
+ }
+ auto n_f = log2(value) / base_2_logs[base] + soft_float::ExtendedFloat::One();
+ auto n = static_cast<std::int64_t>(floor(n_f));
+ soft_float::ExtendedFloat base_to_the_power_of_n = pow(base_f, n);
+ soft_float::ExtendedFloat base_to_the_power_of_minus_n =
+ soft_float::ExtendedFloat::One() / base_to_the_power_of_n;
+ auto scaled_value = value * base_to_the_power_of_minus_n;
+ if(scaled_value + scalbn(soft_float::ExtendedFloat::One(), -62)
+ < inv_base_f) // extra is to handle round-off error
+ {
+ n--;
+ base_to_the_power_of_n *= inv_base_f;
+ base_to_the_power_of_minus_n *= base_f;
+ scaled_value = value * base_to_the_power_of_minus_n;
+ }
+ else if(scaled_value >= soft_float::ExtendedFloat::One())
+ {
+ n++;
+ base_to_the_power_of_n *= base_f;
+ base_to_the_power_of_minus_n *= inv_base_f;
+ scaled_value = value * base_to_the_power_of_minus_n;
+ }
+ std::int64_t k = 0;
+ soft_float::ExtendedFloat s_f = soft_float::ExtendedFloat::One();
+ auto base_to_the_power_of_k = soft_float::ExtendedFloat::One();
+ auto base_to_the_power_of_minus_k = soft_float::ExtendedFloat::One();
+ while(s_f < soft_float::ExtendedFloat::TwoToThe64())
+ {
+ k++;
+ base_to_the_power_of_k *= base_f;
+ base_to_the_power_of_minus_k *= inv_base_f;
+ s_f = round(scaled_value * base_to_the_power_of_k);
+ if(valueIn
+ == static_cast<double>(s_f * base_to_the_power_of_minus_k * base_to_the_power_of_n))
+ break;
+ }
+ std::uint64_t s = static_cast<std::uint64_t>(s_f);
+ char s_digits[max_integer_buffer_size]{};
+ std::size_t s_digits_size = 0;
+ write_unsigned_integer(
+ [&](char ch)
+ {
+ assert(s_digits_size < max_integer_buffer_size);
+ s_digits[s_digits_size++] = ch;
+ },
+ s,
+ base);
+ assert(s_digits_size == static_cast<std::uint64_t>(k));
+ if(k <= n && n <= limit_21)
+ {
+ write_array(write_char, s_digits, s_digits_size);
+ for(std::size_t i = n - k; i > 0; i--)
+ write_char('0');
+ }
+ else if(0 < n && n <= limit_21)
+ {
+ for(std::int64_t i = 0; i < n; i++)
+ write_char(s_digits[i]);
+ write_char('.');
+ for(std::int64_t i = n; i < k; i++)
+ write_char(s_digits[i]);
+ }
+ else if(-limit_6 < n && n <= 0)
+ {
+ write_string(write_char, "0.");
+ for(std::size_t i = -n; i > 0; i--)
+ write_char('0');
+ write_array(write_char, s_digits, s_digits_size);
+ }
+ else if(k == 1)
+ {
+ write_array(write_char, s_digits, s_digits_size);
+ write_char(exponent_char);
+ if(n - 1 >= 0)
+ {
+ write_char('+');
+ write_signed_integer(write_char, n - 1, 10);
+ }
+ else
+ write_signed_integer(write_char, n - 1, 10);
+ }
+ else
+ {
+ write_char(s_digits[0]);
+ write_char('.');
+ for(std::int64_t i = 1; i < k; i++)
+ write_char(s_digits[i]);
+ write_char(exponent_char);
+ if(n - 1 >= 0)
+ {
+ write_char('+');
+ write_signed_integer(write_char, n - 1, 10);
+ }
+ else
+ write_signed_integer(write_char, n - 1, 10);
+ }
+}
+}
+
+std::string number_value::to_string(std::string buffer_in, unsigned base) const
+{
+ buffer_in.clear();
+ std::string retval = std::move(buffer_in);
+ write_number(
+ [&](char ch)
+ {
+ retval += ch;
+ },
+ value,
+ base);
+ return retval;
+}
+
+std::size_t number_value::to_string(char *output_buffer,
+ std::size_t output_buffer_size,
+ bool require_null_terminator,
+ unsigned base) const noexcept
+{
+ if(output_buffer_size == 0)
+ return 0;
+ std::size_t used_buffer_size = 0;
+ std::size_t output_buffer_size_without_terminator = output_buffer_size;
+ if(require_null_terminator)
+ output_buffer_size_without_terminator--;
+ write_number(
+ [&](char ch)
+ {
+ if(used_buffer_size < output_buffer_size_without_terminator)
+ output_buffer[used_buffer_size++] = ch;
+ },
+ value,
+ base);
+ if(used_buffer_size < output_buffer_size)
+ output_buffer[used_buffer_size] = '\0'; // add the null terminator if there is space
+ return used_buffer_size; // report used buffer excluding the null terminator
+}
+
+void number_value::write(std::ostream &os, unsigned base) const
+{
+ write_number(
+ [&](char ch)
+ {
+ os << ch;
+ },
+ value,
+ base);
+}
+
+void object::write(std::ostream &os) const
+{
+ os << '{';
+ auto seperator = "";
+ for(auto &entry : values)
+ {
+ const std::string &key = std::get<0>(entry);
+ const value &value = std::get<1>(entry);
+ os << seperator;
+ seperator = ",";
+ string_value::write(os, key);
+ os << ':';
+ ast::write(os, value);
+ }
+ os << '}';
+}
+
+void array::write(std::ostream &os) const
+{
+ os << '[';
+ auto seperator = "";
+ for(const value &v : values)
+ {
+ os << seperator;
+ seperator = ",";
+ ast::write(os, v);
+ }
+ os << ']';
+}
+}
+}
+}
--- /dev/null
+/*
+ * 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 JSON_JSON_H_
+#define JSON_JSON_H_
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+#include <iosfwd>
+#include <memory>
+#include <utility>
+#include <limits>
+#include "../util/variant.h"
+
+namespace vulkan_cpu
+{
+namespace json
+{
+namespace ast
+{
+struct composite_value
+{
+ composite_value() = default;
+ virtual ~composite_value() = default;
+ virtual void write(std::ostream &os) const = 0;
+ virtual std::unique_ptr<composite_value> duplicate() const = 0;
+};
+
+struct null_value final
+{
+ void write(std::ostream &os) const;
+ null_value duplicate() const noexcept
+ {
+ return {};
+ }
+ const null_value *operator->() const noexcept
+ {
+ return this;
+ }
+ const null_value &operator*() const noexcept
+ {
+ return *this;
+ }
+};
+
+struct boolean_value final
+{
+ bool value;
+ constexpr boolean_value(bool value) noexcept : value(value)
+ {
+ }
+ void write(std::ostream &os) const;
+ boolean_value duplicate() const noexcept
+ {
+ return *this;
+ }
+ const boolean_value *operator->() const noexcept
+ {
+ return this;
+ }
+ const boolean_value &operator*() const noexcept
+ {
+ return *this;
+ }
+};
+
+struct string_value final
+{
+ std::string value;
+ string_value(std::string value) noexcept : value(std::move(value))
+ {
+ }
+ string_value(const char *value) : value(std::move(value))
+ {
+ }
+ static void write(std::ostream &os, const std::string &value);
+ void write(std::ostream &os) const
+ {
+ write(os, value);
+ }
+ string_value duplicate() const noexcept
+ {
+ return *this;
+ }
+ const string_value *operator->() const noexcept
+ {
+ return this;
+ }
+ const string_value &operator*() const noexcept
+ {
+ return *this;
+ }
+};
+
+struct number_value final
+{
+ double value;
+ static_assert(std::numeric_limits<double>::is_iec559 && std::numeric_limits<double>::radix == 2,
+ "double is not a ieee754 float64");
+ number_value(double value) noexcept : value(value)
+ {
+ }
+ explicit operator std::string() const
+ {
+ return to_string();
+ }
+ static constexpr unsigned max_base = 36;
+ static constexpr unsigned min_base = 2;
+ static constexpr unsigned default_base = 10; // the json spec only supports base 10
+ std::string to_string(std::string buffer_in = {}, unsigned base = default_base) const;
+ std::size_t to_string(char *output_buffer,
+ std::size_t output_buffer_size,
+ bool require_null_terminator = true,
+ unsigned base = default_base) const noexcept;
+ void write(std::ostream &os, unsigned base = default_base) const;
+ number_value duplicate() const noexcept
+ {
+ return *this;
+ }
+ const number_value *operator->() const noexcept
+ {
+ return this;
+ }
+ const number_value &operator*() const noexcept
+ {
+ return *this;
+ }
+};
+
+typedef util::
+ variant<null_value, boolean_value, string_value, number_value, std::unique_ptr<composite_value>>
+ value;
+
+inline value duplicate(const value &v)
+{
+ return util::visit(
+ [](const auto &v) -> value
+ {
+ return v->duplicate();
+ },
+ v);
+}
+
+inline void write(std::ostream &os, const value &v)
+{
+ util::visit(
+ [&](const auto &v) -> void
+ {
+ return v->write(os);
+ },
+ v);
+}
+
+struct object final : public composite_value
+{
+ std::unordered_map<std::string, value> values;
+ object() : values()
+ {
+ }
+ object(std::unordered_map<std::string, value> values) noexcept : values(std::move(values))
+ {
+ }
+ virtual void write(std::ostream &os) const override;
+ virtual std::unique_ptr<composite_value> duplicate() const override
+ {
+ std::unordered_map<std::string, value> new_values;
+ for(auto &entry : values)
+ {
+ new_values.emplace(std::get<0>(entry), ast::duplicate(std::get<1>(entry)));
+ }
+ return std::unique_ptr<composite_value>(new object(std::move(new_values)));
+ }
+};
+
+struct array final : public composite_value
+{
+ std::vector<value> values;
+ array() : values()
+ {
+ }
+ array(std::vector<value> values) noexcept : values(std::move(values))
+ {
+ }
+ virtual void write(std::ostream &os) const override;
+ virtual std::unique_ptr<composite_value> duplicate() const override
+ {
+ std::vector<value> new_values;
+ new_values.reserve(values.size());
+ for(auto &value : values)
+ new_values.emplace_back(ast::duplicate(value));
+ return std::unique_ptr<composite_value>(new array(std::move(new_values)));
+ }
+};
+}
+}
+}
+
+#endif /* JSON_JSON_H_ */
#
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
set(sources spirv.cpp)
-add_library(spirv STATIC ${sources})
\ No newline at end of file
+add_library(spirv STATIC ${sources})
+target_link_libraries(spirv util)
\ No newline at end of file
# SOFTWARE.
#
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
-set(sources copy_cv_ref.cpp
+set(sources bit_intrinsics.cpp
+ copy_cv_ref.cpp
in_place.cpp
invoke.cpp
is_referenceable.cpp
is_swappable.cpp
optional.cpp
+ soft_float.cpp
variant.cpp
void_t.cpp)
add_library(util STATIC ${sources})
--- /dev/null
+/*
+ * 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 "bit_intrinsics.h"
--- /dev/null
+/*
+ * 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 UTIL_BIT_INTRINSICS_H_
+#define UTIL_BIT_INTRINSICS_H_
+
+#include <cstdint>
+#include <limits>
+
+#if defined(__clang__)
+#if defined(__apple_build_version__)
+#if __clang_major__ > 5 || (__clang_major__ == 5 && __clang_minor__ >= 1)
+#define VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED 1
+#endif
+#else
+#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 4)
+#define VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED 1
+#endif
+#endif
+#elif defined(__INTEL_COMPILER)
+#warning figure out icc version numbers for constexpr __builtin_clz and __builtin_ctz
+#elif defined(__GNUC__)
+// gcc supports constexpr __builtin_clz and __builtin_ctz before it supports c++14
+#define VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED 1
+#endif
+
+#if 1
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+#undef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+#endif
+#endif
+
+namespace vulkan_cpu
+{
+namespace util
+{
+constexpr std::uint32_t clz4(std::uint8_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 4 : __builtin_clz(v) - __builtin_clz(0x8U);
+#else
+ typedef const std::uint_fast8_t LookupTableType[0x10];
+ return LookupTableType
+ {
+ 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ [v];
+#endif
+}
+
+constexpr std::uint32_t clz8(std::uint8_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 8 : __builtin_clz(v) - __builtin_clz(0x80U);
+#else
+ return ((v & 0xF0) == 0) ? 4 + clz4(v) : clz4(v >> 4);
+#endif
+}
+
+constexpr std::uint32_t clz16(std::uint16_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 16 : __builtin_clz(v) - (std::numeric_limits<int>::digits - 16);
+#else
+ return ((v & 0xFF00U) == 0) ? 8 + clz8(v) : clz8(v >> 8);
+#endif
+}
+
+constexpr std::uint32_t clz32(std::uint32_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 32 : __builtin_clzl(v) - (std::numeric_limits<long>::digits - 32);
+#else
+ return ((v & 0xFFFF0000UL) == 0) ? 16 + clz16(v) : clz16(v >> 16);
+#endif
+}
+
+constexpr std::uint32_t clz64(std::uint64_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 64 : __builtin_clzll(v) - (std::numeric_limits<long long>::digits - 64);
+#else
+ return ((v & 0xFFFFFFFF00000000ULL) == 0) ? 32 + clz32(v) : clz32(v >> 32);
+#endif
+}
+
+constexpr std::uint32_t ctz4(std::uint8_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 4 : __builtin_ctz(v);
+#else
+ typedef const std::uint_fast8_t LookupTableType[0x10];
+ return LookupTableType
+ {
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+ }
+ [v];
+#endif
+}
+
+constexpr std::uint32_t ctz8(std::uint8_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 8 : __builtin_ctz(v);
+#else
+ return ((v & 0xF0) == 0) ? ctz4(v) : 4 + ctz4(v >> 4);
+#endif
+}
+
+constexpr std::uint32_t ctz16(std::uint16_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 16 : __builtin_ctz(v);
+#else
+ return ((v & 0xFF00U) == 0) ? ctz8(v) : 8 + ctz8(v >> 8);
+#endif
+}
+
+constexpr std::uint32_t ctz32(std::uint32_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 32 : __builtin_ctzl(v);
+#else
+ return ((v & 0xFFFF0000UL) == 0) ? ctz16(v) : 16 + ctz16(v >> 16);
+#endif
+}
+
+constexpr std::uint32_t ctz64(std::uint64_t v) noexcept
+{
+#ifdef VULKAN_CPU_UTIL_CONSTEXPR_BUILTIN_CLZ_CTZ_SUPPORTED
+ return v == 0 ? 64 : __builtin_ctzll(v);
+#else
+ return ((v & 0xFFFFFFFF00000000ULL) == 0) ? ctz32(v) : 32 + ctz32(v >> 32);
+#endif
+}
+}
+}
+
+#endif /* UTIL_BIT_INTRINSICS_H_ */
*
*/
-#ifndef SOURCE_UTIL_COPY_CV_REF_H_
-#define SOURCE_UTIL_COPY_CV_REF_H_
+#ifndef UTIL_COPY_CV_REF_H_
+#define UTIL_COPY_CV_REF_H_
namespace vulkan_cpu
{
}
}
-#endif /* SOURCE_UTIL_COPY_CV_REF_H_ */
+#endif /* UTIL_COPY_CV_REF_H_ */
*
*/
-#ifndef SOURCE_UTIL_INVOKE_H_
-#define SOURCE_UTIL_INVOKE_H_
+#ifndef UTIL_INVOKE_H_
+#define UTIL_INVOKE_H_
#include <type_traits>
#include <utility>
}
}
-#endif /* SOURCE_UTIL_INVOKE_H_ */
+#endif /* UTIL_INVOKE_H_ */
--- /dev/null
+/*
+ * Copyright 2016-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.
+ *
+ */
+
+// derived from
+// https://github.com/programmerjake/javascript-tasklets/blob/master/javascript_tasklets/soft_float.cpp
+
+#if 1
+#include "soft_float.h"
+#if 0
+#include <iostream>
+#include <cstdlib>
+#include <string>
+#include <sstream>
+#include <cstdio>
+namespace
+{
+using namespace vulkan_cpu::util::soft_float;
+std::string hexValue(const ExtendedFloat &v)
+{
+ if(v.isNaN())
+ {
+ return "NaN";
+ }
+ if(v.isInfinite())
+ {
+ if(v.sign)
+ return "-Infinity";
+ return "+Infinity";
+ }
+ std::ostringstream ss;
+ ss << std::hex << std::uppercase;
+ ss.fill('0');
+ if(v.sign)
+ ss << "-";
+ else
+ ss << "+";
+ ss << "0x";
+ std::int32_t exponent = v.exponent;
+ exponent -= ExtendedFloat::exponentBias();
+ if(v.isZero())
+ exponent = 0;
+ std::uint64_t mantissa = v.mantissa;
+ unsigned firstDigitBits = 1 + (exponent & 3);
+ ss << (mantissa >> (64 - firstDigitBits));
+ mantissa <<= firstDigitBits;
+ exponent &= ~3;
+ ss << ".";
+ ss.width(16);
+ ss << mantissa;
+ ss << "p";
+ ss << std::dec << std::showpos;
+ ss << exponent;
+ return ss.str();
+}
+std::string hexValue(long double v)
+{
+ if(std::isnan(v))
+ {
+ return "NaN";
+ }
+ if(std::isinf(v))
+ {
+ if(v < 0)
+ return "-Infinity";
+ return "+Infinity";
+ }
+ const std::size_t strSize = 64;
+ char str[strSize];
+ std::snprintf(str, sizeof(str), "%+1.16LA", v);
+ for(char &ch : str)
+ {
+ if(ch == '\0')
+ break;
+ if(ch == 'X')
+ ch = 'x';
+ else if(ch == 'P')
+ ch = 'p';
+ }
+ return str;
+}
+std::string hexValue(std::int64_t v)
+{
+ std::ostringstream ss;
+ ss << std::hex << std::uppercase;
+ ss.fill('0');
+ if(v < 0)
+ ss << "-";
+ else
+ ss << "+";
+ ss << "0x";
+ ss.width(16);
+ if(v < 0)
+ ss << -static_cast<std::uint64_t>(v);
+ else
+ ss << static_cast<std::uint64_t>(v);
+ return ss.str();
+}
+std::string hexValue(std::uint64_t v)
+{
+ std::ostringstream ss;
+ ss << std::hex << std::uppercase;
+ ss.fill('0');
+ ss << "0x";
+ ss.width(16);
+ ss << static_cast<std::uint64_t>(v);
+ return ss.str();
+}
+bool sameValue(long double a, long double b)
+{
+ if(std::isnan(a))
+ return std::isnan(b);
+ if(a == 0)
+ {
+ return b == 0 && std::signbit(a) == std::signbit(b);
+ }
+ return a == b;
+}
+void writeArgs()
+{
+}
+template <typename Arg, typename... Args>
+void writeArgs(Arg arg, Args... args)
+{
+ std::cout << " " << hexValue(arg);
+ writeArgs(args...);
+}
+constexpr bool displayPassedTests = true;
+template <typename TestFn1, typename TestFn2, typename... Args>
+void testCase(const char *name, TestFn1 &&testFn1, TestFn2 &&testFn2, Args... args)
+{
+ long double result1 = static_cast<long double>(testFn1(args...));
+ long double result2 = static_cast<long double>(testFn2(args...));
+ if(!sameValue(result1, result2))
+ {
+ std::cout << name;
+ writeArgs(args...);
+ std::cout << " -> ";
+ std::cout << hexValue(result1) << " != " << hexValue(result2) << std::endl;
+ }
+ else if(displayPassedTests)
+ {
+ std::cout << name;
+ writeArgs(args...);
+ std::cout << " -> ";
+ std::cout << hexValue(result1) << std::endl;
+ }
+}
+template <typename TestFn1, typename TestFn2, typename... Args>
+void testCaseI(const char *name, TestFn1 &&testFn1, TestFn2 &&testFn2, Args... args)
+{
+ auto result1 = testFn1(args...);
+ auto result2 = testFn2(args...);
+ if(result1 != result2)
+ {
+ std::cout << name;
+ writeArgs(args...);
+ std::cout << " -> ";
+ std::cout << hexValue(result1) << " != " << hexValue(result2) << std::endl;
+ }
+ else if(displayPassedTests)
+ {
+ std::cout << name;
+ writeArgs(args...);
+ std::cout << " -> ";
+ std::cout << hexValue(result1) << std::endl;
+ }
+}
+template <typename TestFn1, typename TestFn2, typename... Args>
+void roundTestCases(const char *name, TestFn1 &&testFn1, TestFn2 &&testFn2)
+{
+ const long double NaN = std::numeric_limits<long double>::quiet_NaN();
+ const long double Infinity = std::numeric_limits<long double>::infinity();
+ auto testBothSigns = [&](long double value)
+ {
+ testCase(name, testFn1, testFn2, value);
+ testCase(name, testFn1, testFn2, -value);
+ };
+ testCase(name, testFn1, testFn2, NaN);
+ testBothSigns(0.0L);
+ testBothSigns(Infinity);
+ testBothSigns(1.0L);
+ testBothSigns(0x1.0p-1L);
+ testBothSigns(0x1.8p0L);
+ testBothSigns(0x1.Fp0L);
+ testBothSigns(0x1.Fp-30L);
+ testBothSigns(0x1.Fp30L);
+ testBothSigns(0x1.Fp62L);
+ testBothSigns(0x1.Fp63L);
+ testBothSigns(0x1.Fp64L);
+ testBothSigns(0x1.Fp65L);
+ testBothSigns(0x1.Fp62L + 0.5L);
+ testBothSigns(0x1.Fp63L + 0.5L);
+ testBothSigns(0x1.Fp64L + 0.5L);
+ testBothSigns(0x1.Fp65L + 0.5L);
+ testBothSigns(0x1.Fp62L + 1);
+ testBothSigns(0x1.Fp63L + 1);
+ testBothSigns(0x1.Fp64L + 1);
+ testBothSigns(0x1.Fp65L + 1);
+}
+template <typename TestFn1, typename TestFn2, typename... Args>
+void toIntTestCases(const char *name, TestFn1 &&testFn1, TestFn2 &&testFn2)
+{
+ const long double NaN = std::numeric_limits<long double>::quiet_NaN();
+ const long double Infinity = std::numeric_limits<long double>::infinity();
+ auto testBothSigns = [&](long double value)
+ {
+ testCaseI(name, testFn1, testFn2, value);
+ testCaseI(name, testFn1, testFn2, -value);
+ };
+ testCaseI(name, testFn1, testFn2, NaN);
+ testBothSigns(0.0L);
+ testBothSigns(Infinity);
+ testBothSigns(1.0L);
+ testBothSigns(0x1.0p-1L);
+ testBothSigns(0x1.8p0L);
+ testBothSigns(0x1.Fp0L);
+ testBothSigns(0x1.Fp-30L);
+ testBothSigns(0x1.Fp30L);
+ testBothSigns(0x1.Fp62L);
+ testBothSigns(0x1.Fp63L);
+ testBothSigns(0x1.Fp64L);
+ testBothSigns(0x1.Fp65L);
+ testBothSigns(0x1.Fp62L + 0.5L);
+ testBothSigns(0x1.Fp63L + 0.5L);
+ testBothSigns(0x1.Fp64L + 0.5L);
+ testBothSigns(0x1.Fp65L + 0.5L);
+ testBothSigns(0x1.Fp62L + 1);
+ testBothSigns(0x1.Fp63L + 1);
+ testBothSigns(0x1.Fp64L + 1);
+ testBothSigns(0x1.Fp65L + 1);
+}
+void mainFn()
+{
+ auto add1 = [](long double a, long double b) -> long double
+ {
+ return a + b;
+ };
+ auto add2 = [](long double a, long double b) -> ExtendedFloat
+ {
+ return ExtendedFloat(a) + ExtendedFloat(b);
+ };
+ auto mul1 = [](long double a, long double b) -> long double
+ {
+ return a * b;
+ };
+ auto mul2 = [](long double a, long double b) -> ExtendedFloat
+ {
+ return ExtendedFloat(a) * ExtendedFloat(b);
+ };
+ auto div1 = [](long double a, long double b) -> long double
+ {
+ return a / b;
+ };
+ auto div2 = [](long double a, long double b) -> ExtendedFloat
+ {
+ return ExtendedFloat(a) / ExtendedFloat(b);
+ };
+ auto floor1 = [](long double a) -> long double
+ {
+ return std::floor(a);
+ };
+ auto floor2 = [](long double a) -> ExtendedFloat
+ {
+ return floor(ExtendedFloat(a));
+ };
+ auto ceil1 = [](long double a) -> long double
+ {
+ return std::ceil(a);
+ };
+ auto ceil2 = [](long double a) -> ExtendedFloat
+ {
+ return ceil(ExtendedFloat(a));
+ };
+ auto round1 = [](long double a) -> long double
+ {
+ return std::round(a);
+ };
+ auto round2 = [](long double a) -> ExtendedFloat
+ {
+ return round(ExtendedFloat(a));
+ };
+ auto trunc1 = [](long double a) -> long double
+ {
+ return std::trunc(a);
+ };
+ auto trunc2 = [](long double a) -> ExtendedFloat
+ {
+ return trunc(ExtendedFloat(a));
+ };
+ auto toUInt1 = [](long double a) -> std::uint64_t
+ {
+ if(std::isnan(a))
+ return 0;
+ if(a < std::numeric_limits<std::uint64_t>::min())
+ return std::numeric_limits<std::uint64_t>::min();
+ if(a > std::numeric_limits<std::uint64_t>::max())
+ return std::numeric_limits<std::uint64_t>::max();
+ return static_cast<std::uint64_t>(a);
+ };
+ auto toUInt2 = [](long double a) -> std::uint64_t
+ {
+ return static_cast<std::uint64_t>(ExtendedFloat(a));
+ };
+ auto toInt1 = [](long double a) -> std::int64_t
+ {
+ if(std::isnan(a))
+ return 0;
+ if(a < std::numeric_limits<std::int64_t>::min())
+ return std::numeric_limits<std::int64_t>::min();
+ if(a > std::numeric_limits<std::int64_t>::max())
+ return std::numeric_limits<std::int64_t>::max();
+ return static_cast<std::int64_t>(a);
+ };
+ auto toInt2 = [](long double a) -> std::int64_t
+ {
+ return static_cast<std::int64_t>(ExtendedFloat(a));
+ };
+ auto pow1 = [](long double base, int exponent) -> long double
+ {
+ if(exponent < 0)
+ {
+ base = 1 / base;
+ exponent = -exponent;
+ }
+ else if(exponent == 0)
+ return 1;
+ long double retval = 1;
+ for(;;)
+ {
+ if(exponent == 0)
+ return retval;
+ else if(exponent == 1)
+ return retval * base;
+ if(exponent & 1)
+ {
+ retval *= base;
+ }
+ base *= base;
+ exponent >>= 1;
+ }
+ };
+ auto pow2 = [](long double base, int exponent) -> ExtendedFloat
+ {
+ return pow(ExtendedFloat(base), static_cast<std::int64_t>(exponent));
+ };
+ auto scalbn1 = [](long double a, std::int64_t exponent) -> long double
+ {
+ return std::scalbln(a, static_cast<long>(exponent));
+ };
+ auto scalbn2 = [](long double a, std::int64_t exponent) -> ExtendedFloat
+ {
+ return scalbn(ExtendedFloat(a), exponent);
+ };
+ auto log2_1 = [](long double a) -> long double
+ {
+ return std::log2(a);
+ };
+ auto log2_2 = [](long double a) -> ExtendedFloat
+ {
+ return log2(ExtendedFloat(a));
+ };
+ auto log10_1 = [](long double a) -> long double
+ {
+ return std::log10(a);
+ };
+ auto log10_2 = [](long double a) -> ExtendedFloat
+ {
+ return log10(ExtendedFloat(a));
+ };
+ const long double NaN = std::numeric_limits<long double>::quiet_NaN();
+ const long double Infinity = std::numeric_limits<long double>::infinity();
+ testCase("add", add1, add2, +0.0L, +0.0L);
+ testCase("add", add1, add2, +0.0L, -0.0L);
+ testCase("add", add1, add2, -0.0L, +0.0L);
+ testCase("add", add1, add2, -0.0L, -0.0L);
+ testCase("add", add1, add2, 0.0L, NaN);
+ testCase("add", add1, add2, NaN, 0.0L);
+ testCase("add", add1, add2, NaN, NaN);
+ testCase("add", add1, add2, +Infinity, +Infinity);
+ testCase("add", add1, add2, +Infinity, -Infinity);
+ testCase("add", add1, add2, -Infinity, +Infinity);
+ testCase("add", add1, add2, -Infinity, -Infinity);
+ testCase("add", add1, add2, 0x1.0000000000000002p0L, -0x1.0p-64L);
+ testCase("add", add1, add2, 0x1.p0L, -0x1.0p-65L);
+ testCase("add", add1, add2, 0x1.p0L, -0x0.Fp-65L);
+ testCase("add", add1, add2, 0x1.p0L, -0x1.1p-65L);
+ testCase("add", add1, add2, 0x1.0000000000000002p0L, -0x2.0p-65L);
+ testCase("add", add1, add2, 0x1.0000000000000002p0L, -0x1.Fp-65L);
+ testCase("add", add1, add2, 0x1.0000000000000002p0L, -0x2.1p-65L);
+ testCase("add", add1, add2, 0x1p-16445L, 0x1p-16445L);
+ testCase("add", add1, add2, 0x1p+16383L, 0x1p+16383L);
+ testCase("mul", mul1, mul2, +0.0L, +0.0L);
+ testCase("mul", mul1, mul2, +0.0L, -0.0L);
+ testCase("mul", mul1, mul2, -0.0L, +0.0L);
+ testCase("mul", mul1, mul2, -0.0L, -0.0L);
+ testCase("mul", mul1, mul2, 0.0L, NaN);
+ testCase("mul", mul1, mul2, NaN, 0.0L);
+ testCase("mul", mul1, mul2, NaN, NaN);
+ testCase("mul", mul1, mul2, +Infinity, +Infinity);
+ testCase("mul", mul1, mul2, +Infinity, -Infinity);
+ testCase("mul", mul1, mul2, -Infinity, +Infinity);
+ testCase("mul", mul1, mul2, -Infinity, -Infinity);
+ testCase("mul", mul1, mul2, 0x1p0L, 0x1p0L);
+ testCase("mul", mul1, mul2, 0x1p16000L, 0x1p383L);
+ testCase("mul", mul1, mul2, 0x1p16000L, 0x1p384L);
+ testCase("mul", mul1, mul2, 0x1p-16000L, 0x1p-445L);
+ testCase("mul", mul1, mul2, 0x1p-16000L, 0x1p-446L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.000000001p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.0000000018p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.000000002p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.0000000028p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.000000003p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.0000000038p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.000000004p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.0000000048p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.000000005p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.0000000058p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.000000006p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.0000000068p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.000000007p0L);
+ testCase("mul", mul1, mul2, 0x1.0000001p0L, 0x1.0000000078p0L);
+ testCase("mul",
+ mul1,
+ mul2,
+ 3.1415926535897932384626433832795L,
+ 0.318309886183790671537767526745028724L);
+ testCase("mul",
+ mul1,
+ mul2,
+ 2.718281828459045235360287471352662497757L,
+ 0.3678794411714423215955237701614608674458L);
+ testCase("div", div1, div2, +0.0L, +0.0L);
+ testCase("div", div1, div2, +1.0L, +0.0L);
+ testCase("div", div1, div2, +1.0L, -0.0L);
+ testCase("div", div1, div2, -1.0L, +0.0L);
+ testCase("div", div1, div2, -1.0L, -0.0L);
+ testCase("div", div1, div2, +0.0L, +1.0L);
+ testCase("div", div1, div2, +0.0L, -1.0L);
+ testCase("div", div1, div2, -0.0L, +1.0L);
+ testCase("div", div1, div2, -0.0L, -1.0L);
+ testCase("div", div1, div2, 0.0L, NaN);
+ testCase("div", div1, div2, NaN, 0.0L);
+ testCase("div", div1, div2, NaN, NaN);
+ testCase("div", div1, div2, +Infinity, +Infinity);
+ testCase("div", div1, div2, +1.0L, +Infinity);
+ testCase("div", div1, div2, +1.0L, -Infinity);
+ testCase("div", div1, div2, -1.0L, +Infinity);
+ testCase("div", div1, div2, -1.0L, -Infinity);
+ testCase("div", div1, div2, 1.0L, 3.0L);
+ testCase("div", div1, div2, 1.0L, 5.0L);
+ testCase("div", div1, div2, 1.0L, 7.0L);
+ testCase("div", div1, div2, 1.0L, 9.0L);
+ testCase("div", div1, div2, 1.0L, 11.0L);
+ testCase("div", div1, div2, 1.0L, 3.1415926535897932384626433832795L);
+ testCase("div", div1, div2, 1.0L, 2.718281828459045235360287471352662497757L);
+ testCase("div", div1, div2, 0x1p16000L, 0x1p-383L);
+ testCase("div", div1, div2, 0x1p16000L, 0x1p-384L);
+ testCase("div", div1, div2, 0x1p-16000L, 0x1p445L);
+ testCase("div", div1, div2, 0x1p-16000L, 0x1p446L);
+ roundTestCases("floor", floor1, floor2);
+ roundTestCases("round", round1, round2);
+ roundTestCases("ceil", ceil1, ceil2);
+ roundTestCases("trunc", trunc1, trunc2);
+ toIntTestCases("uint64", toUInt1, toUInt2);
+ toIntTestCases("int64", toInt1, toInt2);
+ testCase("pow", pow1, pow2, 1.0L, static_cast<std::int64_t>(0));
+ testCase("pow", pow1, pow2, 1.0L, static_cast<std::int64_t>(5000));
+ testCase("pow", pow1, pow2, 1.0L, static_cast<std::int64_t>(-5000));
+ testCase("pow", pow1, pow2, 2.0L, static_cast<std::int64_t>(3000));
+ testCase("pow", pow1, pow2, 2.0L, static_cast<std::int64_t>(-3000));
+ testCase("pow", pow1, pow2, 3.0L, static_cast<std::int64_t>(3000));
+ testCase("pow", pow1, pow2, 3.0L, static_cast<std::int64_t>(-3000));
+ testCase("pow", pow1, pow2, 10.0L, static_cast<std::int64_t>(3000));
+ testCase("pow", pow1, pow2, 10.0L, static_cast<std::int64_t>(-3000));
+ testCase("pow", pow1, pow2, 36.0L, static_cast<std::int64_t>(3000));
+ testCase("pow", pow1, pow2, 36.0L, static_cast<std::int64_t>(-3000));
+ testCase("scalbn", scalbn1, scalbn2, 1.0L, static_cast<std::int64_t>(16384));
+ testCase("scalbn", scalbn1, scalbn2, 1.0L, static_cast<std::int64_t>(16383));
+ testCase("scalbn", scalbn1, scalbn2, 1.0L, static_cast<std::int64_t>(3000));
+ testCase("scalbn", scalbn1, scalbn2, 1.0L, static_cast<std::int64_t>(-3000));
+ testCase("scalbn", scalbn1, scalbn2, 1.0L, static_cast<std::int64_t>(-16383));
+ testCase("scalbn", scalbn1, scalbn2, 1.0L, static_cast<std::int64_t>(-16384));
+ testCase("scalbn", scalbn1, scalbn2, 1.0L, static_cast<std::int64_t>(-16445));
+ testCase("scalbn", scalbn1, scalbn2, 1.0L, static_cast<std::int64_t>(-16446));
+ testCase("log2", log2_1, log2_2, NaN);
+ testCase("log2", log2_1, log2_2, Infinity);
+ testCase("log2", log2_1, log2_2, -Infinity);
+ testCase("log2", log2_1, log2_2, 0.0L);
+ testCase("log2", log2_1, log2_2, -0.0L);
+ testCase("log2", log2_1, log2_2, -1.0L);
+ testCase("log2", log2_1, log2_2, 1.0L);
+ testCase("log2", log2_1, log2_2, 2.0L);
+ testCase("log2", log2_1, log2_2, 0x1.0p-16445L);
+ testCase("log2", log2_1, log2_2, 0x1.0p16383L);
+ testCase("log2", log2_1, log2_2, 3.0L);
+ testCase("log2", log2_1, log2_2, 5.0L);
+ testCase("log2", log2_1, log2_2, 7.0L);
+ testCase("log2", log2_1, log2_2, 9.0L);
+ testCase("log2", log2_1, log2_2, 11.0L);
+ testCase("log2", log2_1, log2_2, 1e100L);
+ testCase("log2", log2_1, log2_2, 1e-1L);
+ testCase("log2", log2_1, log2_2, 1e-2L);
+ testCase("log2", log2_1, log2_2, 1.5L);
+ testCase("log2", log2_1, log2_2, 0.693147180559945309417232121458176568L);
+ testCase("log2", log2_1, log2_2, static_cast<long double>(ExtendedFloat::Log10Of2()));
+ testCase("log2", log2_1, log2_2, static_cast<long double>(ExtendedFloat::LogOf2()));
+ testCase("log10", log10_1, log10_2, 1e1001L);
+ testCase("log10", log10_1, log10_2, 1.5L);
+}
+struct Init
+{
+ Init()
+ {
+ mainFn();
+ std::exit(0);
+ }
+};
+Init init;
+}
+#endif
+#else
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <thread>
+#include <list>
+#include <sstream>
+#include <cassert>
+namespace
+{
+unsigned clz8(std::uint8_t v)
+{
+ return __builtin_clz(v) - __builtin_clz(0x80U);
+}
+unsigned ctz8(std::uint8_t v)
+{
+ return v == 0 ? 8 : __builtin_ctz(v);
+}
+struct UInt16 final
+{
+ std::uint8_t high;
+ std::uint8_t low;
+ explicit UInt16(std::uint8_t low = 0) : high(0), low(low)
+ {
+ }
+ UInt16(std::uint8_t high, std::uint8_t low) : high(high), low(low)
+ {
+ }
+ friend unsigned clz16(UInt16 v)
+ {
+ return v.high == 0 ? 8 + clz8(v.low) : clz8(v.high);
+ }
+ friend unsigned ctz16(UInt16 v)
+ {
+ return v.low == 0 ? 8 + ctz8(v.high) : ctz8(v.low);
+ }
+ static UInt16 mul8x8(std::uint8_t a, std::uint8_t b)
+ {
+ unsigned v = a;
+ v *= b;
+ return UInt16(v >> 8, v & 0xFFU);
+ }
+ static bool addCarry(std::uint8_t a, std::uint8_t b)
+ {
+ return static_cast<std::uint16_t>(a) + b > 0xFFU;
+ }
+ static bool addCarry(std::uint8_t a, std::uint8_t b, bool carry)
+ {
+ return static_cast<unsigned>(a) + b + carry > 0xFFU;
+ }
+ static bool subBorrow(std::uint8_t a, std::uint8_t b)
+ {
+ return a < b;
+ }
+ static bool subBorrow(std::uint8_t a, std::uint8_t b, bool borrow)
+ {
+ return a < b || (a == b && borrow);
+ }
+ friend UInt16 operator+(UInt16 a, UInt16 b)
+ {
+ return UInt16(a.high + b.high + addCarry(a.low, b.low), a.low + b.low);
+ }
+ friend UInt16 operator-(UInt16 a, UInt16 b)
+ {
+ return UInt16(a.high - b.high - subBorrow(a.low, b.low), a.low - b.low);
+ }
+ friend UInt16 operator<<(UInt16 v, unsigned shiftAmount)
+ {
+ return shiftAmount == 0 ? v : shiftAmount < 8 ?
+ UInt16((v.high << shiftAmount) | (v.low >> (8 - shiftAmount)),
+ v.low << shiftAmount) :
+ UInt16(v.low << (shiftAmount - 8), 0);
+ }
+ friend UInt16 operator>>(UInt16 v, unsigned shiftAmount)
+ {
+ return shiftAmount == 0 ? v : shiftAmount < 8 ?
+ UInt16(v.high >> shiftAmount,
+ (v.low >> shiftAmount) | (v.high << (8 - shiftAmount))) :
+ UInt16(v.high >> (shiftAmount - 8));
+ }
+ struct DivModResult8 final
+ {
+ std::uint8_t divResult;
+ std::uint8_t modResult;
+ DivModResult8(std::uint8_t divResult, std::uint8_t modResult)
+ : divResult(divResult), modResult(modResult)
+ {
+ }
+ };
+ static DivModResult8 divMod16x8(UInt16 n, std::uint8_t d)
+ {
+ assert(d != 0);
+ std::uint16_t v = n.high;
+ v <<= 8;
+ v |= n.low;
+ std::uint16_t divResult = v / d;
+ std::uint16_t modResult = v % d;
+ assert(divResult <= 0xFFU);
+ assert(modResult <= 0xFFU);
+ return DivModResult8(divResult, modResult);
+ }
+ struct DivModResult;
+ static DivModResult divMod(UInt16 uIn, UInt16 vIn);
+ static DivModResult divMod2(UInt16 n, UInt16 d);
+ friend bool operator==(UInt16 a, UInt16 b) noexcept
+ {
+ return a.high == b.high && a.low == b.low;
+ }
+ friend bool operator!=(UInt16 a, UInt16 b) noexcept
+ {
+ return a.high != b.high || a.low != b.low;
+ }
+ friend bool operator<(UInt16 a, UInt16 b) noexcept
+ {
+ return a.high < b.high || (a.high == b.high && a.low < b.low);
+ }
+ friend bool operator<=(UInt16 a, UInt16 b) noexcept
+ {
+ return a.high < b.high || (a.high == b.high && a.low <= b.low);
+ }
+ friend bool operator>(UInt16 a, UInt16 b) noexcept
+ {
+ return a.high > b.high || (a.high == b.high && a.low > b.low);
+ }
+ friend bool operator>=(UInt16 a, UInt16 b) noexcept
+ {
+ return a.high > b.high || (a.high == b.high && a.low >= b.low);
+ }
+};
+struct UInt16::DivModResult final
+{
+ UInt16 divResult;
+ UInt16 modResult;
+ DivModResult(UInt16 divResult, UInt16 modResult) : divResult(divResult), modResult(modResult)
+ {
+ }
+};
+UInt16::DivModResult UInt16::divMod2(UInt16 n, UInt16 d)
+{
+ std::uint16_t nv = n.high;
+ nv <<= 8;
+ nv |= n.low;
+ std::uint16_t dv = d.high;
+ dv <<= 8;
+ dv |= d.low;
+ std::uint16_t qv = nv / dv;
+ std::uint16_t rv = nv % dv;
+ return DivModResult(UInt16(qv >> 8, qv & 0xFF), UInt16(rv >> 8, rv & 0xFF));
+}
+template <std::size_t NumberSizes,
+ typename Digit,
+ typename DoubleDigit,
+ unsigned DigitBitCount,
+ typename DigitCLZFn>
+void divMod(const Digit(&numerator)[NumberSizes],
+ const Digit(&denominator)[NumberSizes],
+ Digit("ient)[NumberSizes],
+ Digit(&remainder)[NumberSizes])
+{
+ constexpr Digit DigitMax = (static_cast<DoubleDigit>(1) << DigitBitCount) - 1;
+ static_assert(NumberSizes != 0, "bad size");
+ std::size_t m = NumberSizes;
+ for(std::size_t i = 0; i < NumberSizes; i++)
+ {
+ if(denominator[i] != 0)
+ {
+ m = i;
+ break;
+ }
+ }
+ const std::size_t n = NumberSizes - m;
+ if(n <= 1)
+ {
+ assert(denominator[NumberSizes - 1] != 0);
+ for(std::size_t i = 0; i < NumberSizes - 1; i++)
+ {
+ remainder[i] = 0;
+ }
+ Digit currentRemainder = 0;
+ for(std::size_t i = 0; i < NumberSizes; i++)
+ {
+ DoubleDigit n = currentRemainder;
+ n <<= DigitBitCount;
+ n |= numerator[i];
+ quotient[i] = n / denominator[NumberSizes - 1];
+ currentRemainder = n % denominator[NumberSizes - 1];
+ }
+ remainder[NumberSizes - 1] = currentRemainder;
+ return;
+ }
+ // from algorithm D, section 4.3.1 in Art of Computer Programming volume 2 by Knuth.
+ unsigned log2D = DigitCLZFn()(denominator[m]);
+ Digit u[NumberSizes + 1];
+ u[NumberSizes] = (numerator[NumberSizes - 1] << log2D) & DigitMax;
+ u[0] = ((static_cast<DoubleDigit>(numerator[0]) << log2D) >> DigitBitCount) & DigitMax;
+ for(std::size_t i = 1; i < NumberSizes; i++)
+ {
+ DoubleDigit value = numerator[i - 1];
+ value <<= DigitBitCount;
+ value |= numerator[i];
+ value <<= log2D;
+ u[i] = (value >> DigitBitCount) & DigitMax;
+ }
+ Digit v[NumberSizes + 1] = {};
+ v[n] = (denominator[NumberSizes - 1] << log2D) & DigitMax;
+ for(std::size_t i = 1; i < n; i++)
+ {
+ DoubleDigit value = denominator[m + i - 1];
+ value <<= DigitBitCount;
+ value |= denominator[m + i];
+ value <<= log2D;
+ v[i] = (value >> DigitBitCount) & DigitMax;
+ quotient[i - 1] = 0;
+ }
+ for(std::size_t j = 0; j <= m; j++)
+ {
+ DoubleDigit qHat;
+ if(u[j] == v[1])
+ {
+ qHat = DigitMax;
+ }
+ else
+ {
+ qHat = ((static_cast<DoubleDigit>(u[j]) << DigitBitCount) | u[j + 1]) / v[1];
+ }
+ {
+ DoubleDigit lhs = v[2] * qHat;
+ DoubleDigit rhsHigh =
+ ((static_cast<DoubleDigit>(u[j]) << DigitBitCount) | u[j + 1]) - qHat * v[1];
+ Digit rhsLow = u[j + 2];
+ if(rhsHigh < static_cast<DoubleDigit>(1) << DigitBitCount
+ && lhs > ((rhsHigh << DigitBitCount) | rhsLow))
+ {
+ qHat--;
+ lhs -= v[2];
+ rhsHigh += v[1];
+ if(rhsHigh < static_cast<DoubleDigit>(1) << DigitBitCount
+ && lhs > ((rhsHigh << DigitBitCount) | rhsLow))
+ {
+ qHat--;
+ }
+ }
+ }
+ bool borrow = false;
+ {
+ Digit mulCarry = 0;
+ for(std::size_t i = n; i > 0; i--)
+ {
+ assert(i <= NumberSizes);
+ DoubleDigit product = qHat * v[i] + mulCarry;
+ mulCarry = product >> DigitBitCount;
+ product &= DigitMax;
+ bool prevBorrow = borrow;
+ DoubleDigit digit = u[j + i] - product - prevBorrow;
+ borrow = digit != (digit & DigitMax);
+ digit &= DigitMax;
+ u[j + i] = digit;
+ }
+ bool prevBorrow = borrow;
+ DoubleDigit digit = u[j] - mulCarry - prevBorrow;
+ borrow = digit != (digit & DigitMax);
+ digit &= DigitMax;
+ u[j] = digit;
+ }
+ Digit qj = qHat;
+ if(borrow)
+ {
+ qj--;
+ bool carry = false;
+ for(std::size_t i = n; i > 0; i--)
+ {
+ bool prevCarry = carry;
+ assert(i + j <= NumberSizes);
+ DoubleDigit digit = u[j + i] + v[i] + prevCarry;
+ carry = digit != (digit & DigitMax);
+ digit &= DigitMax;
+ u[j + i] = digit;
+ }
+ u[j] = (u[j] + carry) & DigitMax;
+ }
+ quotient[j + n - 1] = qj;
+ }
+ for(std::size_t i = 0; i < NumberSizes; i++)
+ {
+ DoubleDigit value = u[i];
+ value <<= DigitBitCount;
+ value |= u[i + 1];
+ remainder[i] = value >> log2D;
+ }
+}
+struct OpClz4 final
+{
+ constexpr unsigned operator()(std::uint16_t value) const noexcept
+ {
+ return __builtin_clz(value) - (__builtin_clz(0) - 4);
+ }
+};
+UInt16::DivModResult UInt16::divMod(UInt16 uIn, UInt16 vIn)
+{
+ constexpr std::size_t NumberSizes = 4;
+ typedef std::uint16_t Digit;
+ typedef unsigned DoubleDigit;
+ constexpr unsigned DigitBitCount = 4;
+ Digit numerator[NumberSizes], denominator[NumberSizes], quotient[NumberSizes],
+ remainder[NumberSizes];
+ numerator[0] = uIn.high >> 4;
+ numerator[1] = uIn.high & 0xF;
+ numerator[2] = uIn.low >> 4;
+ numerator[3] = uIn.low & 0xF;
+ denominator[0] = vIn.high >> 4;
+ denominator[1] = vIn.high & 0xF;
+ denominator[2] = vIn.low >> 4;
+ denominator[3] = vIn.low & 0xF;
+ ::divMod<NumberSizes, Digit, DoubleDigit, DigitBitCount, OpClz4>(
+ numerator, denominator, quotient, remainder);
+ return DivModResult(
+ UInt16((quotient[0] << 4) | quotient[1], (quotient[2] << 4) | quotient[3]),
+ UInt16((remainder[0] << 4) | remainder[1], (remainder[2] << 4) | remainder[3]));
+}
+void mainFn(std::uint8_t start, std::uint8_t end)
+{
+ for(unsigned dHigh = start; dHigh <= end; dHigh++)
+ {
+ if(start == 0)
+ {
+ std::ostringstream ss;
+ ss << dHigh * 100 / (end + 1) << "%\n";
+ std::cout << ss.str() << std::flush;
+ }
+ for(unsigned dLow = 0; dLow < 0x100U; dLow++)
+ {
+ UInt16 d(dHigh, dLow);
+ if(d == UInt16(0))
+ continue;
+#if 0
+ if(d < UInt16(2, 0))
+ continue;
+#endif
+ for(unsigned nHigh = 0; nHigh < 0x100U; nHigh++)
+ {
+ for(unsigned nLow = 0; nLow < 0x100U; nLow++)
+ {
+ UInt16 n(nHigh, nLow);
+ auto result = UInt16::divMod(n, d);
+ auto result2 = UInt16::divMod2(n, d);
+ if(result.divResult != result2.divResult
+ || result.modResult != result2.modResult)
+ {
+ std::ostringstream ss;
+ ss << std::hex << std::uppercase;
+ ss.fill('0');
+ ss.width(2);
+ ss << static_cast<unsigned>(n.high);
+ ss.width(2);
+ ss << static_cast<unsigned>(n.low);
+ ss << " / ";
+ ss.width(2);
+ ss << static_cast<unsigned>(d.high);
+ ss.width(2);
+ ss << static_cast<unsigned>(d.low);
+ ss << " == ";
+ ss.width(2);
+ ss << static_cast<unsigned>(result.divResult.high);
+ ss.width(2);
+ ss << static_cast<unsigned>(result.divResult.low);
+ ss << ", ";
+ ss.width(2);
+ ss << static_cast<unsigned>(result2.divResult.high);
+ ss.width(2);
+ ss << static_cast<unsigned>(result2.divResult.low);
+ ss << std::endl;
+ ss.width(2);
+ ss << static_cast<unsigned>(n.high);
+ ss.width(2);
+ ss << static_cast<unsigned>(n.low);
+ ss << " % ";
+ ss.width(2);
+ ss << static_cast<unsigned>(d.high);
+ ss.width(2);
+ ss << static_cast<unsigned>(d.low);
+ ss << " == ";
+ ss.width(2);
+ ss << static_cast<unsigned>(result.modResult.high);
+ ss.width(2);
+ ss << static_cast<unsigned>(result.modResult.low);
+ ss << ", ";
+ ss.width(2);
+ ss << static_cast<unsigned>(result2.modResult.high);
+ ss.width(2);
+ ss << static_cast<unsigned>(result2.modResult.low);
+ std::cout << ss.str() << std::endl;
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+struct Init
+{
+ Init()
+ {
+ const std::size_t splitCount = 6;
+ std::list<std::thread> threads;
+ for(std::size_t i = 0; i < splitCount; i++)
+ {
+ auto start = i * 0x100 / splitCount;
+ auto end = (i + 1) * 0x100 / splitCount - 1;
+ threads.push_back(std::thread([=]()
+ {
+ mainFn(start, end);
+ }));
+ }
+ for(std::thread &thread : threads)
+ thread.join();
+ std::exit(0);
+ }
+};
+Init init;
+}
+#endif
--- /dev/null
+/*
+ * Copyright 2016-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.
+ *
+ */
+
+// derived from
+// https://github.com/programmerjake/javascript-tasklets/blob/master/javascript_tasklets/soft_float.h
+
+#ifndef UTIL_SOFT_FLOAT_H_
+#define UTIL_SOFT_FLOAT_H_
+
+#include <cstdint>
+#include <cmath>
+#include <cassert>
+#include "bit_intrinsics.h"
+
+namespace vulkan_cpu
+{
+namespace util
+{
+namespace soft_float
+{
+struct UInt128 final
+{
+ std::uint64_t low;
+ std::uint64_t high;
+ constexpr UInt128(std::uint64_t high, std::uint64_t low) noexcept : low(low), high(high)
+ {
+ }
+ constexpr explicit UInt128(std::uint64_t low = 0) noexcept : low(low), high(0)
+ {
+ }
+ static constexpr bool addCarries(std::uint64_t a, std::uint64_t b) noexcept
+ {
+ return static_cast<std::uint64_t>(a + b) < a;
+ }
+ static constexpr bool subBorrows(std::uint64_t a, std::uint64_t b) noexcept
+ {
+ return static_cast<std::uint64_t>(a - b) > a;
+ }
+ friend constexpr UInt128 operator+(UInt128 a, UInt128 b) noexcept
+ {
+ return UInt128(a.high + b.high + addCarries(a.low, b.low), a.low + b.low);
+ }
+ constexpr UInt128 &operator+=(UInt128 v) noexcept
+ {
+ return *this = *this + v;
+ }
+ friend constexpr UInt128 operator-(UInt128 a, UInt128 b) noexcept
+ {
+ return UInt128(a.high - b.high - subBorrows(a.low, b.low), a.low - b.low);
+ }
+ constexpr UInt128 &operator-=(UInt128 v) noexcept
+ {
+ return *this = *this - v;
+ }
+
+private:
+ static constexpr std::uint64_t multiplyHighHelper2(std::uint64_t h,
+ std::uint64_t m1,
+ std::uint64_t m2,
+ std::uint64_t l) noexcept
+ {
+ return (UInt128(h, l) + UInt128(m1 >> 32, m1 << 32) + UInt128(m2 >> 32, m2 << 32)).high;
+ }
+ static constexpr std::uint64_t multiplyHighHelper1(std::uint32_t ah,
+ std::uint32_t al,
+ std::uint32_t bh,
+ std::uint32_t bl) noexcept
+ {
+ return multiplyHighHelper2(static_cast<std::uint64_t>(ah) * bh,
+ static_cast<std::uint64_t>(ah) * bl,
+ static_cast<std::uint64_t>(al) * bh,
+ static_cast<std::uint64_t>(al) * bl);
+ }
+
+public:
+ static constexpr std::uint64_t multiplyHigh(std::uint64_t a, std::uint64_t b) noexcept
+ {
+ return multiplyHighHelper1(a >> 32, a, b >> 32, b);
+ }
+ friend constexpr UInt128 operator*(UInt128 a, UInt128 b) noexcept
+ {
+ return UInt128(a.high * b.low + a.low * b.high + multiplyHigh(a.low, b.low), a.low * b.low);
+ }
+ constexpr UInt128 &operator*=(UInt128 v) noexcept
+ {
+ return *this = *this * v;
+ }
+ struct DivModResult;
+ static constexpr DivModResult divmod(UInt128 a, UInt128 b) noexcept;
+ static constexpr UInt128 div(UInt128 a, UInt128 b) noexcept;
+ static constexpr UInt128 mod(UInt128 a, UInt128 b) noexcept;
+ friend constexpr UInt128 operator/(UInt128 a, UInt128 b) noexcept
+ {
+ return div(a, b);
+ }
+ friend constexpr UInt128 operator%(UInt128 a, UInt128 b) noexcept
+ {
+ return mod(a, b);
+ }
+ constexpr UInt128 &operator/=(UInt128 v) noexcept
+ {
+ return *this = *this / v;
+ }
+ constexpr UInt128 &operator%=(UInt128 v) noexcept
+ {
+ return *this = *this % v;
+ }
+ friend constexpr UInt128 operator&(UInt128 a, UInt128 b) noexcept
+ {
+ return UInt128(a.high & b.high, a.low & b.low);
+ }
+ constexpr UInt128 &operator&=(UInt128 v) noexcept
+ {
+ return *this = *this & v;
+ }
+ friend constexpr UInt128 operator|(UInt128 a, UInt128 b) noexcept
+ {
+ return UInt128(a.high | b.high, a.low | b.low);
+ }
+ constexpr UInt128 &operator|=(UInt128 v) noexcept
+ {
+ return *this = *this | v;
+ }
+ friend constexpr UInt128 operator^(UInt128 a, UInt128 b) noexcept
+ {
+ return UInt128(a.high ^ b.high, a.low ^ b.low);
+ }
+ constexpr UInt128 &operator^=(UInt128 v) noexcept
+ {
+ return *this = *this ^ v;
+ }
+ friend constexpr UInt128 operator<<(UInt128 v, unsigned shiftAmount) noexcept
+ {
+ assert(shiftAmount < 128);
+ return shiftAmount == 0 ? v : shiftAmount < 64 ?
+ UInt128((v.high << shiftAmount) | (v.low >> (64 - shiftAmount)),
+ v.low << shiftAmount) :
+ shiftAmount == 64 ? UInt128(v.low, 0) :
+ UInt128(v.low << (shiftAmount - 64), 0);
+ }
+ constexpr UInt128 &operator<<=(unsigned shiftAmount) noexcept
+ {
+ return *this = *this << shiftAmount;
+ }
+ friend constexpr UInt128 operator>>(UInt128 v, unsigned shiftAmount) noexcept
+ {
+ assert(shiftAmount < 128);
+ return shiftAmount == 0 ? v : shiftAmount < 64 ?
+ UInt128(v.high >> shiftAmount,
+ (v.low >> shiftAmount) | (v.high << (64 - shiftAmount))) :
+ shiftAmount == 64 ? UInt128(0, v.high) :
+ UInt128(0, v.high >> (shiftAmount - 64));
+ }
+ constexpr UInt128 &operator>>=(unsigned shiftAmount) noexcept
+ {
+ return *this = *this >> shiftAmount;
+ }
+ constexpr UInt128 operator+() noexcept
+ {
+ return *this;
+ }
+ constexpr UInt128 operator~() noexcept
+ {
+ return UInt128(~high, ~low);
+ }
+ constexpr UInt128 operator-() noexcept
+ {
+ return low != 0 ? UInt128(~high, -low) : UInt128(-high, 0);
+ }
+ friend constexpr bool operator==(UInt128 a, UInt128 b) noexcept
+ {
+ return a.high == b.high && a.low == b.low;
+ }
+ friend constexpr bool operator!=(UInt128 a, UInt128 b) noexcept
+ {
+ return a.high != b.high || a.low != b.low;
+ }
+ friend constexpr bool operator<(UInt128 a, UInt128 b) noexcept
+ {
+ return a.high < b.high || (a.high == b.high && a.low < b.low);
+ }
+ friend constexpr bool operator<=(UInt128 a, UInt128 b) noexcept
+ {
+ return a.high < b.high || (a.high == b.high && a.low <= b.low);
+ }
+ friend constexpr bool operator>(UInt128 a, UInt128 b) noexcept
+ {
+ return a.high > b.high || (a.high == b.high && a.low > b.low);
+ }
+ friend constexpr bool operator>=(UInt128 a, UInt128 b) noexcept
+ {
+ return a.high > b.high || (a.high == b.high && a.low >= b.low);
+ }
+ friend constexpr unsigned clz128(UInt128 v) noexcept
+ {
+ return v.high == 0 ? 64 + clz64(v.low) : clz64(v.high);
+ }
+ friend constexpr unsigned ctz128(UInt128 v) noexcept
+ {
+ return v.low == 0 ? 64 + ctz64(v.high) : ctz64(v.low);
+ }
+};
+
+struct UInt128::DivModResult final
+{
+ UInt128 divResult;
+ UInt128 modResult;
+ constexpr DivModResult(UInt128 divResult, UInt128 modResult) noexcept : divResult(divResult),
+ modResult(modResult)
+ {
+ }
+};
+
+constexpr UInt128::DivModResult UInt128::divmod(UInt128 a, UInt128 b) noexcept
+{
+ constexpr std::size_t NumberSizes = 4;
+ typedef std::uint32_t Digit;
+ typedef std::uint64_t DoubleDigit;
+ constexpr unsigned DigitBitCount = 32;
+ struct DigitCLZFn final
+ {
+ constexpr unsigned operator()(Digit v) const noexcept
+ {
+ return clz32(v);
+ }
+ };
+ constexpr Digit DigitMax = (static_cast<DoubleDigit>(1) << DigitBitCount) - 1;
+ const Digit numerator[NumberSizes] = {
+ static_cast<Digit>(a.high >> DigitBitCount),
+ static_cast<Digit>(a.high & DigitMax),
+ static_cast<Digit>(a.low >> DigitBitCount),
+ static_cast<Digit>(a.low & DigitMax),
+ };
+ const Digit denominator[NumberSizes] = {
+ static_cast<Digit>(b.high >> DigitBitCount),
+ static_cast<Digit>(b.high & DigitMax),
+ static_cast<Digit>(b.low >> DigitBitCount),
+ static_cast<Digit>(b.low & DigitMax),
+ };
+ Digit quotient[NumberSizes]{};
+ Digit remainder[NumberSizes]{};
+ std::size_t m = NumberSizes;
+ for(std::size_t i = 0; i < NumberSizes; i++)
+ {
+ if(denominator[i] != 0)
+ {
+ m = i;
+ break;
+ }
+ }
+ const std::size_t n = NumberSizes - m;
+ if(n <= 1)
+ {
+ assert(denominator[NumberSizes - 1] != 0);
+ for(std::size_t i = 0; i < NumberSizes - 1; i++)
+ {
+ remainder[i] = 0;
+ }
+ Digit currentRemainder = 0;
+ for(std::size_t i = 0; i < NumberSizes; i++)
+ {
+ DoubleDigit n = currentRemainder;
+ n <<= DigitBitCount;
+ n |= numerator[i];
+ quotient[i] = n / denominator[NumberSizes - 1];
+ currentRemainder = n % denominator[NumberSizes - 1];
+ }
+ remainder[NumberSizes - 1] = currentRemainder;
+ }
+ else
+ {
+ // from algorithm D, section 4.3.1 in Art of Computer Programming volume 2 by Knuth.
+ unsigned log2D = DigitCLZFn()(denominator[m]);
+ Digit u[NumberSizes + 1]{};
+ u[NumberSizes] = (numerator[NumberSizes - 1] << log2D) & DigitMax;
+ u[0] = ((static_cast<DoubleDigit>(numerator[0]) << log2D) >> DigitBitCount) & DigitMax;
+ for(std::size_t i = 1; i < NumberSizes; i++)
+ {
+ DoubleDigit value = numerator[i - 1];
+ value <<= DigitBitCount;
+ value |= numerator[i];
+ value <<= log2D;
+ u[i] = (value >> DigitBitCount) & DigitMax;
+ }
+ Digit v[NumberSizes + 1] = {};
+ v[n] = (denominator[NumberSizes - 1] << log2D) & DigitMax;
+ for(std::size_t i = 1; i < n; i++)
+ {
+ DoubleDigit value = denominator[m + i - 1];
+ value <<= DigitBitCount;
+ value |= denominator[m + i];
+ value <<= log2D;
+ v[i] = (value >> DigitBitCount) & DigitMax;
+ quotient[i - 1] = 0;
+ }
+ for(std::size_t j = 0; j <= m; j++)
+ {
+ DoubleDigit qHat{};
+ if(u[j] == v[1])
+ {
+ qHat = DigitMax;
+ }
+ else
+ {
+ qHat = ((static_cast<DoubleDigit>(u[j]) << DigitBitCount) | u[j + 1]) / v[1];
+ }
+ {
+ DoubleDigit lhs = v[2] * qHat;
+ DoubleDigit rhsHigh =
+ ((static_cast<DoubleDigit>(u[j]) << DigitBitCount) | u[j + 1]) - qHat * v[1];
+ Digit rhsLow = u[j + 2];
+ if(rhsHigh < static_cast<DoubleDigit>(1) << DigitBitCount
+ && lhs > ((rhsHigh << DigitBitCount) | rhsLow))
+ {
+ qHat--;
+ lhs -= v[2];
+ rhsHigh += v[1];
+ if(rhsHigh < static_cast<DoubleDigit>(1) << DigitBitCount
+ && lhs > ((rhsHigh << DigitBitCount) | rhsLow))
+ {
+ qHat--;
+ }
+ }
+ }
+ bool borrow = false;
+ {
+ Digit mulCarry = 0;
+ for(std::size_t i = n; i > 0; i--)
+ {
+ assert(i <= NumberSizes);
+ DoubleDigit product = qHat * v[i] + mulCarry;
+ mulCarry = product >> DigitBitCount;
+ product &= DigitMax;
+ bool prevBorrow = borrow;
+ DoubleDigit digit = u[j + i] - product - prevBorrow;
+ borrow = digit != (digit & DigitMax);
+ digit &= DigitMax;
+ u[j + i] = digit;
+ }
+ bool prevBorrow = borrow;
+ DoubleDigit digit = u[j] - mulCarry - prevBorrow;
+ borrow = digit != (digit & DigitMax);
+ digit &= DigitMax;
+ u[j] = digit;
+ }
+ Digit qj = qHat;
+ if(borrow)
+ {
+ qj--;
+ bool carry = false;
+ for(std::size_t i = n; i > 0; i--)
+ {
+ bool prevCarry = carry;
+ assert(i + j <= NumberSizes);
+ DoubleDigit digit = u[j + i] + v[i] + prevCarry;
+ carry = digit != (digit & DigitMax);
+ digit &= DigitMax;
+ u[j + i] = digit;
+ }
+ u[j] = (u[j] + carry) & DigitMax;
+ }
+ quotient[j + n - 1] = qj;
+ }
+ for(std::size_t i = 0; i < NumberSizes; i++)
+ {
+ DoubleDigit value = u[i];
+ value <<= DigitBitCount;
+ value |= u[i + 1];
+ remainder[i] = value >> log2D;
+ }
+ }
+ return DivModResult(
+ UInt128((static_cast<DoubleDigit>(quotient[0]) << DigitBitCount) | quotient[1],
+ (static_cast<DoubleDigit>(quotient[2]) << DigitBitCount) | quotient[3]),
+ UInt128((static_cast<DoubleDigit>(remainder[0]) << DigitBitCount) | remainder[1],
+ (static_cast<DoubleDigit>(remainder[2]) << DigitBitCount) | remainder[3]));
+}
+
+constexpr UInt128 UInt128::div(UInt128 a, UInt128 b) noexcept
+{
+ return divmod(a, b).divResult;
+}
+
+constexpr UInt128 UInt128::mod(UInt128 a, UInt128 b) noexcept
+{
+ return divmod(a, b).modResult;
+}
+
+struct ExtendedFloat final // modeled after IEEE754 standard
+{
+ std::uint64_t mantissa;
+ std::uint16_t exponent;
+ bool sign;
+ static constexpr std::uint16_t infinityNaNExponent() noexcept
+ {
+ return 0xFFFFU;
+ }
+ static constexpr std::uint16_t exponentBias() noexcept
+ {
+ return 0x7FFFU;
+ }
+ static constexpr std::uint64_t normalizedMantissaMax() noexcept
+ {
+ return 0xFFFFFFFFFFFFFFFFULL;
+ }
+ static constexpr std::uint64_t normalizedMantissaMin() noexcept
+ {
+ return 0x8000000000000000ULL;
+ }
+ struct NormalizedTag final
+ {
+ };
+ static constexpr ExtendedFloat normalizeHelper(const ExtendedFloat &v,
+ unsigned shiftAmount) noexcept
+ {
+ return shiftAmount > 0 && v.exponent >= shiftAmount ?
+ ExtendedFloat(NormalizedTag{},
+ v.mantissa << shiftAmount,
+ v.exponent - shiftAmount,
+ v.sign) :
+ v;
+ }
+ static constexpr ExtendedFloat normalizeHelper(UInt128 mantissa,
+ std::int32_t exponent,
+ bool sign,
+ int shiftAmount) noexcept
+ {
+ return shiftAmount > 0 && exponent >= shiftAmount ?
+ ExtendedFloat(NormalizedTag{},
+ (mantissa << shiftAmount).high,
+ exponent - shiftAmount,
+ sign) :
+ ExtendedFloat(NormalizedTag{}, mantissa.high, exponent, sign);
+ }
+ static constexpr ExtendedFloat normalize(const ExtendedFloat &v) noexcept
+ {
+ return v.exponent == infinityNaNExponent() ? v : v.mantissa == 0 ?
+ Zero(v.sign) :
+ normalizeHelper(v, clz64(v.mantissa));
+ }
+ static constexpr ExtendedFloat normalize(UInt128 mantissa,
+ std::uint16_t exponent,
+ bool sign) noexcept
+ {
+ return exponent == infinityNaNExponent() ?
+ ExtendedFloat(
+ NormalizedTag{}, mantissa != UInt128(0), infinityNaNExponent(), sign) :
+ mantissa == UInt128(0) ?
+ Zero(sign) :
+ normalizeHelper(mantissa, exponent, sign, clz128(mantissa));
+ }
+ constexpr ExtendedFloat() noexcept : mantissa(0), exponent(0), sign(false)
+ {
+ }
+ constexpr ExtendedFloat(NormalizedTag,
+ std::uint64_t mantissa,
+ std::uint16_t exponent,
+ bool sign = false) noexcept : mantissa(mantissa),
+ exponent(exponent),
+ sign(sign)
+ {
+ }
+ explicit constexpr ExtendedFloat(std::uint64_t mantissa,
+ std::uint16_t exponent = exponentBias() + 63,
+ bool sign = false) noexcept
+ : ExtendedFloat(normalize(ExtendedFloat(NormalizedTag{}, mantissa, exponent, sign)))
+ {
+ }
+ explicit constexpr ExtendedFloat(UInt128 mantissa,
+ std::uint16_t exponent = exponentBias() + 127,
+ bool sign = false) noexcept
+ : ExtendedFloat(normalize(mantissa, exponent, sign))
+ {
+ }
+ explicit constexpr ExtendedFloat(std::int64_t mantissa) noexcept
+ : ExtendedFloat(mantissa < 0 ? -static_cast<std::uint64_t>(mantissa) :
+ static_cast<std::uint64_t>(mantissa),
+ exponentBias() + 63,
+ mantissa < 0)
+ {
+ }
+ explicit ExtendedFloat(double value) noexcept : mantissa(0),
+ exponent(0),
+ sign(std::signbit(value))
+ {
+ value = std::fabs(value);
+ if(std::isnan(value))
+ {
+ mantissa = 1;
+ exponent = infinityNaNExponent();
+ return;
+ }
+ if(std::isinf(value))
+ {
+ exponent = infinityNaNExponent();
+ mantissa = 0;
+ return;
+ }
+ if(value == 0)
+ {
+ exponent = 0;
+ mantissa = 0;
+ return;
+ }
+ int log2Value = std::ilogb(value);
+ if(log2Value <= -static_cast<int>(exponentBias()))
+ exponent = 0;
+ else
+ exponent = log2Value + exponentBias();
+ value = std::scalbn(value, 63 - static_cast<long>(exponent) + exponentBias());
+ mantissa = value;
+ }
+ explicit ExtendedFloat(long double value) noexcept : mantissa(0),
+ exponent(0),
+ sign(std::signbit(value))
+ {
+ value = std::fabs(value);
+ if(std::isnan(value))
+ {
+ mantissa = 1;
+ exponent = infinityNaNExponent();
+ return;
+ }
+ if(std::isinf(value))
+ {
+ exponent = infinityNaNExponent();
+ mantissa = 0;
+ return;
+ }
+ if(value == 0)
+ {
+ exponent = 0;
+ mantissa = 0;
+ return;
+ }
+ int log2Value = std::ilogb(value);
+ if(log2Value <= -static_cast<int>(exponentBias()))
+ exponent = 0;
+ else
+ exponent = log2Value + exponentBias();
+ value = std::scalbn(value, 63 - static_cast<long>(exponent) + exponentBias());
+ mantissa = value;
+ }
+ explicit operator long double() const noexcept
+ {
+ if(exponent == infinityNaNExponent())
+ {
+ double retval = std::numeric_limits<double>::infinity();
+ if(mantissa)
+ retval = std::numeric_limits<double>::quiet_NaN();
+ if(sign)
+ return -retval;
+ return retval;
+ }
+ if(isZero())
+ {
+ if(sign)
+ return -0.0;
+ return 0;
+ }
+ long double value = std::scalbln(static_cast<long double>(mantissa),
+ static_cast<long>(exponent) - exponentBias() - 63);
+ if(sign)
+ return -value;
+ return value;
+ }
+ explicit operator double() const noexcept
+ {
+ if(exponent == infinityNaNExponent())
+ {
+ double retval = std::numeric_limits<double>::infinity();
+ if(mantissa)
+ retval = std::numeric_limits<double>::quiet_NaN();
+ if(sign)
+ return -retval;
+ return retval;
+ }
+ if(isZero())
+ {
+ if(sign)
+ return -0.0;
+ return 0;
+ }
+ double value = std::scalbln(static_cast<double>(mantissa),
+ static_cast<long>(exponent) - exponentBias() - 63);
+ if(sign)
+ return -value;
+ return value;
+ }
+ constexpr bool isNaN() const noexcept
+ {
+ return exponent == infinityNaNExponent() && mantissa != 0;
+ }
+ constexpr bool isInfinite() const noexcept
+ {
+ return exponent == infinityNaNExponent() && mantissa == 0;
+ }
+ constexpr bool isFinite() const noexcept
+ {
+ return exponent != infinityNaNExponent();
+ }
+ constexpr bool isNormal() const noexcept
+ {
+ return exponent != infinityNaNExponent() && exponent != 0;
+ }
+ constexpr bool isDenormal() const noexcept
+ {
+ return exponent == 0 && mantissa != 0;
+ }
+ constexpr bool isZero() const noexcept
+ {
+ return exponent == 0 && mantissa == 0;
+ }
+ constexpr bool signBit() const noexcept
+ {
+ return sign;
+ }
+ static constexpr ExtendedFloat NaN() noexcept
+ {
+ return ExtendedFloat(NormalizedTag{}, 1, infinityNaNExponent());
+ }
+ static constexpr ExtendedFloat One() noexcept
+ {
+ return ExtendedFloat(NormalizedTag{}, 0x8000000000000000ULL, exponentBias());
+ }
+ static constexpr ExtendedFloat TwoToThe64() noexcept
+ {
+ return ExtendedFloat(NormalizedTag{}, 0x8000000000000000ULL, exponentBias() + 64);
+ }
+ static constexpr ExtendedFloat Infinity(bool sign = false) noexcept
+ {
+ return ExtendedFloat(NormalizedTag{}, 0, infinityNaNExponent(), sign);
+ }
+ static constexpr ExtendedFloat Zero(bool sign = false) noexcept
+ {
+ return ExtendedFloat(NormalizedTag{}, 0, 0, sign);
+ }
+ constexpr ExtendedFloat operator+() const noexcept
+ {
+ return *this;
+ }
+ constexpr ExtendedFloat operator-() const noexcept
+ {
+ return ExtendedFloat(NormalizedTag{}, mantissa, exponent, !sign);
+ }
+ static constexpr UInt128 shiftHelper(std::uint64_t a, unsigned shift) noexcept
+ {
+ return shift >= 128 ? UInt128(0) : UInt128(a, 0) >> shift;
+ }
+ static constexpr UInt128 finalRoundHelper(UInt128 v) noexcept
+ {
+ return v.low == 0x8000000000000000ULL && (v.high & 1) == 0 ?
+ UInt128(v.high) :
+ ((v >> 1) + UInt128(0x4000000000000000ULL)) >> 63;
+ }
+ static constexpr ExtendedFloat subtractHelper6(UInt128 mantissa,
+ std::uint16_t exponent,
+ bool sign,
+ unsigned shift)
+ {
+ return ExtendedFloat(finalRoundHelper(mantissa << shift), exponent - shift + 64, sign);
+ }
+ static constexpr ExtendedFloat subtractHelper5(UInt128 mantissa,
+ std::uint16_t exponent,
+ bool sign,
+ unsigned shift)
+ {
+ return subtractHelper6(mantissa, exponent, sign, shift > exponent ? exponent : shift);
+ }
+ static constexpr ExtendedFloat subtractHelper4(UInt128 mantissa,
+ std::uint16_t exponent,
+ bool sign)
+ {
+ return subtractHelper5(mantissa, exponent, sign, clz128(mantissa));
+ }
+ static constexpr ExtendedFloat subtractHelper3(UInt128 aMantissa,
+ UInt128 bMantissa,
+ std::uint16_t exponent) noexcept
+ {
+ return aMantissa == bMantissa ? Zero() : aMantissa < bMantissa ?
+ subtractHelper4(bMantissa - aMantissa, exponent, true) :
+ subtractHelper4(aMantissa - bMantissa, exponent, false);
+ }
+ static constexpr ExtendedFloat subtractHelper2(std::uint64_t aMantissa,
+ std::uint16_t aExponent,
+ std::uint64_t bMantissa,
+ std::uint16_t bExponent,
+ std::uint16_t maxExponent) noexcept
+ {
+ return subtractHelper3(shiftHelper(aMantissa, maxExponent - aExponent),
+ shiftHelper(bMantissa, maxExponent - bExponent),
+ maxExponent);
+ }
+ static constexpr ExtendedFloat subtractHelper(std::uint64_t aMantissa,
+ std::uint16_t aExponent,
+ std::uint64_t bMantissa,
+ std::uint16_t bExponent) noexcept
+ {
+ return subtractHelper2(aMantissa,
+ aExponent,
+ bMantissa,
+ bExponent,
+ aExponent < bExponent ? bExponent : aExponent);
+ }
+ static constexpr ExtendedFloat addHelper3(UInt128 mantissa,
+ std::uint16_t exponent,
+ bool sign) noexcept
+ {
+ return mantissa >= UInt128(0x8000000000000000ULL, 0) ?
+ (exponent + 1 == infinityNaNExponent() ?
+ Infinity(sign) :
+ ExtendedFloat(finalRoundHelper(mantissa), exponent + 65, sign)) :
+ ExtendedFloat(finalRoundHelper(mantissa << 1), exponent + 64, sign);
+ }
+ static constexpr ExtendedFloat addHelper2(std::uint64_t aMantissa,
+ std::uint16_t aExponent,
+ std::uint64_t bMantissa,
+ std::uint16_t bExponent,
+ std::uint16_t maxExponent,
+ bool sign) noexcept
+ {
+ return addHelper3(shiftHelper(aMantissa, maxExponent - aExponent + 1)
+ + shiftHelper(bMantissa, maxExponent - bExponent + 1),
+ maxExponent,
+ sign);
+ }
+ static constexpr ExtendedFloat addHelper(std::uint64_t aMantissa,
+ std::uint16_t aExponent,
+ std::uint64_t bMantissa,
+ std::uint16_t bExponent,
+ bool sign) noexcept
+ {
+ return addHelper2(aMantissa,
+ aExponent,
+ bMantissa,
+ bExponent,
+ aExponent < bExponent ? bExponent : aExponent,
+ sign);
+ }
+ constexpr friend ExtendedFloat operator+(const ExtendedFloat &a,
+ const ExtendedFloat &b) noexcept
+ {
+ return a.isNaN() ? a : b.isNaN() ?
+ b :
+ a.isInfinite() ?
+ (b.isInfinite() ? (a.sign == b.sign ? a : NaN()) : a) :
+ b.isInfinite() ?
+ b :
+ a.isZero() ?
+ (b.isZero() ? Zero(a.sign && b.sign) : b) :
+ b.isZero() ?
+ a :
+ a.sign == b.sign ?
+ addHelper(a.mantissa, a.exponent, b.mantissa, b.exponent, a.sign) :
+ a.sign ? subtractHelper(b.mantissa, b.exponent, a.mantissa, a.exponent) :
+ subtractHelper(a.mantissa, a.exponent, b.mantissa, b.exponent);
+ }
+ constexpr friend ExtendedFloat operator-(const ExtendedFloat &a,
+ const ExtendedFloat &b) noexcept
+ {
+ return a + b.operator-();
+ }
+ constexpr ExtendedFloat &operator+=(const ExtendedFloat &v) noexcept
+ {
+ return *this = *this + v;
+ }
+ constexpr ExtendedFloat &operator-=(const ExtendedFloat &v) noexcept
+ {
+ return *this = *this - v;
+ }
+ friend constexpr bool operator==(const ExtendedFloat &a, const ExtendedFloat &b) noexcept
+ {
+ return a.isNaN() ? false : b.isNaN() ? false : a.isZero() ?
+ b.isZero() :
+ a.exponent == b.exponent && a.mantissa == b.mantissa;
+ }
+ friend constexpr bool operator!=(const ExtendedFloat &a, const ExtendedFloat &b) noexcept
+ {
+ return !(a == b);
+ }
+ static constexpr int compareHelper(const ExtendedFloat &a, const ExtendedFloat &b) noexcept
+ {
+ return a.isZero() ? (b.isZero() ? 0 : (b.sign ? 1 : -1)) : a.sign != b.sign ?
+ (a.sign ? -1 : 1) :
+ a.exponent != b.exponent ?
+ ((a.exponent < b.exponent) != a.sign ? -1 : 1) :
+ a.mantissa == b.mantissa ? 0 :
+ (a.mantissa < b.mantissa) != a.sign ? -1 : 1;
+ }
+ friend constexpr bool operator<(const ExtendedFloat &a, const ExtendedFloat &b) noexcept
+ {
+ return a.isNaN() ? false : b.isNaN() ? false : compareHelper(a, b) < 0;
+ }
+ friend constexpr bool operator<=(const ExtendedFloat &a, const ExtendedFloat &b) noexcept
+ {
+ return a.isNaN() ? false : b.isNaN() ? false : compareHelper(a, b) <= 0;
+ }
+ friend constexpr bool operator>(const ExtendedFloat &a, const ExtendedFloat &b) noexcept
+ {
+ return a.isNaN() ? false : b.isNaN() ? false : compareHelper(a, b) > 0;
+ }
+ friend constexpr bool operator>=(const ExtendedFloat &a, const ExtendedFloat &b) noexcept
+ {
+ return a.isNaN() ? false : b.isNaN() ? false : compareHelper(a, b) >= 0;
+ }
+ static constexpr ExtendedFloat mulHelper4(UInt128 mantissa,
+ std::int32_t exponent,
+ bool sign) noexcept
+ {
+ return exponent >= infinityNaNExponent() ?
+ Infinity(sign) :
+ exponent <= -128 ?
+ Zero(sign) :
+ exponent < 0 ? ExtendedFloat(finalRoundHelper(mantissa >> -exponent), 64, sign) :
+ ExtendedFloat(finalRoundHelper(mantissa), exponent + 64, sign);
+ }
+ static constexpr ExtendedFloat mulHelper3(UInt128 mantissa,
+ std::int32_t exponent,
+ bool sign,
+ unsigned shift) noexcept
+ {
+ return mulHelper4(mantissa << shift, exponent - shift, sign);
+ }
+ static constexpr ExtendedFloat mulHelper2(UInt128 mantissa,
+ std::int32_t exponent,
+ bool sign) noexcept
+ {
+ return mantissa == UInt128(0) ? Zero(sign) :
+ mulHelper3(mantissa, exponent, sign, clz128(mantissa));
+ }
+ static constexpr ExtendedFloat mulHelper(std::uint64_t aMantissa,
+ std::int32_t aExponent,
+ std::uint64_t bMantissa,
+ std::int32_t bExponent,
+ bool sign) noexcept
+ {
+ return mulHelper2(UInt128(aMantissa) * UInt128(bMantissa),
+ aExponent + bExponent - exponentBias() + 1,
+ sign);
+ }
+ constexpr friend ExtendedFloat operator*(const ExtendedFloat &a,
+ const ExtendedFloat &b) noexcept
+ {
+ return a.isNaN() ? a : b.isNaN() ?
+ b :
+ a.isInfinite() ?
+ (b.isZero() ? NaN() : Infinity(a.sign != b.sign)) :
+ b.isInfinite() ?
+ (a.isZero() ? NaN() : Infinity(a.sign != b.sign)) :
+ mulHelper(
+ a.mantissa, a.exponent, b.mantissa, b.exponent, a.sign != b.sign);
+ }
+ constexpr ExtendedFloat &operator*=(const ExtendedFloat &v) noexcept
+ {
+ return *this = *this * v;
+ }
+ static constexpr int compareU128(UInt128 a, UInt128 b) noexcept
+ {
+ return a == b ? 0 : a < b ? -1 : 1;
+ }
+ static constexpr ExtendedFloat divHelper6(UInt128 mantissa,
+ std::int32_t exponent,
+ bool sign) noexcept
+ {
+ return exponent >= infinityNaNExponent() ?
+ Infinity(sign) :
+ exponent <= -128 ?
+ Zero(sign) :
+ exponent < 0 ? ExtendedFloat(finalRoundHelper(mantissa >> -exponent), 64, sign) :
+ ExtendedFloat(finalRoundHelper(mantissa), exponent + 64, sign);
+ }
+ static constexpr ExtendedFloat divHelper5(UInt128 quotient,
+ unsigned shift,
+ int roundExtraBitsCompareValue,
+ std::int32_t exponent,
+ bool sign) noexcept
+ {
+ return divHelper6(
+ ((quotient << 2) | UInt128(static_cast<std::uint64_t>(2 - roundExtraBitsCompareValue)))
+ << (shift - 2),
+ exponent - shift + 64,
+ sign);
+ }
+ static constexpr ExtendedFloat divHelper4(UInt128::DivModResult mantissa,
+ std::uint64_t bMantissa,
+ std::int32_t exponent,
+ bool sign) noexcept
+ {
+ return divHelper5(mantissa.divResult,
+ clz128(mantissa.divResult),
+ compareU128(UInt128(bMantissa), mantissa.modResult << 1),
+ exponent,
+ sign);
+ }
+ static constexpr ExtendedFloat divHelper3(std::uint64_t aMantissa,
+ std::uint64_t bMantissa,
+ std::int32_t exponent,
+ bool sign) noexcept
+ {
+ return divHelper4(
+ UInt128::divmod(UInt128(aMantissa, 0), UInt128(bMantissa)), bMantissa, exponent, sign);
+ }
+ static constexpr ExtendedFloat divHelper2(std::uint64_t aMantissa,
+ std::int32_t aExponent,
+ unsigned aShift,
+ std::uint64_t bMantissa,
+ std::int32_t bExponent,
+ unsigned bShift,
+ bool sign) noexcept
+ {
+ return divHelper3(aMantissa << aShift,
+ bMantissa << bShift,
+ aExponent - aShift - (bExponent - bShift) + exponentBias() - 1,
+ sign);
+ }
+ static constexpr ExtendedFloat divHelper(std::uint64_t aMantissa,
+ std::int32_t aExponent,
+ std::uint64_t bMantissa,
+ std::int32_t bExponent,
+ bool sign) noexcept
+ {
+ return divHelper2(
+ aMantissa, aExponent, clz64(aMantissa), bMantissa, bExponent, clz64(bMantissa), sign);
+ }
+ friend constexpr ExtendedFloat operator/(const ExtendedFloat &a,
+ const ExtendedFloat &b) noexcept
+ {
+ return a.isNaN() ? a : b.isNaN() ?
+ b :
+ a.isInfinite() ?
+ (b.isInfinite() ? NaN() : Infinity(a.sign != b.sign)) :
+ b.isZero() ?
+ (a.isZero() ? NaN() : Infinity(a.sign != b.sign)) :
+ b.isInfinite() || a.isZero() ?
+ Zero(a.sign != b.sign) :
+ divHelper(
+ a.mantissa, a.exponent, b.mantissa, b.exponent, a.sign != b.sign);
+ }
+ constexpr ExtendedFloat &operator/=(const ExtendedFloat &v) noexcept
+ {
+ return *this = *this / v;
+ }
+ static constexpr ExtendedFloat floorCeilHelper2(std::uint64_t mantissa,
+ std::int32_t exponent) noexcept
+ {
+ return exponent >= infinityNaNExponent() ?
+ Infinity() :
+ exponent <= -128 ?
+ Zero() :
+ exponent < 0 ?
+ ExtendedFloat(finalRoundHelper(UInt128(mantissa, 0) >> -exponent), 64) :
+ ExtendedFloat(finalRoundHelper(UInt128(mantissa, 0)), exponent + 64);
+ }
+ static constexpr ExtendedFloat floorCeilHelper(UInt128 mantissa, std::int32_t exponent) noexcept
+ {
+ return mantissa.high != 0 ? floorCeilHelper2((mantissa >> 1).low, exponent + 1) :
+ floorCeilHelper2(mantissa.low, exponent);
+ }
+ static constexpr ExtendedFloat ceilHelper2(UInt128 mantissa) noexcept
+ {
+ return mantissa.low != 0 ? (mantissa.high == ~static_cast<std::uint64_t>(0) ?
+ TwoToThe64() :
+ ExtendedFloat(mantissa.high + 1)) :
+ ExtendedFloat(mantissa.high);
+ }
+ static constexpr ExtendedFloat ceilHelper(std::uint64_t mantissa,
+ std::int32_t exponent) noexcept
+ {
+ return exponent < exponentBias() ?
+ One() :
+ exponent >= exponentBias() + 63 ?
+ ExtendedFloat(NormalizedTag{}, mantissa, exponent) :
+ ceilHelper2(UInt128(mantissa, 0) >> (exponentBias() - exponent + 63));
+ }
+ static constexpr ExtendedFloat floorHelper2(UInt128 mantissa) noexcept
+ {
+ return ExtendedFloat(mantissa.high);
+ }
+ static constexpr ExtendedFloat floorHelper(std::uint64_t mantissa,
+ std::int32_t exponent) noexcept
+ {
+ return exponent < exponentBias() ?
+ Zero() :
+ exponent >= exponentBias() + 63 ?
+ ExtendedFloat(NormalizedTag{}, mantissa, exponent) :
+ floorHelper2(UInt128(mantissa, 0) >> (exponentBias() - exponent + 63));
+ }
+ constexpr friend ExtendedFloat floor(const ExtendedFloat &v) noexcept
+ {
+ return !v.isFinite() || v.isZero() ? v : v.sign ? -ceilHelper(v.mantissa, v.exponent) :
+ floorHelper(v.mantissa, v.exponent);
+ }
+ constexpr friend ExtendedFloat trunc(const ExtendedFloat &v) noexcept
+ {
+ return !v.isFinite() || v.isZero() ? v : v.sign ? -floorHelper(v.mantissa, v.exponent) :
+ floorHelper(v.mantissa, v.exponent);
+ }
+ constexpr friend ExtendedFloat ceil(const ExtendedFloat &v) noexcept
+ {
+ return !v.isFinite() || v.isZero() ? v : v.sign ? -floorHelper(v.mantissa, v.exponent) :
+ ceilHelper(v.mantissa, v.exponent);
+ }
+ static constexpr ExtendedFloat roundHelper(std::uint64_t mantissa,
+ std::int32_t exponent) noexcept
+ {
+ return exponent < exponentBias() - 2 ?
+ Zero() :
+ exponent >= exponentBias() + 63 ?
+ ExtendedFloat(NormalizedTag{}, mantissa, exponent) :
+ ExtendedFloat(((UInt128(mantissa, 0) >> (exponentBias() - exponent + 64))
+ + UInt128(0x4000000000000000ULL))
+ >> 63);
+ }
+ constexpr friend ExtendedFloat round(const ExtendedFloat &v) noexcept
+ {
+ return !v.isFinite() || v.isZero() ? v : v.sign ? -roundHelper(v.mantissa, v.exponent) :
+ roundHelper(v.mantissa, v.exponent);
+ }
+ explicit constexpr operator std::uint64_t() const noexcept
+ {
+ return isNaN() ? 0 : isInfinite() ?
+ (sign ? 0 : ~static_cast<std::uint64_t>(0)) :
+ exponent < exponentBias() || sign ?
+ 0 :
+ *this >= TwoToThe64() ?
+ ~static_cast<std::uint64_t>(0) :
+ (UInt128(mantissa, 0) >> (exponentBias() - exponent + 63)).high;
+ }
+ static constexpr std::int64_t toInt64Helper(bool sign, std::uint64_t uint64Value) noexcept
+ {
+ return sign ? (uint64Value > 0x8000000000000000ULL ?
+ -static_cast<std::int64_t>(0x7FFFFFFFFFFFFFFFULL) - 1 :
+ -static_cast<std::int64_t>(uint64Value)) :
+ uint64Value >= 0x8000000000000000ULL ?
+ static_cast<std::int64_t>(0x7FFFFFFFFFFFFFFFULL) :
+ static_cast<std::int64_t>(uint64Value);
+ }
+ explicit constexpr operator std::int64_t() const noexcept
+ {
+ return isNaN() ? 0 : sign ? toInt64Helper(true, static_cast<std::uint64_t>(operator-())) :
+ toInt64Helper(false, static_cast<std::uint64_t>(*this));
+ }
+ static constexpr ExtendedFloat powHelper(const ExtendedFloat &base,
+ const ExtendedFloat ¤tValue,
+ std::uint64_t exponent) noexcept
+ {
+ return exponent == 0 ? currentValue : exponent == 1 ?
+ currentValue * base :
+ exponent == 2 ?
+ currentValue * (base * base) :
+ exponent & 1 ?
+ powHelper(base * base, currentValue * base, exponent >> 1) :
+ powHelper(base * base, currentValue, exponent >> 1);
+ }
+ constexpr friend ExtendedFloat pow(const ExtendedFloat &base, std::uint64_t exponent) noexcept
+ {
+ return powHelper(base, One(), exponent);
+ }
+ friend ExtendedFloat pow(const ExtendedFloat &base, std::int64_t exponent) noexcept
+ {
+ return exponent < 0 ? powHelper(One() / base, One(), -exponent) :
+ powHelper(base, One(), exponent);
+ }
+ constexpr friend int ilogb(const ExtendedFloat &v) noexcept
+ {
+ return v.isNaN() ? FP_ILOGBNAN : v.isZero() ? FP_ILOGB0 : v.isInfinite() ?
+ std::numeric_limits<int>::max() :
+ static_cast<std::int32_t>(v.exponent)
+ - exponentBias()
+ - clz64(v.mantissa);
+ }
+ static constexpr ExtendedFloat scalbnHelper(std::uint64_t mantissa,
+ std::int64_t exponent,
+ bool sign) noexcept
+ {
+ return exponent >= infinityNaNExponent() ?
+ Infinity(sign) :
+ exponent <= -128 ?
+ Zero(sign) :
+ exponent < 0 ?
+ ExtendedFloat(finalRoundHelper(UInt128(mantissa, 0) >> -exponent), 64, sign) :
+ ExtendedFloat(finalRoundHelper(UInt128(mantissa, 0)), exponent + 64, sign);
+ }
+ constexpr friend ExtendedFloat scalbn(const ExtendedFloat &v, std::int64_t exponent) noexcept
+ {
+ return !v.isFinite() || v.isZero() ? v : scalbnHelper(
+ v.mantissa, v.exponent + exponent, v.sign);
+ }
+ static constexpr std::uint64_t log2Helper4(UInt128 mantissa) noexcept
+ {
+ return ~mantissa.high == 0
+ || ((mantissa.high & 1) == 0 && mantissa.low == 0x8000000000000000ULL) ?
+ mantissa.high :
+ (mantissa + UInt128(0x8000000000000000ULL)).high;
+ }
+ static constexpr UInt128 log2Helper3(UInt128 mantissa, unsigned bitsLeft) noexcept
+ {
+ return (bitsLeft > 0 ?
+ log2Helper2(
+ log2Helper4(mantissa << (mantissa.high & 0x8000000000000000ULL ? 0 : 1)),
+ bitsLeft - 1)
+ >> 1 :
+ UInt128(0))
+ | UInt128(mantissa.high & 0x8000000000000000ULL, 0);
+ }
+ static constexpr UInt128 log2Helper2(std::uint64_t mantissa, unsigned bitsLeft) noexcept
+ {
+ return log2Helper3(UInt128(mantissa) * UInt128(mantissa), bitsLeft);
+ }
+ static constexpr ExtendedFloat log2Helper(const ExtendedFloat &v, unsigned shift) noexcept
+ {
+ return ExtendedFloat(finalRoundHelper(log2Helper2(v.mantissa << shift, 67)),
+ exponentBias() - 1 + 64,
+ 0)
+ + ExtendedFloat(static_cast<std::int64_t>(v.exponent) - exponentBias() - shift);
+ }
+ constexpr friend ExtendedFloat log2(const ExtendedFloat &v) noexcept
+ {
+ return v.isNaN() ? v : v.isZero() ? Infinity(true) : v.sign ?
+ NaN() :
+ v.isInfinite() ? v : log2Helper(v, clz64(v.mantissa));
+ }
+ static constexpr ExtendedFloat Log10Of2() noexcept
+ {
+ return ExtendedFloat(NormalizedTag{}, 0x9A209A84FBCFF799ULL, exponentBias() - 2);
+ }
+ static constexpr ExtendedFloat LogOf2() noexcept
+ {
+ return ExtendedFloat(NormalizedTag{}, 0xB17217F7D1CF79ACULL, exponentBias() - 1);
+ }
+ constexpr friend ExtendedFloat log10(const ExtendedFloat &v) noexcept
+ {
+ return log2(v) * Log10Of2();
+ }
+ constexpr friend ExtendedFloat log(const ExtendedFloat &v) noexcept
+ {
+ return log2(v) * LogOf2();
+ }
+};
+}
+}
+}
+
+#endif /* UTIL_SOFT_FLOAT_H_ */
*
*/
-#ifndef SOURCE_UTIL_VARIANT_H_
-#define SOURCE_UTIL_VARIANT_H_
+#ifndef UTIL_VARIANT_H_
+#define UTIL_VARIANT_H_
#include <utility>
#include <type_traits>
namespace detail
{
+struct variant_base_construct_tag
+{
+ explicit variant_base_construct_tag() = default;
+};
+
template <typename T>
struct variant_identity_type
{
};
template <typename... Types>
-union variant_values
+constexpr bool variant_is_trivially_destructible() noexcept
+{
+ bool values[] = {
+ std::is_trivially_destructible<Types>::value...,
+ };
+ for(bool v : values)
+ if(!v)
+ return false;
+ return true;
+}
+
+template <bool Is_Trivially_Destructible, typename... Types>
+union variant_values_implementation
{
char value;
static constexpr bool is_copy_constructible = true;
static constexpr bool is_move_assignable = true;
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;
static constexpr bool is_equals_comparable = true;
static constexpr bool is_less_comparable = true;
static constexpr bool is_nothrow_equals_comparable = true;
static constexpr bool is_nothrow_less_comparable = true;
- variant_values() = delete;
+ variant_values_implementation() = delete;
template <std::size_t index>
- constexpr variant_values(in_place_index_t<index>) noexcept : value()
+ constexpr variant_values_implementation(in_place_index_t<index>) noexcept : value()
{
}
template <typename U>
{
return variant_npos;
}
- void copy_construct(const variant_values &rt, std::size_t index) noexcept
+ void copy_construct(const variant_values_implementation &rt, std::size_t index) noexcept
{
}
- void move_construct(variant_values &&rt, std::size_t index) noexcept
+ void move_construct(variant_values_implementation &&rt, std::size_t index) noexcept
{
}
- void copy_assign(const variant_values &rt, std::size_t index) noexcept
+ void copy_assign(const variant_values_implementation &rt, std::size_t index) noexcept
{
}
- void move_assign(variant_values &&rt, std::size_t index) noexcept
+ void move_assign(variant_values_implementation &&rt, std::size_t index) noexcept
{
}
- void destroy(std::size_t index) noexcept
+ void destruct(std::size_t index) noexcept
{
}
- void swap(variant_values &rt, std::size_t index) noexcept
+ void swap(variant_values_implementation &rt, std::size_t index) noexcept
{
}
- bool is_equal(const variant_values &rt, std::size_t index) const noexcept
+ bool is_equal(const variant_values_implementation &rt, std::size_t index) const noexcept
{
return true;
}
- bool is_less(const variant_values &rt, std::size_t index) const noexcept
+ bool is_less(const variant_values_implementation &rt, std::size_t index) const noexcept
{
return false;
}
};
-template <typename T, typename... Types>
-union variant_values<T, Types...>
-{
- typedef T type_0;
- static_assert(!std::is_void<T>::value, "invalid variant member type");
- static_assert(!std::is_reference<T>::value, "invalid variant member type");
- static_assert(!std::is_array<T>::value, "invalid variant member type");
- static_assert(!std::is_const<T>::value, "invalid variant member type");
- static_assert(!std::is_volatile<T>::value, "invalid variant member type");
- static_assert(std::is_object<T>::value, "invalid variant member type");
- T current_value;
- variant_values<Types...> other_values;
- static constexpr bool is_copy_constructible =
- std::is_copy_constructible<T>::value && variant_values<Types...>::is_copy_constructible;
- static constexpr bool is_move_constructible =
- std::is_move_constructible<T>::value && variant_values<Types...>::is_move_constructible;
- static constexpr bool is_nothrow_copy_constructible =
- std::is_nothrow_copy_constructible<T>::value
- && variant_values<Types...>::is_nothrow_copy_constructible;
- static constexpr bool is_nothrow_move_constructible =
- std::is_nothrow_move_constructible<T>::value
- && variant_values<Types...>::is_nothrow_move_constructible;
- static constexpr bool is_copy_assignable = std::is_copy_assignable<T>::value
- && std::is_copy_constructible<T>::value
- && variant_values<Types...>::is_copy_assignable;
- static constexpr bool is_move_assignable = std::is_move_assignable<T>::value
- && std::is_move_constructible<T>::value
- && variant_values<Types...>::is_move_assignable;
- static constexpr bool is_nothrow_copy_assignable =
- std::is_nothrow_copy_assignable<T>::value && std::is_nothrow_copy_constructible<T>::value
- && variant_values<Types...>::is_nothrow_copy_assignable;
- static constexpr bool is_nothrow_move_assignable =
- std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value
- && variant_values<Types...>::is_nothrow_move_assignable;
- static constexpr bool is_trivially_destructible =
- std::is_trivially_destructible<T>::value
- && variant_values<Types...>::is_trivially_destructible;
- static constexpr bool is_swappable = is_swappable_v<T> && std::is_move_constructible<T>::value
- && variant_values<Types...>::is_swappable;
- static constexpr bool is_nothrow_swappable =
- is_nothrow_swappable_v<T> && std::is_nothrow_move_constructible<T>::value
- && variant_values<Types...>::is_nothrow_swappable;
- static constexpr bool is_equals_comparable =
- variant_is_equals_comparable<T>::value && variant_values<Types...>::is_equals_comparable;
- static constexpr bool is_less_comparable =
- variant_is_less_comparable<T>::value && variant_values<Types...>::is_less_comparable;
- static constexpr bool is_nothrow_equals_comparable =
- variant_is_nothrow_equals_comparable<T>::value
- && variant_values<Types...>::is_nothrow_equals_comparable;
- static constexpr bool is_nothrow_less_comparable =
- variant_is_nothrow_less_comparable<T>::value
- && variant_values<Types...>::is_nothrow_less_comparable;
- template <typename T2 = T,
- typename = typename std::enable_if<std::is_default_constructible<T2>::value>::type>
- constexpr variant_values() noexcept(std::is_nothrow_default_constructible<T2>::value)
- : current_value()
- {
- }
- template <typename... Args,
- typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>
- constexpr variant_values(in_place_index_t<0>, Args &&... args) noexcept(
- std::is_nothrow_constructible<T, Args...>::value)
- : current_value(std::forward<Args>(args)...)
- {
- }
- template <std::size_t index,
- typename... Args,
- typename = typename std::
- enable_if<index != 0 && std::is_constructible<variant_values<Types...>,
- in_place_index_t<index - 1>,
- Args...>::value>::type>
- constexpr variant_values(in_place_index_t<index>, Args &&... args) noexcept(
- std::is_nothrow_constructible<variant_values<Types...>,
- in_place_index_t<index - 1>,
- Args...>::value)
- : other_values(in_place_index<index - 1>, std::forward<Args>(args)...)
- {
- }
- template <
- typename U,
- typename... Args,
- typename = typename std::
- enable_if<std::is_constructible<T, std::initializer_list<U>, Args...>::value>::type>
- constexpr variant_values(
- in_place_index_t<0>,
- std::initializer_list<U> il,
- Args &&... args) noexcept(std::is_nothrow_constructible<T,
- std::initializer_list<U>,
- Args...>::value)
- : current_value(il, std::forward<Args>(args)...)
- {
- }
- template <typename U>
- static constexpr std::size_t index_from_type() noexcept
- {
- std::size_t next = variant_values<Types...>::template index_from_type<U>();
- if(std::is_same<U, T>::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(is_nothrow_copy_constructible)
- {
- if(index == 0)
- new(const_cast<void *>(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(is_nothrow_move_constructible)
- {
- if(index == 0)
- new(const_cast<void *>(std::addressof(current_value))) T(std::move(rt.current_value));
- else
- other_values.move_construct(std::move(rt.other_values), index - 1);
- }
- void copy_assign(const variant_values &rt,
- std::size_t index) noexcept(is_nothrow_copy_assignable)
- {
- if(index == 0)
- current_value = rt.current_value;
- else
- other_values.copy_assign(rt.other_values, index - 1);
- }
- void move_assign(variant_values &&rt, std::size_t index) noexcept(is_nothrow_move_assignable)
- {
- if(index == 0)
- current_value = std::move(rt.current_value);
- else
- other_values.move_assign(std::move(rt.other_values), index - 1);
- }
- void destruct(std::size_t index) noexcept
- {
- if(index == 0)
- current_value.~T();
- 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);
- }
- bool is_equal(const variant_values &rt, std::size_t index) const
- noexcept(is_nothrow_equals_comparable)
- {
- if(index == 0)
- return static_cast<bool>(current_value == rt.current_value);
- return other_values.is_equal(rt.other_values, index - 1);
- }
- bool is_less(const variant_values &rt, std::size_t index) const
- noexcept(is_nothrow_less_comparable)
- {
- if(index == 0)
- return static_cast<bool>(current_value < rt.current_value);
- return other_values.is_equal(rt.other_values, index - 1);
- }
-};
+template <typename... Types>
+using variant_values =
+ variant_values_implementation<variant_is_trivially_destructible<Types...>(), Types...>;
+
+#define VULKAN_CPU_UTIL_VARIANT_VALUES(Is_Trivially_Destructible, Destructor) \
+ template <typename T, typename... Types> \
+ union variant_values_implementation<Is_Trivially_Destructible, T, Types...> \
+ { \
+ typedef T type_0; \
+ static_assert(!std::is_void<T>::value, "invalid variant member type"); \
+ static_assert(!std::is_reference<T>::value, "invalid variant member type"); \
+ static_assert(!std::is_array<T>::value, "invalid variant member type"); \
+ static_assert(!std::is_const<T>::value, "invalid variant member type"); \
+ static_assert(!std::is_volatile<T>::value, "invalid variant member type"); \
+ static_assert(std::is_object<T>::value, "invalid variant member type"); \
+ T current_value; \
+ variant_values_implementation<Is_Trivially_Destructible, Types...> other_values; \
+ static constexpr bool is_copy_constructible = \
+ std::is_copy_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_copy_constructible; \
+ static constexpr bool is_move_constructible = \
+ std::is_move_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_move_constructible; \
+ static constexpr bool is_nothrow_copy_constructible = \
+ std::is_nothrow_copy_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_nothrow_copy_constructible; \
+ static constexpr bool is_nothrow_move_constructible = \
+ std::is_nothrow_move_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_nothrow_move_constructible; \
+ static constexpr bool is_copy_assignable = \
+ std::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_copy_assignable; \
+ static constexpr bool is_move_assignable = \
+ std::is_move_assignable<T>::value && std::is_move_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_move_assignable; \
+ static constexpr bool is_nothrow_copy_assignable = \
+ std::is_nothrow_copy_assignable<T>::value \
+ && std::is_nothrow_copy_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_nothrow_copy_assignable; \
+ static constexpr bool is_nothrow_move_assignable = \
+ std::is_nothrow_move_assignable<T>::value \
+ && std::is_nothrow_move_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_nothrow_move_assignable; \
+ static constexpr bool is_swappable = \
+ is_swappable_v<T> && std::is_move_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, Types...>::is_swappable; \
+ static constexpr bool is_nothrow_swappable = \
+ is_nothrow_swappable_v<T> && std::is_nothrow_move_constructible<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_nothrow_swappable; \
+ static constexpr bool is_equals_comparable = \
+ variant_is_equals_comparable<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_equals_comparable; \
+ static constexpr bool is_less_comparable = \
+ variant_is_less_comparable<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_less_comparable; \
+ static constexpr bool is_nothrow_equals_comparable = \
+ variant_is_nothrow_equals_comparable<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_nothrow_equals_comparable; \
+ static constexpr bool is_nothrow_less_comparable = \
+ variant_is_nothrow_less_comparable<T>::value \
+ && variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::is_nothrow_less_comparable; \
+ template < \
+ typename T2 = T, \
+ typename = typename std::enable_if<std::is_default_constructible<T2>::value>::type> \
+ constexpr variant_values_implementation() noexcept( \
+ std::is_nothrow_default_constructible<T2>::value) \
+ : current_value() \
+ { \
+ } \
+ template < \
+ typename... Args, \
+ typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type> \
+ constexpr variant_values_implementation(in_place_index_t<0>, Args &&... args) noexcept( \
+ std::is_nothrow_constructible<T, Args...>::value) \
+ : current_value(std::forward<Args>(args)...) \
+ { \
+ } \
+ template <std::size_t index, \
+ typename... Args, \
+ typename = typename std:: \
+ enable_if<index != 0 \
+ && std:: \
+ is_constructible<variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>, \
+ in_place_index_t<index - 1>, \
+ Args...>::value>::type> \
+ constexpr variant_values_implementation(in_place_index_t<index>, Args &&... args) noexcept( \
+ std::is_nothrow_constructible<variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>, \
+ in_place_index_t<index - 1>, \
+ Args...>::value) \
+ : other_values(in_place_index<index - 1>, std::forward<Args>(args)...) \
+ { \
+ } \
+ template < \
+ typename U, \
+ typename... Args, \
+ typename = typename std::enable_if<std::is_constructible<T, \
+ std::initializer_list<U>, \
+ Args...>::value>::type> \
+ constexpr variant_values_implementation( \
+ in_place_index_t<0>, \
+ std::initializer_list<U> il, \
+ Args &&... args) noexcept(std::is_nothrow_constructible<T, \
+ std::initializer_list<U>, \
+ Args...>::value) \
+ : current_value(il, std::forward<Args>(args)...) \
+ { \
+ } \
+ template <typename U> \
+ static constexpr std::size_t index_from_type() noexcept \
+ { \
+ std::size_t next = \
+ variant_values_implementation<Is_Trivially_Destructible, \
+ Types...>::template index_from_type<U>(); \
+ if(std::is_same<U, T>::value && next == variant_npos) \
+ return 0; \
+ if(next == variant_npos) \
+ return variant_npos; \
+ return next + 1; \
+ } \
+ void copy_construct(const variant_values_implementation &rt, \
+ std::size_t index) noexcept(is_nothrow_copy_constructible) \
+ { \
+ if(index == 0) \
+ new(const_cast<void *>(static_cast<const volatile void *>( \
+ std::addressof(current_value)))) T(rt.current_value); \
+ else \
+ other_values.copy_construct(rt.other_values, index - 1); \
+ } \
+ void move_construct(variant_values_implementation &&rt, \
+ std::size_t index) noexcept(is_nothrow_move_constructible) \
+ { \
+ if(index == 0) \
+ new(const_cast<void *>(static_cast<const volatile void *>( \
+ std::addressof(current_value)))) T(std::move(rt.current_value)); \
+ else \
+ other_values.move_construct(std::move(rt.other_values), index - 1); \
+ } \
+ void copy_assign(const variant_values_implementation &rt, \
+ std::size_t index) noexcept(is_nothrow_copy_assignable) \
+ { \
+ if(index == 0) \
+ current_value = rt.current_value; \
+ else \
+ other_values.copy_assign(rt.other_values, index - 1); \
+ } \
+ void move_assign(variant_values_implementation &&rt, \
+ std::size_t index) noexcept(is_nothrow_move_assignable) \
+ { \
+ if(index == 0) \
+ current_value = std::move(rt.current_value); \
+ else \
+ other_values.move_assign(std::move(rt.other_values), index - 1); \
+ } \
+ void destruct(std::size_t index) noexcept \
+ { \
+ if(index == 0) \
+ current_value.~T(); \
+ else \
+ other_values.destruct(index - 1); \
+ } \
+ void swap(variant_values_implementation &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); \
+ } \
+ bool is_equal(const variant_values_implementation &rt, std::size_t index) const \
+ noexcept(is_nothrow_equals_comparable) \
+ { \
+ if(index == 0) \
+ return static_cast<bool>(current_value == rt.current_value); \
+ return other_values.is_equal(rt.other_values, index - 1); \
+ } \
+ bool is_less(const variant_values_implementation &rt, std::size_t index) const \
+ noexcept(is_nothrow_less_comparable) \
+ { \
+ if(index == 0) \
+ return static_cast<bool>(current_value < rt.current_value); \
+ return other_values.is_equal(rt.other_values, index - 1); \
+ } \
+ Destructor \
+ };
+
+VULKAN_CPU_UTIL_VARIANT_VALUES(true, ~variant_values_implementation() = default;)
+VULKAN_CPU_UTIL_VARIANT_VALUES(false, ~variant_values_implementation(){})
+#undef VULKAN_CPU_UTIL_VARIANT_VALUES
template <std::size_t Index, typename... Types>
struct variant_get;
}
};
-#define VULKAN_CPU_UTIL_VARIANT_DISPATCH(Const, Ref) \
- template <typename Fn, \
- typename... Args, \
- typename... Types, \
- std::size_t... Indexes, \
- typename Return_Type = typename std::common_type<decltype(std::declval<Fn>()( \
- std::declval<Const Types Ref>(), std::declval<Args>()...))...>::type> \
- constexpr Return_Type variant_dispatch_helper(Fn &&fn, \
- Const variant_values<Types...> Ref values, \
- std::size_t index, \
- std::index_sequence<Indexes...>, \
- Args &&... args) \
- { \
- typedef Return_Type (*Dispatch_Function)( \
- Fn && fn, Const variant_values<Types...> & values, Args && ... args); \
- const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \
- static_cast<Dispatch_Function>( \
- [](Fn &&fn, Const variant_values<Types...> &values, Args &&... args) \
- -> Return_Type \
- { \
- return std::forward<Fn>(fn)( \
- variant_get<Indexes, Types...>::get( \
- std::forward<Const variant_values<Types...> Ref>(values)), \
- std::forward<Args>(args)...); \
- })..., \
- }; \
- if(index < sizeof...(Types)) \
- return dispatch_functions[index]( \
- std::forward<Fn>(fn), values, std::forward<Args>(args)...); \
- throw bad_variant_access(); \
- } \
- \
- template <typename Fn, typename... Args, typename... Types> \
- constexpr auto variant_dispatch( \
- Fn &&fn, Const variant_values<Types...> Ref values, std::size_t index, Args &&... args) \
- ->decltype( \
- variant_dispatch_helper(std::forward<Fn>(fn), \
- std::forward<Const variant_values<Types...> Ref>(values), \
- index, \
- std::index_sequence_for<Types...>{}, \
- std::forward<Args>(args)...)) \
- { \
- return variant_dispatch_helper(std::forward<Fn>(fn), \
- std::forward<Const variant_values<Types...> Ref>(values), \
- index, \
- std::index_sequence_for<Types...>{}, \
- std::forward<Args>(args)...); \
- } \
- \
- template <typename Fn, \
- typename... Args, \
- typename... Types, \
- std::size_t... Indexes, \
- typename Return_Type = typename std::common_type<decltype(std::declval<Fn>()( \
- std::declval<Const Types Ref>(), std::declval<Args>()...))...>::type> \
- constexpr Return_Type variant_dispatch_helper_nothrow( \
- Fn &&fn, \
- Const variant_values<Types...> Ref values, \
- std::size_t index, \
- std::index_sequence<Indexes...>, \
- Args &&... args) \
- { \
- typedef Return_Type (*Dispatch_Function)( \
- Fn && fn, Const variant_values<Types...> & values, Args && ... args); \
- const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \
- static_cast<Dispatch_Function>( \
- [](Fn &&fn, Const variant_values<Types...> &values, Args &&... args) \
- -> Return_Type \
- { \
- return std::forward<Fn>(fn)( \
- variant_get<Indexes, Types...>::get( \
- std::forward<Const variant_values<Types...> Ref>(values)), \
- std::forward<Args>(args)...); \
- })..., \
- }; \
- if(index < sizeof...(Types)) \
- return dispatch_functions[index]( \
- std::forward<Fn>(fn), values, std::forward<Args>(args)...); \
- return {}; \
- } \
- \
- template <typename Fn, typename... Args, typename... Types> \
- constexpr auto variant_dispatch_nothrow( \
- Fn &&fn, Const variant_values<Types...> Ref values, std::size_t index, Args &&... args) \
- ->decltype(variant_dispatch_helper_nothrow( \
- std::forward<Fn>(fn), \
- std::forward<Const variant_values<Types...> Ref>(values), \
- index, \
- std::index_sequence_for<Types...>{}, \
- std::forward<Args>(args)...)) \
- { \
- return variant_dispatch_helper_nothrow( \
- std::forward<Fn>(fn), \
- std::forward<Const variant_values<Types...> Ref>(values), \
- index, \
- std::index_sequence_for<Types...>{}, \
- std::forward<Args>(args)...); \
+#define VULKAN_CPU_UTIL_VARIANT_DISPATCH(Const, Ref) \
+ template <std::size_t Index, \
+ typename Return_Type, \
+ typename Fn, \
+ typename... Types, \
+ typename... Args> \
+ constexpr Return_Type variant_dispatch_helper_dispatch_function( \
+ Fn &&fn, Const variant_values<Types...> Ref values, Args &&... args) \
+ { \
+ return std::forward<Fn>(fn)(variant_get<Index, Types...>::get( \
+ std::forward<Const variant_values<Types...> Ref>(values)), \
+ std::forward<Args>(args)...); \
+ } \
+ \
+ template <typename Fn, \
+ typename... Args, \
+ typename... Types, \
+ std::size_t... Indexes, \
+ typename Return_Type = typename std::common_type<decltype(std::declval<Fn>()( \
+ std::declval<Const Types Ref>(), std::declval<Args>()...))...>::type> \
+ constexpr Return_Type variant_dispatch_helper(Fn &&fn, \
+ Const variant_values<Types...> Ref values, \
+ std::size_t index, \
+ std::index_sequence<Indexes...>, \
+ Args &&... args) \
+ { \
+ typedef Return_Type (*Dispatch_Function)( \
+ Fn && fn, Const variant_values<Types...> Ref values, Args && ... args); \
+ const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \
+ static_cast<Dispatch_Function>( \
+ &variant_dispatch_helper_dispatch_function<Indexes, Return_Type>)..., \
+ }; \
+ if(index < sizeof...(Types)) \
+ return dispatch_functions[index]( \
+ std::forward<Fn>(fn), \
+ std::forward<Const variant_values<Types...> Ref>(values), \
+ std::forward<Args>(args)...); \
+ throw bad_variant_access(); \
+ } \
+ \
+ template <typename Fn, typename... Args, typename... Types> \
+ constexpr auto variant_dispatch( \
+ Fn &&fn, Const variant_values<Types...> Ref values, std::size_t index, Args &&... args) \
+ ->decltype( \
+ variant_dispatch_helper(std::forward<Fn>(fn), \
+ std::forward<Const variant_values<Types...> Ref>(values), \
+ index, \
+ std::index_sequence_for<Types...>{}, \
+ std::forward<Args>(args)...)) \
+ { \
+ return variant_dispatch_helper(std::forward<Fn>(fn), \
+ std::forward<Const variant_values<Types...> Ref>(values), \
+ index, \
+ std::index_sequence_for<Types...>{}, \
+ std::forward<Args>(args)...); \
+ } \
+ \
+ template <typename Fn, \
+ typename... Args, \
+ typename... Types, \
+ std::size_t... Indexes, \
+ typename Return_Type = typename std::common_type<decltype(std::declval<Fn>()( \
+ std::declval<Const Types Ref>(), std::declval<Args>()...))...>::type> \
+ constexpr Return_Type variant_dispatch_helper_nothrow( \
+ Fn &&fn, \
+ Const variant_values<Types...> Ref values, \
+ std::size_t index, \
+ std::index_sequence<Indexes...>, \
+ Args &&... args) \
+ { \
+ typedef Return_Type (*Dispatch_Function)( \
+ Fn && fn, Const variant_values<Types...> Ref values, Args && ... args); \
+ const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \
+ static_cast<Dispatch_Function>( \
+ &variant_dispatch_helper_dispatch_function<Indexes, Return_Type>)..., \
+ }; \
+ if(index < sizeof...(Types)) \
+ return dispatch_functions[index]( \
+ std::forward<Fn>(fn), \
+ std::forward<Const variant_values<Types...> Ref>(values), \
+ std::forward<Args>(args)...); \
+ return {}; \
+ } \
+ \
+ template <typename Fn, typename... Args, typename... Types> \
+ constexpr auto variant_dispatch_nothrow( \
+ Fn &&fn, Const variant_values<Types...> Ref values, std::size_t index, Args &&... args) \
+ ->decltype(variant_dispatch_helper_nothrow( \
+ std::forward<Fn>(fn), \
+ std::forward<Const variant_values<Types...> Ref>(values), \
+ index, \
+ std::index_sequence_for<Types...>{}, \
+ std::forward<Args>(args)...)) \
+ { \
+ return variant_dispatch_helper_nothrow( \
+ std::forward<Fn>(fn), \
+ std::forward<Const variant_values<Types...> Ref>(values), \
+ index, \
+ std::index_sequence_for<Types...>{}, \
+ std::forward<Args>(args)...); \
}
VULKAN_CPU_UTIL_VARIANT_DISPATCH(, &)
}
};
-template <bool Is_Trivially_Destructible, typename... Types>
-struct variant_base
-{
- detail::variant_values<Types...> values;
- detail::variant_index_type<sizeof...(Types)> index_value;
- template <typename... Args>
- constexpr variant_base(std::size_t index_value, Args &&... args) //
- noexcept(noexcept(new(std::declval<void *>())
- detail::variant_values<Types...>(std::declval<Args>()...)))
- : values(std::forward<Args>(args)...), index_value(index_value)
- {
+template <bool Is_Trivially_Destructible,
+ bool Is_Copy_Constructible,
+ bool Is_Move_Constructible,
+ bool Is_Copy_Assignable,
+ bool Is_Move_Assignable,
+ typename... Types>
+struct variant_base;
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE_DESTRUCTOR_false \
+ ~variant_base() \
+ { \
+ values.destruct(index_value.get()); \
}
- ~variant_base()
- {
- values.destroy(index_value.get());
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE_DESTRUCTOR_true ~variant_base() = default;
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE_COPY_CONSTRUCTOR_true \
+ variant_base(const variant_base &rt) noexcept( \
+ detail::variant_values<Types...>::is_nothrow_copy_constructible) \
+ : values(in_place_index<variant_npos>), index_value(variant_npos) \
+ { \
+ values.copy_construct(rt.values, rt.index_value.get()); \
+ index_value = rt.index_value; \
}
-};
-template <typename... Types>
-struct variant_base<true, Types...>
-{
- detail::variant_values<Types...> values;
- detail::variant_index_type<sizeof...(Types)> index_value;
- template <typename... Args>
- constexpr variant_base(std::size_t index_value, Args &&... args) //
- noexcept(noexcept(new(std::declval<void *>())
- detail::variant_values<Types...>(std::declval<Args>()...)))
- : values(std::forward<Args>(args)...), index_value(index_value)
- {
+#define VULKAN_CPU_UTIL_VARIANT_BASE_COPY_CONSTRUCTOR_false \
+ variant_base(const variant_base &rt) = delete;
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE_MOVE_CONSTRUCTOR_true \
+ variant_base(variant_base &&rt) noexcept( \
+ detail::variant_values<Types...>::is_nothrow_move_constructible) \
+ : values(in_place_index<variant_npos>), index_value(variant_npos) \
+ { \
+ values.move_construct(std::move(rt.values), rt.index_value.get()); \
+ index_value = rt.index_value; \
}
- ~variant_base() = default;
-};
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE_MOVE_CONSTRUCTOR_false \
+ variant_base(variant_base &&rt) = delete;
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE_COPY_ASSIGN_OP_true \
+ variant_base &operator=(const variant_base &rt) noexcept( \
+ detail::variant_values<Types...>::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; \
+ }
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE_COPY_ASSIGN_OP_false \
+ variant_base &operator=(const variant_base &rt) = delete;
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE_MOVE_ASSIGN_OP_true \
+ variant_base &operator=(variant_base &&rt) noexcept( \
+ detail::variant_values<Types...>::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; \
+ }
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE_MOVE_ASSIGN_OP_false \
+ variant_base &operator=(variant_base &&rt) = delete;
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE0(Is_Trivially_Destructible, \
+ Is_Copy_Constructible, \
+ Is_Move_Constructible, \
+ Is_Copy_Assignable, \
+ Is_Move_Assignable) \
+ template <typename... Types> \
+ struct variant_base<Is_Trivially_Destructible, \
+ Is_Copy_Constructible, \
+ Is_Move_Constructible, \
+ Is_Copy_Assignable, \
+ Is_Move_Assignable, \
+ Types...> \
+ { \
+ detail::variant_values<Types...> values; \
+ detail::variant_index_type<sizeof...(Types)> index_value; \
+ template <typename... Args> \
+ constexpr variant_base( \
+ variant_base_construct_tag, \
+ std::size_t index_value, \
+ Args &&... args) noexcept(noexcept(new(std::declval<void *>()) \
+ detail::variant_values<Types...>( \
+ std::declval<Args>()...))) \
+ : values(std::forward<Args>(args)...), index_value(index_value) \
+ { \
+ } \
+ VULKAN_CPU_UTIL_VARIANT_BASE_DESTRUCTOR_##Is_Trivially_Destructible \
+ VULKAN_CPU_UTIL_VARIANT_BASE_COPY_CONSTRUCTOR_##Is_Copy_Constructible \
+ VULKAN_CPU_UTIL_VARIANT_BASE_MOVE_CONSTRUCTOR_##Is_Move_Constructible \
+ VULKAN_CPU_UTIL_VARIANT_BASE_COPY_ASSIGN_OP_##Is_Copy_Assignable \
+ VULKAN_CPU_UTIL_VARIANT_BASE_MOVE_ASSIGN_OP_##Is_Move_Assignable \
+ };
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE1( \
+ Is_Copy_Constructible, Is_Move_Constructible, Is_Copy_Assignable, Is_Move_Assignable) \
+ VULKAN_CPU_UTIL_VARIANT_BASE0(false, \
+ Is_Copy_Constructible, \
+ Is_Move_Constructible, \
+ Is_Copy_Assignable, \
+ Is_Move_Assignable) \
+ VULKAN_CPU_UTIL_VARIANT_BASE0(true, \
+ Is_Copy_Constructible, \
+ Is_Move_Constructible, \
+ Is_Copy_Assignable, \
+ Is_Move_Assignable)
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE2( \
+ Is_Move_Constructible, Is_Copy_Assignable, Is_Move_Assignable) \
+ VULKAN_CPU_UTIL_VARIANT_BASE1( \
+ false, Is_Move_Constructible, Is_Copy_Assignable, Is_Move_Assignable) \
+ VULKAN_CPU_UTIL_VARIANT_BASE1( \
+ true, Is_Move_Constructible, Is_Copy_Assignable, Is_Move_Assignable)
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE3(Is_Copy_Assignable, Is_Move_Assignable) \
+ VULKAN_CPU_UTIL_VARIANT_BASE2(false, Is_Copy_Assignable, Is_Move_Assignable) \
+ VULKAN_CPU_UTIL_VARIANT_BASE2(true, Is_Copy_Assignable, Is_Move_Assignable)
+
+#define VULKAN_CPU_UTIL_VARIANT_BASE4(Is_Move_Assignable) \
+ VULKAN_CPU_UTIL_VARIANT_BASE3(false, Is_Move_Assignable) \
+ VULKAN_CPU_UTIL_VARIANT_BASE3(true, Is_Move_Assignable)
+
+VULKAN_CPU_UTIL_VARIANT_BASE4(false)
+VULKAN_CPU_UTIL_VARIANT_BASE4(true)
template <typename T>
struct variant_is_in_place_index
template <typename Fn, typename... Types, typename... Args>
typename std::common_type<decltype(std::declval<Fn>()(std::declval<const Types &&>()))...>::type
variant_dispatch(Fn &&fn, const variant<Types...> &&v, Args &&... args);
+
+template <typename... Types>
+using variant_base_t = variant_base<detail::variant_is_trivially_destructible<Types...>(),
+ detail::variant_values<Types...>::is_copy_constructible,
+ detail::variant_values<Types...>::is_move_constructible,
+ detail::variant_values<Types...>::is_copy_assignable,
+ detail::variant_values<Types...>::is_move_assignable,
+ Types...>;
}
template <typename... Types>
-class variant
- : private detail::variant_base<detail::variant_values<Types...>::is_trivially_destructible,
- Types...>
+class variant : private detail::variant_base_t<Types...>
{
static_assert(sizeof...(Types) > 0, "empty variant is not permitted");
private:
typedef typename detail::variant_values<Types...>::type_0 type_0;
- typedef detail::variant_base<detail::variant_values<Types...>::is_trivially_destructible,
- Types...> base;
+ typedef detail::variant_base_t<Types...> base;
private:
using base::values;
using base::index_value;
public:
- template <
- typename = typename std::enable_if<std::is_default_constructible<type_0>::value>::value>
+ template <bool extra_condition = true,
+ typename = typename std::
+ enable_if<extra_condition && std::is_default_constructible<type_0>::value>::type>
constexpr variant() noexcept(std::is_nothrow_default_constructible<type_0>::value)
- : base(0)
- {
- }
- template <
- typename =
- typename std::enable_if<detail::variant_values<Types...>::is_copy_constructible>::type>
- variant(const variant &rt) noexcept(
- detail::variant_values<Types...>::is_nothrow_copy_constructible)
- : base(variant_npos, in_place_index<variant_npos>)
+ : base(detail::variant_base_construct_tag{}, 0)
{
- values.copy_construct(rt.values, rt.index_value.get());
- index_value = rt.index_value;
- }
- template <
- typename =
- typename std::enable_if<detail::variant_values<Types...>::is_move_constructible>::type>
- variant(variant &&rt) noexcept(detail::variant_values<Types...>::is_nothrow_move_constructible)
- : base(variant_npos, in_place_index<variant_npos>)
- {
- values.move_construct(std::move(rt.values), rt.index_value.get());
- index_value = rt.index_value;
}
template <
typename T,
T>::value>::type>
constexpr variant(T &&value) noexcept(
std::is_nothrow_constructible<variant_alternative_t<Index, variant<Types...>>, T>::value)
- : base(Index, in_place_index<Index>, std::forward<T>(value))
+ : base(detail::variant_base_construct_tag{},
+ Index,
+ in_place_index<Index>,
+ std::forward<T>(value))
{
}
template <typename T,
&& std::is_constructible<T, Args...>::value>::type>
constexpr explicit variant(in_place_type_t<T>, Args &&... args) noexcept(
std::is_nothrow_constructible<T, Args...>::value)
- : base(Index, in_place_index<Index>, std::forward<Args>(args)...)
+ : base(detail::variant_base_construct_tag{},
+ Index,
+ in_place_index<Index>,
+ std::forward<Args>(args)...)
{
}
template <
Args &&... args) noexcept(std::is_nothrow_constructible<T,
std::initializer_list<U>,
Args...>::value)
- : base(Index, in_place_index<Index>, il, std::forward<Args>(args)...)
+ : base(detail::variant_base_construct_tag{},
+ Index,
+ in_place_index<Index>,
+ il,
+ std::forward<Args>(args)...)
{
}
template <std::size_t Index,
constexpr explicit variant(in_place_index_t<Index>, Args &&... args) noexcept(
std::is_nothrow_constructible<variant_alternative_t<Index, variant<Types...>>,
Args...>::value)
- : base(Index, in_place_index<Index>, std::forward<Args>(args)...)
+ : base(detail::variant_base_construct_tag{},
+ Index,
+ in_place_index<Index>,
+ std::forward<Args>(args)...)
{
}
template <std::size_t Index,
noexcept(std::is_nothrow_constructible<variant_alternative_t<Index, variant<Types...>>,
std::initializer_list<U>,
Args...>::value)
- : base(Index, in_place_index<Index>, il, std::forward<Args>(args)...)
- {
- }
- template <
- typename =
- typename std::enable_if<detail::variant_values<Types...>::is_copy_assignable>::type>
- variant &operator=(const variant &rt) noexcept(
- detail::variant_values<Types...>::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<detail::variant_values<Types...>::is_move_assignable>::type>
- variant &operator=(variant &&rt) noexcept(
- detail::variant_values<Types...>::is_nothrow_move_assignable)
+ : base(detail::variant_base_construct_tag{},
+ Index,
+ in_place_index<Index>,
+ il,
+ std::forward<Args>(args)...)
{
- 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,
values.destruct(index_value.get());
index_value.set(variant_npos); // in case construction throws
auto &value = detail::variant_get<Index, Types...>::get(values);
- new(const_cast<void *>(std::addressof(value)))
+ new(const_cast<void *>(static_cast<const volatile void *>(std::addressof(value))))
variant_alternative_t<Index, variant<Types...>>(std::forward<T>(new_value));
index_value.set(Index);
}
values.destruct(index_value.get());
index_value.set(variant_npos); // in case construction throws
auto &value = detail::variant_get<Index, Types...>::get(values);
- new(const_cast<void *>(std::addressof(value)))
+ new(const_cast<void *>(static_cast<const volatile void *>(std::addressof(value))))
variant_alternative_t<Index, variant<Types...>>(std::forward<Args>(args)...);
index_value.set(Index);
}
values.destruct(index_value.get());
index_value.set(variant_npos); // in case construction throws
auto &value = detail::variant_get<Index, Types...>::get(values);
- new(const_cast<void *>(std::addressof(value)))
+ new(const_cast<void *>(static_cast<const volatile void *>(std::addressof(value))))
variant_alternative_t<Index, variant<Types...>>(il, std::forward<Args>(args)...);
index_value.set(Index);
}
{
return index_value.get();
}
- template <
- typename = typename std::enable_if<detail::variant_values<Types...>::is_swappable>::type>
+ template <bool extra_condition = true,
+ typename =
+ typename std::enable_if<extra_condition
+ && detail::variant_values<Types...>::is_swappable>::type>
void swap(variant &rt) noexcept(detail::variant_values<Types...>::is_nothrow_swappable)
{
if(index_value.get() == rt.index_value.get())
operator<(const variant<Types2...> &l, const variant<Types2...> &r) noexcept(
detail::variant_values<Types2...>::is_nothrow_less_comparable);
template <typename Fn, typename... Types2, typename... Args>
- friend typename std::common_type<decltype(std::declval<Fn>()(std::declval<Types2 &>()))...>::type
+ friend
+ typename std::common_type<decltype(std::declval<Fn>()(std::declval<Types2 &>()))...>::type
detail::variant_dispatch(Fn &&fn, variant<Types2...> &v, Args &&... args);
template <typename Fn, typename... Types2, typename... Args>
friend typename std::common_type<decltype(
}
}
-#endif /* SOURCE_UTIL_VARIANT_H_ */
+#endif /* UTIL_VARIANT_H_ */
*
*/
-#ifndef SOURCE_UTIL_VOID_T_H_
-#define SOURCE_UTIL_VOID_T_H_
+#ifndef UTIL_VOID_T_H_
+#define UTIL_VOID_T_H_
namespace vulkan_cpu
{
}
}
-#endif /* SOURCE_UTIL_VOID_T_H_ */
+#endif /* UTIL_VOID_T_H_ */