everything builds
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 1 Jun 2017 11:21:07 +0000 (04:21 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 1 Jun 2017 11:21:07 +0000 (04:21 -0700)
14 files changed:
src/CMakeLists.txt
src/json/CMakeLists.txt [new file with mode: 0644]
src/json/json.cpp [new file with mode: 0644]
src/json/json.h [new file with mode: 0644]
src/spirv/CMakeLists.txt
src/util/CMakeLists.txt
src/util/bit_intrinsics.cpp [new file with mode: 0644]
src/util/bit_intrinsics.h [new file with mode: 0644]
src/util/copy_cv_ref.h
src/util/invoke.h
src/util/soft_float.cpp [new file with mode: 0644]
src/util/soft_float.h [new file with mode: 0644]
src/util/variant.h
src/util/void_t.h

index 23627cc8c313a2dda48970481a5dafaf92eea0bd..28989b578e9e64ceb5320f18df60b4fc6dfe3973 100644 (file)
@@ -21,4 +21,5 @@
 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
diff --git a/src/json/CMakeLists.txt b/src/json/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9666a76
--- /dev/null
@@ -0,0 +1,24 @@
+# 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
diff --git a/src/json/json.cpp b/src/json/json.cpp
new file mode 100644 (file)
index 0000000..8e2a938
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * 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 << ']';
+}
+}
+}
+}
diff --git a/src/json/json.h b/src/json/json.h
new file mode 100644 (file)
index 0000000..08b2e9c
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 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_ */
index c470ba2b1894816adbd44ab159fbee71ad7239ae..46e589e762f99dfa33213c20ac71a69a4d230e7b 100644 (file)
@@ -20,4 +20,5 @@
 #
 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
index 2059497383c071cecb405032d6283bb552952187..387804f258cc837c8088b96e123082eba82af26a 100644 (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})
diff --git a/src/util/bit_intrinsics.cpp b/src/util/bit_intrinsics.cpp
new file mode 100644 (file)
index 0000000..25fe663
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "bit_intrinsics.h"
diff --git a/src/util/bit_intrinsics.h b/src/util/bit_intrinsics.h
new file mode 100644 (file)
index 0000000..4550042
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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_ */
index ce68ca649e73f609fdbf2e1252829987031e8d7e..c01e06e2d993caefcddd4e4b71012e8d09d98eeb 100644 (file)
@@ -21,8 +21,8 @@
  *
  */
 
-#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
 {
@@ -99,4 +99,4 @@ using copy_cv_ref_t = typename copy_cv_ref<Source, Dest>::type;
 }
 }
 
-#endif /* SOURCE_UTIL_COPY_CV_REF_H_ */
+#endif /* UTIL_COPY_CV_REF_H_ */
index 0a8f05c93241b12521430923794e1c1dbb88cf18..96800400d8f421b5ec1db2bd982b254a1b45f363 100644 (file)
@@ -21,8 +21,8 @@
  *
  */
 
-#ifndef SOURCE_UTIL_INVOKE_H_
-#define SOURCE_UTIL_INVOKE_H_
+#ifndef UTIL_INVOKE_H_
+#define UTIL_INVOKE_H_
 
 #include <type_traits>
 #include <utility>
@@ -274,4 +274,4 @@ constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<R, Fn, Args...>
 }
 }
 
-#endif /* SOURCE_UTIL_INVOKE_H_ */
+#endif /* UTIL_INVOKE_H_ */
diff --git a/src/util/soft_float.cpp b/src/util/soft_float.cpp
new file mode 100644 (file)
index 0000000..7f4d402
--- /dev/null
@@ -0,0 +1,961 @@
+/*
+ * 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(&quotient)[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
diff --git a/src/util/soft_float.h b/src/util/soft_float.h
new file mode 100644 (file)
index 0000000..e8b7efb
--- /dev/null
@@ -0,0 +1,1164 @@
+/*
+ * 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 &currentValue,
+                                             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_ */
index f32aa2a2e95f2c648230c32cf7783d889a2a190d..118629c4013513459724cf52b566286006104fe9 100644 (file)
@@ -21,8 +21,8 @@
  *
  */
 
-#ifndef SOURCE_UTIL_VARIANT_H_
-#define SOURCE_UTIL_VARIANT_H_
+#ifndef UTIL_VARIANT_H_
+#define UTIL_VARIANT_H_
 
 #include <utility>
 #include <type_traits>
@@ -154,6 +154,11 @@ using variant_alternative_t = typename variant_alternative<Index, T>::type;
 
 namespace detail
 {
+struct variant_base_construct_tag
+{
+    explicit variant_base_construct_tag() = default;
+};
+
 template <typename T>
 struct variant_identity_type
 {
@@ -236,7 +241,19 @@ public:
 };
 
 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;
@@ -247,16 +264,15 @@ union variant_values
     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>
@@ -264,197 +280,238 @@ union variant_values
     {
         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;
@@ -505,103 +562,106 @@ struct variant_get<0, T, Types...>
     }
 };
 
-#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(, &)
@@ -671,38 +731,150 @@ struct variant_index_type
     }
 };
 
-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
@@ -743,49 +915,36 @@ typename std::common_type<decltype(std::declval<Fn>()(std::declval<Types &&>()))
 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,
@@ -798,7 +957,10 @@ public:
                                                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,
@@ -808,7 +970,10 @@ public:
                                                  && 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 <
@@ -825,7 +990,11 @@ public:
         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,
@@ -836,7 +1005,10 @@ public:
     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,
@@ -852,46 +1024,12 @@ public:
         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,
@@ -917,7 +1055,7 @@ public:
             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);
         }
@@ -956,7 +1094,7 @@ public:
         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);
     }
@@ -974,7 +1112,7 @@ public:
         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);
     }
@@ -986,8 +1124,10 @@ public:
     {
         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())
@@ -1017,7 +1157,8 @@ public:
         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(
@@ -1314,4 +1455,4 @@ inline void
 }
 }
 
-#endif /* SOURCE_UTIL_VARIANT_H_ */
+#endif /* UTIL_VARIANT_H_ */
index 1e51882b3eac3bb0a28b0ad8ede1f1ace10f754f..7c280f0c542a9cab248021bf0e82065b8e9df536 100644 (file)
@@ -21,8 +21,8 @@
  *
  */
 
-#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
 {
@@ -42,4 +42,4 @@ using void_t = typename detail::void_t_helper<Types...>::type;
 }
 }
 
-#endif /* SOURCE_UTIL_VOID_T_H_ */
+#endif /* UTIL_VOID_T_H_ */