diff --git a/examples/main.cpp b/examples/main.cpp index 1fef70c..0b1dec0 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -91,7 +91,7 @@ int main() { template void print(R&& v) { for (const auto& x : v) { - constexpr bool x_is_pair = small::is_pair_v>; + constexpr bool x_is_pair = small::detail::is_pair_v>; if constexpr (not x_is_pair) { std::cout << x << ' '; } else { diff --git a/source/small/detail/algorithm/console_unicode_guard.h b/source/small/detail/algorithm/console_unicode_guard.h index 0fee076..a4e141c 100644 --- a/source/small/detail/algorithm/console_unicode_guard.h +++ b/source/small/detail/algorithm/console_unicode_guard.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ALGORITHM_CONSOLE_UNICODE_GUARD_H #define SMALL_DETAIL_ALGORITHM_CONSOLE_UNICODE_GUARD_H @@ -18,80 +17,82 @@ #include -#if defined(_WIN32) && __has_include() +#if defined(_WIN32) && __has_include() #include #undef small #endif namespace small { - class console_unicode_guard { - public: - inline console_unicode_guard(std::ostream &os, size_t size, size_t codepoints, bool above_10000 = true) { -#if defined(_WIN32) && __has_include() - const bool is_console = &os == reinterpret_cast(&std::cout) || &os == reinterpret_cast(&std::wcout); - const bool requires_unicode = size != codepoints; - prev_console_output_cp = GetConsoleOutputCP(); - requires_another_console_cp = is_console && requires_unicode && prev_console_output_cp != CP_UTF8; - if (requires_another_console_cp) { - SetConsoleOutputCP(CP_UTF8); - } - // If the highest codepoint is above U+10000, we also need to change the default console font - // to one that supports these characters if the current one can't support them yet. - // Unfortunately, cmd.exe won't support high codepoints even if the corresponding fonts - // support them. But this solves the problem for the terminals, like most IDE terminals, - // and future versions of cmd.exe. - if (requires_unicode && above_10000) { - // Console handle - HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - // Get current font - ZeroMemory(&prev_console_font, sizeof(prev_console_font)); - prev_console_font.cbSize = sizeof(prev_console_font); - if (GetCurrentConsoleFontEx(hStdOut, false, &prev_console_font)) { - // Check if current font supports unicode above 10000 - // There's no simple heuristic to do that, be we do know 1) the default console font (consolas) - // do not support unicode above 10000 and 2) the user probably doesn't want another - // font if they explicitly chose that font. - requires_another_font = std::wcscmp(prev_console_font.FaceName, L"Consolas"); - if (requires_another_font) { - CONSOLE_FONT_INFOEX new_font; - ZeroMemory(&new_font, sizeof(new_font)); - new_font.cbSize = sizeof(new_font); - lstrcpyW(new_font.FaceName, L"Lucida Console"); - SetCurrentConsoleFontEx(hStdOut, false, &new_font); + namespace detail { + class console_unicode_guard { + public: + inline console_unicode_guard(std::ostream &os, size_t size, size_t codepoints, bool above_10000 = true) { +#if defined(_WIN32) && __has_include() + const bool is_console = &os == reinterpret_cast(&std::cout) || + &os == reinterpret_cast(&std::wcout); + const bool requires_unicode = size != codepoints; + prev_console_output_cp = GetConsoleOutputCP(); + requires_another_console_cp = is_console && requires_unicode && prev_console_output_cp != CP_UTF8; + if (requires_another_console_cp) { + SetConsoleOutputCP(CP_UTF8); + } + // If the highest codepoint is above U+10000, we also need to change the default console font + // to one that supports these characters if the current one can't support them yet. + // Unfortunately, cmd.exe won't support high codepoints even if the corresponding fonts + // support them. But this solves the problem for the terminals, like most IDE terminals, + // and future versions of cmd.exe. + if (requires_unicode && above_10000) { + // Console handle + HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + // Get current font + ZeroMemory(&prev_console_font, sizeof(prev_console_font)); + prev_console_font.cbSize = sizeof(prev_console_font); + if (GetCurrentConsoleFontEx(hStdOut, false, &prev_console_font)) { + // Check if current font supports unicode above 10000 + // There's no simple heuristic to do that, be we do know 1) the default console font (consolas) + // do not support unicode above 10000 and 2) the user probably doesn't want another + // font if they explicitly chose that font. + requires_another_font = std::wcscmp(prev_console_font.FaceName, L"Consolas"); + if (requires_another_font) { + CONSOLE_FONT_INFOEX new_font; + ZeroMemory(&new_font, sizeof(new_font)); + new_font.cbSize = sizeof(new_font); + lstrcpyW(new_font.FaceName, L"Lucida Console"); + SetCurrentConsoleFontEx(hStdOut, false, &new_font); + } } } - } #else - // Discard values - (void) os; - (void) size; - (void) codepoints; - (void) above_10000; + // Discard values + (void)os; + (void)size; + (void)codepoints; + (void)above_10000; #endif - } - - - inline ~console_unicode_guard() { -#if defined(_WIN32) && __has_include() - if (requires_another_console_cp) { - SetConsoleOutputCP(prev_console_output_cp); - } - if (requires_another_font) { - HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - SetCurrentConsoleFontEx(hStdOut, false, &prev_console_font); } + + inline ~console_unicode_guard() { +#if defined(_WIN32) && __has_include() + if (requires_another_console_cp) { + SetConsoleOutputCP(prev_console_output_cp); + } + if (requires_another_font) { + HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + SetCurrentConsoleFontEx(hStdOut, false, &prev_console_font); + } #endif - } + } - private: -#if defined(_WIN32) && __has_include() - bool requires_another_console_cp{false}; - UINT prev_console_output_cp{0}; - bool requires_another_font{false}; - CONSOLE_FONT_INFOEX prev_console_font{}; + private: +#if defined(_WIN32) && __has_include() + bool requires_another_console_cp{false}; + UINT prev_console_output_cp{0}; + bool requires_another_font{false}; + CONSOLE_FONT_INFOEX prev_console_font{}; #endif - }; + }; -} + } // namespace detail +} // namespace small #endif // SMALL_DETAIL_ALGORITHM_CONSOLE_UNICODE_GUARD_H diff --git a/source/small/detail/algorithm/intcmp.h b/source/small/detail/algorithm/intcmp.h index e790cf1..b880b90 100644 --- a/source/small/detail/algorithm/intcmp.h +++ b/source/small/detail/algorithm/intcmp.h @@ -5,118 +5,120 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ALGORITHM_INTCMP_H #define SMALL_DETAIL_ALGORITHM_INTCMP_H -#include #include +#include #include "../traits/cpp_version.h" /// \headerfile Compare numbers of different types namespace small { + namespace detail { - template constexpr bool cmp_equal(T t, U u) noexcept { - using UT = std::make_unsigned_t; - using UU = std::make_unsigned_t; - if constexpr (std::is_signed_v == std::is_signed_v) - return t == u; - else if constexpr (std::is_signed_v) - return t < 0 ? false : UT(t) == u; - else - return u < 0 ? false : t == UU(u); - } - - template constexpr bool cmp_not_equal(T t, U u) noexcept { return !cmp_equal(t, u); } + template constexpr bool cmp_equal(T t, U u) noexcept { + using UT = std::make_unsigned_t; + using UU = std::make_unsigned_t; + if constexpr (std::is_signed_v == std::is_signed_v) + return t == u; + else if constexpr (std::is_signed_v) + return t < 0 ? false : UT(t) == u; + else + return u < 0 ? false : t == UU(u); + } - template constexpr bool cmp_less(T t, U u) noexcept { - using UT = std::make_unsigned_t; - using UU = std::make_unsigned_t; - if constexpr (std::is_signed_v == std::is_signed_v) - return t < u; - else if constexpr (std::is_signed_v) - return t < 0 ? true : UT(t) < u; - else - return u < 0 ? false : t < UU(u); - } + template constexpr bool cmp_not_equal(T t, U u) noexcept { return !cmp_equal(t, u); } + + template constexpr bool cmp_less(T t, U u) noexcept { + using UT = std::make_unsigned_t; + using UU = std::make_unsigned_t; + if constexpr (std::is_signed_v == std::is_signed_v) + return t < u; + else if constexpr (std::is_signed_v) + return t < 0 ? true : UT(t) < u; + else + return u < 0 ? false : t < UU(u); + } - template constexpr bool cmp_greater(T t, U u) noexcept { return cmp_less(u, t); } + template constexpr bool cmp_greater(T t, U u) noexcept { return cmp_less(u, t); } - template constexpr bool cmp_less_equal(T t, U u) noexcept { return !cmp_greater(t, u); } + template constexpr bool cmp_less_equal(T t, U u) noexcept { return !cmp_greater(t, u); } - template constexpr bool cmp_greater_equal(T t, U u) noexcept { return !cmp_less(t, u); } + template constexpr bool cmp_greater_equal(T t, U u) noexcept { return !cmp_less(t, u); } - namespace detail { - /// \section Traits to promote integer types + namespace detail { + /// \section Traits to promote integer types - /// \struct Get the integer type for the given parameters - template struct custom_int; + /// \struct Get the integer type for the given parameters + template struct custom_int; - template <> struct custom_int<8, true> { typedef int8_t type; }; + template <> struct custom_int<8, true> { typedef int8_t type; }; - template <> struct custom_int<16, true> { typedef int16_t type; }; + template <> struct custom_int<16, true> { typedef int16_t type; }; - template <> struct custom_int<32, true> { typedef int32_t type; }; + template <> struct custom_int<32, true> { typedef int32_t type; }; - template <> struct custom_int<64, true> { typedef int64_t type; }; + template <> struct custom_int<64, true> { typedef int64_t type; }; - template <> struct custom_int<8, false> { typedef uint8_t type; }; + template <> struct custom_int<8, false> { typedef uint8_t type; }; - template <> struct custom_int<16, false> { typedef uint16_t type; }; + template <> struct custom_int<16, false> { typedef uint16_t type; }; - template <> struct custom_int<32, false> { typedef uint32_t type; }; + template <> struct custom_int<32, false> { typedef uint32_t type; }; - template <> struct custom_int<64, false> { typedef uint64_t type; }; + template <> struct custom_int<64, false> { typedef uint64_t type; }; - template using custom_int_t = typename custom_int::type; + template using custom_int_t = typename custom_int::type; - template struct promoted_size { - static constexpr std::size_t first_size = sizeof(T); - static constexpr std::size_t second_size = sizeof(U); - static constexpr bool first_is_signed = std::is_signed_v; - static constexpr bool second_is_signed = std::is_signed_v; - static constexpr std::size_t largest_size = std::max(first_size, second_size); - static constexpr std::size_t smallest_size = std::min(first_size, second_size); - static constexpr bool largest_is_signed = first_size < second_size ? second_is_signed : first_is_signed; - static constexpr bool smallest_is_signed = first_size < second_size ? first_is_signed : second_is_signed; - static constexpr bool largest_needs_double = - largest_size == smallest_size && largest_size != 64 / 8 && not largest_is_signed && smallest_is_signed; - static constexpr size_t value = largest_size * (largest_needs_double ? 2 : 1); - }; + template struct promoted_size { + static constexpr std::size_t first_size = sizeof(T); + static constexpr std::size_t second_size = sizeof(U); + static constexpr bool first_is_signed = std::is_signed_v; + static constexpr bool second_is_signed = std::is_signed_v; + static constexpr std::size_t largest_size = std::max(first_size, second_size); + static constexpr std::size_t smallest_size = std::min(first_size, second_size); + static constexpr bool largest_is_signed = first_size < second_size ? second_is_signed : first_is_signed; + static constexpr bool smallest_is_signed = + first_size < second_size ? first_is_signed : second_is_signed; + static constexpr bool largest_needs_double = largest_size == smallest_size && largest_size != 64 / 8 && + not largest_is_signed && smallest_is_signed; + static constexpr size_t value = largest_size * (largest_needs_double ? 2 : 1); + }; - template constexpr std::size_t promoted_size_v = promoted_size::value; + template constexpr std::size_t promoted_size_v = promoted_size::value; - /// \struct Promote an integer to the proper type capable of representing both integers - template - using promoted = custom_int * 8, std::is_signed_v || std::is_signed_v>; + /// \struct Promote an integer to the proper type capable of representing both integers + template + using promoted = custom_int * 8, std::is_signed_v || std::is_signed_v>; - template using promoted_t = typename promoted::type; - } // namespace detail + template using promoted_t = typename promoted::type; + } // namespace detail - /// \brief Minimum number of two types. This returns a value rather than - template constexpr detail::promoted_t min_value(T t, U u) noexcept { - if (cmp_less(t, u)) { - return static_cast>(t); - } else { - return static_cast>(u); + /// \brief Minimum number of two types. This returns a value rather than + template constexpr detail::promoted_t min_value(T t, U u) noexcept { + if (cmp_less(t, u)) { + return static_cast>(t); + } else { + return static_cast>(u); + } } - } - template constexpr detail::promoted_t max_value(T t, U u) noexcept { - if (cmp_less(t, u)) { - return static_cast>(u); - } else { - return static_cast>(t); + template constexpr detail::promoted_t max_value(T t, U u) noexcept { + if (cmp_less(t, u)) { + return static_cast>(u); + } else { + return static_cast>(t); + } } - } - inline long long int div_ceil(long long int numerator, long long int denominator) { - lldiv_t res = std::div(numerator, denominator); - return res.rem ? (res.quot + 1) : res.quot; - } + inline long long int div_ceil(long long int numerator, long long int denominator) { + lldiv_t res = std::div(numerator, denominator); + return res.rem ? (res.quot + 1) : res.quot; + } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ALGORITHM_INTCMP_H diff --git a/source/small/detail/algorithm/leading_zeros.h b/source/small/detail/algorithm/leading_zeros.h index 66744b7..a7b7048 100644 --- a/source/small/detail/algorithm/leading_zeros.h +++ b/source/small/detail/algorithm/leading_zeros.h @@ -5,56 +5,59 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ALGORITHM_LEADING_ZEROS_H #define SMALL_DETAIL_ALGORITHM_LEADING_ZEROS_H //! Implementation Detail namespace small { + namespace detail { - /// \brief Count leading zeros utility + /// \brief Count leading zeros utility #if defined(__GNUC__) #ifndef SMALL_HAS_LEADING_ZEROS_FUNCTION #define SMALL_HAS_LEADING_ZEROS_FUNCTION true #endif - inline unsigned int leading_zeros(char value) noexcept { return (char)__builtin_clz(value); } - inline unsigned int leading_zeros(unsigned int value) noexcept { return (unsigned int)__builtin_clz(value); } - inline unsigned int leading_zeros(unsigned long int value) noexcept { return (unsigned int)__builtin_clzl(value); } - inline unsigned int leading_zeros(char32_t value) noexcept { - return sizeof(char32_t) == sizeof(unsigned long int) ? (unsigned int)__builtin_clzl(value) - : (unsigned int)__builtin_clz(value); - } + inline unsigned int leading_zeros(char value) noexcept { return (char)__builtin_clz(value); } + inline unsigned int leading_zeros(unsigned int value) noexcept { return (unsigned int)__builtin_clz(value); } + inline unsigned int leading_zeros(unsigned long int value) noexcept { + return (unsigned int)__builtin_clzl(value); + } + inline unsigned int leading_zeros(char32_t value) noexcept { + return sizeof(char32_t) == sizeof(unsigned long int) ? (unsigned int)__builtin_clzl(value) + : (unsigned int)__builtin_clz(value); + } #elif defined(_MSC_VER) #ifndef SMALL_HAS_LEADING_ZEROS_FUNCTION #define SMALL_HAS_LEADING_ZEROS_FUNCTION true #endif - template inline unsigned int lzcnt(T value) noexcept { - unsigned long value_log2; + template inline unsigned int lzcnt(T value) noexcept { + unsigned long value_log2; #if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) - _BitScanReverse64(&value_log2, static_cast(value)); + _BitScanReverse64(&value_log2, static_cast(value)); #else - _BitScanReverse(&value_log2, static_cast(value)); + _BitScanReverse(&value_log2, static_cast(value)); #endif - return sizeof(T) * 8 - value_log2 - 1; - } - inline unsigned int leading_zeros(std::uint16_t value) noexcept { return lzcnt(value); } - inline unsigned int leading_zeros(std::uint32_t value) noexcept { return lzcnt(value); } + return sizeof(T) * 8 - value_log2 - 1; + } + inline unsigned int leading_zeros(std::uint16_t value) noexcept { return lzcnt(value); } + inline unsigned int leading_zeros(std::uint32_t value) noexcept { return lzcnt(value); } #ifndef WIN32 - inline unsigned int leading_zeros(std::uint64_t value) noexcept { return lzcnt(value); } + inline unsigned int leading_zeros(std::uint64_t value) noexcept { return lzcnt(value); } #endif // WIN32 - inline unsigned int leading_zeros(char32_t value) noexcept { return lzcnt(value); } + inline unsigned int leading_zeros(char32_t value) noexcept { return lzcnt(value); } #endif - /// \brief Wrapping this functionality in a trait + /// \brief Wrapping this functionality in a trait #if defined(SMALL_HAS_LEADING_ZEROS_FUNCTION) && SMALL_HAS_LEADING_ZEROS_FUNCTION == true - struct system_has_leading_zeros : std::true_type {}; + struct system_has_leading_zeros : std::true_type {}; #else - struct system_has_leading_zeros : std::false_type {}; + struct system_has_leading_zeros : std::false_type {}; #endif - constexpr bool system_has_leading_zeros_v = system_has_leading_zeros::value; + constexpr bool system_has_leading_zeros_v = system_has_leading_zeros::value; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ALGORITHM_LEADING_ZEROS_H diff --git a/source/small/detail/algorithm/shift.h b/source/small/detail/algorithm/shift.h index 20e700c..7575068 100644 --- a/source/small/detail/algorithm/shift.h +++ b/source/small/detail/algorithm/shift.h @@ -15,100 +15,108 @@ #include #include -namespace shift { - - template using difference_type_t = typename std::iterator_traits::difference_type; - - template using iterator_category_t = typename std::iterator_traits::iterator_category; +namespace small { + namespace detail { + namespace shift { + + template using difference_type_t = typename std::iterator_traits::difference_type; + + template using iterator_category_t = typename std::iterator_traits::iterator_category; + + template constexpr bool is_category = false; + template + constexpr bool is_category, Tag>>> = + true; + + /// Increment (decrement for negative n) i |n| times or until i == bound, + /// whichever comes first. Returns n - the difference between i's final position + /// and its initial position. (Note: "advance" has overloads with this behavior + /// in the Ranges TS.) + template + constexpr difference_type_t bounded_advance(I &i, difference_type_t n, I const bound) { + if constexpr (is_category) { + for (; n < 0 && i != bound; ++n, void(--i)) { + ; + } + } - template constexpr bool is_category = false; - template - constexpr bool is_category, Tag>>> = true; + for (; n > 0 && i != bound; --n, void(++i)) { + ; + } - /// Increment (decrement for negative n) i |n| times or until i == bound, - /// whichever comes first. Returns n - the difference between i's final position - /// and its initial position. (Note: "advance" has overloads with this behavior - /// in the Ranges TS.) - template constexpr difference_type_t bounded_advance(I &i, difference_type_t n, I const bound) { - if constexpr (is_category) { - for (; n < 0 && i != bound; ++n, void(--i)) { - ; + return n; } - } - - for (; n > 0 && i != bound; --n, void(++i)) { - ; - } - - return n; - } - - template ForwardIt shift_left(ForwardIt first, ForwardIt last, difference_type_t n) { - if (n <= 0) { - return last; - } - - auto mid = first; - if (bounded_advance(mid, n, last)) { - return first; - } - return std::move(std::move(mid), std::move(last), std::move(first)); - } + template + ForwardIt shift_left(ForwardIt first, ForwardIt last, difference_type_t n) { + if (n <= 0) { + return last; + } - template ForwardIt shift_right(ForwardIt first, ForwardIt last, difference_type_t n) { - if (n <= 0) { - return first; - } + auto mid = first; + if (bounded_advance(mid, n, last)) { + return first; + } - if constexpr (is_category) { - auto mid = last; - if (bounded_advance(mid, -n, first)) { - return last; - } - return std::move_backward(std::move(first), std::move(mid), std::move(last)); - } else { - auto result = first; - if (bounded_advance(result, n, last)) { - return last; + return std::move(std::move(mid), std::move(last), std::move(first)); } - // Invariant: next(first, n) == result - // Invariant: next(trail, n) == lead - - auto lead = result; - auto trail = first; - - for (; trail != result; ++lead, void(++trail)) { - if (lead == last) { - // The range looks like: - // - // |-- (n - k) elements --|-- k elements --|-- (n - k) elements --| - // ^-first trail-^ ^-result last-^ - // - // Note that distance(first, trail) == distance(result, last) - std::move(std::move(first), std::move(trail), std::move(result)); - return result; + template + ForwardIt shift_right(ForwardIt first, ForwardIt last, difference_type_t n) { + if (n <= 0) { + return first; } - } - for (;;) { - for (auto mid = first; mid != result; ++lead, void(++trail), ++mid) { - if (lead == last) { - // The range looks like: - // - // |-- (n - k) elements --|-- k elements --|-- ... --|-- n elements --| - // ^-first mid-^ result-^ ^-trail last-^ - // - trail = std::move(mid, result, std::move(trail)); - std::move(std::move(first), std::move(mid), std::move(trail)); - return result; + if constexpr (is_category) { + auto mid = last; + if (bounded_advance(mid, -n, first)) { + return last; + } + return std::move_backward(std::move(first), std::move(mid), std::move(last)); + } else { + auto result = first; + if (bounded_advance(result, n, last)) { + return last; + } + + // Invariant: next(first, n) == result + // Invariant: next(trail, n) == lead + + auto lead = result; + auto trail = first; + + for (; trail != result; ++lead, void(++trail)) { + if (lead == last) { + // The range looks like: + // + // |-- (n - k) elements --|-- k elements --|-- (n - k) elements --| + // ^-first trail-^ ^-result last-^ + // + // Note that distance(first, trail) == distance(result, last) + std::move(std::move(first), std::move(trail), std::move(result)); + return result; + } + } + + for (;;) { + for (auto mid = first; mid != result; ++lead, void(++trail), ++mid) { + if (lead == last) { + // The range looks like: + // + // |-- (n - k) elements --|-- k elements --|-- ... --|-- n elements --| + // ^-first mid-^ result-^ ^-trail last-^ + // + trail = std::move(mid, result, std::move(trail)); + std::move(std::move(first), std::move(mid), std::move(trail)); + return result; + } + std::iter_swap(mid, trail); + } } - std::iter_swap(mid, trail); } } - } - } -} // namespace shift + } // namespace shift + } // namespace detail +} // namespace small #endif // !defined(SMALL_DETAIL_ALGORITHM_SHIFT_H) \ No newline at end of file diff --git a/source/small/detail/algorithm/strlen.h b/source/small/detail/algorithm/strlen.h index d0f74f3..0bb9f67 100644 --- a/source/small/detail/algorithm/strlen.h +++ b/source/small/detail/algorithm/strlen.h @@ -5,33 +5,34 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ALGORITHM_STRLEN_H #define SMALL_DETAIL_ALGORITHM_STRLEN_H #include namespace small { - /// \brief strlen for different character types - template inline std::size_t strlen(const T *str) { - std::size_t len = 0u; - while (*str++) { - ++len; + namespace detail { + /// \brief strlen for different character types + template inline std::size_t strlen(const T *str) { + std::size_t len = 0u; + while (*str++) { + ++len; + } + return len; } - return len; - } - /// \brief Usual strlen function - template <> inline std::size_t strlen(const char *str) { return std::strlen(str); } + /// \brief Usual strlen function + template <> inline std::size_t strlen(const char *str) { return std::strlen(str); } - /// \brief strlen for different character types with a size limit - template inline std::size_t strlen(const T *str, std::size_t limit) { - std::size_t len = 0u; - while (*str++ && len < limit) { - ++len; + /// \brief strlen for different character types with a size limit + template inline std::size_t strlen(const T *str, std::size_t limit) { + std::size_t len = 0u; + while (*str++ && len < limit) { + ++len; + } + return len; } - return len; - } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ALGORITHM_STRLEN_H diff --git a/source/small/detail/algorithm/to_unsigned.h b/source/small/detail/algorithm/to_unsigned.h index 2b52cb7..32b63ca 100644 --- a/source/small/detail/algorithm/to_unsigned.h +++ b/source/small/detail/algorithm/to_unsigned.h @@ -5,65 +5,66 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ALGORITHM_TO_UNSIGNED_H #define SMALL_DETAIL_ALGORITHM_TO_UNSIGNED_H +#include "../traits/is_range.h" #include #include -#include "../traits/is_range.h" namespace small { - /// \brief Convert a range of bytes to an unsigned number - /// We could use *(const std::uint8_t *)key_ptr, but this doesn't generalize well - /// specially because we have lots of cases where the output span has three bytes, - /// and mixing the two doesn't work well. - template < - typename Unsigned, typename InputIt, - std::enable_if_t< - std::is_unsigned_v && sizeof(typename std::iterator_traits::value_type) == 1, int> = 0> - constexpr Unsigned to_unsigned(InputIt first, InputIt last) { - Unsigned result = 0; - while (first != last) { - result <<= 8; - result |= static_cast(*first); - ++first; + namespace detail { + /// \brief Convert a range of bytes to an unsigned number + /// We could use *(const std::uint8_t *)key_ptr, but this doesn't generalize well + /// specially because we have lots of cases where the output span has three bytes, + /// and mixing the two doesn't work well. + template && + sizeof(typename std::iterator_traits::value_type) == 1, + int> = 0> + constexpr Unsigned to_unsigned(InputIt first, InputIt last) { + Unsigned result = 0; + while (first != last) { + result <<= 8; + result |= static_cast(*first); + ++first; + } + return result; } - return result; - } - template && is_range_v, int> = 0> - constexpr Unsigned to_unsigned(Range &&r) { - return to_unsigned(r.begin(), r.end()); - } + template && is_range_v, int> = 0> + constexpr Unsigned to_unsigned(Range &&r) { + return to_unsigned(r.begin(), r.end()); + } - /// \brief Convert an unsigned number to a span of bytes to an unsigned number - template < - typename Unsigned, typename OutputIt, - std::enable_if_t< - std::is_unsigned_v && sizeof(typename std::iterator_traits::value_type) == 1, int> = 0> - constexpr void to_bytes(Unsigned v, OutputIt first, OutputIt last) { - using byte_type = typename std::iterator_traits::value_type; - using difference_type = typename std::iterator_traits::difference_type; - difference_type distance = last - first; - assert(std::abs(distance) < std::numeric_limits::max()); - uint8_t bytes_to_fill = static_cast(std::abs(distance)); - assert(bytes_to_fill <= sizeof(Unsigned)); - uint8_t byte_shift = bytes_to_fill - 1; - while (first != last) { - *first = static_cast((v >> (byte_shift * 8)) & 0xFF); - ++first; - --byte_shift; + /// \brief Convert an unsigned number to a span of bytes to an unsigned number + template && + sizeof(typename std::iterator_traits::value_type) == 1, + int> = 0> + constexpr void to_bytes(Unsigned v, OutputIt first, OutputIt last) { + using byte_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + difference_type distance = last - first; + assert(std::abs(distance) < std::numeric_limits::max()); + uint8_t bytes_to_fill = static_cast(std::abs(distance)); + assert(bytes_to_fill <= sizeof(Unsigned)); + uint8_t byte_shift = bytes_to_fill - 1; + while (first != last) { + *first = static_cast((v >> (byte_shift * 8)) & 0xFF); + ++first; + --byte_shift; + } } - } - template && is_range_v, int> = 0> - constexpr void to_bytes(Unsigned v, Range &&r) { - return to_bytes(v, r.begin(), r.end()); - } + template && is_range_v, int> = 0> + constexpr void to_bytes(Unsigned v, Range &&r) { + return to_bytes(v, r.begin(), r.end()); + } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ALGORITHM_TO_UNSIGNED_H diff --git a/source/small/detail/algorithm/utf.h b/source/small/detail/algorithm/utf.h index a7e1bfd..87c5c4d 100644 --- a/source/small/detail/algorithm/utf.h +++ b/source/small/detail/algorithm/utf.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ALGORITHM_UTF_H #define SMALL_DETAIL_ALGORITHM_UTF_H @@ -19,636 +18,639 @@ /// are adapted from tiny-utf8 namespace small { - /// Set the types for UTF in C++ + namespace detail { + /// Set the types for UTF in C++ #ifdef cpp_char8_t - using utf8_char_type = char8_t; + using utf8_char_type = char8_t; #else - using utf8_char_type = char; + using utf8_char_type = char; #endif #ifdef cpp_unicode_characters - using utf16_char_type = char16_t; - using utf32_char_type = char32_t; + using utf16_char_type = char16_t; + using utf32_char_type = char32_t; #else - #error "Unicode characters not supported." + using utf16_char_type = uint16_t; + using utf32_char_type = uint32_t; #endif - /// \struct Identify the utf8 type of a char type - /// Integral types represent themselves, but wide char might sometimes be a proxy, like a codepoint_reference - /// which is only implicitly convertible to a utf32 char. - /// If it's integral, we use its size to decide. - /// If it's proxy, we attempt to convert from low to high. - /// This second heuristic might fail in intention. - namespace detail { - template - using is_utf_convertible = std::disjunction< - std::is_same, - std::conjunction, - std::conditional_t>, - std::conjunction>, - std::conditional_t, std::true_type, std::false_type>>>; - } - - template using is_utf8 = detail::is_utf_convertible; - - template constexpr bool is_utf8_v = is_utf8::value; - - template using is_utf16 = detail::is_utf_convertible; - - template constexpr bool is_utf16_v = is_utf16::value; - - template using is_utf32 = detail::is_utf_convertible; - - template constexpr bool is_utf32_v = is_utf32::value; - - /// \brief Trait to identify if two types have the same UTF encoding - template - using is_same_utf_encoding = std::disjunction, is_utf8>, - std::conjunction, is_utf16>, - std::conjunction, is_utf32>>; - - template - constexpr bool is_same_utf_encoding_v = is_same_utf_encoding::value; - - /// \brief Check if a char is a UTF8 continuation char/byte - /// If a string is well formed, a continuation char/byte is a char/byte that comes after the first - /// char/byte in a utf8 multibyte code point. - /// \note This function also accepts other char types containing utf8 information - /// \tparam Char Char type - /// \param ch The char that might be a continuation - /// \return True if that char is a utf8 continuation char - template constexpr bool is_utf8_continuation(Char ch) noexcept { - if (ch) { - // Char represented as unsigned integer - const uint32_t char_as_uint = (uint32_t)ch; - // Number of bits we need to shift left to put the char on the leftmost bytes - constexpr size_t shift_left_size = (sizeof(uint32_t) - 1) * 8; - // Shift char - const uint32_t char_leading = char_as_uint << shift_left_size; - // Count leading ones - auto codepoint_bytes = leading_zeros(~char_leading); - // Continuation bytes have one leading 1 - return cmp_equal(codepoint_bytes, 1); - } - return false; - } - - /// \brief Get number of utf8 bytes in a utf8 codepoint that starts with this char - /// - /// If the utf8 code point is well formed, it will have this number of chars. - /// - /// UTF8 size = 1: - /// - 0... last byte - /// UTF8 size = n: - /// - 1110... first byte of n code units - /// - 10... continuation byte - /// - 0... last byte - /// \param first_char First char in the codepoint - /// \param available_code_units How many code units there are for this utf8 codepoint, including first_char - /// \note available_code_units will truncate the utf8 size if there isn't enough codepoints for the size indicated - /// by the first char. Otherwise, only the first char is considered. - /// \return Number of bytes in this codepoint - template - constexpr Result utf8_size(Char first_char, Size available_code_units = 8) noexcept { - if (first_char) { - // Before counting the leading one's we need to shift the byte into the most significant part of the - // integer - constexpr size_t n_last_bits = (sizeof(unsigned int) - 1) * 8; - const unsigned int char_leading = (unsigned int)first_char << n_last_bits; - using unsigned_size = std::make_unsigned_t; - unsigned_size codepoint_bytes = leading_zeros(~char_leading); - - // The test below would actually be ( codepoint_bytes <= available_code_units && codepoint_bytes ), - // but codepoint_bytes is unsigned and thus wraps around zero, which makes the following faster: - if (unsigned_size(codepoint_bytes - 1) < unsigned_size(available_code_units)) { - return (Result)codepoint_bytes; - } + /// \struct Identify the utf8 type of a char type + /// Integral types represent themselves, but wide char might sometimes be a proxy, like a codepoint_reference + /// which is only implicitly convertible to a utf32 char. + /// If it's integral, we use its size to decide. + /// If it's proxy, we attempt to convert from low to high. + /// This second heuristic might fail in intention. + namespace detail { + template + using is_utf_convertible = std::disjunction< + std::is_same, + std::conjunction, + std::conditional_t>, + std::conjunction>, + std::conditional_t, std::true_type, std::false_type>>>; } - return 1; - } - - /// \brief Check if a char is a UTF16 surrogate char - /// If a string is well formed, a surrogate char is a char that comes in a pair of - /// chars representing a code point - /// \note This function also accepts other char types containing utf16 information - /// \tparam Char Char type - /// \param ch The char that might be a continuation - /// \return True if that char is a utf8 continuation char - template constexpr bool is_utf16_surrogate(Char16 ch) noexcept { - return cmp_less(ch - 0xd800u, 2048u); - } - - /// \brief Check if a char is a UTF16 high surrogate char - /// If a string is well formed, a surrogate char is a char that comes in a pair of - /// chars representing a code point - /// \note This function also accepts other char types containing utf16 information - /// \tparam Char Char type - /// \param ch The char that might be a continuation - /// \return True if that char is a utf8 continuation char - template constexpr bool is_utf16_high_surrogate(Char16 ch) noexcept { - return cmp_equal(ch & 0xfffffc00, 0xd800); - } - - /// \brief Check if a char is a UTF16 low surrogate char - /// If a string is well formed, a surrogate char is a char that comes in a pair of - /// chars representing a code point - /// \note This function also accepts other char types containing utf16 information - /// \tparam Char Char type - /// \param ch The char that might be a continuation - /// \return True if that char is a utf8 continuation char - template constexpr bool is_utf16_low_surrogate(Char16 ch) noexcept { - return cmp_equal(ch & 0xfffffc00, 0xdc00); - } - - /// \brief Convert a pair of surrogate bytes to UTF32 - /// If a string is well formed, a surrogate char is a char that comes in a pair of - /// chars representing a code point - /// \note This function also accepts other char types containing utf16 information - /// \tparam Char Char type - /// \tparam Size Size type - /// \param ch The char that might be a continuation - /// \return True if that char is a utf8 continuation char - template - Char32 utf16_surrogates_to_utf32(Char16 high, Char16 low) { - assert(is_utf16_high_surrogate(high)); - assert(is_utf16_low_surrogate(low)); - return (high << 10) + low - 0x35fdc00; - } - - /// \brief Check if a char is a UTF16 is a continuation char - /// In UTF16, this is equivalent to being a low surrogate - /// \tparam Char Char type - /// \param ch The char that might be a continuation - /// \return True if that char is a utf8 continuation char - template constexpr bool is_utf16_continuation(Char16 ch) noexcept { - return is_utf16_low_surrogate(ch); - } - - /// \brief Get number of utf16 code units in a utf16 codepoint that starts with this char - /// - /// This is much simpler than UTF8, where this size can vary a lot. - /// In UTF16, all we have to check is whether this char is a high surrogate. - /// - /// \param first_char First char in the codepoint - /// \param available_code_units How many code units there are for this utf8 codepoint, including first_char - /// \return Number of code units in this codepoint - template - constexpr Result utf16_size(Char first_char, Size available_code_units = 2) noexcept { - return is_utf16_high_surrogate(first_char) && available_code_units > 1 - ? 2 - : static_cast(std::min(Size(1), available_code_units)); - } - - /// \brief Check if a char is a UTF32 is a continuation char - /// In UTF32, there are no continuations. This function is only defined for symmetry. - /// \tparam Char Char type - /// \param ch The char that might be a continuation - /// \return True if that char is a utf32 continuation char - template constexpr bool is_utf32_continuation(Char32) noexcept { return false; } - - /// \brief Get number of utf32 code units in a utf32 codepoint that starts with this char - /// - /// In UTF32, all code points fit in a single code unit. - /// This function is only defined for symmetry. - /// - /// \param first_char First char in the codepoint - /// \param available_code_units How many code units there are for this utf8 codepoint, including first_char - /// \return Number of code units in this codepoint - template - constexpr Result utf32_size(Char32, Size available_code_units = 1) noexcept { - return static_cast(std::min(Size(1), available_code_units)); - } - - /// \brief Get size a utf32 char would have when/if converted to utf8 - /// This function is useful to use before actually converting the from/to another utf encoding - /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. - /// \param first_char Wide char with the codepoint - /// \return Number of bytes in potential utf8 codepoint - template - constexpr Result utf32_size_as_utf8(Char32 wide_char) noexcept { - const utf32_char_type integral_wide_char = wide_char; - if constexpr (system_has_leading_zeros_v) { - if (!integral_wide_char) { - return 1; + + template using is_utf8 = detail::is_utf_convertible; + + template constexpr bool is_utf8_v = is_utf8::value; + + template using is_utf16 = detail::is_utf_convertible; + + template constexpr bool is_utf16_v = is_utf16::value; + + template using is_utf32 = detail::is_utf_convertible; + + template constexpr bool is_utf32_v = is_utf32::value; + + /// \brief Trait to identify if two types have the same UTF encoding + template + using is_same_utf_encoding = std::disjunction, is_utf8>, + std::conjunction, is_utf16>, + std::conjunction, is_utf32>>; + + template + constexpr bool is_same_utf_encoding_v = is_same_utf_encoding::value; + + /// \brief Check if a char is a UTF8 continuation char/byte + /// If a string is well formed, a continuation char/byte is a char/byte that comes after the first + /// char/byte in a utf8 multibyte code point. + /// \note This function also accepts other char types containing utf8 information + /// \tparam Char Char type + /// \param ch The char that might be a continuation + /// \return True if that char is a utf8 continuation char + template constexpr bool is_utf8_continuation(Char ch) noexcept { + if (ch) { + // Char represented as unsigned integer + const uint32_t char_as_uint = (uint32_t)ch; + // Number of bits we need to shift left to put the char on the leftmost bytes + constexpr size_t shift_left_size = (sizeof(uint32_t) - 1) * 8; + // Shift char + const uint32_t char_leading = char_as_uint << shift_left_size; + // Count leading ones + auto codepoint_bytes = leading_zeros(~char_leading); + // Continuation bytes have one leading 1 + return cmp_equal(codepoint_bytes, 1); } - constexpr uint8_t lut[32] = {1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7}; - return lut[31 - leading_zeros(integral_wide_char)]; - } else { - if (integral_wide_char <= 0x7F) { - return 1; - } else if (integral_wide_char <= 0x7FF) { - return 2; - } else if (integral_wide_char <= 0xFFFF) { - return 3; - } else if (integral_wide_char <= 0x1FFFFF) { - return 4; - } else if (integral_wide_char <= 0x3FFFFFF) { - return 5; - } else if (integral_wide_char <= 0x7FFFFFFF) { - return 6; + return false; + } + + /// \brief Get number of utf8 bytes in a utf8 codepoint that starts with this char + /// + /// If the utf8 code point is well formed, it will have this number of chars. + /// + /// UTF8 size = 1: + /// - 0... last byte + /// UTF8 size = n: + /// - 1110... first byte of n code units + /// - 10... continuation byte + /// - 0... last byte + /// \param first_char First char in the codepoint + /// \param available_code_units How many code units there are for this utf8 codepoint, including first_char + /// \note available_code_units will truncate the utf8 size if there isn't enough codepoints for the size + /// indicated by the first char. Otherwise, only the first char is considered. \return Number of bytes in this + /// codepoint + template + constexpr Result utf8_size(Char first_char, Size available_code_units = 8) noexcept { + if (first_char) { + // Before counting the leading one's we need to shift the byte into the most significant part of the + // integer + constexpr size_t n_last_bits = (sizeof(unsigned int) - 1) * 8; + const unsigned int char_leading = (unsigned int)first_char << n_last_bits; + using unsigned_size = std::make_unsigned_t; + unsigned_size codepoint_bytes = leading_zeros(~char_leading); + + // The test below would actually be ( codepoint_bytes <= available_code_units && codepoint_bytes ), + // but codepoint_bytes is unsigned and thus wraps around zero, which makes the following faster: + if (unsigned_size(codepoint_bytes - 1) < unsigned_size(available_code_units)) { + return (Result)codepoint_bytes; + } } - return 7; - } - } - - /// \brief Get size a utf32 char would have when/if converted to utf16 - /// This function is useful to use before actually converting the from/to another utf encoding - /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. - /// \param first_char Wide char with the codepoint - /// \return Number of code units in potential utf16 codepoint - template constexpr Result utf32_size_as_utf16(Char32 ch) noexcept { - return (ch <= 0x0000FFFF) || (ch > 0x0010FFFF) ? 1 : 2; - } - - /// \brief Convert a sequence of UTF16 code points to a single UTF32 char - template = 0> - constexpr Char32 from_utf16_to_utf32(InputIt first, Size count) noexcept { - Char32 cp; - if (count == 0) { - return 0; + return 1; + } + + /// \brief Check if a char is a UTF16 surrogate char + /// If a string is well formed, a surrogate char is a char that comes in a pair of + /// chars representing a code point + /// \note This function also accepts other char types containing utf16 information + /// \tparam Char Char type + /// \param ch The char that might be a continuation + /// \return True if that char is a utf8 continuation char + template constexpr bool is_utf16_surrogate(Char16 ch) noexcept { + return cmp_less(ch - 0xd800u, 2048u); + } + + /// \brief Check if a char is a UTF16 high surrogate char + /// If a string is well formed, a surrogate char is a char that comes in a pair of + /// chars representing a code point + /// \note This function also accepts other char types containing utf16 information + /// \tparam Char Char type + /// \param ch The char that might be a continuation + /// \return True if that char is a utf8 continuation char + template constexpr bool is_utf16_high_surrogate(Char16 ch) noexcept { + return cmp_equal(ch & 0xfffffc00, 0xd800); } - if (!is_utf16_surrogate(first[0])) { - cp = first[0]; - } else { - if (is_utf16_high_surrogate(first[0]) && count > 1 && is_utf16_low_surrogate(first[1])) { - cp = utf16_surrogates_to_utf32(first[0], first[1]); + + /// \brief Check if a char is a UTF16 low surrogate char + /// If a string is well formed, a surrogate char is a char that comes in a pair of + /// chars representing a code point + /// \note This function also accepts other char types containing utf16 information + /// \tparam Char Char type + /// \param ch The char that might be a continuation + /// \return True if that char is a utf8 continuation char + template constexpr bool is_utf16_low_surrogate(Char16 ch) noexcept { + return cmp_equal(ch & 0xfffffc00, 0xdc00); + } + + /// \brief Convert a pair of surrogate bytes to UTF32 + /// If a string is well formed, a surrogate char is a char that comes in a pair of + /// chars representing a code point + /// \note This function also accepts other char types containing utf16 information + /// \tparam Char Char type + /// \tparam Size Size type + /// \param ch The char that might be a continuation + /// \return True if that char is a utf8 continuation char + template + Char32 utf16_surrogates_to_utf32(Char16 high, Char16 low) { + assert(is_utf16_high_surrogate(high)); + assert(is_utf16_low_surrogate(low)); + return (high << 10) + low - 0x35fdc00; + } + + /// \brief Check if a char is a UTF16 is a continuation char + /// In UTF16, this is equivalent to being a low surrogate + /// \tparam Char Char type + /// \param ch The char that might be a continuation + /// \return True if that char is a utf8 continuation char + template constexpr bool is_utf16_continuation(Char16 ch) noexcept { + return is_utf16_low_surrogate(ch); + } + + /// \brief Get number of utf16 code units in a utf16 codepoint that starts with this char + /// + /// This is much simpler than UTF8, where this size can vary a lot. + /// In UTF16, all we have to check is whether this char is a high surrogate. + /// + /// \param first_char First char in the codepoint + /// \param available_code_units How many code units there are for this utf8 codepoint, including first_char + /// \return Number of code units in this codepoint + template + constexpr Result utf16_size(Char first_char, Size available_code_units = 2) noexcept { + return is_utf16_high_surrogate(first_char) && available_code_units > 1 + ? 2 + : static_cast(std::min(Size(1), available_code_units)); + } + + /// \brief Check if a char is a UTF32 is a continuation char + /// In UTF32, there are no continuations. This function is only defined for symmetry. + /// \tparam Char Char type + /// \param ch The char that might be a continuation + /// \return True if that char is a utf32 continuation char + template constexpr bool is_utf32_continuation(Char32) noexcept { + return false; + } + + /// \brief Get number of utf32 code units in a utf32 codepoint that starts with this char + /// + /// In UTF32, all code points fit in a single code unit. + /// This function is only defined for symmetry. + /// + /// \param first_char First char in the codepoint + /// \param available_code_units How many code units there are for this utf8 codepoint, including first_char + /// \return Number of code units in this codepoint + template + constexpr Result utf32_size(Char32, Size available_code_units = 1) noexcept { + return static_cast(std::min(Size(1), available_code_units)); + } + + /// \brief Get size a utf32 char would have when/if converted to utf8 + /// This function is useful to use before actually converting the from/to another utf encoding + /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. + /// \param first_char Wide char with the codepoint + /// \return Number of bytes in potential utf8 codepoint + template + constexpr Result utf32_size_as_utf8(Char32 wide_char) noexcept { + const utf32_char_type integral_wide_char = wide_char; + if constexpr (system_has_leading_zeros_v) { + if (!integral_wide_char) { + return 1; + } + constexpr uint8_t lut[32] = {1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7}; + return lut[31 - leading_zeros(integral_wide_char)]; } else { - return 0; + if (integral_wide_char <= 0x7F) { + return 1; + } else if (integral_wide_char <= 0x7FF) { + return 2; + } else if (integral_wide_char <= 0xFFFF) { + return 3; + } else if (integral_wide_char <= 0x1FFFFF) { + return 4; + } else if (integral_wide_char <= 0x3FFFFFF) { + return 5; + } else if (integral_wide_char <= 0x7FFFFFFF) { + return 6; + } + return 7; } } - return cp; - } - - /// \brief Get size a utf16 sequence would have when/if converted to utf8 - /// This function is useful to use before actually converting the from/to another utf encoding - /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. - /// \param source Iterator to first element in the UTF16 sequence - /// \param source_count Number of elements in the UTF16 code point - /// \return Number of bytes in potential utf8 codepoint - template - constexpr Result utf16_size_as_utf8(InputIt source, Size source_count) noexcept { - utf32_char_type wider_char = from_utf16_to_utf32(source, source_count); - return utf32_size_as_utf8(wider_char); - } - - /// \brief Get size a utf8 sequence would have when/if converted to utf16 - /// This function is useful to use before actually converting the from/to another utf encoding - /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. - /// \param source Iterator to first element in the UTF16 sequence - /// \param source_count Number of elements in the UTF16 code point - /// \return Number of code units in potential utf16 codepoint - template - constexpr Result utf8_size_as_utf16(InputIt source, Size source_count) noexcept { - utf32_char_type wider_char = from_utf8_to_utf32(source, source_count); - return utf32_size_as_utf16(wider_char); - } - - /// \brief Get size a utf16 char would have when/if converted to utf32 - /// This is always 1 for utf32, but we keep this function for symmetry - /// This function is useful to use before actually converting the from/to another utf encoding - /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf32. - /// \param first_char Wide char with the codepoint - /// \return Number of code units in potential utf32 codepoint - template - constexpr Result utf16_size_as_utf32(InputIt, Size count) noexcept { - return std::min(1, count); - } - - /// \brief Get size a utf8 sequence would have when/if converted to utf32 - /// This is always 1 for utf32, but we keep this function for symmetry - /// This function is useful to use before actually converting the from/to another utf encoding - /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. - /// \param source Iterator to first element in the UTF8 sequence - /// \param source_count Number of elements in the UTF8 code point - /// \return Number of code units in potential utf32 codepoint - template - constexpr Result utf8_size_as_utf32(InputIt, Size count) noexcept { - return std::min(1, count); - } - - /// \brief Get size a utf sequence would have when/if converted to utf8 - /// The input encoding is inferred from the input type - template - constexpr Result utf_size_as_utf8(InputIt source, Size count) noexcept { - using input_value_type = typename std::iterator_traits::value_type; - if constexpr (is_utf32_v) { - return utf32_size_as_utf8(*source); - } else if constexpr (is_utf16_v) { - return utf16_size_as_utf8(source, count); - } else { - return utf8_size(*source, count); - } - } - - /// \brief Get size a utf sequence would have when/if converted to utf16 - /// The input encoding is inferred from the input type - template - constexpr Result utf_size_as_utf16(InputIt source, Size count) noexcept { - using input_value_type = typename std::iterator_traits::value_type; - if constexpr (is_utf32_v) { - return utf32_size_as_utf16(*source); - } else if constexpr (is_utf16_v) { - return utf16_size(*source, count); - } else { - return utf8_size_as_utf16(source, count); - } - } - - /// \brief Get size a utf sequence would have when/if converted to utf32 - /// The input encoding is inferred from the input type - template - constexpr Result utf_size_as_utf32(InputIt, Size count) noexcept { - return std::min(1, count); - } - - /// \brief Get size a utf sequence would have when/if converted to utf8/utf16/utf32 - /// The input encoding is inferred from the input type - /// The output encoding is inferred from the output type - template - constexpr Result utf_size_as(InputIt source, Size count) noexcept { - if constexpr (is_utf32_v) { - return utf_size_as_utf32(source, count); - } else if constexpr (is_utf16_v) { - return utf_size_as_utf16(source, count); - } else { - return utf_size_as_utf8(source, count); - } - } - - /// \brief Check if a char is a UTF continuation char - /// The encoding is inferred from the input type. - /// \tparam Char Char type - /// \param ch The char that might be a continuation - /// \return True if that char is a utf32 continuation char - template constexpr bool is_utf_continuation(Char ch) noexcept { - if constexpr (is_utf32_v) { - return is_utf32_continuation(ch); - } else if constexpr (is_utf16_v) { - return is_utf16_continuation(ch); - } else { - return is_utf8_continuation(ch); - } - } - - /// \brief Get number of utf code units in a utf codepoint that starts with this char - /// The encoding is inferred from the input type. - /// \param first_char First char in the codepoint - /// \param available_code_units How many code units there are for this utf8 codepoint, including first_char - /// \return Number of code units in this codepoint - template - constexpr Result utf_size(Char first_char, Size available_code_units) noexcept { - if constexpr (is_utf32_v) { - return utf32_size(first_char, available_code_units); - } else if constexpr (is_utf16_v) { - return utf16_size(first_char, available_code_units); - } else { - return utf8_size(first_char, available_code_units); - } - } - - /// \brief Convert a sequence of utf8 byte / code units into an utf16 array of code units - template - Size2 from_utf8_to_utf16(InputIt src, Size1 utf8_size, OutputIt dest, Size2 utf16_size) noexcept { - // Convert to unicode bits - size_t source_idx = 0; - unsigned long uni; - size_t todo; - unsigned char ch = src[source_idx++]; - if (ch <= 0x7F) { - uni = ch; - todo = 0; - } else if (ch <= 0xBF) { - // Invalid input - return 0; - } else if (ch <= 0xDF) { - uni = ch & 0x1F; - todo = 1; - } else if (ch <= 0xEF) { - uni = ch & 0x0F; - todo = 2; - } else if (ch <= 0xF7) { - uni = ch & 0x07; - todo = 3; - } else { - // Invalid input - return 0; + + /// \brief Get size a utf32 char would have when/if converted to utf16 + /// This function is useful to use before actually converting the from/to another utf encoding + /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. + /// \param first_char Wide char with the codepoint + /// \return Number of code units in potential utf16 codepoint + template constexpr Result utf32_size_as_utf16(Char32 ch) noexcept { + return (ch <= 0x0000FFFF) || (ch > 0x0010FFFF) ? 1 : 2; } - for (size_t j = 0; j < todo; ++j) { - if (cmp_equal(source_idx, utf8_size)) { - // Invalid input + + /// \brief Convert a sequence of UTF16 code points to a single UTF32 char + template = 0> + constexpr Char32 from_utf16_to_utf32(InputIt first, Size count) noexcept { + Char32 cp; + if (count == 0) { return 0; } - unsigned char ch2 = src[source_idx++]; - if (ch2 < 0x80 || ch2 > 0xBF) - // Invalid input - return 0; - uni <<= 6; - uni += ch2 & 0x3F; + if (!is_utf16_surrogate(first[0])) { + cp = first[0]; + } else { + if (is_utf16_high_surrogate(first[0]) && count > 1 && is_utf16_low_surrogate(first[1])) { + cp = utf16_surrogates_to_utf32(first[0], first[1]); + } else { + return 0; + } + } + return cp; } - if (uni >= 0xD800 && uni <= 0xDFFF) - // Invalid input - return 0; - if (uni > 0x10FFFF) - // Invalid input - return 0; - // Convert unicode to UTF16 output - if (uni <= 0xFFFF) { - if (utf16_size > 0) { - *dest = (wchar_t)uni; - return 1; + /// \brief Get size a utf16 sequence would have when/if converted to utf8 + /// This function is useful to use before actually converting the from/to another utf encoding + /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. + /// \param source Iterator to first element in the UTF16 sequence + /// \param source_count Number of elements in the UTF16 code point + /// \return Number of bytes in potential utf8 codepoint + template + constexpr Result utf16_size_as_utf8(InputIt source, Size source_count) noexcept { + utf32_char_type wider_char = from_utf16_to_utf32(source, source_count); + return utf32_size_as_utf8(wider_char); + } + + /// \brief Get size a utf8 sequence would have when/if converted to utf16 + /// This function is useful to use before actually converting the from/to another utf encoding + /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. + /// \param source Iterator to first element in the UTF16 sequence + /// \param source_count Number of elements in the UTF16 code point + /// \return Number of code units in potential utf16 codepoint + template + constexpr Result utf8_size_as_utf16(InputIt source, Size source_count) noexcept { + utf32_char_type wider_char = from_utf8_to_utf32(source, source_count); + return utf32_size_as_utf16(wider_char); + } + + /// \brief Get size a utf16 char would have when/if converted to utf32 + /// This is always 1 for utf32, but we keep this function for symmetry + /// This function is useful to use before actually converting the from/to another utf encoding + /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf32. + /// \param first_char Wide char with the codepoint + /// \return Number of code units in potential utf32 codepoint + template + constexpr Result utf16_size_as_utf32(InputIt, Size count) noexcept { + return std::min(1, count); + } + + /// \brief Get size a utf8 sequence would have when/if converted to utf32 + /// This is always 1 for utf32, but we keep this function for symmetry + /// This function is useful to use before actually converting the from/to another utf encoding + /// If the char is a malformed, i.e. a continuation code unit, we consider the malformed size in utf8. + /// \param source Iterator to first element in the UTF8 sequence + /// \param source_count Number of elements in the UTF8 code point + /// \return Number of code units in potential utf32 codepoint + template + constexpr Result utf8_size_as_utf32(InputIt, Size count) noexcept { + return std::min(1, count); + } + + /// \brief Get size a utf sequence would have when/if converted to utf8 + /// The input encoding is inferred from the input type + template + constexpr Result utf_size_as_utf8(InputIt source, Size count) noexcept { + using input_value_type = typename std::iterator_traits::value_type; + if constexpr (is_utf32_v) { + return utf32_size_as_utf8(*source); + } else if constexpr (is_utf16_v) { + return utf16_size_as_utf8(source, count); } else { - return 0; + return utf8_size(*source, count); } - } else { - uni -= 0x10000; - if (utf16_size > 0) { - *dest = (wchar_t)((uni >> 10) + 0xD800); - ++dest; + } + + /// \brief Get size a utf sequence would have when/if converted to utf16 + /// The input encoding is inferred from the input type + template + constexpr Result utf_size_as_utf16(InputIt source, Size count) noexcept { + using input_value_type = typename std::iterator_traits::value_type; + if constexpr (is_utf32_v) { + return utf32_size_as_utf16(*source); + } else if constexpr (is_utf16_v) { + return utf16_size(*source, count); } else { - return 0; + return utf8_size_as_utf16(source, count); } - if (utf16_size > 1) { - *dest = (wchar_t)((uni & 0x3FF) + 0xDC00); - return 2; + } + + /// \brief Get size a utf sequence would have when/if converted to utf32 + /// The input encoding is inferred from the input type + template + constexpr Result utf_size_as_utf32(InputIt, Size count) noexcept { + return std::min(1, count); + } + + /// \brief Get size a utf sequence would have when/if converted to utf8/utf16/utf32 + /// The input encoding is inferred from the input type + /// The output encoding is inferred from the output type + template + constexpr Result utf_size_as(InputIt source, Size count) noexcept { + if constexpr (is_utf32_v) { + return utf_size_as_utf32(source, count); + } else if constexpr (is_utf16_v) { + return utf_size_as_utf16(source, count); } else { - return 1; + return utf_size_as_utf8(source, count); } } - } - - /// \brief Convert a sequence of utf8 bytes to a single UTF32 char - template = 0> - constexpr Char32 from_utf8_to_utf32(InputIt first, Size count) noexcept { - Char32 cp = (unsigned char)*first; - if (count > 1) { - // Mask out the header bits - cp &= 0x7F >> count; - for (uint8_t i = 1; i < count; i++) { - cp = (cp << 6) | ((unsigned char)first[i] & 0x3F); + + /// \brief Check if a char is a UTF continuation char + /// The encoding is inferred from the input type. + /// \tparam Char Char type + /// \param ch The char that might be a continuation + /// \return True if that char is a utf32 continuation char + template constexpr bool is_utf_continuation(Char ch) noexcept { + if constexpr (is_utf32_v) { + return is_utf32_continuation(ch); + } else if constexpr (is_utf16_v) { + return is_utf16_continuation(ch); + } else { + return is_utf8_continuation(ch); + } + } + + /// \brief Get number of utf code units in a utf codepoint that starts with this char + /// The encoding is inferred from the input type. + /// \param first_char First char in the codepoint + /// \param available_code_units How many code units there are for this utf8 codepoint, including first_char + /// \return Number of code units in this codepoint + template + constexpr Result utf_size(Char first_char, Size available_code_units) noexcept { + if constexpr (is_utf32_v) { + return utf32_size(first_char, available_code_units); + } else if constexpr (is_utf16_v) { + return utf16_size(first_char, available_code_units); + } else { + return utf8_size(first_char, available_code_units); } } - return cp; - } - - /// \brief Convert a utf32 char/codepoint into an utf8 array of bytes - /// The destination iterator should be able to hold utf8 size bytes - /// \param wide_char A wide char - /// \param dest Destination of the utf8 code units - /// \param utf8_size Size of the utf8 array - /// \return utf8 size inserted in dest - template - Size from_utf32_to_utf8(Char32 ch, OutputIt dest, Size utf8_size) noexcept { - uint8_t size_in_utf8 = utf32_size_as_utf8(ch); - switch (min_value(min_value(size_in_utf8, utf8_size), sizeof(Char32))) { - case 7: - *std::next(dest, size_in_utf8 - 6) = 0x80 | ((ch >> 30) & 0x3F); - [[fallthrough]]; - case 6: - *std::next(dest, size_in_utf8 - 5) = 0x80 | ((ch >> 24) & 0x3F); - [[fallthrough]]; - case 5: - *std::next(dest, size_in_utf8 - 4) = 0x80 | ((ch >> 18) & 0x3F); - [[fallthrough]]; - case 4: - *std::next(dest, size_in_utf8 - 3) = 0x80 | ((ch >> 12) & 0x3F); - [[fallthrough]]; - case 3: - *std::next(dest, size_in_utf8 - 2) = 0x80 | ((ch >> 6) & 0x3F); - [[fallthrough]]; - case 2: - *std::next(dest, size_in_utf8 - 1) = 0x80 | ((ch >> 0) & 0x3F); - *std::next(dest, 0) = - (unsigned char)((std::uint_least16_t(0xFF00uL) >> size_in_utf8) | (ch >> (6 * size_in_utf8 - 6))); - break; - case 1: - *std::next(dest, 0) = (unsigned char)ch; - break; - } - return size_in_utf8; - } - - /// \brief Convert a utf32 code point to a sequence of utf16 code units - template - Size from_utf32_to_utf16(Char32 ch, OutputIt dest, Size utf16_size) noexcept { - using dest_value_type = typename std::iterator_traits::value_type; - if (utf16_size != 0) { - if (ch <= 0x0000FFFF) { - /* UTF-16 surrogate values are illegal in UTF-32 - 0xFFFF or 0xFFFE are both reserved values */ - if (ch >= 0xD800 && ch <= 0xDFFF) { - *dest++ = 0x0000FFFD; + + /// \brief Convert a sequence of utf8 byte / code units into an utf16 array of code units + template + Size2 from_utf8_to_utf16(InputIt src, Size1 utf8_size, OutputIt dest, Size2 utf16_size) noexcept { + // Convert to unicode bits + size_t source_idx = 0; + unsigned long uni; + size_t todo; + unsigned char ch = src[source_idx++]; + if (ch <= 0x7F) { + uni = ch; + todo = 0; + } else if (ch <= 0xBF) { + // Invalid input + return 0; + } else if (ch <= 0xDF) { + uni = ch & 0x1F; + todo = 1; + } else if (ch <= 0xEF) { + uni = ch & 0x0F; + todo = 2; + } else if (ch <= 0xF7) { + uni = ch & 0x07; + todo = 3; + } else { + // Invalid input + return 0; + } + for (size_t j = 0; j < todo; ++j) { + if (cmp_equal(source_idx, utf8_size)) { + // Invalid input + return 0; + } + unsigned char ch2 = src[source_idx++]; + if (ch2 < 0x80 || ch2 > 0xBF) + // Invalid input + return 0; + uni <<= 6; + uni += ch2 & 0x3F; + } + if (uni >= 0xD800 && uni <= 0xDFFF) + // Invalid input + return 0; + if (uni > 0x10FFFF) + // Invalid input + return 0; + + // Convert unicode to UTF16 output + if (uni <= 0xFFFF) { + if (utf16_size > 0) { + *dest = (wchar_t)uni; + return 1; } else { - /* source is a BMP Character */ - *dest = static_cast(ch); + return 0; + } + } else { + uni -= 0x10000; + if (utf16_size > 0) { + *dest = (wchar_t)((uni >> 10) + 0xD800); ++dest; + } else { + return 0; } - return 1; - } else if (ch > 0x0010FFFF) { - /* U+10FFFF is the largest code point of Unicode Character Set */ - *dest = 0x0000FFFD; - ++dest; + if (utf16_size > 1) { + *dest = (wchar_t)((uni & 0x3FF) + 0xDC00); + return 2; + } else { + return 1; + } + } + } + + /// \brief Convert a sequence of utf8 bytes to a single UTF32 char + template = 0> + constexpr Char32 from_utf8_to_utf32(InputIt first, Size count) noexcept { + Char32 cp = (unsigned char)*first; + if (count > 1) { + // Mask out the header bits + cp &= 0x7F >> count; + for (uint8_t i = 1; i < count; i++) { + cp = (cp << 6) | ((unsigned char)first[i] & 0x3F); + } + } + return cp; + } + + /// \brief Convert a utf32 char/codepoint into an utf8 array of bytes + /// The destination iterator should be able to hold utf8 size bytes + /// \param wide_char A wide char + /// \param dest Destination of the utf8 code units + /// \param utf8_size Size of the utf8 array + /// \return utf8 size inserted in dest + template + Size from_utf32_to_utf8(Char32 ch, OutputIt dest, Size utf8_size) noexcept { + uint8_t size_in_utf8 = utf32_size_as_utf8(ch); + switch (min_value(min_value(size_in_utf8, utf8_size), sizeof(Char32))) { + case 7: + *std::next(dest, size_in_utf8 - 6) = 0x80 | ((ch >> 30) & 0x3F); + [[fallthrough]]; + case 6: + *std::next(dest, size_in_utf8 - 5) = 0x80 | ((ch >> 24) & 0x3F); + [[fallthrough]]; + case 5: + *std::next(dest, size_in_utf8 - 4) = 0x80 | ((ch >> 18) & 0x3F); + [[fallthrough]]; + case 4: + *std::next(dest, size_in_utf8 - 3) = 0x80 | ((ch >> 12) & 0x3F); + [[fallthrough]]; + case 3: + *std::next(dest, size_in_utf8 - 2) = 0x80 | ((ch >> 6) & 0x3F); + [[fallthrough]]; + case 2: + *std::next(dest, size_in_utf8 - 1) = 0x80 | ((ch >> 0) & 0x3F); + *std::next(dest, 0) = + (unsigned char)((std::uint_least16_t(0xFF00uL) >> size_in_utf8) | (ch >> (6 * size_in_utf8 - 6))); + break; + case 1: + *std::next(dest, 0) = (unsigned char)ch; + break; + } + return size_in_utf8; + } + + /// \brief Convert a utf32 code point to a sequence of utf16 code units + template + Size from_utf32_to_utf16(Char32 ch, OutputIt dest, Size utf16_size) noexcept { + using dest_value_type = typename std::iterator_traits::value_type; + if (utf16_size != 0) { + if (ch <= 0x0000FFFF) { + /* UTF-16 surrogate values are illegal in UTF-32 + 0xFFFF or 0xFFFE are both reserved values */ + if (ch >= 0xD800 && ch <= 0xDFFF) { + *dest++ = 0x0000FFFD; + } else { + /* source is a BMP Character */ + *dest = static_cast(ch); + ++dest; + } + return 1; + } else if (ch > 0x0010FFFF) { + /* U+10FFFF is the largest code point of Unicode Character Set */ + *dest = 0x0000FFFD; + ++dest; + return 1; + } else { + /* source is a character in range 0xFFFF - 0x10FFFF */ + ch -= 0x0010000UL; + *dest++ = static_cast((ch >> 10) + 0xD800); + *dest++ = static_cast((ch & 0x3FFUL) + 0xDC00); + return 2; + } + } + return 0; + } + + /// \brief Convert a sequence of utf16 code units into an utf8 array of bytes + template + OutputSize from_utf16_to_utf8(InputIt src, InputSize utf16_size, OutputIt dest, OutputSize utf8_size) noexcept { + auto utf32_cp = from_utf16_to_utf32(src, utf16_size); + return from_utf32_to_utf8(utf32_cp, dest, utf8_size); + } + + /// \brief Convert a range of utf8/utf16/utf32 code units to a range of utf8 code units + /// The source UTF type is inferred from the input type + /// The destination iterator should be able to hold the required number of code units + /// \return Number of code units inserted in the destination + template + uint8_t to_utf8(InputIt source, InputSize source_count, OutputIt dest, OutputSize dest_count) noexcept { + using input_value_type = typename std::iterator_traits::value_type; + if constexpr (is_utf32_v) { + return static_cast(from_utf32_to_utf8(*source, dest, dest_count)); + } else if constexpr (is_utf16_v) { + return static_cast(from_utf16_to_utf8(source, source_count, dest, dest_count)); + } else { + using output_value_type = typename std::iterator_traits::value_type; + std::transform(source, source + min_value(source_count, dest_count), dest, + [](auto in) { return static_cast(in); }); + return static_cast(min_value(source_count, dest_count)); + } + } + + /// \brief Convert a range of utf8/utf16/utf32 code units to a range of utf16 code units + /// The source UTF type is inferred from the input type + /// The destination iterator should be able to hold the required number of code units + /// \return Number of code units inserted in the destination + template + uint8_t to_utf16(InputIt source, InputSize source_count, OutputIt dest, OutputSize dest_count) noexcept { + using input_value_type = typename std::iterator_traits::value_type; + if constexpr (is_utf32_v) { + return static_cast(from_utf32_to_utf16(*source, dest, dest_count)); + } else if constexpr (is_utf16_v) { + using output_value_type = typename std::iterator_traits::value_type; + std::transform(source, source + std::min(source_count, dest_count), dest, + [](auto in) { return static_cast(in); }); + return static_cast(std::min(source_count, dest_count)); + } else { + return static_cast(from_utf8_to_utf16(source, source_count, dest, dest_count)); + } + } + + /// \brief Convert a range of utf8/utf16/utf32 code units to a range of utf32 code units + /// The source UTF type is inferred from the input type + /// The destination iterator should be able to hold the required number of code units + /// We are only going to spend one code unit for the UTF32 codepoint, but we still + /// expect an iterator as input in conformity with the other conversion functions. + /// \return Number of code units inserted in the destination + template + uint8_t to_utf32(InputIt source, InputSize source_count, OutputIt dest, OutputSize dest_count) noexcept { + using input_value_type = typename std::iterator_traits::value_type; + if constexpr (is_utf32_v) { + using output_value_type = typename std::iterator_traits::value_type; + std::transform(source, source + min_value(source_count, dest_count), dest, + [](auto in) { return static_cast(in); }); + return static_cast(min_value(source_count, dest_count)); + } else if constexpr (is_utf16_v) { + *dest = from_utf16_to_utf32(source, source_count); return 1; } else { - /* source is a character in range 0xFFFF - 0x10FFFF */ - ch -= 0x0010000UL; - *dest++ = static_cast((ch >> 10) + 0xD800); - *dest++ = static_cast((ch & 0x3FFUL) + 0xDC00); - return 2; + *dest = from_utf8_to_utf32(source, source_count); + return 1; } } - return 0; - } - - /// \brief Convert a sequence of utf16 code units into an utf8 array of bytes - template - OutputSize from_utf16_to_utf8(InputIt src, InputSize utf16_size, OutputIt dest, OutputSize utf8_size) noexcept { - auto utf32_cp = from_utf16_to_utf32(src, utf16_size); - return from_utf32_to_utf8(utf32_cp, dest, utf8_size); - } - - /// \brief Convert a range of utf8/utf16/utf32 code units to a range of utf8 code units - /// The source UTF type is inferred from the input type - /// The destination iterator should be able to hold the required number of code units - /// \return Number of code units inserted in the destination - template - uint8_t to_utf8(InputIt source, InputSize source_count, OutputIt dest, OutputSize dest_count) noexcept { - using input_value_type = typename std::iterator_traits::value_type; - if constexpr (is_utf32_v) { - return static_cast(from_utf32_to_utf8(*source, dest, dest_count)); - } else if constexpr (is_utf16_v) { - return static_cast(from_utf16_to_utf8(source, source_count, dest, dest_count)); - } else { - using output_value_type = typename std::iterator_traits::value_type; - std::transform(source, source + min_value(source_count, dest_count), dest, - [](auto in) { return static_cast(in); }); - return static_cast(min_value(source_count, dest_count)); - } - } - - /// \brief Convert a range of utf8/utf16/utf32 code units to a range of utf16 code units - /// The source UTF type is inferred from the input type - /// The destination iterator should be able to hold the required number of code units - /// \return Number of code units inserted in the destination - template - uint8_t to_utf16(InputIt source, InputSize source_count, OutputIt dest, OutputSize dest_count) noexcept { - using input_value_type = typename std::iterator_traits::value_type; - if constexpr (is_utf32_v) { - return static_cast(from_utf32_to_utf16(*source, dest, dest_count)); - } else if constexpr (is_utf16_v) { - using output_value_type = typename std::iterator_traits::value_type; - std::transform(source, source + std::min(source_count, dest_count), dest, - [](auto in) { return static_cast(in); }); - return static_cast(std::min(source_count, dest_count)); - } else { - return static_cast(from_utf8_to_utf16(source, source_count, dest, dest_count)); - } - } - - /// \brief Convert a range of utf8/utf16/utf32 code units to a range of utf32 code units - /// The source UTF type is inferred from the input type - /// The destination iterator should be able to hold the required number of code units - /// We are only going to spend one code unit for the UTF32 codepoint, but we still - /// expect an iterator as input in conformity with the other conversion functions. - /// \return Number of code units inserted in the destination - template - uint8_t to_utf32(InputIt source, InputSize source_count, OutputIt dest, OutputSize dest_count) noexcept { - using input_value_type = typename std::iterator_traits::value_type; - if constexpr (is_utf32_v) { + + /// \brief Convert a range of utf8/utf16/or utf32 code units to a range of utf8/utf16/or utf32 code units + /// The source UTF type is inferred from the input type. + /// The output UTF type is inferred from the output type. + /// The destination iterator should be able to hold the required number of code units. + /// \return Number of code units inserted in the destination + template + uint8_t to_utf(InputIt source, InputSize source_count, OutputIt dest, OutputSize dest_count) noexcept { using output_value_type = typename std::iterator_traits::value_type; - std::transform(source, source + min_value(source_count, dest_count), dest, [](auto in) { - return static_cast(in); - }); - return static_cast(min_value(source_count, dest_count)); - } else if constexpr (is_utf16_v) { - *dest = from_utf16_to_utf32(source, source_count); - return 1; - } else { - *dest = from_utf8_to_utf32(source, source_count); - return 1; + if constexpr (is_utf32_v) { + return to_utf32(source, source_count, dest, dest_count); + } else if constexpr (is_utf16_v) { + return to_utf16(source, source_count, dest, dest_count); + } else { + return to_utf8(source, source_count, dest, dest_count); + } } - } - - /// \brief Convert a range of utf8/utf16/or utf32 code units to a range of utf8/utf16/or utf32 code units - /// The source UTF type is inferred from the input type. - /// The output UTF type is inferred from the output type. - /// The destination iterator should be able to hold the required number of code units. - /// \return Number of code units inserted in the destination - template - uint8_t to_utf(InputIt source, InputSize source_count, OutputIt dest, OutputSize dest_count) noexcept { - using output_value_type = typename std::iterator_traits::value_type; - if constexpr (is_utf32_v) { - return to_utf32(source, source_count, dest, dest_count); - } else if constexpr (is_utf16_v) { - return to_utf16(source, source_count, dest, dest_count); - } else { - return to_utf8(source, source_count, dest, dest_count); - } - } - + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ALGORITHM_UTF_H diff --git a/source/small/detail/container/aligned_storage_vector.h b/source/small/detail/container/aligned_storage_vector.h index d72b6d0..28b5d62 100644 --- a/source/small/detail/container/aligned_storage_vector.h +++ b/source/small/detail/container/aligned_storage_vector.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_CONTAINER_ALIGNED_STORAGE_VECTOR_H #define SMALL_DETAIL_CONTAINER_ALIGNED_STORAGE_VECTOR_H @@ -23,672 +22,675 @@ /// This is only here for reference namespace small { - /// Forward-declare small_vector to make it a friend of aligned_storage_vector - template class vector; - - /// \brief Small array of elements - /// This is a class very similar to small_vector in the - /// sense that it allocates elements in the stack. - /// The main difference is once we reach the maximum - /// aligned_storage_vector capacity, there's no buffer to allocate extra - /// elements. This is useful when we know we won't need - /// this buffer or we can erase elements we don't need - /// at certain points. - /// \note This is somewhat equivalent to boost::static_vector - /// \tparam T Array type - /// \tparam N Array maximum size - template ) * 4) / sizeof(T), std::size_t(5))> - class aligned_storage_vector { - public /* types */: - // There's no custom allocator for aligned_storage_vector - typedef T &reference; - typedef const T &const_reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef T *pointer; - typedef const T *const_pointer; - typedef pointer_wrapper iterator; - typedef pointer_wrapper const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - public /* constructors */: - /// \brief Construct empty small array - constexpr aligned_storage_vector() noexcept : aligned_storage_vector(0) {} - - /// \brief Construct small array with size n - constexpr explicit aligned_storage_vector(size_type n) : size_(n) { - for (size_type pos = 0; pos < size_; ++pos) { - construct_at(pos); - } - assert(invariants()); - } + namespace detail { + /// Forward-declare small_vector to make it a friend of aligned_storage_vector + template class vector; + + /// \brief Small array of elements + /// This is a class very similar to small_vector in the + /// sense that it allocates elements in the stack. + /// The main difference is once we reach the maximum + /// aligned_storage_vector capacity, there's no buffer to allocate extra + /// elements. This is useful when we know we won't need + /// this buffer or we can erase elements we don't need + /// at certain points. + /// \note This is somewhat equivalent to boost::static_vector + /// \tparam T Array type + /// \tparam N Array maximum size + template ) * 4) / sizeof(T), std::size_t(5))> + class aligned_storage_vector { + public /* types */: + // There's no custom allocator for aligned_storage_vector + typedef T &reference; + typedef const T &const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef pointer_wrapper iterator; + typedef pointer_wrapper const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + public /* constructors */: + /// \brief Construct empty small array + constexpr aligned_storage_vector() noexcept : aligned_storage_vector(0) {} + + /// \brief Construct small array with size n + constexpr explicit aligned_storage_vector(size_type n) : size_(n) { + for (size_type pos = 0; pos < size_; ++pos) { + construct_at(pos); + } + assert(invariants()); + } - /// \brief Construct small array with size n and fill with single value - constexpr aligned_storage_vector(size_type n, const value_type &value) : size_(n) { - for (size_type pos = 0; pos < size_; ++pos) { - construct_at(pos, value); + /// \brief Construct small array with size n and fill with single value + constexpr aligned_storage_vector(size_type n, const value_type &value) : size_(n) { + for (size_type pos = 0; pos < size_; ++pos) { + construct_at(pos, value); + } + assert(invariants()); } - assert(invariants()); - } - /// \brief Construct small array from a pair of iterators - template - constexpr aligned_storage_vector(InputIterator first, enable_if_iterator_t last) - : size_(std::distance(first, last)) { - auto it = first; - for (size_type pos = 0; pos < size_; ++pos) { - construct_at(pos, *it); - ++it; + /// \brief Construct small array from a pair of iterators + template + constexpr aligned_storage_vector(InputIterator first, enable_if_iterator_t last) + : size_(std::distance(first, last)) { + auto it = first; + for (size_type pos = 0; pos < size_; ++pos) { + construct_at(pos, *it); + ++it; + } + assert(invariants()); } - assert(invariants()); - } - /// \brief Construct small array from initializer list - constexpr aligned_storage_vector(std::initializer_list il) - : aligned_storage_vector(il.begin(), il.end()) {} + /// \brief Construct small array from initializer list + constexpr aligned_storage_vector(std::initializer_list il) + : aligned_storage_vector(il.begin(), il.end()) {} - public /* rule of five */: - /// \brief Rule of 5: Destructor - ~aligned_storage_vector() { - // Call the destructor for element we previously allocated - destroy_all(); - } + public /* rule of five */: + /// \brief Rule of 5: Destructor + ~aligned_storage_vector() { + // Call the destructor for element we previously allocated + destroy_all(); + } - /// \brief Rule of 5: Copy Constructor - aligned_storage_vector(const aligned_storage_vector &other) : size_(other.size_) { - // Replicate share - for (size_type pos = 0; pos < size_; ++pos) { - // Construct each element with copy constructor - construct_at(pos, other[pos]); + /// \brief Rule of 5: Copy Constructor + aligned_storage_vector(const aligned_storage_vector &other) : size_(other.size_) { + // Replicate share + for (size_type pos = 0; pos < size_; ++pos) { + // Construct each element with copy constructor + construct_at(pos, other[pos]); + } } - } - /// \brief Rule of 5: Move Constructor - aligned_storage_vector(aligned_storage_vector &&other) noexcept : size_(other.size_) { - // Move resource ownership - // Construct each element with move constructor - for (size_type pos = 0; pos < other.size(); ++pos) { - construct_at(pos, std::move(other[pos])); + /// \brief Rule of 5: Move Constructor + aligned_storage_vector(aligned_storage_vector &&other) noexcept : size_(other.size_) { + // Move resource ownership + // Construct each element with move constructor + for (size_type pos = 0; pos < other.size(); ++pos) { + construct_at(pos, std::move(other[pos])); + } + // Destroy elements in other + other.destroy_all(); + other.size_ = 0; } - // Destroy elements in other - other.destroy_all(); - other.size_ = 0; - } - /// \brief Rule of 5: Copy Assignment - aligned_storage_vector &operator=(const aligned_storage_vector &other) { - // Make sure they are not the same - if (this == &other) { + /// \brief Rule of 5: Copy Assignment + aligned_storage_vector &operator=(const aligned_storage_vector &other) { + // Make sure they are not the same + if (this == &other) { + return *this; + } + // Reuse copy constructor to replicate share + destroy_all(); + for (size_type pos = 0; pos < other.size(); ++pos) { + construct_at(pos, other[pos]); + } + size_ = other.size_; return *this; } - // Reuse copy constructor to replicate share - destroy_all(); - for (size_type pos = 0; pos < other.size(); ++pos) { - construct_at(pos, other[pos]); - } - size_ = other.size_; - return *this; - } - /// \brief Rule of 5: Move Assignment - aligned_storage_vector &operator=(aligned_storage_vector &&other) noexcept { - // Make sure they are not the same - if (this == &other) { + /// \brief Rule of 5: Move Assignment + aligned_storage_vector &operator=(aligned_storage_vector &&other) noexcept { + // Make sure they are not the same + if (this == &other) { + return *this; + } + // Move resource ownership + destroy_all(); + for (size_type pos = 0; pos < other.size(); ++pos) { + // Construct each element with move constructor + construct_at(pos, std::move(other[pos])); + } + // Destruct the elements from the original vector + other.destroy_all(); + size_ = other.size_; + other.size_ = 0; return *this; } - // Move resource ownership - destroy_all(); - for (size_type pos = 0; pos < other.size(); ++pos) { - // Construct each element with move constructor - construct_at(pos, std::move(other[pos])); - } - // Destruct the elements from the original vector - other.destroy_all(); - size_ = other.size_; - other.size_ = 0; - return *this; - } - - public /* assign, fill, and swap */: - /// \brief Assign small array from initializer list - constexpr aligned_storage_vector &operator=(std::initializer_list il) { - assign(il); - return *this; - } - /// \brief Assign small array from iterators - template - constexpr void assign(InputIterator first, enable_if_iterator_t last) { - const auto n = std::distance(first, last); - assert((size_t(n) <= capacity()) && - "assign() called with more elements than aligned_storage_vector capacity"); + public /* assign, fill, and swap */: + /// \brief Assign small array from initializer list + constexpr aligned_storage_vector &operator=(std::initializer_list il) { + assign(il); + return *this; + } - // Destroy all - destroy_all(); - size_ = 0; + /// \brief Assign small array from iterators + template + constexpr void assign(InputIterator first, enable_if_iterator_t last) { + const auto n = std::distance(first, last); + assert((size_t(n) <= capacity()) && + "assign() called with more elements than aligned_storage_vector capacity"); + + // Destroy all + destroy_all(); + size_ = 0; + + // Construct copies + for (auto it = first; it != last; ++it) { + // Construct each element with move constructor + emplace_back(*it); + } - // Construct copies - for (auto it = first; it != last; ++it) { - // Construct each element with move constructor - emplace_back(*it); + assert(invariants()); } - assert(invariants()); - } + /// \brief Assign small array from size and fill with value + constexpr void assign(size_type n, const value_type &u) { + assert((size_t(n) <= capacity()) && + "assign() called with more elements than aligned_storage_vector capacity"); - /// \brief Assign small array from size and fill with value - constexpr void assign(size_type n, const value_type &u) { - assert((size_t(n) <= capacity()) && - "assign() called with more elements than aligned_storage_vector capacity"); + // Destroy all + destroy_all(); - // Destroy all - destroy_all(); + // Construct copies + for (size_type pos = 0; pos < n; ++pos) { + construct_at(pos, u); + } + size_ = n; - // Construct copies - for (size_type pos = 0; pos < n; ++pos) { - construct_at(pos, u); + assert(invariants()); } - size_ = n; - - assert(invariants()); - } - - /// \brief Assign small array from initializer list - constexpr void assign(std::initializer_list il) { assign(il.begin(), il.end()); } - - /// \brief Fill small array with value u - constexpr void fill(const T &u) { - std::fill(begin(), end(), u); - assert(invariants()); - } - /// \brief Swap the contents of two small arrays - constexpr void swap(aligned_storage_vector &rhs) noexcept(std::is_nothrow_swappable_v) { - std::swap_ranges(data(), data() + N, rhs.data()); - std::swap(size_, rhs.size_); - assert(invariants()); - } + /// \brief Assign small array from initializer list + constexpr void assign(std::initializer_list il) { assign(il.begin(), il.end()); } - public /* iterators */: - /// \brief Get iterator to first element - constexpr iterator begin() noexcept { return iterator(data()); } + /// \brief Fill small array with value u + constexpr void fill(const T &u) { + std::fill(begin(), end(), u); + assert(invariants()); + } - /// \brief Get constant iterator to first element[[nodiscard]] - [[nodiscard]] constexpr const_iterator begin() const noexcept { return cbegin(); } + /// \brief Swap the contents of two small arrays + constexpr void swap(aligned_storage_vector &rhs) noexcept(std::is_nothrow_swappable_v) { + std::swap_ranges(data(), data() + N, rhs.data()); + std::swap(size_, rhs.size_); + assert(invariants()); + } - /// \brief Get iterator to last element - constexpr iterator end() noexcept { return iterator(data() + size_); } + public /* iterators */: + /// \brief Get iterator to first element + constexpr iterator begin() noexcept { return iterator(data()); } - /// \brief Get constant iterator to last element - [[nodiscard]] constexpr const_iterator end() const noexcept { return cend(); } + /// \brief Get constant iterator to first element[[nodiscard]] + [[nodiscard]] constexpr const_iterator begin() const noexcept { return cbegin(); } - /// \brief Get iterator to first element in reverse order - constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator(end()); } + /// \brief Get iterator to last element + constexpr iterator end() noexcept { return iterator(data() + size_); } - /// \brief Get constant iterator to first element in reverse order - [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { - return std::reverse_iterator(end()); - } + /// \brief Get constant iterator to last element + [[nodiscard]] constexpr const_iterator end() const noexcept { return cend(); } - /// \brief Get iterator to last element in reverse order - constexpr reverse_iterator rend() noexcept { return std::reverse_iterator(begin()); } + /// \brief Get iterator to first element in reverse order + constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator(end()); } - /// \brief Get constant iterator to last element in reverse order - [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { - return std::reverse_iterator(begin()); - } + /// \brief Get constant iterator to first element in reverse order + [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { + return std::reverse_iterator(end()); + } - /// \brief Get constant iterator to first element - [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return const_iterator(data()); } + /// \brief Get iterator to last element in reverse order + constexpr reverse_iterator rend() noexcept { return std::reverse_iterator(begin()); } - /// \brief Get constant iterator to last element - [[nodiscard]] constexpr const_iterator cend() const noexcept { return const_iterator(data() + size_); } + /// \brief Get constant iterator to last element in reverse order + [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { + return std::reverse_iterator(begin()); + } - /// \brief Get constant iterator to first element in reverse order - [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { - return std::reverse_iterator(cend()); - } + /// \brief Get constant iterator to first element + [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return const_iterator(data()); } - /// \brief Get constant iterator to last element in reverse order - [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { - return std::reverse_iterator(cbegin()); - } + /// \brief Get constant iterator to last element + [[nodiscard]] constexpr const_iterator cend() const noexcept { return const_iterator(data() + size_); } - public /* capacity */: - /// \brief Get small array size - [[nodiscard]] constexpr size_type size() const noexcept { return size_; } + /// \brief Get constant iterator to first element in reverse order + [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { + return std::reverse_iterator(cend()); + } - /// \brief Get small array max size - [[nodiscard]] constexpr size_type max_size() const noexcept { return N; } + /// \brief Get constant iterator to last element in reverse order + [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { + return std::reverse_iterator(cbegin()); + } - /// \brief Check if small array is empty - [[nodiscard]] constexpr bool empty() const noexcept { return size_ == 0; } + public /* capacity */: + /// \brief Get small array size + [[nodiscard]] constexpr size_type size() const noexcept { return size_; } - /// \brief Get small array capacity (same as max_size()) - [[nodiscard]] constexpr size_type capacity() const noexcept { return max_size(); } + /// \brief Get small array max size + [[nodiscard]] constexpr size_type max_size() const noexcept { return N; } - /// \brief Check if small array is full - /// This is a convenience for small arrays only. - /// Like empty() is better than size() == 0, full() is better than size() == capacity() - [[nodiscard]] constexpr bool full() const noexcept { return size_ == N; } + /// \brief Check if small array is empty + [[nodiscard]] constexpr bool empty() const noexcept { return size_ == 0; } - public /* element access */: - /// \brief Get reference to n-th element in small array - constexpr reference operator[](size_type n) { - assert(n < size() && "aligned_storage_vector[] index out of bounds"); - return *(data() + n); - } + /// \brief Get small array capacity (same as max_size()) + [[nodiscard]] constexpr size_type capacity() const noexcept { return max_size(); } - /// \brief Get constant reference to n-th element in small array - constexpr const_reference operator[](size_type n) const { - assert(n < size() && "aligned_storage_vector[] index out of bounds"); - return *(data() + n); - } + /// \brief Check if small array is full + /// This is a convenience for small arrays only. + /// Like empty() is better than size() == 0, full() is better than size() == capacity() + [[nodiscard]] constexpr bool full() const noexcept { return size_ == N; } - /// \brief Check bounds and get reference to n-th element in small array - constexpr reference at(size_type n) { - if (n >= size()) { - throw_exception("at: cannot access element after vector::size()"); + public /* element access */: + /// \brief Get reference to n-th element in small array + constexpr reference operator[](size_type n) { + assert(n < size() && "aligned_storage_vector[] index out of bounds"); + return *(data() + n); } - return operator[](n); - } - /// \brief Check bounds and get constant reference to n-th element in small array - constexpr const_reference at(size_type n) const { - if (n >= size()) { - throw_exception("at: cannot access element after vector::size()"); + /// \brief Get constant reference to n-th element in small array + constexpr const_reference operator[](size_type n) const { + assert(n < size() && "aligned_storage_vector[] index out of bounds"); + return *(data() + n); } - return operator[](n); - } - - /// \brief Get reference to first element in small array - constexpr reference front() { - assert(!empty() && "front() called for empty small array"); - return operator[](0); - } - /// \brief Get constant reference to first element in small array - constexpr const_reference front() const { - assert(!empty() && "front() called for empty small array"); - return operator[](0); - } + /// \brief Check bounds and get reference to n-th element in small array + constexpr reference at(size_type n) { + if (n >= size()) { + throw_exception("at: cannot access element after vector::size()"); + } + return operator[](n); + } - /// \brief Get reference to last element in small array - constexpr reference back() { - assert(!empty() && "back() called for empty small array"); - return operator[](size_ - 1); - } + /// \brief Check bounds and get constant reference to n-th element in small array + constexpr const_reference at(size_type n) const { + if (n >= size()) { + throw_exception("at: cannot access element after vector::size()"); + } + return operator[](n); + } - /// \brief Get constant reference to last element in small array - constexpr const_reference back() const { - assert(!empty() && "back() called for empty small array"); - return operator[](size_ - 1); - } + /// \brief Get reference to first element in small array + constexpr reference front() { + assert(!empty() && "front() called for empty small array"); + return operator[](0); + } - /// \brief Get reference to internal pointer to small array data - constexpr T *data() noexcept { return reinterpret_cast(&data_[0]); } + /// \brief Get constant reference to first element in small array + constexpr const_reference front() const { + assert(!empty() && "front() called for empty small array"); + return operator[](0); + } - /// \brief Get constant reference to internal pointer to small array data - constexpr const T *data() const noexcept { return reinterpret_cast(&data_[0]); } + /// \brief Get reference to last element in small array + constexpr reference back() { + assert(!empty() && "back() called for empty small array"); + return operator[](size_ - 1); + } - public /* modifiers */: - /// \brief Copy element to end of small array - constexpr void push_back(const value_type &x) { emplace_back(x); } + /// \brief Get constant reference to last element in small array + constexpr const_reference back() const { + assert(!empty() && "back() called for empty small array"); + return operator[](size_ - 1); + } - /// \brief Move element to end of small array - constexpr void push_back(value_type &&x) { emplace_back(std::move(x)); } + /// \brief Get reference to internal pointer to small array data + constexpr T *data() noexcept { return reinterpret_cast(&data_[0]); } - /// \brief Emplace element to end of small array - template constexpr reference emplace_back(Args &&...args) { - assert(!full() && "emplace_back() called for full small array"); - construct_at(size_, std::forward(args)...); - ++size_; - assert(invariants()); - return back(); - } + /// \brief Get constant reference to internal pointer to small array data + constexpr const T *data() const noexcept { return reinterpret_cast(&data_[0]); } - /// \brief Remove element from end of small array - constexpr void pop_back() { - assert(!empty() && "pop_back() called for empty small array"); - destroy_at(size_ - 1); - --size_; - assert(invariants()); - } + public /* modifiers */: + /// \brief Copy element to end of small array + constexpr void push_back(const value_type &x) { emplace_back(x); } - /// \brief Emplace element to a position in small array - template constexpr iterator emplace(const_iterator position, Args &&...args) { - assert(!full() && "emplace() called for full small array"); - size_t p = position - begin(); - ++size_; - const auto underlying_position = &data_[0] + p; - const auto underlying_new_end = &data_[0] + size_; - shift_right(underlying_position, underlying_new_end, 1); - construct_at(p, std::forward(args)...); - assert(invariants()); - return begin() + p; - } + /// \brief Move element to end of small array + constexpr void push_back(value_type &&x) { emplace_back(std::move(x)); } - /// \brief Copy element to a position in small array - constexpr iterator insert(const_iterator position, const value_type &x) { - assert(!full() && "insert() called for full small array"); - return emplace(position, x); - } + /// \brief Emplace element to end of small array + template constexpr reference emplace_back(Args &&...args) { + assert(!full() && "emplace_back() called for full small array"); + construct_at(size_, std::forward(args)...); + ++size_; + assert(invariants()); + return back(); + } - /// \brief Move element to a position in small array - constexpr iterator insert(const_iterator position, value_type &&x) { - assert(!full() && "insert() called for full small array"); - return emplace(position, std::move(x)); - } + /// \brief Remove element from end of small array + constexpr void pop_back() { + assert(!empty() && "pop_back() called for empty small array"); + destroy_at(size_ - 1); + --size_; + assert(invariants()); + } - /// \brief Copy n elements to a position in small array - constexpr iterator insert(const_iterator position, size_type n, const value_type &x) { - assert((size_ + n <= capacity()) && "insert() called with more elements than small array capacity"); - size_t p = position - begin(); - size_ += n; - const auto underlying_position = &data_[0] + p; - const auto underlying_new_end = &data_[0] + size_; - shift_right(underlying_position, underlying_new_end, n); - for (size_t i = p; i < p + n; ++i) { - construct_at(i, x); - } - assert(invariants()); - return begin() + p; - } + /// \brief Emplace element to a position in small array + template constexpr iterator emplace(const_iterator position, Args &&...args) { + assert(!full() && "emplace() called for full small array"); + size_t p = position - begin(); + ++size_; + const auto underlying_position = &data_[0] + p; + const auto underlying_new_end = &data_[0] + size_; + shift_right(underlying_position, underlying_new_end, 1); + construct_at(p, std::forward(args)...); + assert(invariants()); + return begin() + p; + } - /// \brief Copy element range stating at a position in small array - template - constexpr iterator insert(const_iterator position, InputIterator first, - enable_if_iterator_t last) { - const size_t n = std::distance(first, last); - assert((size_ + n <= capacity()) && "insert() called with more elements than small array capacity"); - size_t p = position - begin(); - size_ += n; - // open space for n elements - const auto underlying_position = &data_[0] + p; - const auto underlying_new_end = &data_[0] + size_; - shift_right(underlying_position, underlying_new_end, n); - size_t i = p; - for (auto it = first; it != last; ++it) { - construct_at(i++, *it); - } - assert(invariants()); - return begin() + p; - } + /// \brief Copy element to a position in small array + constexpr iterator insert(const_iterator position, const value_type &x) { + assert(!full() && "insert() called for full small array"); + return emplace(position, x); + } - /// \brief Copy elements from initializer list to a position in small array - constexpr iterator insert(const_iterator position, std::initializer_list il) { - assert((size_ + il.size() <= capacity()) && "insert() called with more elements than small array capacity"); - return insert(position, il.begin(), il.end()); - } + /// \brief Move element to a position in small array + constexpr iterator insert(const_iterator position, value_type &&x) { + assert(!full() && "insert() called for full small array"); + return emplace(position, std::move(x)); + } - /// \brief Erase element at a position in small array - constexpr iterator erase(const_iterator position) { - assert(!empty() && "erase() called for empty small array"); - size_type p = position - begin(); - const auto underlying_position = &data_[0] + p; - const auto underlying_end = &data_[0] + size_; - shift_left(underlying_position, underlying_end, 1); - destroy_at(size_ - 1); - --size_; - assert(invariants()); - return begin() + p; - } + /// \brief Copy n elements to a position in small array + constexpr iterator insert(const_iterator position, size_type n, const value_type &x) { + assert((size_ + n <= capacity()) && "insert() called with more elements than small array capacity"); + size_t p = position - begin(); + size_ += n; + const auto underlying_position = &data_[0] + p; + const auto underlying_new_end = &data_[0] + size_; + shift_right(underlying_position, underlying_new_end, n); + for (size_t i = p; i < p + n; ++i) { + construct_at(i, x); + } + assert(invariants()); + return begin() + p; + } - /// \brief Erase range of elements in the small array - constexpr iterator erase(const_iterator first, const_iterator last) { - size_t n = std::distance(first, last); - assert((n <= size_) && "erase() called for more elements than small array size"); - size_type p = first - begin(); - const auto underlying_position = &data_[0] + p; - const auto underlying_end = &data_[0] + size_; - shift_left(underlying_position, underlying_end, n); - for (size_type i = size_ - n; i != size_; ++i) { - destroy_at(i); - } - size_ -= n; - assert(invariants()); - return begin() + p; - } + /// \brief Copy element range stating at a position in small array + template + constexpr iterator insert(const_iterator position, InputIterator first, + enable_if_iterator_t last) { + const size_t n = std::distance(first, last); + assert((size_ + n <= capacity()) && "insert() called with more elements than small array capacity"); + size_t p = position - begin(); + size_ += n; + // open space for n elements + const auto underlying_position = &data_[0] + p; + const auto underlying_new_end = &data_[0] + size_; + shift_right(underlying_position, underlying_new_end, n); + size_t i = p; + for (auto it = first; it != last; ++it) { + construct_at(i++, *it); + } + assert(invariants()); + return begin() + p; + } - /// \brief Clear elements in the small array - constexpr void clear() noexcept { - destroy_all(); - size_ = 0; - assert(invariants()); - } + /// \brief Copy elements from initializer list to a position in small array + constexpr iterator insert(const_iterator position, std::initializer_list il) { + assert((size_ + il.size() <= capacity()) && + "insert() called with more elements than small array capacity"); + return insert(position, il.begin(), il.end()); + } - /// \brief Resize the small array - constexpr void resize(size_type sz) { - assert((sz <= capacity()) && "resize() called for more elements than small array capacity"); - if (sz > size_) { - for (size_type i = size_; i != sz; ++i) { - construct_at(i); - } - } else if (sz < size_) { - for (size_type i = sz; i != size_; ++i) { - destroy_at(i); - } + /// \brief Erase element at a position in small array + constexpr iterator erase(const_iterator position) { + assert(!empty() && "erase() called for empty small array"); + size_type p = position - begin(); + const auto underlying_position = &data_[0] + p; + const auto underlying_end = &data_[0] + size_; + shift_left(underlying_position, underlying_end, 1); + destroy_at(size_ - 1); + --size_; + assert(invariants()); + return begin() + p; } - size_ = sz; - assert(invariants()); - } - /// \brief Resize and fill the small array - constexpr void resize(size_type sz, const value_type &c) { - assert((sz <= capacity()) && "resize() called for more elements than small array capacity"); - if (sz > size_) { - for (size_type i = size_; i != sz; ++i) { - construct_at(i, c); - } - } else if (sz < size_) { - for (size_type i = sz; i != size_; ++i) { + /// \brief Erase range of elements in the small array + constexpr iterator erase(const_iterator first, const_iterator last) { + size_t n = std::distance(first, last); + assert((n <= size_) && "erase() called for more elements than small array size"); + size_type p = first - begin(); + const auto underlying_position = &data_[0] + p; + const auto underlying_end = &data_[0] + size_; + shift_left(underlying_position, underlying_end, n); + for (size_type i = size_ - n; i != size_; ++i) { destroy_at(i); } + size_ -= n; + assert(invariants()); + return begin() + p; } - size_ = sz; - assert(invariants()); - } - private: - /// \brief Check if small array invariants are ok - [[nodiscard]] constexpr bool invariants() const { - if (size_ > capacity()) { - return false; + /// \brief Clear elements in the small array + constexpr void clear() noexcept { + destroy_all(); + size_ = 0; + assert(invariants()); } - return true; - } - /// \brief Construct element at a given position - template void construct_at(size_type pos, Args &&...args) { - if (pos >= N) { - throw_exception(); + /// \brief Resize the small array + constexpr void resize(size_type sz) { + assert((sz <= capacity()) && "resize() called for more elements than small array capacity"); + if (sz > size_) { + for (size_type i = size_; i != sz; ++i) { + construct_at(i); + } + } else if (sz < size_) { + for (size_type i = sz; i != size_; ++i) { + destroy_at(i); + } + } + size_ = sz; + assert(invariants()); } - new (&data_[pos]) T(std::forward(args)...); - } - /// \brief Destroy element at a given position - void destroy_at(size_type pos) { - if (pos >= N) { - throw_exception(); + /// \brief Resize and fill the small array + constexpr void resize(size_type sz, const value_type &c) { + assert((sz <= capacity()) && "resize() called for more elements than small array capacity"); + if (sz > size_) { + for (size_type i = size_; i != sz; ++i) { + construct_at(i, c); + } + } else if (sz < size_) { + for (size_type i = sz; i != size_; ++i) { + destroy_at(i); + } + } + size_ = sz; + assert(invariants()); } - reinterpret_cast(&data_[pos])->~T(); - } - /// \brief Destroy all elements allocated - void destroy_all() { - for (size_type pos = 0; pos < size_; ++pos) { - destroy_at(pos); + private: + /// \brief Check if small array invariants are ok + [[nodiscard]] constexpr bool invariants() const { + if (size_ > capacity()) { + return false; + } + return true; } - } - /// \brief Increment/decrement the mid iterator i by n positions - /// \note Adapted from https://github.com/danra/shift_proposal/ - /// Increment (decrement for negative n) i |n| times or until i == bound, - /// whichever comes first. Returns n - the difference between i's final position - /// and its initial position. (Note: "advance" has overloads with this behavior - /// in the Ranges TS.) - template - constexpr difference_type_type bounded_advance(I &i, difference_type_type n, I const bound) { - if constexpr (is_category_convertible) { - while (n < 0 && i != bound) { - ++n; - void(--i); + /// \brief Construct element at a given position + template void construct_at(size_type pos, Args &&...args) { + if (pos >= N) { + throw_exception(); } + new (&data_[pos]) T(std::forward(args)...); } - while (n > 0 && i != bound) { - --n; - void(++i); + /// \brief Destroy element at a given position + void destroy_at(size_type pos) { + if (pos >= N) { + throw_exception(); + } + reinterpret_cast(&data_[pos])->~T(); } - return n; - } - - /// \brief Shift elements left - /// \note Adapted from https://github.com/danra/shift_proposal/ - template - ForwardIt shift_left(ForwardIt first, ForwardIt last, difference_type_type n) { - if (n <= 0) { - return last; + /// \brief Destroy all elements allocated + void destroy_all() { + for (size_type pos = 0; pos < size_; ++pos) { + destroy_at(pos); + } } - auto mid = first; - if (bounded_advance(mid, n, last)) { - return first; - } + /// \brief Increment/decrement the mid iterator i by n positions + /// \note Adapted from https://github.com/danra/shift_proposal/ + /// Increment (decrement for negative n) i |n| times or until i == bound, + /// whichever comes first. Returns n - the difference between i's final position + /// and its initial position. (Note: "advance" has overloads with this behavior + /// in the Ranges TS.) + template + constexpr difference_type_type bounded_advance(I &i, difference_type_type n, I const bound) { + if constexpr (is_category_convertible) { + while (n < 0 && i != bound) { + ++n; + void(--i); + } + } - return std::move(std::move(mid), std::move(last), std::move(first)); - } + while (n > 0 && i != bound) { + --n; + void(++i); + } - /// \brief Shift elements right - /// \note Adapted from https://github.com/danra/shift_proposal/ - template - ForwardIt shift_right(ForwardIt first, ForwardIt last, difference_type_type n) { - if (n <= 0) { - return first; + return n; } - if constexpr (is_category_convertible) { - auto mid = last; - if (bounded_advance(mid, -n, first)) { + /// \brief Shift elements left + /// \note Adapted from https://github.com/danra/shift_proposal/ + template + ForwardIt shift_left(ForwardIt first, ForwardIt last, difference_type_type n) { + if (n <= 0) { return last; } - return std::move_backward(std::move(first), std::move(mid), std::move(last)); - } else { - auto result = first; - if (bounded_advance(result, n, last)) { - return last; + + auto mid = first; + if (bounded_advance(mid, n, last)) { + return first; } - // Invariant: next(first, n) == result - // Invariant: next(trail, n) == lead - auto lead = result; - auto trail = first; - - for (; trail != result; ++lead, void(++trail)) { - if (lead == last) { - // The range looks like: - // - // |-- (n - k) elements --|-- k elements --|-- (n - k) elements --| - // ^-first trail-^ ^-result last-^ - // - // Note that distance(first, trail) == distance(result, last) - std::move(std::move(first), std::move(trail), std::move(result)); - return result; - } + return std::move(std::move(mid), std::move(last), std::move(first)); + } + + /// \brief Shift elements right + /// \note Adapted from https://github.com/danra/shift_proposal/ + template + ForwardIt shift_right(ForwardIt first, ForwardIt last, difference_type_type n) { + if (n <= 0) { + return first; } - for (;;) { - for (auto mid = first; mid != result; ++lead, void(++trail), ++mid) { + if constexpr (is_category_convertible) { + auto mid = last; + if (bounded_advance(mid, -n, first)) { + return last; + } + return std::move_backward(std::move(first), std::move(mid), std::move(last)); + } else { + auto result = first; + if (bounded_advance(result, n, last)) { + return last; + } + + // Invariant: next(first, n) == result + // Invariant: next(trail, n) == lead + auto lead = result; + auto trail = first; + + for (; trail != result; ++lead, void(++trail)) { if (lead == last) { // The range looks like: // - // |-- (n - k) elements --|-- k elements --|-- ... --|-- n elements - // --| - // ^-first mid-^ result-^ ^-trail last-^ + // |-- (n - k) elements --|-- k elements --|-- (n - k) elements --| + // ^-first trail-^ ^-result last-^ // - trail = std::move(mid, result, std::move(trail)); - std::move(std::move(first), std::move(mid), std::move(trail)); + // Note that distance(first, trail) == distance(result, last) + std::move(std::move(first), std::move(trail), std::move(result)); return result; } - std::iter_swap(mid, trail); + } + + for (;;) { + for (auto mid = first; mid != result; ++lead, void(++trail), ++mid) { + if (lead == last) { + // The range looks like: + // + // |-- (n - k) elements --|-- k elements --|-- ... --|-- n elements + // --| + // ^-first mid-^ result-^ ^-trail last-^ + // + trail = std::move(mid, result, std::move(trail)); + std::move(std::move(first), std::move(mid), std::move(trail)); + return result; + } + std::iter_swap(mid, trail); + } } } } + + private: + /// \brief Internal array + /// We need aligned storage rather than array because we need + /// properly aligned *uninitialized* storage for the elements + /// An array would try to initialize all elements in the array + /// even if we don't use them + /// \see https://en.cppreference.com/w/cpp/types/aligned_storage + typename std::aligned_storage::type data_[N]; + + /// \brief How much of the internal array we are actually using + size_t size_{0}; + }; + + /// Type deduction + template aligned_storage_vector(T, U...) -> aligned_storage_vector; + + /// \brief operator== for small arrays + template + constexpr bool operator==(const aligned_storage_vector &x, const aligned_storage_vector &y) { + return std::equal(x.begin(), x.end(), y.begin(), y.end()); } - private: - /// \brief Internal array - /// We need aligned storage rather than array because we need - /// properly aligned *uninitialized* storage for the elements - /// An array would try to initialize all elements in the array - /// even if we don't use them - /// \see https://en.cppreference.com/w/cpp/types/aligned_storage - typename std::aligned_storage::type data_[N]; - - /// \brief How much of the internal array we are actually using - size_t size_{0}; - }; - - /// Type deduction - template aligned_storage_vector(T, U...) -> aligned_storage_vector; - - /// \brief operator== for small arrays - template - constexpr bool operator==(const aligned_storage_vector &x, const aligned_storage_vector &y) { - return std::equal(x.begin(), x.end(), y.begin(), y.end()); - } - - /// \brief operator!= for small arrays - template - constexpr bool operator!=(const aligned_storage_vector &x, const aligned_storage_vector &y) { - return !(x == y); - } - - /// \brief operator< for small arrays - template - constexpr bool operator<(const aligned_storage_vector &x, const aligned_storage_vector &y) { - return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); - } - - /// \brief operator> for small arrays - template - constexpr bool operator>(const aligned_storage_vector &x, const aligned_storage_vector &y) { - return y < x; - } - - /// \brief operator<= for small arrays - template - constexpr bool operator<=(const aligned_storage_vector &x, const aligned_storage_vector &y) { - return !(y < x); - } - - /// \brief operator>= for small arrays - template - constexpr bool operator>=(const aligned_storage_vector &x, const aligned_storage_vector &y) { - return !(x < y); - } - - /// \brief swap the contents of two small arrays - template - void swap(aligned_storage_vector &x, aligned_storage_vector &y) noexcept(noexcept(x.swap(y))) { - x.swap(y); - } - - /// \brief create small array from raw array - template - constexpr aligned_storage_vector, N_OUTPUT> to_small_array(T (&a)[N_INPUT]) { - return aligned_storage_vector, N_OUTPUT>(a, a + N_INPUT); - } - - /// \brief create small array from raw array - template - constexpr aligned_storage_vector, N_OUTPUT> to_small_array(T(&&a)[N_INPUT]) { - return aligned_storage_vector, N_OUTPUT>(a, a + N_INPUT); - } + /// \brief operator!= for small arrays + template + constexpr bool operator!=(const aligned_storage_vector &x, const aligned_storage_vector &y) { + return !(x == y); + } + + /// \brief operator< for small arrays + template + constexpr bool operator<(const aligned_storage_vector &x, const aligned_storage_vector &y) { + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); + } + + /// \brief operator> for small arrays + template + constexpr bool operator>(const aligned_storage_vector &x, const aligned_storage_vector &y) { + return y < x; + } + + /// \brief operator<= for small arrays + template + constexpr bool operator<=(const aligned_storage_vector &x, const aligned_storage_vector &y) { + return !(y < x); + } + + /// \brief operator>= for small arrays + template + constexpr bool operator>=(const aligned_storage_vector &x, const aligned_storage_vector &y) { + return !(x < y); + } + + /// \brief swap the contents of two small arrays + template + void swap(aligned_storage_vector &x, aligned_storage_vector &y) noexcept(noexcept(x.swap(y))) { + x.swap(y); + } + + /// \brief create small array from raw array + template + constexpr aligned_storage_vector, N_OUTPUT> to_small_array(T (&a)[N_INPUT]) { + return aligned_storage_vector, N_OUTPUT>(a, a + N_INPUT); + } + + /// \brief create small array from raw array + template + constexpr aligned_storage_vector, N_OUTPUT> to_small_array(T (&&a)[N_INPUT]) { + return aligned_storage_vector, N_OUTPUT>(a, a + N_INPUT); + } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_CONTAINER_ALIGNED_STORAGE_VECTOR_H diff --git a/source/small/detail/container/associative_vector.h b/source/small/detail/container/associative_vector.h index 1206224..a8a5147 100644 --- a/source/small/detail/container/associative_vector.h +++ b/source/small/detail/container/associative_vector.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_CONTAINER_ASSOCIATIVE_VECTOR_H #define SMALL_DETAIL_CONTAINER_ASSOCIATIVE_VECTOR_H @@ -20,602 +19,624 @@ #include "../traits/has_allocator.h" namespace small { - /// \brief A set/map represented with any sorted vector type - /// - /// - More cache friendly node types - /// - Small vectors for small maps - /// - Optional random access with order statistic tree - /// - Each node stores its size so we can trivially find a position - /// - Inline allocation for small number of elements - /// - Custom expected size - /// - Special treatment of relocatable types - /// - Better default grow factors - /// - Custom grow factors - /// - /// This is similar to boost::vector_map, with the main difference - /// that it works as a container adapter for vector types rather - /// than a map that uses a specific kind of vector internally. - /// - /// Unlike other std:: container adapters, it forces you to make what - /// type of vector type to use explicit and then inherits its types - /// from the vector type instead of requiring the same key/value type - /// parameters twice. - /// - /// \tparam IsMap Whether this represents a map or a set - /// \tparam IsMulti Whether repeated keys are allowed - /// \tparam IsOrdered Whether the elements should be ordered - /// \tparam Vector A vector-like container of pairs - /// \tparam Compare Comparison function to sort elements - template > - class associative_vector { - public /* types */: - typedef Vector vector_type; - - template struct first_type_is_const : std::false_type {}; - template - struct first_type_is_const> : std::is_const {}; - template struct second_type_is_const : std::false_type {}; - template - struct second_type_is_const> : std::is_const { - }; - template struct first_type_or_void { using type = void; }; - template struct first_type_or_void> { - using type = typename T::first_type; - }; - template struct second_type_or_void { using type = void; }; - template struct second_type_or_void> { - using type = typename T::second_type; - }; - template using first_type_or_void_t = typename first_type_or_void::type; - template using second_type_or_void_t = typename second_type_or_void::type; - - /* static asserts */ - static_assert(!IsMap || (is_pair::value), - "vector_map: vector value_type must be std::pair"); - - static_assert(!IsMap || (!first_type_is_const::value), - "vector_map: vector key_type should be mutable / cannot be constant"); - - static_assert(!IsMap || (!second_type_is_const::value), - "vector_map: vector mapped_type should be mutable / cannot be constant"); - - typedef typename vector_type::value_type mutable_value_type; + namespace detail { + /// \brief A set/map represented with any sorted vector type + /// + /// - More cache friendly node types + /// - Small vectors for small maps + /// - Optional random access with order statistic tree + /// - Each node stores its size so we can trivially find a position + /// - Inline allocation for small number of elements + /// - Custom expected size + /// - Special treatment of relocatable types + /// - Better default grow factors + /// - Custom grow factors + /// + /// This is similar to boost::vector_map, with the main difference + /// that it works as a container adapter for vector types rather + /// than a map that uses a specific kind of vector internally. + /// + /// Unlike other std:: container adapters, it forces you to make what + /// type of vector type to use explicit and then inherits its types + /// from the vector type instead of requiring the same key/value type + /// parameters twice. + /// + /// \tparam IsMap Whether this represents a map or a set + /// \tparam IsMulti Whether repeated keys are allowed + /// \tparam IsOrdered Whether the elements should be ordered + /// \tparam Vector A vector-like container of pairs + /// \tparam Compare Comparison function to sort elements + template > + class associative_vector { + public /* types */: + typedef Vector vector_type; + + template struct first_type_is_const : std::false_type {}; + template + struct first_type_is_const> : std::is_const { + }; + template struct second_type_is_const : std::false_type {}; + template + struct second_type_is_const> + : std::is_const {}; + template struct first_type_or_void { using type = void; }; + template struct first_type_or_void> { + using type = typename T::first_type; + }; + template struct second_type_or_void { using type = void; }; + template struct second_type_or_void> { + using type = typename T::second_type; + }; + template using first_type_or_void_t = typename first_type_or_void::type; + template using second_type_or_void_t = typename second_type_or_void::type; + + /* static asserts */ + static_assert(!IsMap || (is_pair::value), + "vector_map: vector value_type must be std::pair"); + + static_assert(!IsMap || (!first_type_is_const::value), + "vector_map: vector key_type should be mutable / cannot be constant"); + + static_assert(!IsMap || (!second_type_is_const::value), + "vector_map: vector mapped_type should be mutable / cannot be constant"); + + typedef typename vector_type::value_type mutable_value_type; + + using key_type = std::conditional_t, + typename vector_type::value_type>; + using mapped_type = std::conditional_t, + typename vector_type::value_type>; + + using value_type = std::conditional_t::type, key_type>; + + static_assert(!IsMap || (std::is_const_v>), + "vector_map: vector_map::value_type::first_type must be constant"); + + /// Default allocator type for a vector type with no allocator + template struct default_allocator_type { + typedef std::allocator type; + }; + + /// Default allocator type for a vector type with an allocator type + template + struct default_allocator_type< + T, std::void_t().get_allocator()), typename T::allocator_type>> { + typedef typename T::allocator_type type; + }; + + /* default container types */ + typedef Compare key_compare; + typedef typename default_allocator_type::type allocator_type; + typedef value_type &reference; + typedef const value_type &const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef value_type *pointer; + typedef const value_type *const_pointer; + + typedef std::conditional_t, + typename vector_type::iterator> + iterator; + typedef std::conditional_t, + typename vector_type::const_iterator> + const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static_assert((std::is_same::value), + "Allocator::value_type must be same type as value_type"); + + /// \brief Construct vector depending the existence of an allocator type + static constexpr vector_type construct_vector(const allocator_type &alloc) { + if constexpr (has_allocator_v) { + return vector_type(alloc); + } else { + return vector_type(); + } + } - using key_type = std::conditional_t, - typename vector_type::value_type>; - using mapped_type = std::conditional_t, - typename vector_type::value_type>; + /// \brief Construct vector depending the existence of an allocator type + template + static constexpr vector_type construct_vector(InputIterator first, + enable_if_iterator_t last, + const allocator_type &alloc) { + if constexpr (has_allocator_v) { + return vector_type(first, last, alloc); + } else { + return vector_type(first, last); + } + } - using value_type = std::conditional_t::type, key_type>; + public /* Comparison type */: + /// Object encapsulating the comparison function for values from + /// the comparison function for keys + class value_compare { + friend class associative_vector; - static_assert(!IsMap || (std::is_const_v>), - "vector_map: vector_map::value_type::first_type must be constant"); + public: + typedef value_type first_argument_type; + typedef value_type second_argument_type; + typedef bool result_type; - /// Default allocator type for a vector type with no allocator - template struct default_allocator_type { - typedef std::allocator type; - }; + protected: + /// Function to compare keys + key_compare comp; - /// Default allocator type for a vector type with an allocator type - template - struct default_allocator_type< - T, std::void_t().get_allocator()), typename T::allocator_type>> { - typedef typename T::allocator_type type; - }; + /// Construct value compare object + constexpr explicit value_compare(key_compare c) : comp(c) {} - /* default container types */ - typedef Compare key_compare; - typedef typename default_allocator_type::type allocator_type; - typedef value_type &reference; - typedef const value_type &const_reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef value_type *pointer; - typedef const value_type *const_pointer; - - typedef std::conditional_t, - typename vector_type::iterator> - iterator; - typedef std::conditional_t, - typename vector_type::const_iterator> - const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - static_assert((std::is_same::value), - "Allocator::value_type must be same type as value_type"); - - /// \brief Construct vector depending the existence of an allocator type - static constexpr vector_type construct_vector(const allocator_type &alloc) { - if constexpr (has_allocator_v) { - return vector_type(alloc); - } else { - return vector_type(); + public: + /// Evaluate the comparison function to sort elements + constexpr bool operator()(const value_type &x, const value_type &y) const { + if constexpr (IsMap) { + return comp(x.first, y.first); + } else { + return comp(x, y); + } + } + }; + + public /* constructors */: + /// \brief Construct empty small map with default allocator + constexpr associative_vector() noexcept(std::is_nothrow_default_constructible::value + &&std::is_nothrow_default_constructible::value + &&std::is_nothrow_copy_constructible::value) + : associative_vector(key_compare(), allocator_type()) {} + + /// \brief Construct empty small map with comparison function + explicit constexpr associative_vector(const key_compare &comp) + : associative_vector(comp, allocator_type()) {} + + /// \brief Construct small vector with a given allocator + constexpr explicit associative_vector(const allocator_type &alloc) + : associative_vector(key_compare(), alloc) {} + + /// \brief Construct empty small vector with a comparison function and given allocator + constexpr explicit associative_vector(const key_compare &comp, const allocator_type &alloc) + : data_(construct_vector(alloc)), comp_(comp) {} + + /// \brief Construct small map from a pair of iterators + template + constexpr associative_vector(InputIterator first, enable_if_iterator_t last, + const key_compare &comp = key_compare(), + const allocator_type &alloc = allocator_type()) + : data_(construct_vector(first, last, alloc)), comp_(comp) { + if constexpr (IsOrdered) { + std::sort(data_.begin(), data_.end(), value_comp()); + } + assert(invariants()); } - } - /// \brief Construct vector depending the existence of an allocator type - template - static constexpr vector_type construct_vector(InputIterator first, - enable_if_iterator_t last, - const allocator_type &alloc) { - if constexpr (has_allocator_v) { - return vector_type(first, last, alloc); - } else { - return vector_type(first, last); + /// \brief Construct from another map but change the allocator + associative_vector(const associative_vector &m, const allocator_type &a) + : associative_vector(m.begin(), m.end(), m.comp_, a) {} + + /// \brief Construct small map from initializer list + constexpr associative_vector(std::initializer_list il, + const key_compare &comp = key_compare(), + const allocator_type &alloc = allocator_type()) + : associative_vector(il.begin(), il.end(), comp, alloc) {} + + /// \brief Construct from iterators and allocator + template + associative_vector(InputIterator first, InputIterator last, const allocator_type &a) + : associative_vector(first, last, Compare(), a) {} + + /// \brief Construct from initializer list and allocator + associative_vector(std::initializer_list il, const allocator_type &a) + : associative_vector(il, Compare(), a) {} + + /// \brief Assign small map from initializer list + constexpr associative_vector &operator=(std::initializer_list il) { + assign(il); + return *this; } - } - - public /* Comparison type */: - /// Object encapsulating the comparison function for values from - /// the comparison function for keys - class value_compare { - friend class associative_vector; - public: - typedef value_type first_argument_type; - typedef value_type second_argument_type; - typedef bool result_type; + /// \brief Assign small map from iterators + template + constexpr void assign(InputIterator first, enable_if_iterator_t last) { + clear(); + insert(first, last); + assert(invariants()); + } - protected: - /// Function to compare keys - key_compare comp; + /// \brief Assign small map from initializer list + constexpr void assign(std::initializer_list il) { assign(il.begin(), il.end()); } - /// Construct value compare object - constexpr explicit value_compare(key_compare c) : comp(c) {} + /// \brief Swap the contents of two flat maps + constexpr void + swap(associative_vector &a) noexcept(std::allocator_traits::is_always_equal::value + &&std::is_nothrow_swappable::value) { + std::swap(comp_, a.comp_); + data_.swap(a.data_); + assert(invariants()); + } - public: - /// Evaluate the comparison function to sort elements - constexpr bool operator()(const value_type &x, const value_type &y) const { - if constexpr (IsMap) { - return comp(x.first, y.first); + public /* observers */: + /// \brief Get copy of allocator for dynamic vector + allocator_type get_allocator() const noexcept { + if constexpr (has_allocator_v) { + return data_.get_allocator(); } else { - return comp(x, y); + return allocator_type(); } } - }; - - public /* constructors */: - /// \brief Construct empty small map with default allocator - constexpr associative_vector() noexcept(std::is_nothrow_default_constructible::value - &&std::is_nothrow_default_constructible::value - &&std::is_nothrow_copy_constructible::value) - : associative_vector(key_compare(), allocator_type()) {} - - /// \brief Construct empty small map with comparison function - explicit constexpr associative_vector(const key_compare &comp) : associative_vector(comp, allocator_type()) {} - - /// \brief Construct small vector with a given allocator - constexpr explicit associative_vector(const allocator_type &alloc) : associative_vector(key_compare(), alloc) {} - - /// \brief Construct empty small vector with a comparison function and given allocator - constexpr explicit associative_vector(const key_compare &comp, const allocator_type &alloc) - : data_(construct_vector(alloc)), comp_(comp) {} - - /// \brief Construct small map from a pair of iterators - template - constexpr associative_vector(InputIterator first, enable_if_iterator_t last, - const key_compare &comp = key_compare(), - const allocator_type &alloc = allocator_type()) - : data_(construct_vector(first, last, alloc)), comp_(comp) { - if constexpr (IsOrdered) { - std::sort(data_.begin(), data_.end(), value_comp()); - } - assert(invariants()); - } - - /// \brief Construct from another map but change the allocator - associative_vector(const associative_vector &m, const allocator_type &a) - : associative_vector(m.begin(), m.end(), m.comp_, a) {} - - /// \brief Construct small map from initializer list - constexpr associative_vector(std::initializer_list il, - const key_compare &comp = key_compare(), - const allocator_type &alloc = allocator_type()) - : associative_vector(il.begin(), il.end(), comp, alloc) {} - - /// \brief Construct from iterators and allocator - template - associative_vector(InputIterator first, InputIterator last, const allocator_type &a) - : associative_vector(first, last, Compare(), a) {} - - /// \brief Construct from initializer list and allocator - associative_vector(std::initializer_list il, const allocator_type &a) - : associative_vector(il, Compare(), a) {} - - /// \brief Assign small map from initializer list - constexpr associative_vector &operator=(std::initializer_list il) { - assign(il); - return *this; - } - /// \brief Assign small map from iterators - template - constexpr void assign(InputIterator first, enable_if_iterator_t last) { - clear(); - insert(first, last); - assert(invariants()); - } + /// \brief Get copy of key comparison function + key_compare key_comp() const { return comp_; } - /// \brief Assign small map from initializer list - constexpr void assign(std::initializer_list il) { assign(il.begin(), il.end()); } + /// \brief Get copy of value comparison function + value_compare value_comp() const { return value_compare(comp_); } - /// \brief Swap the contents of two flat maps - constexpr void - swap(associative_vector &a) noexcept(std::allocator_traits::is_always_equal::value - &&std::is_nothrow_swappable::value) { - std::swap(comp_, a.comp_); - data_.swap(a.data_); - assert(invariants()); - } + public /* iterators */: + /// \brief Get iterator to first element + constexpr iterator begin() noexcept { return iterator(data_.begin()); } - public /* observers */: - /// \brief Get copy of allocator for dynamic vector - allocator_type get_allocator() const noexcept { - if constexpr (has_allocator_v) { - return data_.get_allocator(); - } else { - return allocator_type(); - } - } + /// \brief Get constant iterator to first element[[nodiscard]] + constexpr const_iterator begin() const noexcept { return const_iterator(data_.begin()); } - /// \brief Get copy of key comparison function - key_compare key_comp() const { return comp_; } + /// \brief Get iterator to last element + constexpr iterator end() noexcept { return iterator(data_.end()); } - /// \brief Get copy of value comparison function - value_compare value_comp() const { return value_compare(comp_); } + /// \brief Get constant iterator to last element + constexpr const_iterator end() const noexcept { return const_iterator(data_.end()); } - public /* iterators */: - /// \brief Get iterator to first element - constexpr iterator begin() noexcept { return iterator(data_.begin()); } + /// \brief Get iterator to first element in reverse order + constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator(end()); } - /// \brief Get constant iterator to first element[[nodiscard]] - constexpr const_iterator begin() const noexcept { return const_iterator(data_.begin()); } + /// \brief Get constant iterator to first element in reverse order + constexpr const_reverse_iterator rbegin() const noexcept { + return std::reverse_iterator(end()); + } - /// \brief Get iterator to last element - constexpr iterator end() noexcept { return iterator(data_.end()); } + /// \brief Get iterator to last element in reverse order + constexpr reverse_iterator rend() noexcept { return std::reverse_iterator(begin()); } - /// \brief Get constant iterator to last element - constexpr const_iterator end() const noexcept { return const_iterator(data_.end()); } + /// \brief Get constant iterator to last element in reverse order + constexpr const_reverse_iterator rend() const noexcept { + return std::reverse_iterator(begin()); + } - /// \brief Get iterator to first element in reverse order - constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator(end()); } + /// \brief Get constant iterator to first element + constexpr const_iterator cbegin() const noexcept { return const_iterator(data_.cbegin()); } - /// \brief Get constant iterator to first element in reverse order - constexpr const_reverse_iterator rbegin() const noexcept { - return std::reverse_iterator(end()); - } + /// \brief Get constant iterator to last element + constexpr const_iterator cend() const noexcept { return const_iterator(data_.cend()); } - /// \brief Get iterator to last element in reverse order - constexpr reverse_iterator rend() noexcept { return std::reverse_iterator(begin()); } + /// \brief Get constant iterator to first element in reverse order + constexpr const_reverse_iterator crbegin() const noexcept { + return std::reverse_iterator(cend()); + } - /// \brief Get constant iterator to last element in reverse order - constexpr const_reverse_iterator rend() const noexcept { - return std::reverse_iterator(begin()); - } + /// \brief Get constant iterator to last element in reverse order + constexpr const_reverse_iterator crend() const noexcept { + return std::reverse_iterator(cbegin()); + } - /// \brief Get constant iterator to first element - constexpr const_iterator cbegin() const noexcept { return const_iterator(data_.cbegin()); } + public /* capacity */: + /// \brief Check if small map is empty + [[nodiscard]] constexpr bool empty() const noexcept { return data_.empty(); } - /// \brief Get constant iterator to last element - constexpr const_iterator cend() const noexcept { return const_iterator(data_.cend()); } + /// \brief Get small map size + [[nodiscard]] constexpr size_type size() const noexcept { return data_.size(); } - /// \brief Get constant iterator to first element in reverse order - constexpr const_reverse_iterator crbegin() const noexcept { - return std::reverse_iterator(cend()); - } + /// \brief Get small map max size + [[nodiscard]] constexpr size_type max_size() const noexcept { return data_.max_size(); } - /// \brief Get constant iterator to last element in reverse order - constexpr const_reverse_iterator crend() const noexcept { - return std::reverse_iterator(cbegin()); - } + /// \brief Get small map current capacity (might be smaller for buffer) + [[nodiscard]] constexpr size_type capacity() const noexcept { return data_.capacity(); } - public /* capacity */: - /// \brief Check if small map is empty - [[nodiscard]] constexpr bool empty() const noexcept { return data_.empty(); } + /// \brief Reserve space for n elements + /// This might reserve space in the buffer or switch to a map_type already + /// We concentrate the logic to switch the variant types in these functions + void reserve(size_type n) { + if constexpr (has_allocator_v) { + data_.reserve(n); + } + } - /// \brief Get small map size - [[nodiscard]] constexpr size_type size() const noexcept { return data_.size(); } + /// \brief Shrink internal array to fit only the current elements + /// We concentrate the logic to switch the variant types in these functions + void shrink_to_fit() noexcept { + if constexpr (has_allocator_v) { + data_.shrink_to_fit(); + } + } - /// \brief Get small map max size - [[nodiscard]] constexpr size_type max_size() const noexcept { return data_.max_size(); } + public /* element access */: + /// \brief Get reference to element in buffered map + constexpr mapped_type &operator[](const key_type &k) { + return element_access_implementation(std::move(k)); + } - /// \brief Get small map current capacity (might be smaller for buffer) - [[nodiscard]] constexpr size_type capacity() const noexcept { return data_.capacity(); } + /// \brief Get reference to element in buffered map + template constexpr mapped_type &operator[](const K &k) { + return element_access_implementation(k); + } - /// \brief Reserve space for n elements - /// This might reserve space in the buffer or switch to a map_type already - /// We concentrate the logic to switch the variant types in these functions - void reserve(size_type n) { - if constexpr (has_allocator_v) { - data_.reserve(n); + /// \brief Get reference to element in buffered map + constexpr mapped_type &operator[](key_type &&k) { + return element_access_implementation(std::move(k)); } - } - /// \brief Shrink internal array to fit only the current elements - /// We concentrate the logic to switch the variant types in these functions - void shrink_to_fit() noexcept { - if constexpr (has_allocator_v) { - data_.shrink_to_fit(); + /// \brief Get reference to element in buffered map + template constexpr mapped_type &operator[](K &&k) { + return element_access_implementation(std::move(k)); } - } - public /* element access */: - /// \brief Get reference to element in buffered map - constexpr mapped_type &operator[](const key_type &k) { - return element_access_implementation(std::move(k)); - } + /// \brief Check bound and get reference to element in buffered map + constexpr mapped_type &at(const key_type &k) { return element_access_implementation(k); } - /// \brief Get reference to element in buffered map - template constexpr mapped_type &operator[](const K &k) { - return element_access_implementation(k); - } + /// \brief Check bound and get reference to element in buffered map + template constexpr mapped_type &at(const K &k) { return element_access_implementation(k); } - /// \brief Get reference to element in buffered map - constexpr mapped_type &operator[](key_type &&k) { return element_access_implementation(std::move(k)); } + /// \brief Check bound and get reference to element in buffered map + constexpr mapped_type &at(key_type &&k) { return element_access_implementation(std::move(k)); } - /// \brief Get reference to element in buffered map - template constexpr mapped_type &operator[](K &&k) { - return element_access_implementation(std::move(k)); - } + /// \brief Check bound and get reference to element in buffered map + template constexpr mapped_type &at(K &&k) { + return element_access_implementation(std::move(k)); + } - /// \brief Check bound and get reference to element in buffered map - constexpr mapped_type &at(const key_type &k) { return element_access_implementation(k); } + /// \brief Check bound and get reference to element in buffered map + constexpr const mapped_type &at(const key_type &k) const { return element_access_implementation(k); } - /// \brief Check bound and get reference to element in buffered map - template constexpr mapped_type &at(const K &k) { return element_access_implementation(k); } + /// \brief Check bound and get reference to element in buffered map + constexpr const mapped_type &at(key_type &&k) const { + return element_access_implementation(std::move(k)); + } - /// \brief Check bound and get reference to element in buffered map - constexpr mapped_type &at(key_type &&k) { return element_access_implementation(std::move(k)); } + /// \brief Check bound and get reference to element in buffered map + template constexpr const mapped_type &at(const K &k) const { + return element_access_implementation(k); + } - /// \brief Check bound and get reference to element in buffered map - template constexpr mapped_type &at(K &&k) { - return element_access_implementation(std::move(k)); - } + /// \brief Check bound and get reference to element in buffered map + template constexpr const mapped_type &at(K &&k) const { + return element_access_implementation(std::move(k)); + } - /// \brief Check bound and get reference to element in buffered map - constexpr const mapped_type &at(const key_type &k) const { return element_access_implementation(k); } + /// \brief Get reference to first element in small array + constexpr reference front() { return reinterpret_cast(data_.front()); } - /// \brief Check bound and get reference to element in buffered map - constexpr const mapped_type &at(key_type &&k) const { - return element_access_implementation(std::move(k)); - } + /// \brief Get constant reference to first element in small array + constexpr const_reference front() const { return reinterpret_cast(data_.front()); } - /// \brief Check bound and get reference to element in buffered map - template constexpr const mapped_type &at(const K &k) const { - return element_access_implementation(k); - } + /// \brief Get reference to last element in small array + constexpr reference back() { return reinterpret_cast(data_.back()); } - /// \brief Check bound and get reference to element in buffered map - template constexpr const mapped_type &at(K &&k) const { - return element_access_implementation(std::move(k)); - } + /// \brief Get constant reference to last element in small array + constexpr const_reference back() const { return reinterpret_cast(data_.back()); } + + /// \brief Get reference to internal pointer to small array data + constexpr pointer data() noexcept { return reinterpret_cast(data_.data()); } - /// \brief Get reference to first element in small array - constexpr reference front() { return reinterpret_cast(data_.front()); } - - /// \brief Get constant reference to first element in small array - constexpr const_reference front() const { return reinterpret_cast(data_.front()); } - - /// \brief Get reference to last element in small array - constexpr reference back() { return reinterpret_cast(data_.back()); } - - /// \brief Get constant reference to last element in small array - constexpr const_reference back() const { return reinterpret_cast(data_.back()); } - - /// \brief Get reference to internal pointer to small array data - constexpr pointer data() noexcept { return reinterpret_cast(data_.data()); } - - /// \brief Get constant reference to internal pointer to small array data - constexpr const_pointer data() const noexcept { return reinterpret_cast(data_.data()); } - - public /* modifiers */: - /// \brief Emplace element at hint position of the small map - /// \param position Position before element will be constructed - template iterator emplace_hint(const_iterator position, Args &&...args) { - value_type obj(std::forward(args)...); - // Handle iterator to end() - if (position == end() && comp_(maybe_first(data_.back()), maybe_first(obj))) { - return iterator(data_.emplace(data_.end(), std::move(obj))); - } else { - // else, check if object should come after position... - if (comp_(maybe_first(*position), maybe_first(obj))) { - // ... and check if object should come before next position - auto next_position = std::next(position); - if (next_position == end() || comp_(maybe_first(obj), maybe_first(*position))) { - // If so, insert element there with this correct hint and return - return iterator(data_.emplace(maybe_base(position), std::move(obj))); + /// \brief Get constant reference to internal pointer to small array data + constexpr const_pointer data() const noexcept { return reinterpret_cast(data_.data()); } + + public /* modifiers */: + /// \brief Emplace element at hint position of the small map + /// \param position Position before element will be constructed + template iterator emplace_hint(const_iterator position, Args &&...args) { + value_type obj(std::forward(args)...); + // Handle iterator to end() + if (position == end() && comp_(maybe_first(data_.back()), maybe_first(obj))) { + return iterator(data_.emplace(data_.end(), std::move(obj))); + } else { + // else, check if object should come after position... + if (comp_(maybe_first(*position), maybe_first(obj))) { + // ... and check if object should come before next position + auto next_position = std::next(position); + if (next_position == end() || comp_(maybe_first(obj), maybe_first(*position))) { + // If so, insert element there with this correct hint and return + return iterator(data_.emplace(maybe_base(position), std::move(obj))); + } } } - } - // Otherwise, use normal emplace instead of failing - return emplace(std::move(obj)).first; - } + // Otherwise, use normal emplace instead of failing + return emplace(std::move(obj)).first; + } - /// \brief Emplace element to end of small map - /// In a usual map, the node would be constructed in-place and then - /// attached to its proper position. We unfortunately cannot do this - /// here because we need to construct the object before find its - /// proper position in the vector. We can then move the object, if - /// this is possible. - template constexpr std::pair emplace(Args &&...args) { - value_type tmp(std::forward(args)...); - iterator emplace_pos; - if constexpr (IsOrdered) { - emplace_pos = lower_bound(maybe_first(tmp)); - } else { - emplace_pos = end(); - } - if (emplace_pos == end()) { - data_.emplace_back(std::move(tmp)); - return std::make_pair(std::prev(end()), true); - } else { - const bool same_key = !comp_(maybe_first(*emplace_pos), maybe_first(tmp)) && - !comp_(maybe_first(tmp), maybe_first(*emplace_pos)); - if (IsMulti || !same_key) { - typename vector_type::iterator emplaced_it = data_.emplace(maybe_base(emplace_pos), std::move(tmp)); - return std::make_pair(iterator(emplaced_it), true); + /// \brief Emplace element to end of small map + /// In a usual map, the node would be constructed in-place and then + /// attached to its proper position. We unfortunately cannot do this + /// here because we need to construct the object before find its + /// proper position in the vector. We can then move the object, if + /// this is possible. + template constexpr std::pair emplace(Args &&...args) { + value_type tmp(std::forward(args)...); + iterator emplace_pos; + if constexpr (IsOrdered) { + emplace_pos = lower_bound(maybe_first(tmp)); } else { - return std::make_pair(emplace_pos, false); + emplace_pos = end(); + } + if (emplace_pos == end()) { + data_.emplace_back(std::move(tmp)); + return std::make_pair(std::prev(end()), true); + } else { + const bool same_key = !comp_(maybe_first(*emplace_pos), maybe_first(tmp)) && + !comp_(maybe_first(tmp), maybe_first(*emplace_pos)); + if (IsMulti || !same_key) { + typename vector_type::iterator emplaced_it = + data_.emplace(maybe_base(emplace_pos), std::move(tmp)); + return std::make_pair(iterator(emplaced_it), true); + } else { + return std::make_pair(emplace_pos, false); + } } } - } - /// \brief Insert value type - copy - std::pair insert(const value_type &v) { return emplace(v); } + /// \brief Insert value type - copy + std::pair insert(const value_type &v) { return emplace(v); } - /// \brief Insert value type - move - std::pair insert(value_type &&v) { return emplace(std::move(v)); } + /// \brief Insert value type - move + std::pair insert(value_type &&v) { return emplace(std::move(v)); } - /// \brief Insert value - construct - template - std::enable_if_t, std::pair> insert(P &&p) { - return emplace(std::forward

(p)); - } + /// \brief Insert value - construct + template + std::enable_if_t, std::pair> insert(P &&p) { + return emplace(std::forward

(p)); + } - /// \brief Insert in position - copy - iterator insert(const_iterator position, const value_type &v) { return emplace_hint(position, v); } + /// \brief Insert in position - copy + iterator insert(const_iterator position, const value_type &v) { return emplace_hint(position, v); } - /// \brief Insert in position - move - iterator insert(const_iterator position, value_type &&v) { return emplace_hint(position, std::move(v)); } + /// \brief Insert in position - move + iterator insert(const_iterator position, value_type &&v) { return emplace_hint(position, std::move(v)); } - /// \brief Insert value with hint - template - std::enable_if_t, iterator> insert(const_iterator position, P &&p) { - return emplace_hint(position, std::forward

(p)); - } + /// \brief Insert value with hint + template + std::enable_if_t, iterator> insert(const_iterator position, + P &&p) { + return emplace_hint(position, std::forward

(p)); + } - /// \brief Insert all values from iterators - template - void insert(InputIterator first, enable_if_iterator_t last) { - while (first != last) { - insert(*first); - ++first; + /// \brief Insert all values from iterators + template + void insert(InputIterator first, enable_if_iterator_t last) { + while (first != last) { + insert(*first); + ++first; + } } - } - /// \brief Insert all values from initializer list - void insert(std::initializer_list il) { insert(il.begin(), il.end()); } + /// \brief Insert all values from initializer list + void insert(std::initializer_list il) { insert(il.begin(), il.end()); } - /// \brief Emplace if key doesn't exist yet - template std::pair try_emplace(const key_type &k, Args &&...args) { - return emplace(value_type(std::piecewise_construct, std::forward_as_tuple(k), - std::forward_as_tuple(std::forward(args)...))); - } + /// \brief Emplace if key doesn't exist yet + template std::pair try_emplace(const key_type &k, Args &&...args) { + return emplace(value_type(std::piecewise_construct, std::forward_as_tuple(k), + std::forward_as_tuple(std::forward(args)...))); + } - /// \brief Emplace if key doesn't exist yet - template std::pair try_emplace(key_type &&k, Args &&...args) { - return emplace(value_type(std::piecewise_construct, std::forward_as_tuple(std::move(k)), - std::forward_as_tuple(std::forward(args)...))); - } + /// \brief Emplace if key doesn't exist yet + template std::pair try_emplace(key_type &&k, Args &&...args) { + return emplace(value_type(std::piecewise_construct, std::forward_as_tuple(std::move(k)), + std::forward_as_tuple(std::forward(args)...))); + } - /// \brief Emplace if key doesn't exist yet - template iterator try_emplace(const_iterator hint, const key_type &k, Args &&...args) { - return emplace_hint(hint, value_type(std::piecewise_construct, std::forward_as_tuple(k), - std::forward_as_tuple(std::forward(args)...))); - } + /// \brief Emplace if key doesn't exist yet + template iterator try_emplace(const_iterator hint, const key_type &k, Args &&...args) { + return emplace_hint(hint, value_type(std::piecewise_construct, std::forward_as_tuple(k), + std::forward_as_tuple(std::forward(args)...))); + } - /// \brief Emplace if key doesn't exist yet - template iterator try_emplace(const_iterator hint, key_type &&k, Args &&...args) { - return emplace_hint(hint, value_type(std::piecewise_construct, std::forward_as_tuple(std::move(k)), - std::forward_as_tuple(std::forward(args)...))); - } + /// \brief Emplace if key doesn't exist yet + template iterator try_emplace(const_iterator hint, key_type &&k, Args &&...args) { + return emplace_hint(hint, value_type(std::piecewise_construct, std::forward_as_tuple(std::move(k)), + std::forward_as_tuple(std::forward(args)...))); + } - /// \brief Insert if key doesn't exist, assign if key already exists - template std::pair insert_or_assign(const key_type &k, M &&obj) { - auto [it, ok] = insert(value_type(k, std::forward(obj))); - if (!ok) { - it->second = std::forward(obj); + /// \brief Insert if key doesn't exist, assign if key already exists + template std::pair insert_or_assign(const key_type &k, M &&obj) { + auto [it, ok] = insert(value_type(k, std::forward(obj))); + if (!ok) { + it->second = std::forward(obj); + } + return std::make_pair(it, ok); } - return std::make_pair(it, ok); - } - /// \brief Insert if key doesn't exist, assign if key already exists - template std::pair insert_or_assign(key_type &&k, M &&obj) { - auto [it, ok] = insert(value_type(std::move(k), std::forward(obj))); - if (!ok) { - it->second = std::forward(obj); + /// \brief Insert if key doesn't exist, assign if key already exists + template std::pair insert_or_assign(key_type &&k, M &&obj) { + auto [it, ok] = insert(value_type(std::move(k), std::forward(obj))); + if (!ok) { + it->second = std::forward(obj); + } + return std::make_pair(it, ok); } - return std::make_pair(it, ok); - } - /// \brief Insert if key doesn't exist, assign if key already exists - template iterator insert_or_assign(const_iterator hint, const key_type &k, M &&obj) { - auto [it, ok] = insert(hint, value_type(k, std::forward(obj))); - if (!ok) { - it->second = std::forward(obj); + /// \brief Insert if key doesn't exist, assign if key already exists + template iterator insert_or_assign(const_iterator hint, const key_type &k, M &&obj) { + auto [it, ok] = insert(hint, value_type(k, std::forward(obj))); + if (!ok) { + it->second = std::forward(obj); + } + return std::make_pair(it, ok); } - return std::make_pair(it, ok); - } - /// \brief Insert if key doesn't exist, assign if key already exists - template iterator insert_or_assign(const_iterator hint, key_type &&k, M &&obj) { - auto [it, ok] = insert(hint, value_type(std::move(k), std::forward(obj))); - if (!ok) { - it->second = std::forward(obj); + /// \brief Insert if key doesn't exist, assign if key already exists + template iterator insert_or_assign(const_iterator hint, key_type &&k, M &&obj) { + auto [it, ok] = insert(hint, value_type(std::move(k), std::forward(obj))); + if (!ok) { + it->second = std::forward(obj); + } + return std::make_pair(it, ok); } - return std::make_pair(it, ok); - } - /// \brief Erase element at a position in small map - constexpr iterator erase(const_iterator position) { return data_.erase(position.base()); } + /// \brief Erase element at a position in small map + constexpr iterator erase(const_iterator position) { return data_.erase(position.base()); } - /// \brief Erase element at a position in small map - iterator erase(iterator position) { - if constexpr (IsMap) { - return iterator(data_.erase(position.base())); - } else { - return iterator(data_.erase(position)); + /// \brief Erase element at a position in small map + iterator erase(iterator position) { + if constexpr (IsMap) { + return iterator(data_.erase(position.base())); + } else { + return iterator(data_.erase(position)); + } } - } - /// \brief Erase element at a position in small map - size_type erase(const key_type &k) { - auto it = find(k); - if (it != end()) { - erase(it); - return 1; + /// \brief Erase element at a position in small map + size_type erase(const key_type &k) { + auto it = find(k); + if (it != end()) { + erase(it); + return 1; + } + return 0; } - return 0; - } - /// \brief Erase range of elements in the small map - constexpr iterator erase(const_iterator first, const_iterator last) { - if constexpr (IsMap) { - return const_key_iterator(data_.erase(first.base(), last.base())); - } else { - return iterator(data_.erase(first, last)); + /// \brief Erase range of elements in the small map + constexpr iterator erase(const_iterator first, const_iterator last) { + if constexpr (IsMap) { + return const_key_iterator(data_.erase(first.base(), last.base())); + } else { + return iterator(data_.erase(first, last)); + } } - } - /// \brief Clear elements in the small map - constexpr void clear() noexcept { data_.clear(); } + /// \brief Clear elements in the small map + constexpr void clear() noexcept { data_.clear(); } - /// \brief Merge two flat maps - template - void merge(associative_vector &source) { - data_.insert(data_.end(), source.begin(), source.end()); - if constexpr (IsOrdered) { - std::sort(data_.begin(), data_.end(), value_comp()); + /// \brief Merge two flat maps + template + void merge(associative_vector &source) { + data_.insert(data_.end(), source.begin(), source.end()); + if constexpr (IsOrdered) { + std::sort(data_.begin(), data_.end(), value_comp()); + } } - } - /// \brief Merge two flat maps - template - void merge(associative_vector &&source) { - data_.insert(std::move_iterator(source.begin()), std::move_iterator(source.end())); - source.clear(); - if constexpr (IsOrdered) { - std::sort(data_.begin(), data_.end(), value_comp()); + /// \brief Merge two flat maps + template + void merge(associative_vector &&source) { + data_.insert(std::move_iterator(source.begin()), std::move_iterator(source.end())); + source.clear(); + if constexpr (IsOrdered) { + std::sort(data_.begin(), data_.end(), value_comp()); + } } - } - public /* map operations */: - /// \brief Find element in the small map - iterator find(const key_type &k) { - if (!IsOrdered || data_.size() < 100) { - for (auto it = data_.begin(); it != data_.end(); ++it) { + public /* map operations */: + /// \brief Find element in the small map + iterator find(const key_type &k) { + if (!IsOrdered || data_.size() < 100) { + for (auto it = data_.begin(); it != data_.end(); ++it) { + const bool found = [&]() { + if constexpr (IsMap) { + return it->first == k; + } else { + return *it == k; + } + }(); + if (found) { + return iterator(it); + } + } + return end(); + } else { + auto it = lower_bound(k); const bool found = [&]() { if constexpr (IsMap) { return it->first == k; @@ -624,268 +645,257 @@ namespace small { } }(); if (found) { - return iterator(it); - } - } - return end(); - } else { - auto it = lower_bound(k); - const bool found = [&]() { - if constexpr (IsMap) { - return it->first == k; + return it; } else { - return *it == k; + return end(); } - }(); - if (found) { - return it; - } else { - return end(); } } - } - /// \brief Find element in the small map - const_iterator find(const key_type &k) const { return (const_cast(this))->find(k); } + /// \brief Find element in the small map + const_iterator find(const key_type &k) const { return (const_cast(this))->find(k); } - /// \brief Find element in the small map - template iterator find(const K &x) { - if (!IsOrdered || data_.size() < 100) { - for (auto it = data_.begin(); it != data_.end(); ++it) { - if (it->first == x) { - return const_key_iterator(it); + /// \brief Find element in the small map + template iterator find(const K &x) { + if (!IsOrdered || data_.size() < 100) { + for (auto it = data_.begin(); it != data_.end(); ++it) { + if (it->first == x) { + return const_key_iterator(it); + } } - } - return end(); - } else { - auto it = lower_bound(x); - if (it->first == x) { - return it; - } else { return end(); + } else { + auto it = lower_bound(x); + if (it->first == x) { + return it; + } else { + return end(); + } } } - } - /// \brief Find element in the small map - template const_iterator find(const K &x) const { - return (const_cast(this))->find(x); - } + /// \brief Find element in the small map + template const_iterator find(const K &x) const { + return (const_cast(this))->find(x); + } - /// \brief Count elements with a given key (0 or 1) - template size_type count(const K &x) const { return find(x) != end() ? 1 : 0; } + /// \brief Count elements with a given key (0 or 1) + template size_type count(const K &x) const { return find(x) != end() ? 1 : 0; } - /// \brief Count elements with a given key (0 or 1) - size_type count(const key_type &k) const { return find(k) != end() ? 1 : 0; } + /// \brief Count elements with a given key (0 or 1) + size_type count(const key_type &k) const { return find(k) != end() ? 1 : 0; } - /// \brief Check if elements with a given key exists - template bool contains(const K &x) const { return count(x) > 0; } + /// \brief Check if elements with a given key exists + template bool contains(const K &x) const { return count(x) > 0; } - /// \brief Check if elements with a given key exists - bool contains(const key_type &x) const { return count(x) > 0; } + /// \brief Check if elements with a given key exists + bool contains(const key_type &x) const { return count(x) > 0; } - /// \brief Iterator to first element not less than key - /// This will only work properly for ordered containers - iterator lower_bound(const key_type &k) { - return iterator(std::lower_bound(data_.begin(), data_.end(), k, [this](const auto &p, const auto &v) { - return comp_(maybe_first(p), v); - })); - } + /// \brief Iterator to first element not less than key + /// This will only work properly for ordered containers + iterator lower_bound(const key_type &k) { + return iterator(std::lower_bound(data_.begin(), data_.end(), k, [this](const auto &p, const auto &v) { + return comp_(maybe_first(p), v); + })); + } - /// \brief Iterator to first element not less than key - /// This will only work properly for ordered containers - const_iterator lower_bound(const key_type &k) const { - return const_iterator((const_cast(this))->template lower_bound(k)); - } + /// \brief Iterator to first element not less than key + /// This will only work properly for ordered containers + const_iterator lower_bound(const key_type &k) const { + return const_iterator((const_cast(this))->template lower_bound(k)); + } - /// \brief Iterator to first element not less than key - /// This will only work properly for ordered containers - template iterator lower_bound(const K &x) { - return const_key_iterator(std::lower_bound( - data_.begin(), data_.end(), x, - [this](const typename vector_type::value_type &p, const K &v) { return comp_(p.first, v); })); - } + /// \brief Iterator to first element not less than key + /// This will only work properly for ordered containers + template iterator lower_bound(const K &x) { + return const_key_iterator(std::lower_bound( + data_.begin(), data_.end(), x, + [this](const typename vector_type::value_type &p, const K &v) { return comp_(p.first, v); })); + } - /// \brief Iterator to first element not less than key - template const_iterator lower_bound(const K &x) const { - return const_iterator((const_cast(this))->template lower_bound(x)); - } + /// \brief Iterator to first element not less than key + template const_iterator lower_bound(const K &x) const { + return const_iterator((const_cast(this))->template lower_bound(x)); + } - /// \brief Iterator to first element greater than key - iterator upper_bound(const key_type &k) { - return const_key_iterator(std::upper_bound( - data_.begin(), data_.end(), k, - [this](const typename vector_type::value_type &p, const key_type &v) { return comp_(p.first, v); })); - } + /// \brief Iterator to first element greater than key + iterator upper_bound(const key_type &k) { + return const_key_iterator(std::upper_bound(data_.begin(), data_.end(), k, + [this](const typename vector_type::value_type &p, + const key_type &v) { return comp_(p.first, v); })); + } - /// \brief Iterator to first element greater than key - const_iterator upper_bound(const key_type &k) const { - return const_iterator((const_cast(this))->template upper_bound(k)); - } + /// \brief Iterator to first element greater than key + const_iterator upper_bound(const key_type &k) const { + return const_iterator((const_cast(this))->template upper_bound(k)); + } - /// \brief Iterator to first element greater than key - template iterator upper_bound(const K &x) { - return const_key_iterator(std::upper_bound( - data_.begin(), data_.end(), x, [this](const auto &p, const auto &v) { return comp_(p.first, v); })); - } + /// \brief Iterator to first element greater than key + template iterator upper_bound(const K &x) { + return const_key_iterator(std::upper_bound( + data_.begin(), data_.end(), x, [this](const auto &p, const auto &v) { return comp_(p.first, v); })); + } - /// \brief Iterator to first element greater than key - template const_iterator upper_bound(const K &x) const { - return const_iterator((const_cast(this))->template upper_bound(x)); - } + /// \brief Iterator to first element greater than key + template const_iterator upper_bound(const K &x) const { + return const_iterator((const_cast(this))->template upper_bound(x)); + } - /// \brief Get pair with lower_bound and upper_bound - std::pair equal_range(const key_type &k) { - return std::make_pair(lower_bound(k), upper_bound(k)); - } + /// \brief Get pair with lower_bound and upper_bound + std::pair equal_range(const key_type &k) { + return std::make_pair(lower_bound(k), upper_bound(k)); + } - /// \brief Get pair with lower_bound and upper_bound - std::pair equal_range(const key_type &k) const { - return std::make_pair(lower_bound(k), upper_bound(k)); - } + /// \brief Get pair with lower_bound and upper_bound + std::pair equal_range(const key_type &k) const { + return std::make_pair(lower_bound(k), upper_bound(k)); + } - /// \brief Get pair with lower_bound and upper_bound - template std::pair equal_range(const K &x) { - return std::make_pair(lower_bound(x), upper_bound(x)); - } + /// \brief Get pair with lower_bound and upper_bound + template std::pair equal_range(const K &x) { + return std::make_pair(lower_bound(x), upper_bound(x)); + } - /// \brief Get pair with lower_bound and upper_bound - template std::pair equal_range(const K &x) const { - return std::make_pair(lower_bound(x), upper_bound(x)); - } + /// \brief Get pair with lower_bound and upper_bound + template std::pair equal_range(const K &x) const { + return std::make_pair(lower_bound(x), upper_bound(x)); + } - private: - private /* element access */: - /// \brief Logic to access a mapped_type - template constexpr mapped_type &element_access_implementation(const K &k) { - if constexpr (IsMap) { - iterator it = find(k); - if (it == end()) { - if constexpr (create_if_not_found) { - std::tie(it, std::ignore) = - emplace(std::piecewise_construct, std::forward_as_tuple(k), std::tuple<>()); - } else { - throw_exception("at(): cannot find element in vector map"); + private: + private /* element access */: + /// \brief Logic to access a mapped_type + template + constexpr mapped_type &element_access_implementation(const K &k) { + if constexpr (IsMap) { + iterator it = find(k); + if (it == end()) { + if constexpr (create_if_not_found) { + std::tie(it, std::ignore) = + emplace(std::piecewise_construct, std::forward_as_tuple(k), std::tuple<>()); + } else { + throw_exception("at(): cannot find element in vector map"); + } } + return it->second; + } else { + return data_.at(k); } - return it->second; - } else { - return data_.at(k); } - } - /// \brief Logic to access a mapped_type - template constexpr mapped_type &element_access_implementation(K &&k) { - if constexpr (IsMap) { - iterator it = find(k); - if (it == end()) { - if constexpr (create_if_not_found) { - std::tie(it, std::ignore) = - emplace(std::piecewise_construct, std::forward_as_tuple(std::move(k)), std::tuple<>()); - } else { - throw_exception("at(): cannot find element in vector map"); + /// \brief Logic to access a mapped_type + template constexpr mapped_type &element_access_implementation(K &&k) { + if constexpr (IsMap) { + iterator it = find(k); + if (it == end()) { + if constexpr (create_if_not_found) { + std::tie(it, std::ignore) = + emplace(std::piecewise_construct, std::forward_as_tuple(std::move(k)), std::tuple<>()); + } else { + throw_exception("at(): cannot find element in vector map"); + } } + return it->second; + } else { + return data_.at(k); + } + } + + /// \brief Logic to access a mapped_type + template + constexpr mapped_type &element_access_implementation(const K &k) const { + return (const_cast(this))->template element_access_implementation(k); + } + + /// \brief Logic to access a mapped_type + template + constexpr mapped_type &element_access_implementation(K &&k) const { + return (const_cast(this)) + ->template element_access_implementation(std::move(k)); + } + + /// \brief Check if small map invariants are ok + [[nodiscard]] constexpr bool invariants() const { + if constexpr (IsOrdered) { + return std::is_sorted(data_.begin(), data_.end(), value_comp()); + } else { + return true; + } + } + + template constexpr static auto &maybe_first(EL &el) { + if constexpr (IsMap) { + return el.first; + } else { + return el; + } + } + + template constexpr static auto maybe_base(EL &el) { + if constexpr (IsMap) { + return el.base(); + } else { + return el; } - return it->second; - } else { - return data_.at(k); } + + private: + /// \brief Internal vector or map + vector_type data_{}; + + /// \brief A copy of the allocator so we can allocate vectors if needed + key_compare comp_{}; + }; + + /// \brief operator== for flat maps + template + constexpr bool operator==(const associative_vector &x, + const associative_vector &y) { + return std::equal(x.begin(), x.end(), y.begin(), y.end()); } - /// \brief Logic to access a mapped_type - template - constexpr mapped_type &element_access_implementation(const K &k) const { - return (const_cast(this))->template element_access_implementation(k); + /// \brief operator!= for flat maps + template + constexpr bool operator!=(const associative_vector &x, + const associative_vector &y) { + return !(x == y); } - /// \brief Logic to access a mapped_type - template constexpr mapped_type &element_access_implementation(K &&k) const { - return (const_cast(this)) - ->template element_access_implementation(std::move(k)); + /// \brief operator< for flat maps + template + constexpr bool operator<(const associative_vector &x, + const associative_vector &y) { + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } - /// \brief Check if small map invariants are ok - [[nodiscard]] constexpr bool invariants() const { - if constexpr (IsOrdered) { - return std::is_sorted(data_.begin(), data_.end(), value_comp()); - } else { - return true; - } + /// \brief operator> for flat maps + template + constexpr bool operator>(const associative_vector &x, + const associative_vector &y) { + return y < x; } - template constexpr static auto &maybe_first(EL &el) { - if constexpr (IsMap) { - return el.first; - } else { - return el; - } + /// \brief operator<= for flat maps + template + constexpr bool operator<=(const associative_vector &x, + const associative_vector &y) { + return !(y < x); } - template constexpr static auto maybe_base(EL &el) { - if constexpr (IsMap) { - return el.base(); - } else { - return el; - } + /// \brief operator>= for flat maps + template + constexpr bool operator>=(const associative_vector &x, + const associative_vector &y) { + return !(x < y); } - private: - /// \brief Internal vector or map - vector_type data_{}; - - /// \brief A copy of the allocator so we can allocate vectors if needed - key_compare comp_{}; - }; - - /// \brief operator== for flat maps - template - constexpr bool operator==(const associative_vector &x, - const associative_vector &y) { - return std::equal(x.begin(), x.end(), y.begin(), y.end()); - } - - /// \brief operator!= for flat maps - template - constexpr bool operator!=(const associative_vector &x, - const associative_vector &y) { - return !(x == y); - } - - /// \brief operator< for flat maps - template - constexpr bool operator<(const associative_vector &x, - const associative_vector &y) { - return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); - } - - /// \brief operator> for flat maps - template - constexpr bool operator>(const associative_vector &x, - const associative_vector &y) { - return y < x; - } - - /// \brief operator<= for flat maps - template - constexpr bool operator<=(const associative_vector &x, - const associative_vector &y) { - return !(y < x); - } - - /// \brief operator>= for flat maps - template - constexpr bool operator>=(const associative_vector &x, - const associative_vector &y) { - return !(x < y); - } - - /// \brief swap the contents of two flat maps - template - void swap(associative_vector &x, - associative_vector &y) noexcept(noexcept(x.swap(y))) { - x.swap(y); - } + /// \brief swap the contents of two flat maps + template + void swap(associative_vector &x, + associative_vector &y) noexcept(noexcept(x.swap(y))) { + x.swap(y); + } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_CONTAINER_ASSOCIATIVE_VECTOR_H diff --git a/source/small/detail/container/lookup_table_view.h b/source/small/detail/container/lookup_table_view.h index fa09cd9..0f9afb2 100644 --- a/source/small/detail/container/lookup_table_view.h +++ b/source/small/detail/container/lookup_table_view.h @@ -5,1319 +5,1337 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_CONTAINER_LOOKUP_TABLE_VIEW_H #define SMALL_DETAIL_CONTAINER_LOOKUP_TABLE_VIEW_H -#include #include +#include #include "../algorithm/to_unsigned.h" #include "../algorithm/utf.h" #include "small/detail/algorithm/shift.h" -#include "span-lite.h" #include "small/detail/exception/throw.h" +#include "span-lite.h" namespace small { - /// \class small::string lookup table - /// - /// This container represents a span of bytes from a small::string representing a lookup table for codepoints. - /// Because of how these tables works, the API is a little weird as it resembles the vector API when inserting - /// elements and the map API when querying elements. - /// - /// We can access and manipulate this lookup table from an API that resembles a map so that - /// it's easy and efficient to manipulate the lookup table from the a small::string. - /// - /// Lookup tables are fundamental to allow random access to utf8 strings, since these string - /// may contain multibyte codepoints. - /// - /// With this lookup table, we can access any codepoint in O(1) time! - /// - /// A codepoint iterator is a random access iterator to (logical) tuples generated lazily. - /// - /// An iterator that points to the i-th multibyte codepoint, lazily/logically dereferences to - /// a std::tuple with the following elements: - /// - <0>: index of the i-th multibyte codepoint among other multibyte codepoints - /// - <1>: index of the i-th multibyte codepoint in the byte string (in which byte it starts) - /// - <2>: index of the i-th multibyte codepoint among all codepoints - /// - /// This values are calculated are returned by the iterator but not stored anywhere. - /// So to make this easier to remember and to avoid calculating something we don't need, - /// each iterator provides the following functions to calculate only the relevante elements: - /// - <0>: iterator::multibyte_index(); - /// - <1>: iterator::byte_index(); - /// - <2>: iterator::codepoint_index(); - /// - /// Example: - /// - If we create a string "a😀b😆c🤣" - /// - The lookup table will contain information about the "😀", "😆", "🤣" codepoints - /// - Iterating these codepoints from begin() to end() and returning all its values we would get: - /// - pre condition: it = table.begin(); - /// - step 1: it == make_tuple(/* multibyte_index */ 0, /* byte_index /* 1, /* codepoint_index */ 1); it++; - /// - step 2: it == make_tuple(/* multibyte_index */ 1, /* byte_index /* 6, /* codepoint_index */ 3); it++; - /// - step 3: it == make_tuple(/* multibyte_index */ 2, /* byte_index /* 11, /* codepoint_index */ 5); it++; - /// - post condition: it == table.end(); - /// - /// The internal workings of this table are a little more complicated. - /// - /// Example: - /// - The string "a😀b😆c🤣" has: - /// - 6 codepoints - /// - 3 1-byte codepoints - /// - 3 4-byte codepoints - /// - 3 * 1 + 3 * 4 = 15 bytes in total - /// - /// - The codepoint positions (0-indexed) are: - /// - 'a' - codepoint_index: 0 - byte_index: 0 - /// - '😀' - codepoint_index: 1 - byte_index: 1 - /// - 'b' - codepoint_index: 2 - byte_index: 5 - /// - '😆' - codepoint_index: 3 - byte_index: 6 - /// - 'c' - codepoint_index: 4 - byte_index: 10 - /// - '🤣' - codepoint_index: 5 - byte_index: 11 - /// - /// - The lookup table indexes only multibyte codepoints, so it contains: - /// - '😀' - multibyte_codepoint_index: 0: byte_index: 1 (codepoint_index: 1) - /// - '😆' - multibyte_codepoint_index: 1: byte_index: 6 (codepoint_index: 3) - /// - '🤣' - multibyte_codepoint_index: 2: byte_index: 11 (codepoint_index: 5) - /// - /// - In C++, the codepoint iterators in the range begin()/end() would dereference to: - /// - '😀' - std::pair(/* multibyte_index */ 0, /* byte_index */ 1) /* codepoint_index 1 */ - /// - '😆' - std::pair(/* multibyte_index */ 1, /* byte_index */ 6) /* codepoint_index 3 */ - /// - '🤣' - std::pair(/* multibyte_index */ 2, /* byte_index */ 11) /* codepoint_index 5 */ - /// - /// This compact information allows us to find codepoints in a string by their index - /// in O(m) time, where m is the number of multibyte indexes. Meanwhile, the common - /// 1-byte codepoint strings are not penalized and still have random access in O(1) time. - /// - /// Note that: - /// (i) even though '😆' is in the table, if we want the codepoint index 3 of '😆', this table does - /// not contain this information. We need to iterate the multibyte indexes to identify the - /// codepoint index of '😆'. This is what makes the operation O(m) on the number of multibyte - /// codepoints. - /// (ii) the table makes us spend at least one extra byte per multibyte codepoint in strings - /// with up to 256 bytes (two extra bytes in strings with up to 2^15=65536). If the - /// string is mostly multibyte, we have a 25%-100% larger string (from 4 byte codepoints - /// to 2 byte codepoints). If we consider the usual growth factor of vectors and assume - /// we always use their reserved space, this would be more like 6%-75%. - /// - /// So we are very efficient for strings with mostly 1-byte codepoints, but the next problem - /// is generalizing that for strings with O(n) multibyte codepoints. So, in summary, our - /// next problem is: - /// - We have this high time and memory cost when generalizing for strings with O(n) - /// multibyte codepoints, where O(m) becomes O(n)). - /// - we already spend about 6%-75% extra memory for codepoints, which is a reasonable cost, - /// but we cannot store much more stuff in the lookup table or it would be less efficient - /// than converting from and to UTF32. - /// - /// From the perspective of memory, the problem with many extra bytes is not that they are O(m), - /// but that this constant needs to be less than 3 bytes for most cases or it would be simpler to - /// use UTF16 and UTF32 strings when we have O(n) multibyte codepoints. Although simply not supporting - /// this operation in O(1) for this case, we want our strings to at least generalize well with O(1) - /// time when that's the case. - /// - /// Given these constraints, when generalizing the lookup tables to make them O(1) for - /// strings with O(n) multibyte codepoints, some obvious (bad) ideas come to mind: - /// - Storing the codepoint index rather than the byte index (this is just replacing one - /// rarer O(m) operation with one expensive O(n) on which we depend more) - /// - Storing the codepoint index AND the byte index in the lookup table. This does work, - /// but makes us spend 12%-150% more bytes per code points, which is not reasonable. - /// - /// The solution to this problem is to spread the codepoint index information in the table. - /// If we know the codepoint index of a codepoint, we also know the codepoint index of the next - /// codepoint with a constant operation. - /// - /// We do not need the codepoint index of all codepoints to keep this operation constant. - /// All we need is the information for some codepoint such that we can ensure we can find a relative - /// codepoint index in constant time: - /// - /// - Inserting codepoint indexes in the table (codepoint stride = 1) - /// - '😀' - multibyte_codepoint_index: 0 / byte_index: 1 / codepoint_index: 1 - /// - '😆' - multibyte_codepoint_index: 1 / byte_index: 6 / codepoint_index: 3 - /// - '🤣' - multibyte_codepoint_index: 2 / byte_index: 11 / codepoint_index: 5 - /// - /// - Inserting codepoint indexes in the table (codepoint stride = 2) - /// - '😀' - multibyte_codepoint_index: 0 / byte_index: 1 - /// - '😆' - multibyte_codepoint_index: 1 / byte_index: 6 / codepoint_index: 3 - /// - '🤣' - multibyte_codepoint_index: 2 / byte_index: 11 - /// - /// Note that we create a codepoint entry when (i % stride == stride - 1) instead of - /// i % stride == 0 to ensure no larger entries are created unless we need to. - /// - /// When the stride = 1, we have 1 codepoint index reference for each codepoint. - /// - [6% , 75%] extra memory per multibyte codepoint indexed in the lookup table - /// - First subscript access as fast as in 1-byte codepoint string (but O(1) rather than O(m)) - /// When the stride = 2, we have 1 codepoint index reference for every 2 codepoints. - /// - [3% , 37%] extra memory per multibyte codepoint indexed in the lookup table - /// - First subscript access 1.5 slower as in 1-byte codepoint string (but still O(1) rather than O(m)) - /// When the stride = 10, we have 1 codepoint index reference for every 10 codepoints. - /// - [2.5% , 7.5%] extra memory per multibyte codepoint indexed in the lookup table - /// - First subscript access 5 times slower as in 1-byte codepoint string (but still O(1) rather than O(m)) - /// When the stride = 100, we have 1 codepoint index reference for every 100 codepoints. - /// - [0.25% , 0.75%] extra memory per multibyte codepoint indexed in the lookup table - /// - First subscript access 50 times slower as in 1-byte codepoint string (but still O(1) rather than O(m)) - /// When the stride = n, we have 1 codepoint index reference for every n codepoints. - /// - [25/n%, 37/n%] extra memory per multibyte codepoint indexed in the lookup table - /// - First subscript access n/2 slower as in 1-byte codepoint string (but still O(1) rather than O(m)) - /// - /// A minor problem is that entries in the lookup table don't have fixed size anymore, which - /// is fine, as we are already operating the the byte level and these steps are predictable. - /// - /// A second problem is defining a default step size. - /// - /// Although any O(1) step size will keep subscript access to O(1) in any case, and bidirectional - /// iterators can take it from there: - /// - subscript access is still fast (O(1)) whenever m = O(1) - /// - a small n will make multibyte subscript access faster (still O(1)) at a higher memory cost when m = O(n) - /// - a large n will make multibyte subscript access slower (still O(1)) at a lower memory cost when m = O(n) - /// - /// Considering that: - /// - this an edge case for which we still want O(1) subscript access, - /// - there's no extra access cost after the first access if user uses iterators from the first codepoint found, - /// - the proportions involved in memory cost when changing to UTF16-UTF32: [100%,400%] more for all codepoints - /// - this step size can be adjusted through an extra template parameter if this happens to be a problem - /// - /// We settle on a default step size = 10: - /// - an extra [2.5% , 7.5%] memory cost is much less than the [100%,400%] memory cost of UTF16/UTF32 - /// - an extra 10 times subscript access cost for the first access can be easily amortized by subsequent - /// accesses with iterators or by not using subscript access at all - /// - there's no penalty at all for one-byte codepoint strings - /// - template - class lookup_table_view_impl { - public: - /// \section Custom types - using byte_type = - std::conditional_t; - static constexpr nonstd::span_lite::extent_t dynamic_extent_value = nonstd::span_lite::dynamic_extent; - using byte_span_type = nonstd::span; - using string_view_type = std::basic_string_view; - - public: - /// \section Usual map types - /// The types return SizeType because that's what they refer to - /// A number of transformations need happen before the size_type value is obtained - /// because the values are stored in less than sizeof(size_type) bytes, so this container - /// doesn't return references at all, because there's no point in emulating them. - - typedef SizeType key_type; - typedef SizeType mapped_type; - typedef std::pair value_type; - typedef std::less<> key_compare; - typedef value_type reference; - typedef const value_type const_reference; - typedef value_type pointer; - typedef const value_type const_pointer; - typedef SizeType size_type; - typedef ptrdiff_t difference_type; - - private: - /// \section Iterator implementation - - /// \brief An iterator to access the values in the lookup table - /// The layout of a lookup table in bytes is somewhat reversed - /// - The last byte indicates the size of its size - /// - The bytes before indicate its size - /// - The bytes before represent the entries - /// That's why the iterator is moving backwards in the span when it's moving forward in the table - template class iterator_impl { - public: - /// \section Types - /// The types are the same for const and mutable iterators because this container - /// is a view that doesn't return references. Everything is calculated and returned by value. - typedef std::random_access_iterator_tag iterator_category; - typedef typename lookup_table_view_impl::value_type value_type; - typedef typename lookup_table_view_impl::difference_type difference_type; - typedef typename lookup_table_view_impl::pointer pointer; - typedef typename lookup_table_view_impl::reference reference; - + namespace detail { + /// \class small::string lookup table + /// + /// This container represents a span of bytes from a small::string representing a lookup table for codepoints. + /// Because of how these tables works, the API is a little weird as it resembles the vector API when inserting + /// elements and the map API when querying elements. + /// + /// We can access and manipulate this lookup table from an API that resembles a map so that + /// it's easy and efficient to manipulate the lookup table from the a small::string. + /// + /// Lookup tables are fundamental to allow random access to utf8 strings, since these string + /// may contain multibyte codepoints. + /// + /// With this lookup table, we can access any codepoint in O(1) time! + /// + /// A codepoint iterator is a random access iterator to (logical) tuples generated lazily. + /// + /// An iterator that points to the i-th multibyte codepoint, lazily/logically dereferences to + /// a std::tuple with the following elements: + /// - <0>: index of the i-th multibyte codepoint among other multibyte codepoints + /// - <1>: index of the i-th multibyte codepoint in the byte string (in which byte it starts) + /// - <2>: index of the i-th multibyte codepoint among all codepoints + /// + /// This values are calculated are returned by the iterator but not stored anywhere. + /// So to make this easier to remember and to avoid calculating something we don't need, + /// each iterator provides the following functions to calculate only the relevante elements: + /// - <0>: iterator::multibyte_index(); + /// - <1>: iterator::byte_index(); + /// - <2>: iterator::codepoint_index(); + /// + /// Example: + /// - If we create a string "a😀b😆c🤣" + /// - The lookup table will contain information about the "😀", "😆", "🤣" codepoints + /// - Iterating these codepoints from begin() to end() and returning all its values we would get: + /// - pre condition: it = table.begin(); + /// - step 1: it == make_tuple(/* multibyte_index */ 0, /* byte_index /* 1, /* codepoint_index */ 1); + /// it++; + /// - step 2: it == make_tuple(/* multibyte_index */ 1, /* byte_index /* 6, /* codepoint_index */ 3); + /// it++; + /// - step 3: it == make_tuple(/* multibyte_index */ 2, /* byte_index /* 11, /* codepoint_index */ 5); + /// it++; + /// - post condition: it == table.end(); + /// + /// The internal workings of this table are a little more complicated. + /// + /// Example: + /// - The string "a😀b😆c🤣" has: + /// - 6 codepoints + /// - 3 1-byte codepoints + /// - 3 4-byte codepoints + /// - 3 * 1 + 3 * 4 = 15 bytes in total + /// + /// - The codepoint positions (0-indexed) are: + /// - 'a' - codepoint_index: 0 - byte_index: 0 + /// - '😀' - codepoint_index: 1 - byte_index: 1 + /// - 'b' - codepoint_index: 2 - byte_index: 5 + /// - '😆' - codepoint_index: 3 - byte_index: 6 + /// - 'c' - codepoint_index: 4 - byte_index: 10 + /// - '🤣' - codepoint_index: 5 - byte_index: 11 + /// + /// - The lookup table indexes only multibyte codepoints, so it contains: + /// - '😀' - multibyte_codepoint_index: 0: byte_index: 1 (codepoint_index: 1) + /// - '😆' - multibyte_codepoint_index: 1: byte_index: 6 (codepoint_index: 3) + /// - '🤣' - multibyte_codepoint_index: 2: byte_index: 11 (codepoint_index: 5) + /// + /// - In C++, the codepoint iterators in the range begin()/end() would dereference to: + /// - '😀' - std::pair(/* multibyte_index */ 0, /* byte_index */ 1) /* codepoint_index 1 */ + /// - '😆' - std::pair(/* multibyte_index */ 1, /* byte_index */ 6) /* codepoint_index 3 */ + /// - '🤣' - std::pair(/* multibyte_index */ 2, /* byte_index */ 11) /* codepoint_index 5 */ + /// + /// This compact information allows us to find codepoints in a string by their index + /// in O(m) time, where m is the number of multibyte indexes. Meanwhile, the common + /// 1-byte codepoint strings are not penalized and still have random access in O(1) time. + /// + /// Note that: + /// (i) even though '😆' is in the table, if we want the codepoint index 3 of '😆', this table does + /// not contain this information. We need to iterate the multibyte indexes to identify the + /// codepoint index of '😆'. This is what makes the operation O(m) on the number of multibyte + /// codepoints. + /// (ii) the table makes us spend at least one extra byte per multibyte codepoint in strings + /// with up to 256 bytes (two extra bytes in strings with up to 2^15=65536). If the + /// string is mostly multibyte, we have a 25%-100% larger string (from 4 byte codepoints + /// to 2 byte codepoints). If we consider the usual growth factor of vectors and assume + /// we always use their reserved space, this would be more like 6%-75%. + /// + /// So we are very efficient for strings with mostly 1-byte codepoints, but the next problem + /// is generalizing that for strings with O(n) multibyte codepoints. So, in summary, our + /// next problem is: + /// - We have this high time and memory cost when generalizing for strings with O(n) + /// multibyte codepoints, where O(m) becomes O(n)). + /// - we already spend about 6%-75% extra memory for codepoints, which is a reasonable cost, + /// but we cannot store much more stuff in the lookup table or it would be less efficient + /// than converting from and to UTF32. + /// + /// From the perspective of memory, the problem with many extra bytes is not that they are O(m), + /// but that this constant needs to be less than 3 bytes for most cases or it would be simpler to + /// use UTF16 and UTF32 strings when we have O(n) multibyte codepoints. Although simply not supporting + /// this operation in O(1) for this case, we want our strings to at least generalize well with O(1) + /// time when that's the case. + /// + /// Given these constraints, when generalizing the lookup tables to make them O(1) for + /// strings with O(n) multibyte codepoints, some obvious (bad) ideas come to mind: + /// - Storing the codepoint index rather than the byte index (this is just replacing one + /// rarer O(m) operation with one expensive O(n) on which we depend more) + /// - Storing the codepoint index AND the byte index in the lookup table. This does work, + /// but makes us spend 12%-150% more bytes per code points, which is not reasonable. + /// + /// The solution to this problem is to spread the codepoint index information in the table. + /// If we know the codepoint index of a codepoint, we also know the codepoint index of the next + /// codepoint with a constant operation. + /// + /// We do not need the codepoint index of all codepoints to keep this operation constant. + /// All we need is the information for some codepoint such that we can ensure we can find a relative + /// codepoint index in constant time: + /// + /// - Inserting codepoint indexes in the table (codepoint stride = 1) + /// - '😀' - multibyte_codepoint_index: 0 / byte_index: 1 / codepoint_index: 1 + /// - '😆' - multibyte_codepoint_index: 1 / byte_index: 6 / codepoint_index: 3 + /// - '🤣' - multibyte_codepoint_index: 2 / byte_index: 11 / codepoint_index: 5 + /// + /// - Inserting codepoint indexes in the table (codepoint stride = 2) + /// - '😀' - multibyte_codepoint_index: 0 / byte_index: 1 + /// - '😆' - multibyte_codepoint_index: 1 / byte_index: 6 / codepoint_index: 3 + /// - '🤣' - multibyte_codepoint_index: 2 / byte_index: 11 + /// + /// Note that we create a codepoint entry when (i % stride == stride - 1) instead of + /// i % stride == 0 to ensure no larger entries are created unless we need to. + /// + /// When the stride = 1, we have 1 codepoint index reference for each codepoint. + /// - [6% , 75%] extra memory per multibyte codepoint indexed in the lookup table + /// - First subscript access as fast as in 1-byte codepoint string (but O(1) rather than O(m)) + /// When the stride = 2, we have 1 codepoint index reference for every 2 codepoints. + /// - [3% , 37%] extra memory per multibyte codepoint indexed in the lookup table + /// - First subscript access 1.5 slower as in 1-byte codepoint string (but still O(1) rather than O(m)) + /// When the stride = 10, we have 1 codepoint index reference for every 10 codepoints. + /// - [2.5% , 7.5%] extra memory per multibyte codepoint indexed in the lookup table + /// - First subscript access 5 times slower as in 1-byte codepoint string (but still O(1) rather than O(m)) + /// When the stride = 100, we have 1 codepoint index reference for every 100 codepoints. + /// - [0.25% , 0.75%] extra memory per multibyte codepoint indexed in the lookup table + /// - First subscript access 50 times slower as in 1-byte codepoint string (but still O(1) rather than O(m)) + /// When the stride = n, we have 1 codepoint index reference for every n codepoints. + /// - [25/n%, 37/n%] extra memory per multibyte codepoint indexed in the lookup table + /// - First subscript access n/2 slower as in 1-byte codepoint string (but still O(1) rather than O(m)) + /// + /// A minor problem is that entries in the lookup table don't have fixed size anymore, which + /// is fine, as we are already operating the the byte level and these steps are predictable. + /// + /// A second problem is defining a default step size. + /// + /// Although any O(1) step size will keep subscript access to O(1) in any case, and bidirectional + /// iterators can take it from there: + /// - subscript access is still fast (O(1)) whenever m = O(1) + /// - a small n will make multibyte subscript access faster (still O(1)) at a higher memory cost when m = O(n) + /// - a large n will make multibyte subscript access slower (still O(1)) at a lower memory cost when m = O(n) + /// + /// Considering that: + /// - this an edge case for which we still want O(1) subscript access, + /// - there's no extra access cost after the first access if user uses iterators from the first codepoint found, + /// - the proportions involved in memory cost when changing to UTF16-UTF32: [100%,400%] more for all codepoints + /// - this step size can be adjusted through an extra template parameter if this happens to be a problem + /// + /// We settle on a default step size = 10: + /// - an extra [2.5% , 7.5%] memory cost is much less than the [100%,400%] memory cost of UTF16/UTF32 + /// - an extra 10 times subscript access cost for the first access can be easily amortized by subsequent + /// accesses with iterators or by not using subscript access at all + /// - there's no penalty at all for one-byte codepoint strings + /// + template + class lookup_table_view_impl { public: - /// \section Constructors - - /// \brief Construct empty lookup table iterator which not good for much - constexpr iterator_impl() noexcept : base_table_(nullptr), multibyte_index_(0) {} - - /// \brief Construct lookup table iterator from the table and the position - constexpr explicit iterator_impl(const lookup_table_view_impl *base, size_type index) noexcept - : base_table_(base), multibyte_index_(index) {} - - /// \brief Construct lookup table iterator from another lookup table iterator - /// Const iterators can be created from mutable iterators but not the other way around - template = 0> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr iterator_impl(const iterator_impl &rhs) noexcept - : base_table_(rhs.base_table_), multibyte_index_(rhs.multibyte_index_) {} + /// \section Custom types + using byte_type = std::conditional_t; + static constexpr nonstd::span_lite::extent_t dynamic_extent_value = nonstd::span_lite::dynamic_extent; + using byte_span_type = nonstd::span; + using string_view_type = std::basic_string_view; public: - /// \section Codepoint information functions - /// These are the functions we really need because they are more efficient and - /// it's where the logic for finding codepoint indexes is implemented - - /// \brief Get the multibyte index of this codepoint among other multibyte indexes - /// This is the easiest function because it's what the iterator refers to - constexpr size_type multibyte_index() const { return multibyte_index_; } - - /// \brief Get the span on bytes in the lookup table representing this entry - /// A pointer to the position where the mapped type of a byte index is stored - /// and the entry size is obtained in the resulting span - /// \return Span to bytes in the lookup table relative to this iterator - [[nodiscard]] constexpr byte_span_type span() const { - assert(multibyte_index_ <= base_table_->size() && - "lookup_table_view::iterator::byte_index: attempting to access more multibytes than there are"); - typename byte_span_type::pointer key_ptr = base_table_->data_.data() + base_table_->data_.size(); - // move back 1 byte that always represents the size of size - key_ptr--; - // move back the number of bytes always representing the size itself - const size_type s = base_table_->size_of_size(); - key_ptr -= s; - // move back the number of entries + 1 (1 for this entry itself) - const uint8_t es = base_table_->entry_size(); - key_ptr -= (multibyte_index_ + 1) * es; - // move back the number of special codepoint entries we have between usual byte_index entries - // we have a special codepoint entry every step_size entries (see the class comments) - key_ptr -= multibyte_index_ / step_size; - // we arrived at the position representing the byte index - return byte_span_type(key_ptr, es); - } - - /// \brief If this is an entry at a step size, get the byte span representing this value - [[nodiscard]] constexpr byte_span_type codepoint_span() const { - assert((multibyte_index_ % step_size == step_size - 1) && - "this_step_codepoint_index: this iterator is not at a step size"); - // So we do know its codepoint index. It's stored one entry ahead - auto bytes = span(); - // Return previous bytes - return byte_span_type(bytes.data() - bytes.size(), bytes.size()); - } + /// \section Usual map types + /// The types return SizeType because that's what they refer to + /// A number of transformations need happen before the size_type value is obtained + /// because the values are stored in less than sizeof(size_type) bytes, so this container + /// doesn't return references at all, because there's no point in emulating them. + + typedef SizeType key_type; + typedef SizeType mapped_type; + typedef std::pair value_type; + typedef std::less<> key_compare; + typedef value_type reference; + typedef const value_type const_reference; + typedef value_type pointer; + typedef const value_type const_pointer; + typedef SizeType size_type; + typedef ptrdiff_t difference_type; - /// \brief Get the byte index of this codepoint in the base string - /// We need to find the byte corresponding to this codepoint in the table as bytes - /// and the convert the value we find to size_type. - /// This is very dependant on the layout of the lookup table - constexpr size_type byte_index() const { - if (base_table_->empty() || is_end()) { - return base_table_->str_.size(); + private: + /// \section Iterator implementation + + /// \brief An iterator to access the values in the lookup table + /// The layout of a lookup table in bytes is somewhat reversed + /// - The last byte indicates the size of its size + /// - The bytes before indicate its size + /// - The bytes before represent the entries + /// That's why the iterator is moving backwards in the span when it's moving forward in the table + template class iterator_impl { + public: + /// \section Types + /// The types are the same for const and mutable iterators because this container + /// is a view that doesn't return references. Everything is calculated and returned by value. + typedef std::random_access_iterator_tag iterator_category; + typedef typename lookup_table_view_impl::value_type value_type; + typedef typename lookup_table_view_impl::difference_type difference_type; + typedef typename lookup_table_view_impl::pointer pointer; + typedef typename lookup_table_view_impl::reference reference; + + public: + /// \section Constructors + + /// \brief Construct empty lookup table iterator which not good for much + constexpr iterator_impl() noexcept : base_table_(nullptr), multibyte_index_(0) {} + + /// \brief Construct lookup table iterator from the table and the position + constexpr explicit iterator_impl(const lookup_table_view_impl *base, size_type index) noexcept + : base_table_(base), multibyte_index_(index) {} + + /// \brief Construct lookup table iterator from another lookup table iterator + /// Const iterators can be created from mutable iterators but not the other way around + template = 0> + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr iterator_impl(const iterator_impl &rhs) noexcept + : base_table_(rhs.base_table_), multibyte_index_(rhs.multibyte_index_) {} + + public: + /// \section Codepoint information functions + /// These are the functions we really need because they are more efficient and + /// it's where the logic for finding codepoint indexes is implemented + + /// \brief Get the multibyte index of this codepoint among other multibyte indexes + /// This is the easiest function because it's what the iterator refers to + constexpr size_type multibyte_index() const { return multibyte_index_; } + + /// \brief Get the span on bytes in the lookup table representing this entry + /// A pointer to the position where the mapped type of a byte index is stored + /// and the entry size is obtained in the resulting span + /// \return Span to bytes in the lookup table relative to this iterator + [[nodiscard]] constexpr byte_span_type span() const { + assert( + multibyte_index_ <= base_table_->size() && + "lookup_table_view::iterator::byte_index: attempting to access more multibytes than there are"); + typename byte_span_type::pointer key_ptr = base_table_->data_.data() + base_table_->data_.size(); + // move back 1 byte that always represents the size of size + key_ptr--; + // move back the number of bytes always representing the size itself + const size_type s = base_table_->size_of_size(); + key_ptr -= s; + // move back the number of entries + 1 (1 for this entry itself) + const uint8_t es = base_table_->entry_size(); + key_ptr -= (multibyte_index_ + 1) * es; + // move back the number of special codepoint entries we have between usual byte_index entries + // we have a special codepoint entry every step_size entries (see the class comments) + key_ptr -= multibyte_index_ / step_size; + // we arrived at the position representing the byte index + return byte_span_type(key_ptr, es); } - // Get bytes in the lookup table that represent this iterator position - auto entry_bytes = span(); - // We just need to convert this entry from its proper size type now - return to_unsigned(entry_bytes); - } - /// \brief Set the byte index of this codepoint in the base string - constexpr void byte_index(size_type index) const { - if (base_table_->empty()) { - return; + /// \brief If this is an entry at a step size, get the byte span representing this value + [[nodiscard]] constexpr byte_span_type codepoint_span() const { + assert((multibyte_index_ % step_size == step_size - 1) && + "this_step_codepoint_index: this iterator is not at a step size"); + // So we do know its codepoint index. It's stored one entry ahead + auto bytes = span(); + // Return previous bytes + return byte_span_type(bytes.data() - bytes.size(), bytes.size()); } - // Get bytes in the lookup table that represent this iterator position - auto entry_bytes = span(); - // We just need to convert this entry from its proper size type now - return to_bytes(index, entry_bytes); - } - /// \brief Get the codepoint index of this multibyte codepoint IFF this is at a step size - [[nodiscard]] constexpr bool is_at_step_size() const { - return multibyte_index_ % step_size == step_size - 1 && not is_end(); - } - - /// \brief Check if this is the end iterator - [[nodiscard]] constexpr bool is_end() const { return base_table_->size() == multibyte_index_; } + /// \brief Get the byte index of this codepoint in the base string + /// We need to find the byte corresponding to this codepoint in the table as bytes + /// and the convert the value we find to size_type. + /// This is very dependant on the layout of the lookup table + constexpr size_type byte_index() const { + if (base_table_->empty() || is_end()) { + return base_table_->str_.size(); + } + // Get bytes in the lookup table that represent this iterator position + auto entry_bytes = span(); + // We just need to convert this entry from its proper size type now + return to_unsigned(entry_bytes); + } - /// \brief Get the codepoint index of this multibyte codepoint IFF this is at a step size - [[nodiscard]] constexpr bool contains_codepoint_information() const { - return is_at_step_size() || multibyte_index_ == 0; - } + /// \brief Set the byte index of this codepoint in the base string + constexpr void byte_index(size_type index) const { + if (base_table_->empty()) { + return; + } + // Get bytes in the lookup table that represent this iterator position + auto entry_bytes = span(); + // We just need to convert this entry from its proper size type now + return to_bytes(index, entry_bytes); + } - private: - /// \brief Get the codepoint index of this multibyte codepoint IFF this is at a step size - constexpr size_type this_step_codepoint_index() const { - // A special case - if (multibyte_index_ == 0) { - return byte_index(); + /// \brief Get the codepoint index of this multibyte codepoint IFF this is at a step size + [[nodiscard]] constexpr bool is_at_step_size() const { + return multibyte_index_ % step_size == step_size - 1 && not is_end(); } - byte_span_type previous_bytes = codepoint_span(); - return to_unsigned(previous_bytes); - } - public: - /// \brief The utf8 size in bytes of this multibyte codepoint - constexpr uint8_t utf8_size() { - const auto codepoint_first_byte = base_table_->str_[byte_index()]; - const auto bytes_left = base_table_->str_.size() - codepoint_first_byte; - return ::small::utf8_size(codepoint_first_byte, bytes_left); - } + /// \brief Check if this is the end iterator + [[nodiscard]] constexpr bool is_end() const { return base_table_->size() == multibyte_index_; } - /// \brief Get the codepoint index of this multibyte codepoint among all codepoints - /// This is still a little more complicated than the previous operation because - /// we only know the codepoint for codepoints at every step_size positions - /// \param force_from_previous Force using only previous elements (rather than closest) as a reference - /// \return The codepoint index of that multibyte codepoint - constexpr size_type codepoint_index() const { - if (base_table_->empty()) { - // if this is an empty table, this is a special case of is_end() - // the end iterator should assume we are talking about the final - // null char. If the multibyte table is empty, the codepoint size - // is the same as the number of bytes - return base_table_->str_.size(); + /// \brief Get the codepoint index of this multibyte codepoint IFF this is at a step size + [[nodiscard]] constexpr bool contains_codepoint_information() const { + return is_at_step_size() || multibyte_index_ == 0; } - if (is_end()) { - // If this is the end iterator, we should assume this refers to - // the null char. If we got here, the table is not empty so this - // is not the same as the size() because we have multibyte codepoints. - // We can't use size_codepoint() either because base_table_->str_ is a - // string view. So we take the last entry in the multibyte table - // and calculate the difference from there. - iterator_impl last = std::prev(*this); - const size_type last_multibyte_codepoint_idx = last.codepoint_index(); - const size_type last_multibyte_codeunit_idx = last.byte_index(); - const size_type end_multibyte_byte_idx = this->byte_index(); - const size_type byte_distance = end_multibyte_byte_idx - last_multibyte_codeunit_idx; - const size_type codepoint_distance = byte_distance - last.utf8_size() + 1; - const size_type end_multibyte_codepoint_idx = last_multibyte_codepoint_idx + codepoint_distance; - return end_multibyte_codepoint_idx; + + private: + /// \brief Get the codepoint index of this multibyte codepoint IFF this is at a step size + constexpr size_type this_step_codepoint_index() const { + // A special case + if (multibyte_index_ == 0) { + return byte_index(); + } + byte_span_type previous_bytes = codepoint_span(); + return to_unsigned(previous_bytes); } - // Check if this is a multibyte index for which we also know the codepoint index - if (contains_codepoint_information()) { - // So we know this contains a codepoint index too - return this_step_codepoint_index(); + + public: + /// \brief The utf8 size in bytes of this multibyte codepoint + constexpr uint8_t utf8_size() { + const auto codepoint_first_byte = base_table_->str_[byte_index()]; + const auto bytes_left = base_table_->str_.size() - codepoint_first_byte; + return ::small::detail::utf8_size(codepoint_first_byte, bytes_left); } - // Otherwise, things get a little more complicated. - // The previous entry with a codepoint index - const size_type step_size_mod = multibyte_index_ % step_size; - const size_type positions_before_to_step_size = step_size_mod + 1; - const size_type positions_before_to_first = multibyte_index_; - const size_type positions_before = std::min(positions_before_to_first, positions_before_to_step_size); - - // Get iterator to its PREVIOUS codepoint for which we know the index explicitly - iterator_impl multibyte_it(base_table_, multibyte_index_ - positions_before); - // Store its codepoint index as a starting point - size_type codepoint_index = multibyte_it.this_step_codepoint_index(); - - // Get iterator to its NEXT multibyte codepoint - iterator_impl adjancent_multibyte_it = std::next(multibyte_it); - for (;;) { - // Compare their distances in bytes in the original string - const size_type multibyte_byte_idx = multibyte_it.byte_index(); - const size_type adjacent_multibyte_byte_idx = adjancent_multibyte_it.byte_index(); - assert(adjacent_multibyte_byte_idx > multibyte_byte_idx); - const size_type byte_distance = adjacent_multibyte_byte_idx - multibyte_byte_idx; - // The number of 1-byte codepoints between them should be roughly this distance, - // but we still need to access the underlying string to know the exact number - const auto codepoint_first_byte = base_table_->str_[multibyte_byte_idx]; - const uint8_t multibyte_bytes = - ::small::utf8_size(codepoint_first_byte, base_table_->str_.size() - multibyte_byte_idx); - // Increment the number of codepoints between these two multibyte codepoints - // - One codepoint for each one-byte codepoint, which is not in the table - // - Minus the number of bytes of this multibyte (which we can't count as more than one) - // - Plus 1 for the current multibyte codepoint (which we haven't counted yet) - codepoint_index += byte_distance - multibyte_bytes + 1; - // Advance iterators - if (adjancent_multibyte_it != *this) { - ++multibyte_it; - ++adjancent_multibyte_it; - } else { - break; + /// \brief Get the codepoint index of this multibyte codepoint among all codepoints + /// This is still a little more complicated than the previous operation because + /// we only know the codepoint for codepoints at every step_size positions + /// \param force_from_previous Force using only previous elements (rather than closest) as a reference + /// \return The codepoint index of that multibyte codepoint + constexpr size_type codepoint_index() const { + if (base_table_->empty()) { + // if this is an empty table, this is a special case of is_end() + // the end iterator should assume we are talking about the final + // null char. If the multibyte table is empty, the codepoint size + // is the same as the number of bytes + return base_table_->str_.size(); + } + if (is_end()) { + // If this is the end iterator, we should assume this refers to + // the null char. If we got here, the table is not empty so this + // is not the same as the size() because we have multibyte codepoints. + // We can't use size_codepoint() either because base_table_->str_ is a + // string view. So we take the last entry in the multibyte table + // and calculate the difference from there. + iterator_impl last = std::prev(*this); + const size_type last_multibyte_codepoint_idx = last.codepoint_index(); + const size_type last_multibyte_codeunit_idx = last.byte_index(); + const size_type end_multibyte_byte_idx = this->byte_index(); + const size_type byte_distance = end_multibyte_byte_idx - last_multibyte_codeunit_idx; + const size_type codepoint_distance = byte_distance - last.utf8_size() + 1; + const size_type end_multibyte_codepoint_idx = last_multibyte_codepoint_idx + codepoint_distance; + return end_multibyte_codepoint_idx; } + // Check if this is a multibyte index for which we also know the codepoint index + if (contains_codepoint_information()) { + // So we know this contains a codepoint index too + return this_step_codepoint_index(); + } + + // Otherwise, things get a little more complicated. + // The previous entry with a codepoint index + const size_type step_size_mod = multibyte_index_ % step_size; + const size_type positions_before_to_step_size = step_size_mod + 1; + const size_type positions_before_to_first = multibyte_index_; + const size_type positions_before = + std::min(positions_before_to_first, positions_before_to_step_size); + + // Get iterator to its PREVIOUS codepoint for which we know the index explicitly + iterator_impl multibyte_it(base_table_, multibyte_index_ - positions_before); + // Store its codepoint index as a starting point + size_type codepoint_index = multibyte_it.this_step_codepoint_index(); + + // Get iterator to its NEXT multibyte codepoint + iterator_impl adjancent_multibyte_it = std::next(multibyte_it); + for (;;) { + // Compare their distances in bytes in the original string + const size_type multibyte_byte_idx = multibyte_it.byte_index(); + const size_type adjacent_multibyte_byte_idx = adjancent_multibyte_it.byte_index(); + assert(adjacent_multibyte_byte_idx > multibyte_byte_idx); + const size_type byte_distance = adjacent_multibyte_byte_idx - multibyte_byte_idx; + // The number of 1-byte codepoints between them should be roughly this distance, + // but we still need to access the underlying string to know the exact number + const auto codepoint_first_byte = base_table_->str_[multibyte_byte_idx]; + const uint8_t multibyte_bytes = ::small::detail::utf8_size( + codepoint_first_byte, base_table_->str_.size() - multibyte_byte_idx); + // Increment the number of codepoints between these two multibyte codepoints + // - One codepoint for each one-byte codepoint, which is not in the table + // - Minus the number of bytes of this multibyte (which we can't count as more than one) + // - Plus 1 for the current multibyte codepoint (which we haven't counted yet) + codepoint_index += byte_distance - multibyte_bytes + 1; + // Advance iterators + if (adjancent_multibyte_it != *this) { + ++multibyte_it; + ++adjancent_multibyte_it; + } else { + break; + } + } + return codepoint_index; } - return codepoint_index; - } - public: - /// \section Element access + public: + /// \section Element access - /// \brief Dereference iterator - /// We could also return the codepoint index here but we don't expose that because - /// this is a more expensive operation for which can also get the results with codepoint_index() - constexpr reference operator*() const noexcept { return std::make_pair(multibyte_index(), byte_index()); } + /// \brief Dereference iterator + /// We could also return the codepoint index here but we don't expose that because + /// this is a more expensive operation for which can also get the results with codepoint_index() + constexpr reference operator*() const noexcept { + return std::make_pair(multibyte_index(), byte_index()); + } - /// \brief Dereference iterator and get member - constexpr pointer operator->() const noexcept { return operator*(); } + /// \brief Dereference iterator and get member + constexpr pointer operator->() const noexcept { return operator*(); } - /// \brief Dereference iterator n positions ahead - constexpr reference operator[](difference_type n) const noexcept { - iterator_impl it(*this); - it += n; - return it.operator*(); - } + /// \brief Dereference iterator n positions ahead + constexpr reference operator[](difference_type n) const noexcept { + iterator_impl it(*this); + it += n; + return it.operator*(); + } - /// \brief Get base index in the table - constexpr size_type base() const noexcept { return multibyte_index_; } + /// \brief Get base index in the table + constexpr size_type base() const noexcept { return multibyte_index_; } - /// \brief Get reference to the base table - constexpr const lookup_table_view_impl &base_table() const noexcept { return *base_table_; } + /// \brief Get reference to the base table + constexpr const lookup_table_view_impl &base_table() const noexcept { return *base_table_; } - public /* modifiers */: - /// \brief Advance iterator - constexpr iterator_impl &operator++() noexcept { - ++multibyte_index_; - return *this; - } + public /* modifiers */: + /// \brief Advance iterator + constexpr iterator_impl &operator++() noexcept { + ++multibyte_index_; + return *this; + } - /// \brief Advance iterator (postfix) - constexpr iterator_impl operator++(int) noexcept { // NOLINT(cert-dcl21-cpp) - iterator_impl tmp(*this); - ++(*this); - return tmp; - } + /// \brief Advance iterator (postfix) + constexpr iterator_impl operator++(int) noexcept { // NOLINT(cert-dcl21-cpp) + iterator_impl tmp(*this); + ++(*this); + return tmp; + } - /// \brief Rewind iterator - constexpr iterator_impl &operator--() noexcept { - --multibyte_index_; - return *this; - } + /// \brief Rewind iterator + constexpr iterator_impl &operator--() noexcept { + --multibyte_index_; + return *this; + } - /// \brief Rewind iterator (postfix) - constexpr iterator_impl operator--(int) noexcept { // NOLINT(cert-dcl21-cpp) - iterator_impl tmp(*this); - --(*this); - return tmp; - } + /// \brief Rewind iterator (postfix) + constexpr iterator_impl operator--(int) noexcept { // NOLINT(cert-dcl21-cpp) + iterator_impl tmp(*this); + --(*this); + return tmp; + } - /// \brief Return copy of iterator advanced by n positions - constexpr iterator_impl operator+(difference_type n) const noexcept { - iterator_impl w(*this); - w += n; - return w; - } + /// \brief Return copy of iterator advanced by n positions + constexpr iterator_impl operator+(difference_type n) const noexcept { + iterator_impl w(*this); + w += n; + return w; + } - /// \brief Advance iterator by n positions - constexpr iterator_impl &operator+=(difference_type n) noexcept { - multibyte_index_ += n; - return *this; - } + /// \brief Advance iterator by n positions + constexpr iterator_impl &operator+=(difference_type n) noexcept { + multibyte_index_ += n; + return *this; + } - /// \brief Return copy of iterator n positions behind - constexpr iterator_impl operator-(difference_type n) const noexcept { return *this + (-n); } + /// \brief Return copy of iterator n positions behind + constexpr iterator_impl operator-(difference_type n) const noexcept { return *this + (-n); } - /// \brief Rewind iterator by n positions - constexpr iterator_impl &operator-=(difference_type n) noexcept { - *this += -n; - return *this; - } + /// \brief Rewind iterator by n positions + constexpr iterator_impl &operator-=(difference_type n) noexcept { + *this += -n; + return *this; + } - public /* relational operators */: - /// \brief Make the other lookup table iterator type a friend - template friend class iterator_impl; + public /* relational operators */: + /// \brief Make the other lookup table iterator type a friend + template friend class iterator_impl; + + public /* friends */: + /// \brief Get distance between iterators + template + constexpr friend auto operator-(const iterator_impl &x, + const iterator_impl &y) noexcept + -> decltype(x.multibyte_index() - y.multibyte_index()); + + /// \brief Sum iterators + template + constexpr friend iterator_impl + operator+(typename iterator_impl::difference_type, iterator_impl) noexcept; + + public: + /// \section Equality + template + constexpr friend bool operator==(const iterator_impl &x, + const iterator_impl &y) noexcept { + return x.multibyte_index() == y.multibyte_index(); + } - public /* friends */: - /// \brief Get distance between iterators - template - constexpr friend auto operator-(const iterator_impl &x, - const iterator_impl &y) noexcept - -> decltype(x.multibyte_index() - y.multibyte_index()); + template + constexpr friend bool operator!=(const iterator_impl &x, + const iterator_impl &y) noexcept { + return !(x == y); + } - /// \brief Sum iterators - template - constexpr friend iterator_impl - operator+(typename iterator_impl::difference_type, iterator_impl) noexcept; + template + constexpr friend bool operator<(const iterator_impl &x, const iterator_impl &y) noexcept { + return x.multibyte_index() < y.multibyte_index(); + } - public: - /// \section Equality - template - constexpr friend bool operator==(const iterator_impl &x, const iterator_impl &y) noexcept { - return x.multibyte_index() == y.multibyte_index(); - } + template + constexpr friend bool operator>(const iterator_impl &x, const iterator_impl &y) noexcept { + return y < x; + } - template - constexpr friend bool operator!=(const iterator_impl &x, const iterator_impl &y) noexcept { - return !(x == y); - } + template + constexpr friend bool operator>=(const iterator_impl &x, + const iterator_impl &y) noexcept { + return !(x < y); + } - template - constexpr friend bool operator<(const iterator_impl &x, const iterator_impl &y) noexcept { - return x.multibyte_index() < y.multibyte_index(); - } + template + constexpr friend bool operator<=(const iterator_impl &x, + const iterator_impl &y) noexcept { + return !(y < x); + } - template - constexpr friend bool operator>(const iterator_impl &x, const iterator_impl &y) noexcept { - return y < x; - } + template , int> = 0> + constexpr friend bool operator==(const iterator_impl &x, const MultibyteIndexType &y) noexcept { + return x.multibyte_index() == y; + } - template - constexpr friend bool operator>=(const iterator_impl &x, const iterator_impl &y) noexcept { - return !(x < y); - } + template , int> = 0> + constexpr friend bool operator!=(const iterator_impl &x, const MultibyteIndexType &y) noexcept { + return !(x == y); + } - template - constexpr friend bool operator<=(const iterator_impl &x, const iterator_impl &y) noexcept { - return !(y < x); - } + template , int> = 0> + constexpr friend bool operator>(const iterator_impl &x, const MultibyteIndexType &y) noexcept { + return y < x; + } - template , int> = 0> - constexpr friend bool operator==(const iterator_impl &x, const MultibyteIndexType &y) noexcept { - return x.multibyte_index() == y; - } + template , int> = 0> + constexpr friend bool operator>=(const iterator_impl &x, const MultibyteIndexType &y) noexcept { + return !(x < y); + } - template , int> = 0> - constexpr friend bool operator!=(const iterator_impl &x, const MultibyteIndexType &y) noexcept { - return !(x == y); - } + template , int> = 0> + constexpr friend bool operator<=(const iterator_impl &x, const MultibyteIndexType &y) noexcept { + return !(y < x); + } - template , int> = 0> - constexpr friend bool operator>(const iterator_impl &x, const MultibyteIndexType &y) noexcept { - return y < x; - } + template , int> = 0> + constexpr friend bool operator==(const MultibyteIndexType &x, const iterator_impl &y) noexcept { + return x == y.multibyte_index(); + } - template , int> = 0> - constexpr friend bool operator>=(const iterator_impl &x, const MultibyteIndexType &y) noexcept { - return !(x < y); - } + template , int> = 0> + constexpr friend bool operator!=(const MultibyteIndexType &x, const iterator_impl &y) noexcept { + return !(x == y); + } - template , int> = 0> - constexpr friend bool operator<=(const iterator_impl &x, const MultibyteIndexType &y) noexcept { - return !(y < x); - } + template , int> = 0> + constexpr friend bool operator>(const MultibyteIndexType &x, const iterator_impl &y) noexcept { + return y < x; + } - template , int> = 0> - constexpr friend bool operator==(const MultibyteIndexType &x, const iterator_impl &y) noexcept { - return x == y.multibyte_index(); - } + template , int> = 0> + constexpr friend bool operator>=(const MultibyteIndexType &x, const iterator_impl &y) noexcept { + return !(x < y); + } - template , int> = 0> - constexpr friend bool operator!=(const MultibyteIndexType &x, const iterator_impl &y) noexcept { - return !(x == y); - } + template , int> = 0> + constexpr friend bool operator<=(const MultibyteIndexType &x, const iterator_impl &y) noexcept { + return !(y < x); + } - template , int> = 0> - constexpr friend bool operator>(const MultibyteIndexType &x, const iterator_impl &y) noexcept { - return y < x; - } + template + constexpr friend size_type operator-(const iterator_impl &x, + const iterator_impl &y) noexcept { + return x.multibyte_index() - y.multibyte_index(); + } - template , int> = 0> - constexpr friend bool operator>=(const MultibyteIndexType &x, const iterator_impl &y) noexcept { - return !(x < y); - } + template + constexpr friend iterator_impl operator+(typename iterator_impl::difference_type n, + iterator_impl x) noexcept { + x += n; + return x; + } - template , int> = 0> - constexpr friend bool operator<=(const MultibyteIndexType &x, const iterator_impl &y) noexcept { - return !(y < x); - } + private: + /// \brief A pointer to the table + /// We need to access its byte layout + const lookup_table_view_impl *base_table_{nullptr}; - template - constexpr friend size_type operator-(const iterator_impl &x, - const iterator_impl &y) noexcept { - return x.multibyte_index() - y.multibyte_index(); - } + /// \brief The index of the element among multibyte codepoints + size_type multibyte_index_{0}; + }; - template - constexpr friend iterator_impl operator+(typename iterator_impl::difference_type n, - iterator_impl x) noexcept { - x += n; - return x; - } + public: + /// \section Iterator aliases + typedef iterator_impl iterator; + typedef iterator_impl const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + /// \class This is just a proxy for std::less + class value_compare { + friend class lookup_table_view_impl; + + protected: + key_compare comp; + constexpr explicit value_compare() : comp(key_compare()) {} + constexpr explicit value_compare(key_compare c) : comp(c) {} + + public: + constexpr bool operator()(const value_type &x, const value_type &y) const { + return comp(x.first, y.first); + } + }; private: - /// \brief A pointer to the table - /// We need to access its byte layout - const lookup_table_view_impl *base_table_{nullptr}; + /// \brief Convert to appropriate byte span type + template constexpr static byte_span_type to_byte_span(const SpanType &span) { + if constexpr (IS_CONST_LOOKUP) { + return nonstd::as_bytes(span); + } else { + return nonstd::as_writable_bytes(span); + } + } - /// \brief The index of the element among multibyte codepoints - size_type multibyte_index_{0}; - }; + public: + /// \section construct/copy/destroy + /// The constructors API are more similar to the span constructor than map constructors + /// We just delegate everything to the span constructors + /// However, the codepoint map needs to know the size of the string it's indexing because + /// it affects how many bytes we should spend per entry + + /// \brief Constructor: Empty table + constexpr lookup_table_view_impl() noexcept : data_(), str_() {} + + /// \brief Constructor: From iterator and count + template + constexpr lookup_table_view_impl(It first, size_type count, string_view_type str) + : data_(to_byte_span(nonstd::span(first, count))), str_(str) {} + + /// \brief Constructor: From iterator pairs + template + constexpr lookup_table_view_impl(It first, End last, string_view_type str) + : data_(to_byte_span(nonstd::span(first, last))), str_(str) {} + + /// \brief Constructor: From literal array of bytes + template + constexpr lookup_table_view_impl(byte_type (&arr)[N], string_view_type str) noexcept + : data_(to_byte_span(nonstd::span(arr))), str_(str) {} + + /// \brief Constructor: From c++ array + template + constexpr lookup_table_view_impl(const std::array &arr, string_view_type str) noexcept + : data_(to_byte_span(nonstd::span(arr))), str_(str) {} + + /// \brief Constructor: From ranges + template + constexpr lookup_table_view_impl(R &&range, string_view_type str) + : data_(to_byte_span(nonstd::span(range))), str_(str) {} + + /// \brief Constructor: From source map/span + template + constexpr lookup_table_view_impl(const nonstd::span &source, + string_view_type str) noexcept + : data_(to_byte_span(source)), str_(str) {} + + /// \brief Constructor: Copy + constexpr lookup_table_view_impl(const lookup_table_view_impl &other) noexcept = default; - public: - /// \section Iterator aliases - typedef iterator_impl iterator; - typedef iterator_impl const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; + public: + /// \section Iterators to the multibyte codepoints in the string + /// These iterators can return the multibyte_index, byte_index, and codepoint_index of each + /// multibyte codepoint. - /// \class This is just a proxy for std::less - class value_compare { - friend class lookup_table_view_impl; + /// \brief Iterator to first multibyte codepoint + constexpr iterator begin() noexcept { return iterator(this, 0); } - protected: - key_compare comp; - constexpr explicit value_compare() : comp(key_compare()) {} - constexpr explicit value_compare(key_compare c) : comp(c) {} + constexpr const_iterator cbegin() const noexcept { return const_iterator(this, 0); } - public: - constexpr bool operator()(const value_type &x, const value_type &y) const { return comp(x.first, y.first); } - }; + constexpr const_iterator begin() const noexcept { return cbegin(); } - private: - /// \brief Convert to appropriate byte span type - template constexpr static byte_span_type to_byte_span(const SpanType &span) { - if constexpr (IS_CONST_LOOKUP) { - return nonstd::as_bytes(span); - } else { - return nonstd::as_writable_bytes(span); - } - } + constexpr iterator end() noexcept { return iterator(this, size()); } - public: - /// \section construct/copy/destroy - /// The constructors API are more similar to the span constructor than map constructors - /// We just delegate everything to the span constructors - /// However, the codepoint map needs to know the size of the string it's indexing because - /// it affects how many bytes we should spend per entry + constexpr const_iterator cend() const noexcept { return const_iterator(this, size()); } - /// \brief Constructor: Empty table - constexpr lookup_table_view_impl() noexcept : data_(), str_() {} + constexpr const_iterator end() const noexcept { return cend(); } - /// \brief Constructor: From iterator and count - template - constexpr lookup_table_view_impl(It first, size_type count, string_view_type str) - : data_(to_byte_span(nonstd::span(first, count))), str_(str) {} + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } - /// \brief Constructor: From iterator pairs - template - constexpr lookup_table_view_impl(It first, End last, string_view_type str) - : data_(to_byte_span(nonstd::span(first, last))), str_(str) {} + constexpr const_reverse_iterator rbegin() const noexcept { return reverse_iterator(cend()); } - /// \brief Constructor: From literal array of bytes - template - constexpr lookup_table_view_impl(byte_type (&arr)[N], string_view_type str) noexcept - : data_(to_byte_span(nonstd::span(arr))), str_(str) {} + constexpr const_reverse_iterator crbegin() const noexcept { return reverse_iterator(cend()); } - /// \brief Constructor: From c++ array - template - constexpr lookup_table_view_impl(const std::array &arr, string_view_type str) noexcept - : data_(to_byte_span(nonstd::span(arr))), str_(str) {} + constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } - /// \brief Constructor: From ranges - template - constexpr lookup_table_view_impl(R &&range, string_view_type str) - : data_(to_byte_span(nonstd::span(range))), str_(str) {} + constexpr const_reverse_iterator rend() const noexcept { return reverse_iterator(cbegin()); } - /// \brief Constructor: From source map/span - template - constexpr lookup_table_view_impl(const nonstd::span &source, - string_view_type str) noexcept - : data_(to_byte_span(source)), str_(str) {} + constexpr const_reverse_iterator crend() const noexcept { return reverse_iterator(cbegin()); } - /// \brief Constructor: Copy - constexpr lookup_table_view_impl(const lookup_table_view_impl &other) noexcept = default; + public: + /// \section Capacity in the lookup table + /// We have a few kinds of sizes involved here: + /// - The size of the indicator: 1 + /// - The size of size components: 1-4 (depends on number of multibyte codepoints) + /// - The size of each entry: 1-4 (depends on the string size) + /// + /// We usually have function pairs such as resize and resize_for + /// - The first function resets the indicator with the number of multibyte indexes in the table + /// - Setting the size indicator is usually enough + /// - The second function rearranges the table entries so that they can index a new number of codepoints + + /// \brief True if table is empty + /// We can make this cheaper than !size() by only checking the indicator + [[nodiscard]] constexpr bool empty() const noexcept { + return data_.back() == byte_type(0) || data_.empty(); + } - public: - /// \section Iterators to the multibyte codepoints in the string - /// These iterators can return the multibyte_index, byte_index, and codepoint_index of each - /// multibyte codepoint. + /// \brief Number of multibyte codepoints in this table + constexpr size_type size() const noexcept { + const size_type ss = size_of_size(); + byte_span_type size_representation_span(data_.end() - 1 - ss, data_.end() - 1); + return to_unsigned(size_representation_span); + } + + /// \brief Number of bytes we need for this lookup table + constexpr size_type size_for() noexcept { return size_for(str_.size(), size()); } - /// \brief Iterator to first multibyte codepoint - constexpr iterator begin() noexcept { return iterator(this, 0); } + /// \brief Calculate number of bytes we need for a lookup table with that number of entries + constexpr static size_type size_for(size_type total_codeunits, size_type multibyte_codepoints) noexcept { + const size_type indicator_size = 1; + const size_type size_size = size_of_size_for(multibyte_codepoints); + const size_type entries_size = entry_size_for(total_codeunits) * multibyte_codepoints; + const size_type codepoint_hints_size = entries_size / step_size; + return indicator_size + size_size + entries_size + codepoint_hints_size; + } - constexpr const_iterator cbegin() const noexcept { return const_iterator(this, 0); } + /// \brief Get the max number of entries we can store in the lookup table as it is + /// This number usually not be much larger than the number of codepoints in the string + /// because the reserved storage for strings is somewhat proportional to the + /// number of bytes in the main buffer. However, this might vary a little, because string + /// resizing takes into account an estimate on the number of multibyte codepoints + /// that currently exist in the string. + constexpr size_type max_size() const noexcept { + // External constraints on this table + const size_type data_span_capacity = data_.size(); + const size_type str_size = str_.size(); + // Each size component constraints on this table + const size_type size_of_size_indicator = 1; + const size_type size_of_size = entry_size_for(str_size); + const size_type entry_size = entry_size_for(str_size); + // Return number of entries we can store outside the indicators + const size_type byte_capacity_for_entries = data_span_capacity - size_of_size_indicator + size_of_size; + return byte_capacity_for_entries / entry_size; + } - constexpr const_iterator begin() const noexcept { return cbegin(); } + /// \brief Reset the table size for a new number of multibyte codepoints + /// This doesn't affect the size of an entry. Only the size indicators. + /// If changing the size makes us have a new size of size, then this is + /// a more expensive operation because we need to move the entries back + /// and forth to match the new layout. This case needs to be handled + /// but it shouldn't happen very often. + /// \param new_size Number of multibyte codepoints in the string + /// \return + constexpr void resize(size_type max_multibyte_codepoints) noexcept { + // Old and new indicators + // const size_type old_size = size(); + const size_type old_size = size(); + const size_type old_size_of_size = size_of_size(); + const size_type new_size = max_multibyte_codepoints; + const size_type new_size_of_size = size_of_size_for(new_size); + // Set the size of size indicator + assert(!data_.empty() && "cannot resize an empty data span"); + data_.back() = static_cast(new_size_of_size); + + // Check old and new size spans + if (old_size_of_size != 0 && old_size_of_size != new_size_of_size) { + // Shift all entries to make room for the new size + // 1) Find range of pointer to all table entries + // 1.a) First byte is where the last is stored + iterator last_it = std::prev(end()); + const size_type codepoint_hint_shift = last_it.is_at_step_size() ? entry_size_for(old_size) : 0; + typename byte_span_type::pointer byte_begin_pos = last_it.span().data() - codepoint_hint_shift; + // 1.b) Last byte is after where the first is stored (where size storage begins) + typename byte_span_type::pointer byte_end_pos = data_.end() - 1 - old_size_of_size; + // Shift the table entries: + // - left by new_size_of_size - old_size_of_size bytes, or + // - right by old_size_of_size - new_size_of_size bytes + if (new_size_of_size > old_size_of_size) { + const size_type shift_size = old_size_of_size - new_size_of_size; + typename byte_span_type::pointer new_byte_begin = byte_begin_pos - shift_size; + shift::shift_left(new_byte_begin, byte_end_pos, shift_size); + } else { + const size_type shift_size = old_size_of_size - new_size_of_size; + typename byte_span_type::pointer new_byte_end = byte_end_pos + shift_size; + shift::shift_right(byte_begin_pos, new_byte_end, shift_size); + } + } - constexpr iterator end() noexcept { return iterator(this, size()); } + // Set the new size in the byte representation + byte_span_type size_representation(data_.end() - 1 - new_size_of_size, data_.end() - 1); + to_bytes(new_size, size_representation); + } - constexpr const_iterator cend() const noexcept { return const_iterator(this, size()); } + /// \brief Change the entry sizes to index a new number of 1-byte or multibyte codepoints + constexpr void resize_for(size_type n_codepoints) const noexcept { + // Check how many bytes an entry for n_codepoints takes + constexpr size_type new_entry_size = entry_size_for(n_codepoints); + constexpr size_type old_entry_size = entry_size(); + // Resize the entries if we need to + if (new_entry_size != old_entry_size) { + // Range of pointers to the old entries + iterator last_it = rbegin().multibyte_index(); + typename byte_span_type::pointer old_first_address = last_it.span().data(); + if (last_it.is_at_step_size()) { + old_first_address -= old_entry_size; + } + iterator first_it = begin(); + typename byte_span_type::pointer old_last_address = first_it.span().data() + old_entry_size; + + // Number of slots we need to move + // This includes not only the main entries but also the special codepoint index entries + auto slots_to_move = (old_last_address - old_first_address) / old_entry_size; + + // Range of pointers to the new entries + typename byte_span_type::pointer new_last_address = old_last_address; + typename byte_span_type::pointer new_first_address = + new_last_address - slots_to_move * new_entry_size; + + // Shift the entries + const bool expand_left = new_entry_size > old_entry_size; + const bool compress_right = new_entry_size < old_entry_size; + if (expand_left) { + // Copy everything from the old range to the new range, expanding the entries + auto entry_size_diff = new_entry_size - old_entry_size; + while (old_first_address != old_last_address && new_first_address != new_last_address) { + std::memset(new_first_address, 0, entry_size_diff); + std::memcpy(new_first_address + entry_size_diff, old_first_address, old_entry_size); + new_first_address += new_entry_size; + old_first_address += old_entry_size; + } + } else if (compress_right) { + // Copy everything from the old range to the new range, compressing the entries + // We need to go from last to first then + auto entry_size_diff = old_entry_size - new_entry_size; + while (old_first_address != old_last_address && new_first_address != new_last_address) { + std::memcpy(new_last_address - new_entry_size, + old_last_address - old_entry_size + entry_size_diff, + old_entry_size - entry_size_diff); + new_last_address -= new_entry_size; + old_last_address -= old_entry_size; + } + } + } + } - constexpr const_iterator end() const noexcept { return cend(); } + /// \brief Max. number of codepoints we can index in this table as it is + /// The data_ span should also include the bytes we are not using for this to work + constexpr size_type capacity() const noexcept { + constexpr size_type span_size = data_.size(); + constexpr size_type indicator_size = 1; + constexpr size_type size_size = size_of_size(); + constexpr size_type entries_size = size() * entry_size(); + constexpr size_type spare_size = span_size - indicator_size - size_size - entries_size; + return spare_size / entry_size(); + } - constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + /// \brief Minmax number of bytes for the indicator with the size of size + constexpr static uint8_t max_size_of_size = sizeof(size_type); + constexpr static uint8_t min_size_of_size = 0; - constexpr const_reverse_iterator rbegin() const noexcept { return reverse_iterator(cend()); } + /// \brief Number of bytes we need to represent the size of this lookup table + [[nodiscard]] constexpr uint8_t size_of_size() const noexcept { + return data_.empty() ? min_size_of_size : size_type(data_.back()); + } - constexpr const_reverse_iterator crbegin() const noexcept { return reverse_iterator(cend()); } + /// \brief Number of bytes we need to represent the size of size of a lookup table for n elements + constexpr static size_type size_of_size_for(size_type n_multibytes_entries) noexcept { + return n_multibytes_entries == 0 ? min_size_of_size : entry_size_for(n_multibytes_entries); + } - constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + /// \brief The size, in bytes, of each entry in the codepoint lookup table + /// This calculate how many bytes we need in a table indexing "string_size_" bytes + /// The size of entries depend on how many entries we have in the original string + [[nodiscard]] constexpr uint8_t entry_size() const noexcept { return entry_size_for(str_.size()); } + + /// \brief Calculates the entry size of a table indexing n bytes + /// \param n Number of codepoints in the string + /// \return Size of an entry in the table + static constexpr uint8_t entry_size_for(size_type n) noexcept { + return n <= (size_type)std::numeric_limits::max() + 1 ? sizeof(std::uint8_t) + : n <= (size_type)std::numeric_limits::max() + 1 ? sizeof(std::uint16_t) + : n <= (size_type)std::numeric_limits::max() + 1 ? sizeof(std::uint32_t) + : sizeof(std::uint64_t); + } - constexpr const_reverse_iterator rend() const noexcept { return reverse_iterator(cbegin()); } + public: + /// \section Element access - constexpr const_reverse_iterator crend() const noexcept { return reverse_iterator(cbegin()); } + /// \brief Byte index of the k-th multibyte codepoint + constexpr mapped_type operator[](const key_type &k) { + assert(k < size()); + return (begin() + k).byte_index(); + } - public: - /// \section Capacity in the lookup table - /// We have a few kinds of sizes involved here: - /// - The size of the indicator: 1 - /// - The size of size components: 1-4 (depends on number of multibyte codepoints) - /// - The size of each entry: 1-4 (depends on the string size) - /// - /// We usually have function pairs such as resize and resize_for - /// - The first function resets the indicator with the number of multibyte indexes in the table - /// - Setting the size indicator is usually enough - /// - The second function rearranges the table entries so that they can index a new number of codepoints - - /// \brief True if table is empty - /// We can make this cheaper than !size() by only checking the indicator - [[nodiscard]] constexpr bool empty() const noexcept { return data_.back() == byte_type(0) || data_.empty(); } - - /// \brief Number of multibyte codepoints in this table - constexpr size_type size() const noexcept { - const size_type ss = size_of_size(); - byte_span_type size_representation_span(data_.end() - 1 - ss, data_.end() - 1); - return to_unsigned(size_representation_span); - } - - /// \brief Number of bytes we need for this lookup table - constexpr size_type size_for() noexcept { return size_for(str_.size(), size()); } - - /// \brief Calculate number of bytes we need for a lookup table with that number of entries - constexpr static size_type size_for(size_type total_codeunits, size_type multibyte_codepoints) noexcept { - const size_type indicator_size = 1; - const size_type size_size = size_of_size_for(multibyte_codepoints); - const size_type entries_size = entry_size_for(total_codeunits) * multibyte_codepoints; - const size_type codepoint_hints_size = entries_size / step_size; - return indicator_size + size_size + entries_size + codepoint_hints_size; - } - - /// \brief Get the max number of entries we can store in the lookup table as it is - /// This number usually not be much larger than the number of codepoints in the string - /// because the reserved storage for strings is somewhat proportional to the - /// number of bytes in the main buffer. However, this might vary a little, because string - /// resizing takes into account an estimate on the number of multibyte codepoints - /// that currently exist in the string. - constexpr size_type max_size() const noexcept { - // External constraints on this table - const size_type data_span_capacity = data_.size(); - const size_type str_size = str_.size(); - // Each size component constraints on this table - const size_type size_of_size_indicator = 1; - const size_type size_of_size = entry_size_for(str_size); - const size_type entry_size = entry_size_for(str_size); - // Return number of entries we can store outside the indicators - const size_type byte_capacity_for_entries = data_span_capacity - size_of_size_indicator + size_of_size; - return byte_capacity_for_entries / entry_size; - } - - /// \brief Reset the table size for a new number of multibyte codepoints - /// This doesn't affect the size of an entry. Only the size indicators. - /// If changing the size makes us have a new size of size, then this is - /// a more expensive operation because we need to move the entries back - /// and forth to match the new layout. This case needs to be handled - /// but it shouldn't happen very often. - /// \param new_size Number of multibyte codepoints in the string - /// \return - constexpr void resize(size_type max_multibyte_codepoints) noexcept { - // Old and new indicators - // const size_type old_size = size(); - const size_type old_size = size(); - const size_type old_size_of_size = size_of_size(); - const size_type new_size = max_multibyte_codepoints; - const size_type new_size_of_size = size_of_size_for(new_size); - // Set the size of size indicator - assert(!data_.empty() && "cannot resize an empty data span"); - data_.back() = static_cast(new_size_of_size); - - // Check old and new size spans - if (old_size_of_size != 0 && old_size_of_size != new_size_of_size) { - // Shift all entries to make room for the new size - // 1) Find range of pointer to all table entries - // 1.a) First byte is where the last is stored - iterator last_it = std::prev(end()); - const size_type codepoint_hint_shift = last_it.is_at_step_size() ? entry_size_for(old_size) : 0; - typename byte_span_type::pointer byte_begin_pos = last_it.span().data() - codepoint_hint_shift; - // 1.b) Last byte is after where the first is stored (where size storage begins) - typename byte_span_type::pointer byte_end_pos = data_.end() - 1 - old_size_of_size; - // Shift the table entries: - // - left by new_size_of_size - old_size_of_size bytes, or - // - right by old_size_of_size - new_size_of_size bytes - if (new_size_of_size > old_size_of_size) { - const size_type shift_size = old_size_of_size - new_size_of_size; - typename byte_span_type::pointer new_byte_begin = byte_begin_pos - shift_size; - shift::shift_left(new_byte_begin, byte_end_pos, shift_size); - } else { - const size_type shift_size = old_size_of_size - new_size_of_size; - typename byte_span_type::pointer new_byte_end = byte_end_pos + shift_size; - shift::shift_right(byte_begin_pos, new_byte_end, shift_size); + constexpr mapped_type at(const key_type &k) { + if (k < size()) { + throw_exception( + "lookup_table_view: out of bounds. Multibyte index not in the table"); } + return (begin() + k).byte_index(); } - // Set the new size in the byte representation - byte_span_type size_representation(data_.end() - 1 - new_size_of_size, data_.end() - 1); - to_bytes(new_size, size_representation); - } - - /// \brief Change the entry sizes to index a new number of 1-byte or multibyte codepoints - constexpr void resize_for(size_type n_codepoints) const noexcept { - // Check how many bytes an entry for n_codepoints takes - constexpr size_type new_entry_size = entry_size_for(n_codepoints); - constexpr size_type old_entry_size = entry_size(); - // Resize the entries if we need to - if (new_entry_size != old_entry_size) { - // Range of pointers to the old entries - iterator last_it = rbegin().multibyte_index(); - typename byte_span_type::pointer old_first_address = last_it.span().data(); - if (last_it.is_at_step_size()) { - old_first_address -= old_entry_size; - } - iterator first_it = begin(); - typename byte_span_type::pointer old_last_address = first_it.span().data() + old_entry_size; - - // Number of slots we need to move - // This includes not only the main entries but also the special codepoint index entries - auto slots_to_move = (old_last_address - old_first_address) / old_entry_size; - - // Range of pointers to the new entries - typename byte_span_type::pointer new_last_address = old_last_address; - typename byte_span_type::pointer new_first_address = new_last_address - slots_to_move * new_entry_size; - - // Shift the entries - const bool expand_left = new_entry_size > old_entry_size; - const bool compress_right = new_entry_size < old_entry_size; - if (expand_left) { - // Copy everything from the old range to the new range, expanding the entries - auto entry_size_diff = new_entry_size - old_entry_size; - while (old_first_address != old_last_address && new_first_address != new_last_address) { - std::memset(new_first_address, 0, entry_size_diff); - std::memcpy(new_first_address + entry_size_diff, old_first_address, old_entry_size); - new_first_address += new_entry_size; - old_first_address += old_entry_size; - } - } else if (compress_right) { - // Copy everything from the old range to the new range, compressing the entries - // We need to go from last to first then - auto entry_size_diff = old_entry_size - new_entry_size; - while (old_first_address != old_last_address && new_first_address != new_last_address) { - std::memcpy(new_last_address - new_entry_size, - old_last_address - old_entry_size + entry_size_diff, - old_entry_size - entry_size_diff); - new_last_address -= new_entry_size; - old_last_address -= old_entry_size; + public: + /// \section Modifiers + + /// \brief Insert a new index in the multibyte index table + /// \param byte_index The byte index of the new last multibyte index + constexpr void push_back(const mapped_type &byte_index) { + assert(max_size() >= size() + 1 && "Lookup table has no room for another index"); + // resize the lookup table + size_type prev_size = size(); + size_type new_size = prev_size + 1; + resize(new_size); + // find the last element + iterator it = std::prev(end()); + // get its byte span + byte_span_type s = it.span(); + // set its value to the byte index + to_bytes(byte_index, s); + // check if we need to store the codepoint index + if (it.is_at_step_size()) { + // span where we should store the codepoint index + byte_span_type codepoint_bytes = it.codepoint_span(); + // calculate the codepoint index from the previous elements + if (new_size != 1) { + iterator prev_it = std::prev(it); + size_type prev_multibyte_codepoint_idx = prev_it.codepoint_index(true); + size_type codepoint_distance = byte_index - prev_it.byte_index() + 1 - prev_it.utf8_size(); + to_bytes(prev_multibyte_codepoint_idx + codepoint_distance, codepoint_bytes); + } else { + to_bytes(byte_index, codepoint_bytes); } } } - } - - /// \brief Max. number of codepoints we can index in this table as it is - /// The data_ span should also include the bytes we are not using for this to work - constexpr size_type capacity() const noexcept { - constexpr size_type span_size = data_.size(); - constexpr size_type indicator_size = 1; - constexpr size_type size_size = size_of_size(); - constexpr size_type entries_size = size() * entry_size(); - constexpr size_type spare_size = span_size - indicator_size - size_size - entries_size; - return spare_size / entry_size(); - } - - /// \brief Minmax number of bytes for the indicator with the size of size - constexpr static uint8_t max_size_of_size = sizeof(size_type); - constexpr static uint8_t min_size_of_size = 0; - - /// \brief Number of bytes we need to represent the size of this lookup table - [[nodiscard]] constexpr uint8_t size_of_size() const noexcept { - return data_.empty() ? min_size_of_size : size_type(data_.back()); - } - - /// \brief Number of bytes we need to represent the size of size of a lookup table for n elements - constexpr static size_type size_of_size_for(size_type n_multibytes_entries) noexcept { - return n_multibytes_entries == 0 ? min_size_of_size : entry_size_for(n_multibytes_entries); - } - - /// \brief The size, in bytes, of each entry in the codepoint lookup table - /// This calculate how many bytes we need in a table indexing "string_size_" bytes - /// The size of entries depend on how many entries we have in the original string - [[nodiscard]] constexpr uint8_t entry_size() const noexcept { return entry_size_for(str_.size()); } - - /// \brief Calculates the entry size of a table indexing n bytes - /// \param n Number of codepoints in the string - /// \return Size of an entry in the table - static constexpr uint8_t entry_size_for(size_type n) noexcept { - return n <= (size_type)std::numeric_limits::max() + 1 ? sizeof(std::uint8_t) - : n <= (size_type)std::numeric_limits::max() + 1 ? sizeof(std::uint16_t) - : n <= (size_type)std::numeric_limits::max() + 1 ? sizeof(std::uint32_t) - : sizeof(std::uint64_t); - } - - public: - /// \section Element access - - /// \brief Byte index of the k-th multibyte codepoint - constexpr mapped_type operator[](const key_type &k) { - assert(k < size()); - return (begin() + k).byte_index(); - } - - constexpr mapped_type at(const key_type &k) { - if (k < size()) { - throw_exception( - "lookup_table_view: out of bounds. Multibyte index not in the table"); - } - return (begin() + k).byte_index(); - } - - public: - /// \section Modifiers - - /// \brief Insert a new index in the multibyte index table - /// \param byte_index The byte index of the new last multibyte index - constexpr void push_back(const mapped_type &byte_index) { - assert(max_size() >= size() + 1 && "Lookup table has no room for another index"); - // resize the lookup table - size_type prev_size = size(); - size_type new_size = prev_size + 1; - resize(new_size); - // find the last element - iterator it = std::prev(end()); - // get its byte span - byte_span_type s = it.span(); - // set its value to the byte index - to_bytes(byte_index, s); - // check if we need to store the codepoint index - if (it.is_at_step_size()) { - // span where we should store the codepoint index - byte_span_type codepoint_bytes = it.codepoint_span(); - // calculate the codepoint index from the previous elements - if (new_size != 1) { - iterator prev_it = std::prev(it); - size_type prev_multibyte_codepoint_idx = prev_it.codepoint_index(true); - size_type codepoint_distance = byte_index - prev_it.byte_index() + 1 - prev_it.utf8_size(); - to_bytes(prev_multibyte_codepoint_idx + codepoint_distance, codepoint_bytes); + + /// \brief Set the byte index of the k-th multibyte codepoint if it's not there yet + constexpr std::pair insert(const key_type &multibyte_index, const mapped_type &byte_index) { + // Find an iterator for this multibyte index + auto it = find(multibyte_index); + auto end_it = end(); + if (it == end_it) { + // multibyte index must be >= size() + push_back(byte_index); + return std::make_pair(std::prev(end_it), true); } else { - to_bytes(byte_index, codepoint_bytes); + return std::make_pair(it, false); } } - } - - /// \brief Set the byte index of the k-th multibyte codepoint if it's not there yet - constexpr std::pair insert(const key_type &multibyte_index, const mapped_type &byte_index) { - // Find an iterator for this multibyte index - auto it = find(multibyte_index); - auto end_it = end(); - if (it == end_it) { - // multibyte index must be >= size() - push_back(byte_index); - return std::make_pair(std::prev(end_it), true); - } else { - return std::make_pair(it, false); - } - } - - constexpr std::pair insert(value_type &&v) { return insert(v.first, v.second); } - - /// \brief Set the byte index of the k-th multibyte codepoint - constexpr std::pair - insert_or_assign(const key_type &multibyte_index, const mapped_type &byte_index, - const std::optional &codepoint_index = std::nullopt) { - // Find an iterator for this multibyte index - assert(multibyte_index <= size() && - "lookup_table_view::insert_or_assign: multibyte index is larger than capacity"); - iterator it = find(multibyte_index); - iterator end_it = end(); - if (it == end_it) { - resize(size() + 1); - iterator last_it = std::prev(end()); - byte_span_type last_span = last_it.span(); - to_bytes(byte_index, last_span.begin(), last_span.end()); - if (last_it.is_at_step_size()) { - if (codepoint_index) { - byte_span_type codepoint_span = last_it.codepoint_span(); - to_bytes(*codepoint_index, codepoint_span); - } else { - if (it != begin()) { - iterator before_last_it = std::prev(last_it); - const size_type before_codepoint_idx = before_last_it.codepoint_index(); - const size_type byte_distance = byte_index - before_last_it.byte_index(); - const size_type codepoint_distance = byte_distance - before_last_it.utf8_size() + 1; - const size_type last_codepoint_idx = before_codepoint_idx + codepoint_distance; + + constexpr std::pair insert(value_type &&v) { return insert(v.first, v.second); } + + /// \brief Set the byte index of the k-th multibyte codepoint + constexpr std::pair + insert_or_assign(const key_type &multibyte_index, const mapped_type &byte_index, + const std::optional &codepoint_index = std::nullopt) { + // Find an iterator for this multibyte index + assert(multibyte_index <= size() && + "lookup_table_view::insert_or_assign: multibyte index is larger than capacity"); + iterator it = find(multibyte_index); + iterator end_it = end(); + if (it == end_it) { + resize(size() + 1); + iterator last_it = std::prev(end()); + byte_span_type last_span = last_it.span(); + to_bytes(byte_index, last_span.begin(), last_span.end()); + if (last_it.is_at_step_size()) { + if (codepoint_index) { byte_span_type codepoint_span = last_it.codepoint_span(); - to_bytes(last_codepoint_idx, codepoint_span); + to_bytes(*codepoint_index, codepoint_span); } else { - byte_span_type codepoint_span = last_it.codepoint_span(); - to_bytes(byte_index, codepoint_span); + if (it != begin()) { + iterator before_last_it = std::prev(last_it); + const size_type before_codepoint_idx = before_last_it.codepoint_index(); + const size_type byte_distance = byte_index - before_last_it.byte_index(); + const size_type codepoint_distance = byte_distance - before_last_it.utf8_size() + 1; + const size_type last_codepoint_idx = before_codepoint_idx + codepoint_distance; + byte_span_type codepoint_span = last_it.codepoint_span(); + to_bytes(last_codepoint_idx, codepoint_span); + } else { + byte_span_type codepoint_span = last_it.codepoint_span(); + to_bytes(byte_index, codepoint_span); + } } } - } - return std::make_pair(std::prev(end_it), true); - } else { - // update span of that entry - byte_span_type bytes = it.span(); - to_bytes(byte_index, bytes); - if (it.is_at_step_size()) { - if (codepoint_index) { - byte_span_type codepoint_span = it.codepoint_span(); - to_bytes(*codepoint_index, codepoint_span); - } else { - if (it != begin()) { - iterator prev_it = std::prev(it); - const size_type before_codepoint_idx = prev_it.codepoint_index(); - const size_type byte_distance = byte_index - prev_it.byte_index(); - const size_type codepoint_distance = byte_distance - prev_it.utf8_size() + 1; - const size_type last_codepoint_idx = before_codepoint_idx + codepoint_distance; + return std::make_pair(std::prev(end_it), true); + } else { + // update span of that entry + byte_span_type bytes = it.span(); + to_bytes(byte_index, bytes); + if (it.is_at_step_size()) { + if (codepoint_index) { byte_span_type codepoint_span = it.codepoint_span(); - to_bytes(last_codepoint_idx, codepoint_span); + to_bytes(*codepoint_index, codepoint_span); } else { - byte_span_type codepoint_span = it.codepoint_span(); - to_bytes(byte_index, codepoint_span); + if (it != begin()) { + iterator prev_it = std::prev(it); + const size_type before_codepoint_idx = prev_it.codepoint_index(); + const size_type byte_distance = byte_index - prev_it.byte_index(); + const size_type codepoint_distance = byte_distance - prev_it.utf8_size() + 1; + const size_type last_codepoint_idx = before_codepoint_idx + codepoint_distance; + byte_span_type codepoint_span = it.codepoint_span(); + to_bytes(last_codepoint_idx, codepoint_span); + } else { + byte_span_type codepoint_span = it.codepoint_span(); + to_bytes(byte_index, codepoint_span); + } } } + return std::make_pair(it, false); } - return std::make_pair(it, false); - } - } - - /// \brief Erase an entry from the table - constexpr size_type erase(const key_type &multibyte_index) { - auto it = find(multibyte_index); - if (it != end()) { - erase(it); - return 1; } - return 0; - } - - constexpr iterator erase(iterator first, iterator last) { - // Trivial case - auto end_it = end(); - if (first == end_it) { - // go directly to resizing. the previous entry bytes are now garbage. - resize(size() - 1); - return end(); + + /// \brief Erase an entry from the table + constexpr size_type erase(const key_type &multibyte_index) { + auto it = find(multibyte_index); + if (it != end()) { + erase(it); + return 1; + } + return 0; } - // The iterator contains a multibyte index from which we need to: - // 1) remove that entry value by shifting back all entry values after this position in the layout - // 2) update the codepoint indexes for all step sizes that where moved - iterator from_position = last; - iterator to_position = first; - while (from_position != end_it) { - if (to_position.is_at_step_size()) { - // The destination position should have a codepoint index hint - // We should calculate this for the source position and set it here - // Calculate it before setting the byte indexes because they - // are part of this equation - const size_type next_codepoint_index = next_codepoint_index.codepoint_index(); - to_position.byte_index(from_position.byte_index()); - to_position.codepoint_index(next_codepoint_index); - } else { - to_position.byte_index(from_position.byte_index()); + constexpr iterator erase(iterator first, iterator last) { + // Trivial case + auto end_it = end(); + if (first == end_it) { + // go directly to resizing. the previous entry bytes are now garbage. + resize(size() - 1); + return end(); } - ++to_position; - ++from_position; + + // The iterator contains a multibyte index from which we need to: + // 1) remove that entry value by shifting back all entry values after this position in the layout + // 2) update the codepoint indexes for all step sizes that where moved + iterator from_position = last; + iterator to_position = first; + while (from_position != end_it) { + if (to_position.is_at_step_size()) { + // The destination position should have a codepoint index hint + // We should calculate this for the source position and set it here + // Calculate it before setting the byte indexes because they + // are part of this equation + const size_type next_codepoint_index = next_codepoint_index.codepoint_index(); + to_position.byte_index(from_position.byte_index()); + to_position.codepoint_index(next_codepoint_index); + } else { + to_position.byte_index(from_position.byte_index()); + } + ++to_position; + ++from_position; + } + + // 3) update the table size with all the memory tricks we need + resize(size() - 1); } - // 3) update the table size with all the memory tricks we need - resize(size() - 1); - } - - constexpr iterator erase(const_iterator first, const_iterator last) { - return erase(const_iterator(this, first.multibyte_index()), const_iterator(this, last.multibyte_index())); - } - - /// \brief Set the indicators to make this map have 0 entries - /// We manually erase the last bytes of the lookup table span so that - /// everything before that is considered garbage and there's nothing - /// to shift - constexpr void clear() noexcept { to_bytes(0U, std::prev(data_.end()), data_.end()); } - - public: - /// \section Observers: - /// This is just the std::less function - - [[nodiscard]] constexpr key_compare key_comp() const { return key_compare(); } - [[nodiscard]] constexpr value_compare value_comp() const { return value_compare(); } - - public: - /// \section map operations - /// Because this "map" is based on an array, the find functions are only returning - /// offsets from the last elements - - /// \brief Find the element that refers to the k-th multibyte codepoint - /// \param k Multibyte index - /// \return - constexpr iterator find(const key_type &multibyte_index) { - if (multibyte_index < size()) { - return iterator(this, multibyte_index); - } else { - return end(); + constexpr iterator erase(const_iterator first, const_iterator last) { + return erase(const_iterator(this, first.multibyte_index()), + const_iterator(this, last.multibyte_index())); } - } - constexpr const_iterator find(const key_type &multibyte_index) const { - if (multibyte_index < size()) { - return const_iterator(this, multibyte_index); - } else { - return end(); + /// \brief Set the indicators to make this map have 0 entries + /// We manually erase the last bytes of the lookup table span so that + /// everything before that is considered garbage and there's nothing + /// to shift + constexpr void clear() noexcept { to_bytes(0U, std::prev(data_.end()), data_.end()); } + + public: + /// \section Observers: + /// This is just the std::less function + + [[nodiscard]] constexpr key_compare key_comp() const { return key_compare(); } + [[nodiscard]] constexpr value_compare value_comp() const { return value_compare(); } + + public: + /// \section map operations + /// Because this "map" is based on an array, the find functions are only returning + /// offsets from the last elements + + /// \brief Find the element that refers to the k-th multibyte codepoint + /// \param k Multibyte index + /// \return + constexpr iterator find(const key_type &multibyte_index) { + if (multibyte_index < size()) { + return iterator(this, multibyte_index); + } else { + return end(); + } } - } - /// \brief Find the first multibyte element whose codepoint >= codepoint_index - /// - /// This implements a binary search on the multibyte entries with the exception that - /// only elements at step sizes are considered. After that, we can use a linear - /// search to find what we want. - /// - /// We often need to find the last multibyte element whose codepoint < new_codepoint_index, - /// or the element before the first multibyte element whose codepoint >=new_codepoint_index. - /// - /// So we need a binary search for that, but we also need this binary search to - /// skip the iterators to multibyte indexes for which we don't know the codepoints. - /// \param codepoint_index Codepoint index we are looking for - /// \return An iterator to the first multibyte element in the table whose codepoint is >= codepoint_index - /// \return The codepoint of this element, which is useful to avoid recalculating when != codepoint_index - constexpr std::pair lower_bound_codepoint(const key_type &codepoint_index) { - // Trivial case - if (empty()) { - return std::make_pair(end(), std::numeric_limits::max()); + constexpr const_iterator find(const key_type &multibyte_index) const { + if (multibyte_index < size()) { + return const_iterator(this, multibyte_index); + } else { + return end(); + } } - // 1) Use a binary search to find the step size entry that matches the codepoint index better - iterator it; - difference_type step{0}; - auto first = begin(); - auto last = end(); - difference_type search_range = std::distance(first, last); - while (cmp_greater(search_range, step_size - 1)) { - it = first; - step = search_range / 2; - std::advance(it, step); - if (not it.contains_codepoint_information()) { - // We can go a few indexes ahead or behind to fix this - const size_type indexes_behind = (step_size - 1) - (it.multibyte_index() % step_size); - const size_type indexes_ahead = step_size - indexes_behind; - const bool move_back_is_possible = it.multibyte_index() > indexes_behind; - const bool move_forward_is_possible = it + indexes_ahead < end(); - if (move_back_is_possible && (indexes_behind < indexes_ahead || move_forward_is_possible)) { - std::advance(it, -difference_type(indexes_behind)); - } else if (move_forward_is_possible) { - std::advance(it, indexes_ahead); + + /// \brief Find the first multibyte element whose codepoint >= codepoint_index + /// + /// This implements a binary search on the multibyte entries with the exception that + /// only elements at step sizes are considered. After that, we can use a linear + /// search to find what we want. + /// + /// We often need to find the last multibyte element whose codepoint < new_codepoint_index, + /// or the element before the first multibyte element whose codepoint >=new_codepoint_index. + /// + /// So we need a binary search for that, but we also need this binary search to + /// skip the iterators to multibyte indexes for which we don't know the codepoints. + /// \param codepoint_index Codepoint index we are looking for + /// \return An iterator to the first multibyte element in the table whose codepoint is >= codepoint_index + /// \return The codepoint of this element, which is useful to avoid recalculating when != codepoint_index + constexpr std::pair lower_bound_codepoint(const key_type &codepoint_index) { + // Trivial case + if (empty()) { + return std::make_pair(end(), std::numeric_limits::max()); + } + // 1) Use a binary search to find the step size entry that matches the codepoint index better + iterator it; + difference_type step{0}; + auto first = begin(); + auto last = end(); + difference_type search_range = std::distance(first, last); + while (cmp_greater(search_range, step_size - 1)) { + it = first; + step = search_range / 2; + std::advance(it, step); + if (not it.contains_codepoint_information()) { + // We can go a few indexes ahead or behind to fix this + const size_type indexes_behind = (step_size - 1) - (it.multibyte_index() % step_size); + const size_type indexes_ahead = step_size - indexes_behind; + const bool move_back_is_possible = it.multibyte_index() > indexes_behind; + const bool move_forward_is_possible = it + indexes_ahead < end(); + if (move_back_is_possible && (indexes_behind < indexes_ahead || move_forward_is_possible)) { + std::advance(it, -difference_type(indexes_behind)); + } else if (move_forward_is_possible) { + std::advance(it, indexes_ahead); + } else { + // No more codepoints to find + break; + } + } + if (it.codepoint_index() < codepoint_index) { + first = ++it; + search_range -= step + 1; } else { - // No more codepoints to find - break; + search_range = step; } } - if (it.codepoint_index() < codepoint_index) { - first = ++it; - search_range -= step + 1; - } else { - search_range = step; + // 2) Move or advance around this iterator to find a better match + size_type first_codepoint_index = first.codepoint_index(); + if (first_codepoint_index < codepoint_index) { + // The best match is the first _not less_ than the codepoint we are looking for + // This snippet is then equivalent to: + // while (first.codepoint_index() < codepoint_index) { + // ++first; + // } + // However, we know we are going to iterate through codepoints which + // don't know they codepoint indexes now. So we accumulate the indexes + // ourselves. + while (first != last && first_codepoint_index < codepoint_index) { + const size_type prev_byte_index = first.byte_index(); + uint8_t prev_utf_size = first.utf8_size(); + ++first; + const size_type cur_byte_index = first.byte_index(); + const size_type byte_distance = cur_byte_index - prev_byte_index; + const size_type codepoint_distance = byte_distance - prev_utf_size + 1; + first_codepoint_index += codepoint_distance; + } + } else if (first_codepoint_index > codepoint_index) { + // We do the opposite of the previous operation here + // We move backwards until we find the element we want + iterator begin_it = begin(); + while (first != begin_it && first_codepoint_index >= codepoint_index) { + const size_type prev_byte_index = first.byte_index(); + --first; + uint8_t cur_utf_size = first.utf8_size(); + const size_type cur_byte_index = first.byte_index(); + const size_type byte_distance = prev_byte_index - cur_byte_index; + const size_type codepoint_distance = byte_distance - cur_utf_size + 1; + first_codepoint_index -= codepoint_distance; + } + // Move to the next, where the codepoint is greater or equal, which is + // what we expect from this function + if (first != last && first_codepoint_index < codepoint_index) { + // Move to next and adjust the codepoint index we are going to return + const size_type prev_byte_index = first.byte_index(); + uint8_t prev_utf_size = first.utf8_size(); + ++first; + const size_type cur_byte_index = first.byte_index(); + const size_type byte_distance = cur_byte_index - prev_byte_index; + const size_type codepoint_distance = byte_distance - prev_utf_size + 1; + first_codepoint_index += codepoint_distance; + } } + return std::make_pair(first, first_codepoint_index); } - // 2) Move or advance around this iterator to find a better match - size_type first_codepoint_index = first.codepoint_index(); - if (first_codepoint_index < codepoint_index) { - // The best match is the first _not less_ than the codepoint we are looking for - // This snippet is then equivalent to: - // while (first.codepoint_index() < codepoint_index) { - // ++first; - // } - // However, we know we are going to iterate through codepoints which - // don't know they codepoint indexes now. So we accumulate the indexes - // ourselves. - while (first != last && first_codepoint_index < codepoint_index) { - const size_type prev_byte_index = first.byte_index(); - uint8_t prev_utf_size = first.utf8_size(); - ++first; - const size_type cur_byte_index = first.byte_index(); - const size_type byte_distance = cur_byte_index - prev_byte_index; - const size_type codepoint_distance = byte_distance - prev_utf_size + 1; - first_codepoint_index += codepoint_distance; - } - } else if (first_codepoint_index > codepoint_index) { - // We do the opposite of the previous operation here - // We move backwards until we find the element we want - iterator begin_it = begin(); - while (first != begin_it && first_codepoint_index >= codepoint_index) { - const size_type prev_byte_index = first.byte_index(); - --first; - uint8_t cur_utf_size = first.utf8_size(); - const size_type cur_byte_index = first.byte_index(); - const size_type byte_distance = prev_byte_index - cur_byte_index; - const size_type codepoint_distance = byte_distance - cur_utf_size + 1; - first_codepoint_index -= codepoint_distance; + + /// \brief Find the first multibyte element whose codeunit >= codeunit_index + constexpr iterator lower_bound_codeunit(const key_type &codeunit_index) { + // Trivial case + if (empty()) { + return end(); } - // Move to the next, where the codepoint is greater or equal, which is - // what we expect from this function - if (first != last && first_codepoint_index < codepoint_index) { - // Move to next and adjust the codepoint index we are going to return - const size_type prev_byte_index = first.byte_index(); - uint8_t prev_utf_size = first.utf8_size(); - ++first; - const size_type cur_byte_index = first.byte_index(); - const size_type byte_distance = cur_byte_index - prev_byte_index; - const size_type codepoint_distance = byte_distance - prev_utf_size + 1; - first_codepoint_index += codepoint_distance; + // Since all iterators have an associated code unit, we use a regular binary search on the iterators + // Each iterator returns a pair with + return std::lower_bound( + begin(), end(), codeunit_index, + [](const auto &p1, const key_type &codeunit_index) { return p1.second < codeunit_index; }); + } + + /// \brief Check if the table has something associated with the k-th multibyte index + constexpr bool contains(const key_type &k) const { return k < size(); } + + /// \brief Find the first multibyte index >= k + constexpr iterator lower_bound(const key_type &k) { return find(k); } + + constexpr const_iterator lower_bound(const key_type &k) const { return find(k); } + + /// \brief Find the first multibyte index > k + constexpr iterator upper_bound(const key_type &k) { + iterator it = find(k); + if (it != end()) { + ++it; } + return it; } - return std::make_pair(first, first_codepoint_index); - } - - /// \brief Find the first multibyte element whose codeunit >= codeunit_index - constexpr iterator lower_bound_codeunit(const key_type &codeunit_index) { - // Trivial case - if (empty()) { - return end(); + + constexpr const_iterator upper_bound(const key_type &k) const { + const_iterator it = find(k); + if (it != end()) { + ++it; + } + return it; } - // Since all iterators have an associated code unit, we use a regular binary search on the iterators - // Each iterator returns a pair with - return std::lower_bound(begin(), end(), codeunit_index, [](const auto &p1, const key_type &codeunit_index) { - return p1.second < codeunit_index; - }); - } - - /// \brief Check if the table has something associated with the k-th multibyte index - constexpr bool contains(const key_type &k) const { return k < size(); } - - /// \brief Find the first multibyte index >= k - constexpr iterator lower_bound(const key_type &k) { return find(k); } - - constexpr const_iterator lower_bound(const key_type &k) const { return find(k); } - - /// \brief Find the first multibyte index > k - constexpr iterator upper_bound(const key_type &k) { - iterator it = find(k); - if (it != end()) { - ++it; + + constexpr std::pair equal_range(const key_type &k) { + iterator first = find(k); + iterator last = first != end() ? std::next(first) : first; + return std::make_pair(first, last); } - return it; - } - constexpr const_iterator upper_bound(const key_type &k) const { - const_iterator it = find(k); - if (it != end()) { - ++it; + constexpr std::pair equal_range(const key_type &k) const { + const_iterator first = find(k); + const_iterator last = first != end() ? std::next(first) : first; + return std::make_pair(first, last); } - return it; - } - - constexpr std::pair equal_range(const key_type &k) { - iterator first = find(k); - iterator last = first != end() ? std::next(first) : first; - return std::make_pair(first, last); - } - - constexpr std::pair equal_range(const key_type &k) const { - const_iterator first = find(k); - const_iterator last = first != end() ? std::next(first) : first; - return std::make_pair(first, last); - } - - private: - /// \brief The lookup table is represented as a span of bytes - /// This span is part of the string buffer, whose spare allocated bytes we use for the table - /// This span has the following layout: - /// (i) spare bytes - /// (ii) codepoint indexes - /// - index of the n-th multibyte codepoint - /// - index of the n-1-th multibyte codepoint - /// - index of the n-2-th multibyte codepoint - /// - ... - /// - index of the 1-st multibyte codepoint - /// (iii) number of codepoint indexes / size - /// (iv) size of size / number of bytes needed to represent 4 - /// - /// Note that: - /// - In this layout, with the size at the last position, operations usually read from the span - /// data_.end() to its data_.begin() looking for elements. This is purposefully so because this - /// table is usually stored at the extra reserved bytes of string buffers. - /// - Unibyte codepoints are not represented in the table. They are simply inferred from the local - /// multibyte codepoints, so finding - /// - The table size is only 1 byte when the table is empty, in which case it simply decays into - /// an indicator - byte_span_type data_; - /// \brief A reference to the underlying string - string_view_type str_{}; - }; + private: + /// \brief The lookup table is represented as a span of bytes + /// This span is part of the string buffer, whose spare allocated bytes we use for the table + /// This span has the following layout: + /// (i) spare bytes + /// (ii) codepoint indexes + /// - index of the n-th multibyte codepoint + /// - index of the n-1-th multibyte codepoint + /// - index of the n-2-th multibyte codepoint + /// - ... + /// - index of the 1-st multibyte codepoint + /// (iii) number of codepoint indexes / size + /// (iv) size of size / number of bytes needed to represent 4 + /// + /// Note that: + /// - In this layout, with the size at the last position, operations usually read from the span + /// data_.end() to its data_.begin() looking for elements. This is purposefully so because this + /// table is usually stored at the extra reserved bytes of string buffers. + /// - Unibyte codepoints are not represented in the table. They are simply inferred from the local + /// multibyte codepoints, so finding + /// - The table size is only 1 byte when the table is empty, in which case it simply decays into + /// an indicator + byte_span_type data_; + + /// \brief A reference to the underlying string + string_view_type str_{}; + }; - template - using lookup_table_view = lookup_table_view_impl; + template + using lookup_table_view = lookup_table_view_impl; - template - using const_lookup_table_view = lookup_table_view_impl; + template + using const_lookup_table_view = lookup_table_view_impl; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_CONTAINER_LOOKUP_TABLE_VIEW_H diff --git a/source/small/detail/container/span-lite.h b/source/small/detail/container/span-lite.h index 24b9024..1f8fb97 100644 --- a/source/small/detail/container/span-lite.h +++ b/source/small/detail/container/span-lite.h @@ -642,8 +642,7 @@ namespace nonstd { #elif span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR) - template - inline span_constexpr auto size(const T (&)[N]) span_noexcept -> size_t { + template inline span_constexpr auto size(const T (&)[N]) span_noexcept->size_t { return N; } @@ -651,7 +650,7 @@ namespace nonstd { return cont.size(); } - template inline span_constexpr auto data(T (&arr)[N]) span_noexcept -> T * { + template inline span_constexpr auto data(T (&arr)[N]) span_noexcept->T * { return &arr[0]; } @@ -664,7 +663,7 @@ namespace nonstd { } template - inline span_constexpr auto data(std::initializer_list il) span_noexcept -> E const * { + inline span_constexpr auto data(std::initializer_list il) span_noexcept->E const * { return il.begin(); } @@ -1372,28 +1371,28 @@ namespace nonstd { #if span_USES_STD_SPAN template ()))> - inline span_constexpr auto make_span(Container &cont) span_noexcept - -> span::type> { + inline span_constexpr auto + make_span(Container &cont) span_noexcept->span::type> { return span::type>(cont); } template ()))> - inline span_constexpr auto make_span(Container const &cont) span_noexcept - -> span::type> { + inline span_constexpr auto + make_span(Container const &cont) span_noexcept->span::type> { return span::type>(cont); } #elif span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR) && span_HAVE(AUTO) template ()))> - inline span_constexpr auto make_span(Container &cont) span_noexcept - -> span::type> { + inline span_constexpr auto + make_span(Container &cont) span_noexcept->span::type> { return span::type>(cont); } template ()))> - inline span_constexpr auto make_span(Container const &cont) span_noexcept - -> span::type> { + inline span_constexpr auto + make_span(Container const &cont) span_noexcept->span::type> { return span::type>(cont); } @@ -1521,13 +1520,12 @@ namespace nonstd { namespace nonstd { namespace span_lite { - template - inline span_constexpr auto byte_span(T &t) span_noexcept -> span { + template inline span_constexpr auto byte_span(T &t) span_noexcept->span { return span(reinterpret_cast(&t), span_sizeof(T)); } template - inline span_constexpr auto byte_span(T const &t) span_noexcept -> span { + inline span_constexpr auto byte_span(T const &t) span_noexcept->span { return span(reinterpret_cast(&t), span_sizeof(T)); } diff --git a/source/small/detail/container/variant_vector.h b/source/small/detail/container/variant_vector.h index 309d7b9..d77340d 100644 --- a/source/small/detail/container/variant_vector.h +++ b/source/small/detail/container/variant_vector.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_CONTAINER_VARIANT_VECTOR_H #define SMALL_DETAIL_CONTAINER_VARIANT_VECTOR_H @@ -24,653 +23,664 @@ /// This is only kept here for reference namespace small { - /// \brief Vector of elements with a buffer for small vectors - /// - /// A vector optimized for the case when it's small. - /// - /// - Inline allocation for small number of elements - /// - Custom expected size - /// - Special treatment of relocatable types - /// - Relocatable types are defined by default for POD types and aggregate types of PODs - /// - Some types might be dynamically relocatable (don't have internal pointers all the time) - /// - Better default grow factors - /// - Custom grow factors - /// - Consider the cache line size in allocations (https://github.com/NickStrupat/CacheLineSize) - /// - /// When there are less elements than a given threshold, - /// the elements are kept in a stack buffer for small vectors. - /// Otherwise, it works as usual. This makes cache locality - /// even better. - /// - /// This is what is usually used as a data structure for - /// small vector. However, if you are 100% sure you will never - /// need more than N elements, a max_size_vector is a more - /// appropriate container. - /// - /// At worst, a std::vector would take sizeof(std::vector) - /// bytes. So a small vector with sizeof(std::vector)/sizeof(T) - /// elements is a very conservative default because you would have - /// using sizeof(std::vector) bytes on the stack anyway. - /// For instance: - /// - sizeof(std::vector)/sizeof(int) == 6 - /// - sizeof(std::vector)/sizeof(int) == 24 - /// - sizeof(std::vector)/sizeof(float) == 6 - /// - /// This works well as a conservative default for fundamental data - /// structures, but this will result in 1 for most other data - /// structures. Thus, we also use a minimum of 5 elements for - /// this default because even the smallest vectors are probably - /// going to have at least 5 elements. - /// - /// \tparam T Array type - /// \tparam N Array maximum expected size - template ) * 2) / sizeof(T), std::size_t(5)), - class Allocator = std::allocator> - class small_vector { - private: - /// Classes of small vector errors - enum class small_vector_error_code : int { - none = 0, - out_of_range, - }; + namespace detail { + /// \brief Vector of elements with a buffer for small vectors + /// + /// A vector optimized for the case when it's small. + /// + /// - Inline allocation for small number of elements + /// - Custom expected size + /// - Special treatment of relocatable types + /// - Relocatable types are defined by default for POD types and aggregate types of PODs + /// - Some types might be dynamically relocatable (don't have internal pointers all the time) + /// - Better default grow factors + /// - Custom grow factors + /// - Consider the cache line size in allocations (https://github.com/NickStrupat/CacheLineSize) + /// + /// When there are less elements than a given threshold, + /// the elements are kept in a stack buffer for small vectors. + /// Otherwise, it works as usual. This makes cache locality + /// even better. + /// + /// This is what is usually used as a data structure for + /// small vector. However, if you are 100% sure you will never + /// need more than N elements, a max_size_vector is a more + /// appropriate container. + /// + /// At worst, a std::vector would take sizeof(std::vector) + /// bytes. So a small vector with sizeof(std::vector)/sizeof(T) + /// elements is a very conservative default because you would have + /// using sizeof(std::vector) bytes on the stack anyway. + /// For instance: + /// - sizeof(std::vector)/sizeof(int) == 6 + /// - sizeof(std::vector)/sizeof(int) == 24 + /// - sizeof(std::vector)/sizeof(float) == 6 + /// + /// This works well as a conservative default for fundamental data + /// structures, but this will result in 1 for most other data + /// structures. Thus, we also use a minimum of 5 elements for + /// this default because even the smallest vectors are probably + /// going to have at least 5 elements. + /// + /// \tparam T Array type + /// \tparam N Array maximum expected size + template ) * 2) / sizeof(T), std::size_t(5)), + class Allocator = std::allocator> + class small_vector { + private: + /// Classes of small vector errors + enum class small_vector_error_code : int { + none = 0, + out_of_range, + }; + + /// \brief An unknown error category for new error types + /// This is better than generic category, which has very specific + /// messages associated with its error codes + class small_vector_error_category_type : public std::error_category { + public: + /// \brief Constructs the error category object + constexpr small_vector_error_category_type() noexcept = default; + + /// \brief destructs an error_category + ~small_vector_error_category_type() override = default; + + /// \brief Obtains the name of the category + [[nodiscard]] const char *name() const noexcept override { return "small_vector"; } + + /// \brief Maps error_code to error_condition + [[nodiscard]] std::error_condition default_error_condition(int code) const noexcept override { + return std::error_condition(code, *this); + } - /// \brief An unknown error category for new error types - /// This is better than generic category, which has very specific - /// messages associated with its error codes - class small_vector_error_category_type : public std::error_category { - public: - /// \brief Constructs the error category object - constexpr small_vector_error_category_type() noexcept = default; + /// \brief Checks whether error code is equivalent to an error condition for the error category + [[nodiscard]] bool equivalent(int code, const std::error_condition &condition) const noexcept override { + return default_error_condition(code) == condition; + } - /// \brief destructs an error_category - ~small_vector_error_category_type() override = default; + /// \brief Checks whether error code is equivalent to an error condition for the error category + [[nodiscard]] bool equivalent(const std::error_code &code, int condition) const noexcept override { + return *this == code.category() && code.value() == condition; + } - /// \brief Obtains the name of the category - [[nodiscard]] const char *name() const noexcept override { return "small_vector"; } + /// \brief Obtains the explanatory string + [[nodiscard]] std::string message(int code) const override { + // return the same string for all error codes + switch (code) { + case static_cast(small_vector_error_code::none): + return ""; + case static_cast(small_vector_error_code::out_of_range): + return "Out of range"; + default: + return "Small vector unknown error"; + } + } + }; - /// \brief Maps error_code to error_condition - [[nodiscard]] std::error_condition default_error_condition(int code) const noexcept override { - return std::error_condition(code, *this); + /// \brief Obtains a reference to the static error category object for unknown errors + static const std::error_category &small_vector_error_category() noexcept { + static small_vector_error_category_type c; + return c; } - /// \brief Checks whether error code is equivalent to an error condition for the error category - [[nodiscard]] bool equivalent(int code, const std::error_condition &condition) const noexcept override { - return default_error_condition(code) == condition; + public /* types */: + typedef Allocator allocator_type; + typedef T &reference; + typedef const T &const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef pointer_wrapper iterator; + typedef pointer_wrapper const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static_assert((std::is_same::value), + "Allocator::value_type must be same type as value_type"); + + private /* types */: + /// Small array type to keep array in stack + using small_vector_type = max_size_vector; + + /// Vector type to keep array in heap + using large_vector_type = std::vector; + + /// Variant type to keep array in stack or heap + using variant_type = std::variant; + + public /* constructors */: + /// \brief Construct empty small array + constexpr small_vector() noexcept(std::is_nothrow_default_constructible::value) + : small_vector(allocator_type()) {} + + /// \brief Construct small vector with a given allocator + constexpr explicit small_vector(const allocator_type &alloc) : small_vector(0, alloc) {} + + /// \brief Construct small array with size n + constexpr explicit small_vector(size_type n, const allocator_type &alloc = allocator_type()) + : alloc_(alloc), + data_(n > N ? variant_type(large_vector_type(n, alloc)) : variant_type(small_vector_type(n))) { + assert(invariants()); } - /// \brief Checks whether error code is equivalent to an error condition for the error category - [[nodiscard]] bool equivalent(const std::error_code &code, int condition) const noexcept override { - return *this == code.category() && code.value() == condition; + /// \brief Construct small array with size n and fill with single value + constexpr small_vector(size_type n, const value_type &value, const allocator_type &alloc = allocator_type()) + : small_vector(n, alloc) { + std::fill(begin(), end(), value); + assert(invariants()); } - /// \brief Obtains the explanatory string - [[nodiscard]] std::string message(int code) const override { - // return the same string for all error codes - switch (code) { - case static_cast(small_vector_error_code::none): - return ""; - case static_cast(small_vector_error_code::out_of_range): - return "Out of range"; - default: - return "Small vector unknown error"; - } + /// \brief Construct small array from a pair of iterators + template + constexpr small_vector(InputIterator first, enable_if_iterator_t last, + const allocator_type &alloc = allocator_type()) + : alloc_(alloc), data_(std::distance(first, last) > difference_type(N) + ? variant_type(large_vector_type(first, last, alloc)) + : variant_type(small_vector_type(first, last))) { + assert(invariants()); } - }; - /// \brief Obtains a reference to the static error category object for unknown errors - static const std::error_category &small_vector_error_category() noexcept { - static small_vector_error_category_type c; - return c; - } + /// \brief Construct small array from initializer list + constexpr small_vector(std::initializer_list il, const allocator_type &alloc = allocator_type()) + : small_vector(il.begin(), il.end(), alloc) {} - public /* types */: - typedef Allocator allocator_type; - typedef T &reference; - typedef const T &const_reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef T *pointer; - typedef const T *const_pointer; - typedef pointer_wrapper iterator; - typedef pointer_wrapper const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - static_assert((std::is_same::value), - "Allocator::value_type must be same type as value_type"); - - private /* types */: - /// Small array type to keep array in stack - using small_vector_type = max_size_vector; - - /// Vector type to keep array in heap - using large_vector_type = std::vector; - - /// Variant type to keep array in stack or heap - using variant_type = std::variant; - - public /* constructors */: - /// \brief Construct empty small array - constexpr small_vector() noexcept(std::is_nothrow_default_constructible::value) - : small_vector(allocator_type()) {} - - /// \brief Construct small vector with a given allocator - constexpr explicit small_vector(const allocator_type &alloc) : small_vector(0, alloc) {} - - /// \brief Construct small array with size n - constexpr explicit small_vector(size_type n, const allocator_type &alloc = allocator_type()) - : alloc_(alloc), - data_(n > N ? variant_type(large_vector_type(n, alloc)) : variant_type(small_vector_type(n))) { - assert(invariants()); - } - - /// \brief Construct small array with size n and fill with single value - constexpr small_vector(size_type n, const value_type &value, const allocator_type &alloc = allocator_type()) - : small_vector(n, alloc) { - std::fill(begin(), end(), value); - assert(invariants()); - } - - /// \brief Construct small array from a pair of iterators - template - constexpr small_vector(InputIterator first, enable_if_iterator_t last, - const allocator_type &alloc = allocator_type()) - : alloc_(alloc), data_(std::distance(first, last) > difference_type(N) - ? variant_type(large_vector_type(first, last, alloc)) - : variant_type(small_vector_type(first, last))) { - assert(invariants()); - } - - /// \brief Construct small array from initializer list - constexpr small_vector(std::initializer_list il, const allocator_type &alloc = allocator_type()) - : small_vector(il.begin(), il.end(), alloc) {} - - /// \brief Assign small array from initializer list - constexpr small_vector &operator=(std::initializer_list il) { - assign(il); - return *this; - } + /// \brief Assign small array from initializer list + constexpr small_vector &operator=(std::initializer_list il) { + assign(il); + return *this; + } - /// \brief Assign small array from iterators - template - constexpr void assign(InputIterator first, enable_if_iterator_t last) { - auto n = std::distance(first, last); - resize(n); - std::copy(first, last, begin()); - assert(invariants()); - } + /// \brief Assign small array from iterators + template + constexpr void assign(InputIterator first, enable_if_iterator_t last) { + auto n = std::distance(first, last); + resize(n); + std::copy(first, last, begin()); + assert(invariants()); + } - /// \brief Assign small array from size and fill with value - constexpr void assign(size_type n, const value_type &u) { - resize(n); - std::fill(begin(), end(), u); - assert(invariants()); - } + /// \brief Assign small array from size and fill with value + constexpr void assign(size_type n, const value_type &u) { + resize(n); + std::fill(begin(), end(), u); + assert(invariants()); + } - /// \brief Assign small array from initializer list - constexpr void assign(std::initializer_list il) { - resize(il.size()); - std::copy(il.begin(), il.end(), begin()); - assert(invariants()); - } + /// \brief Assign small array from initializer list + constexpr void assign(std::initializer_list il) { + resize(il.size()); + std::copy(il.begin(), il.end(), begin()); + assert(invariants()); + } - /// \brief Fill small array with value u - constexpr void fill(const T &u) { - std::fill(begin(), end(), u); - assert(invariants()); - } + /// \brief Fill small array with value u + constexpr void fill(const T &u) { + std::fill(begin(), end(), u); + assert(invariants()); + } - /// \brief Swap the contents of two small arrays - constexpr void swap(small_vector &a) noexcept(std::is_nothrow_swappable_v) { - data_.swap(a.data_); - std::swap(alloc_, a.alloc_); - assert(invariants()); - } + /// \brief Swap the contents of two small arrays + constexpr void swap(small_vector &a) noexcept(std::is_nothrow_swappable_v) { + data_.swap(a.data_); + std::swap(alloc_, a.alloc_); + assert(invariants()); + } - /// \brief Get copy of allocator for dynamic vector - allocator_type get_allocator() const noexcept { return alloc_; } + /// \brief Get copy of allocator for dynamic vector + allocator_type get_allocator() const noexcept { return alloc_; } - public /* iterators */: - /// \brief Get iterator to first element - constexpr iterator begin() noexcept { - return iterator(std::visit([](auto &x) { return x.data(); }, data_)); - } + public /* iterators */: + /// \brief Get iterator to first element + constexpr iterator begin() noexcept { + return iterator(std::visit([](auto &x) { return x.data(); }, data_)); + } - /// \brief Get constant iterator to first element[[nodiscard]] - constexpr const_iterator begin() const noexcept { - return const_iterator(std::visit([](auto &x) { return x.data(); }, data_)); - } + /// \brief Get constant iterator to first element[[nodiscard]] + constexpr const_iterator begin() const noexcept { + return const_iterator(std::visit([](auto &x) { return x.data(); }, data_)); + } - /// \brief Get iterator to last element - constexpr iterator end() noexcept { return begin() + size(); } + /// \brief Get iterator to last element + constexpr iterator end() noexcept { return begin() + size(); } - /// \brief Get constant iterator to last element - constexpr const_iterator end() const noexcept { return begin() + size(); } + /// \brief Get constant iterator to last element + constexpr const_iterator end() const noexcept { return begin() + size(); } - /// \brief Get iterator to first element in reverse order - constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator(end()); } + /// \brief Get iterator to first element in reverse order + constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator(end()); } - /// \brief Get constant iterator to first element in reverse order - constexpr const_reverse_iterator rbegin() const noexcept { - return std::reverse_iterator(end()); - } + /// \brief Get constant iterator to first element in reverse order + constexpr const_reverse_iterator rbegin() const noexcept { + return std::reverse_iterator(end()); + } - /// \brief Get iterator to last element in reverse order - constexpr reverse_iterator rend() noexcept { return std::reverse_iterator(begin()); } + /// \brief Get iterator to last element in reverse order + constexpr reverse_iterator rend() noexcept { return std::reverse_iterator(begin()); } - /// \brief Get constant iterator to last element in reverse order - constexpr const_reverse_iterator rend() const noexcept { - return std::reverse_iterator(begin()); - } + /// \brief Get constant iterator to last element in reverse order + constexpr const_reverse_iterator rend() const noexcept { + return std::reverse_iterator(begin()); + } - /// \brief Get constant iterator to first element - constexpr const_iterator cbegin() const noexcept { - return const_iterator(std::visit([](auto &x) { return &x[0]; }, data_)); - } + /// \brief Get constant iterator to first element + constexpr const_iterator cbegin() const noexcept { + return const_iterator(std::visit([](auto &x) { return &x[0]; }, data_)); + } - /// \brief Get constant iterator to last element - constexpr const_iterator cend() const noexcept { return cbegin() + size(); } + /// \brief Get constant iterator to last element + constexpr const_iterator cend() const noexcept { return cbegin() + size(); } - /// \brief Get constant iterator to first element in reverse order - constexpr const_reverse_iterator crbegin() const noexcept { - return std::reverse_iterator(cend()); - } + /// \brief Get constant iterator to first element in reverse order + constexpr const_reverse_iterator crbegin() const noexcept { + return std::reverse_iterator(cend()); + } - /// \brief Get constant iterator to last element in reverse order - constexpr const_reverse_iterator crend() const noexcept { - return std::reverse_iterator(cbegin()); - } + /// \brief Get constant iterator to last element in reverse order + constexpr const_reverse_iterator crend() const noexcept { + return std::reverse_iterator(cbegin()); + } - public /* capacity */: - /// \brief Get small array size - [[nodiscard]] constexpr size_type size() const noexcept { - return std::visit([](auto &x) { return x.size(); }, data_); - } + public /* capacity */: + /// \brief Get small array size + [[nodiscard]] constexpr size_type size() const noexcept { + return std::visit([](auto &x) { return x.size(); }, data_); + } - /// \brief Get small array max size - [[nodiscard]] constexpr size_type max_size() const noexcept { - return std::min(std::allocator_traits::max_size(alloc_), - std::numeric_limits::max()); - } + /// \brief Get small array max size + [[nodiscard]] constexpr size_type max_size() const noexcept { + return std::min(std::allocator_traits::max_size(alloc_), + std::numeric_limits::max()); + } - /// \brief Get small array capacity (same as max_size()) - [[nodiscard]] constexpr size_type capacity() const noexcept { - return std::visit([](auto &x) { return x.capacity(); }, data_); - } + /// \brief Get small array capacity (same as max_size()) + [[nodiscard]] constexpr size_type capacity() const noexcept { + return std::visit([](auto &x) { return x.capacity(); }, data_); + } - /// \brief Check if small array is empty - [[nodiscard]] constexpr bool empty() const noexcept { - return std::visit([](auto &x) { return x.empty(); }, data_); - } + /// \brief Check if small array is empty + [[nodiscard]] constexpr bool empty() const noexcept { + return std::visit([](auto &x) { return x.empty(); }, data_); + } - /// \brief Reserve space for n elements - /// We concentrate the logic to switch the variant types in these functions - void reserve(size_type n) { - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - if (n > data_as_array.max_size()) { - std::vector tmp(data_as_array.begin(), data_as_array.end()); - tmp.reserve(n); - data_ = std::move(tmp); + /// \brief Reserve space for n elements + /// We concentrate the logic to switch the variant types in these functions + void reserve(size_type n) { + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + if (n > data_as_array.max_size()) { + std::vector tmp(data_as_array.begin(), data_as_array.end()); + tmp.reserve(n); + data_ = std::move(tmp); + } + } else { + auto &data_as_vector = std::get(data_); + data_as_vector.reserve(n); } - } else { - auto &data_as_vector = std::get(data_); - data_as_vector.reserve(n); } - } - /// \brief Shrink internal array to fit only the current elements - /// We concentrate the logic to switch the variant types in these functions - void shrink_to_fit() noexcept { - if (std::holds_alternative(data_)) { - auto &data_as_vector = std::get(data_); - if (data_as_vector.size() > N) { - data_as_vector.shrink_to_fit(); - } else { - small_vector_type tmp(data_as_vector.begin(), data_as_vector.end()); - data_ = std::move(tmp); + /// \brief Shrink internal array to fit only the current elements + /// We concentrate the logic to switch the variant types in these functions + void shrink_to_fit() noexcept { + if (std::holds_alternative(data_)) { + auto &data_as_vector = std::get(data_); + if (data_as_vector.size() > N) { + data_as_vector.shrink_to_fit(); + } else { + small_vector_type tmp(data_as_vector.begin(), data_as_vector.end()); + data_ = std::move(tmp); + } } } - } - public /* element access */: - /// \brief Get reference to n-th element in small array - constexpr reference operator[](size_type n) { - assert(n < size() && "small_vector[] index out of bounds"); - return begin()[n]; - } + public /* element access */: + /// \brief Get reference to n-th element in small array + constexpr reference operator[](size_type n) { + assert(n < size() && "small_vector[] index out of bounds"); + return begin()[n]; + } - /// \brief Get constant reference to n-th element in small array - constexpr const_reference operator[](size_type n) const { - assert(n < size() && "small_vector[] index out of bounds"); - return cbegin()[n]; - } + /// \brief Get constant reference to n-th element in small array + constexpr const_reference operator[](size_type n) const { + assert(n < size() && "small_vector[] index out of bounds"); + return cbegin()[n]; + } - /// \brief Check bounds and get reference to n-th element in small array - constexpr reference at(size_type n) { - if (n >= size()) { - this->throw_out_of_range("at({0}): cannot access element {0} in array of size {1}", n, size()); + /// \brief Check bounds and get reference to n-th element in small array + constexpr reference at(size_type n) { + if (n >= size()) { + this->throw_out_of_range("at({0}): cannot access element {0} in array of size {1}", n, size()); + } + return begin()[n]; } - return begin()[n]; - } - /// \brief Check bounds and get constant reference to n-th element in small array - constexpr const_reference at(size_type n) const { - if (n >= size()) { - this->throw_out_of_range("at({0}) const: cannot access element {0} in array of size {1}", n, size()); + /// \brief Check bounds and get constant reference to n-th element in small array + constexpr const_reference at(size_type n) const { + if (n >= size()) { + this->throw_out_of_range("at({0}) const: cannot access element {0} in array of size {1}", n, + size()); + } + return begin()[n]; } - return begin()[n]; - } - /// \brief Get reference to first element in small array - constexpr reference front() { - assert(!empty() && "front() called for empty small array"); - return operator[](0); - } + /// \brief Get reference to first element in small array + constexpr reference front() { + assert(!empty() && "front() called for empty small array"); + return operator[](0); + } - /// \brief Get constant reference to first element in small array - constexpr const_reference front() const { - assert(!empty() && "front() called for empty small array"); - return operator[](0); - } + /// \brief Get constant reference to first element in small array + constexpr const_reference front() const { + assert(!empty() && "front() called for empty small array"); + return operator[](0); + } - /// \brief Get reference to last element in small array - constexpr reference back() { - assert(!empty() && "back() called for empty small array"); - return operator[](size() - 1); - } + /// \brief Get reference to last element in small array + constexpr reference back() { + assert(!empty() && "back() called for empty small array"); + return operator[](size() - 1); + } - /// \brief Get constant reference to last element in small array - constexpr const_reference back() const { - assert(!empty() && "back() called for empty small array"); - return operator[](size() - 1); - } + /// \brief Get constant reference to last element in small array + constexpr const_reference back() const { + assert(!empty() && "back() called for empty small array"); + return operator[](size() - 1); + } - /// \brief Get reference to internal pointer to small array data - constexpr T *data() noexcept { return begin().base(); } + /// \brief Get reference to internal pointer to small array data + constexpr T *data() noexcept { return begin().base(); } - /// \brief Get constant reference to internal pointer to small array data - constexpr const T *data() const noexcept { return begin().base(); } + /// \brief Get constant reference to internal pointer to small array data + constexpr const T *data() const noexcept { return begin().base(); } - public /* modifiers */: - /// \brief Copy element to end of small array - constexpr void push_back(const value_type &x) { - reserve(size() + 1); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - data_as_array.push_back(x); - } else { - auto &data_as_vector = std::get(data_); - data_as_vector.push_back(x); + public /* modifiers */: + /// \brief Copy element to end of small array + constexpr void push_back(const value_type &x) { + reserve(size() + 1); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + data_as_array.push_back(x); + } else { + auto &data_as_vector = std::get(data_); + data_as_vector.push_back(x); + } } - } - /// \brief Move element to end of small array - constexpr void push_back(value_type &&x) { - reserve(size() + 1); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - data_as_array.push_back(std::move(x)); - } else { - auto &data_as_vector = std::get(data_); - data_as_vector.push_back(std::move(x)); + /// \brief Move element to end of small array + constexpr void push_back(value_type &&x) { + reserve(size() + 1); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + data_as_array.push_back(std::move(x)); + } else { + auto &data_as_vector = std::get(data_); + data_as_vector.push_back(std::move(x)); + } } - } - /// \brief Emplace element to end of small array - template constexpr reference emplace_back(Args &&...args) { - reserve(size() + 1); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - return data_as_array.emplace_back(std::forward(args)...); - } else { - auto &data_as_vector = std::get(data_); - return data_as_vector.emplace_back(std::forward(args)...); + /// \brief Emplace element to end of small array + template constexpr reference emplace_back(Args &&...args) { + reserve(size() + 1); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + return data_as_array.emplace_back(std::forward(args)...); + } else { + auto &data_as_vector = std::get(data_); + return data_as_vector.emplace_back(std::forward(args)...); + } } - } - /// \brief Remove element from end of small array - constexpr void pop_back() { - return std::visit([](auto &d) { return d.pop_back(); }, data_); - } - - /// \brief Emplace element to a position in small array - template constexpr iterator emplace(const_iterator position, Args &&...args) { - size_t p = position - begin(); - reserve(size() + 1); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - return iterator(&*data_as_array.emplace(data_as_array.begin() + p, std::forward(args)...)); - } else { - auto &data_as_vector = std::get(data_); - return iterator(&*data_as_vector.emplace(data_as_vector.begin() + p, std::forward(args)...)); + /// \brief Remove element from end of small array + constexpr void pop_back() { + return std::visit([](auto &d) { return d.pop_back(); }, data_); } - } - /// \brief Copy element to a position in small array - constexpr iterator insert(const_iterator position, const value_type &x) { - size_t p = position - begin(); - reserve(size() + 1); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - return iterator(&*data_as_array.insert(data_as_array.begin() + p, x)); - } else { - auto &data_as_vector = std::get(data_); - return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, x)); + /// \brief Emplace element to a position in small array + template constexpr iterator emplace(const_iterator position, Args &&...args) { + size_t p = position - begin(); + reserve(size() + 1); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + return iterator(&*data_as_array.emplace(data_as_array.begin() + p, std::forward(args)...)); + } else { + auto &data_as_vector = std::get(data_); + return iterator(&*data_as_vector.emplace(data_as_vector.begin() + p, std::forward(args)...)); + } } - } - /// \brief Move element to a position in small array - constexpr iterator insert(const_iterator position, value_type &&x) { - size_t p = position - begin(); - reserve(size() + 1); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - return iterator(&*data_as_array.insert(data_as_array.begin() + p, std::move(x))); - } else { - auto &data_as_vector = std::get(data_); - return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, std::move(x))); + /// \brief Copy element to a position in small array + constexpr iterator insert(const_iterator position, const value_type &x) { + size_t p = position - begin(); + reserve(size() + 1); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + return iterator(&*data_as_array.insert(data_as_array.begin() + p, x)); + } else { + auto &data_as_vector = std::get(data_); + return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, x)); + } } - } - /// \brief Copy n elements to a position in small array - constexpr iterator insert(const_iterator position, size_type n, const value_type &x) { - size_t p = position - begin(); - reserve(size() + n); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - return iterator(&*data_as_array.insert(data_as_array.begin() + p, n, x)); - } else { - auto &data_as_vector = std::get(data_); - return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, n, x)); + /// \brief Move element to a position in small array + constexpr iterator insert(const_iterator position, value_type &&x) { + size_t p = position - begin(); + reserve(size() + 1); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + return iterator(&*data_as_array.insert(data_as_array.begin() + p, std::move(x))); + } else { + auto &data_as_vector = std::get(data_); + return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, std::move(x))); + } } - } - /// \brief Copy element range stating at a position in small array - template - constexpr iterator insert(const_iterator position, InputIterator first, - enable_if_iterator_t last) { - size_t p = position - begin(); - reserve(size() + std::distance(first, last)); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - return iterator(&*data_as_array.insert(data_as_array.begin() + p, first, last)); - } else { - auto &data_as_vector = std::get(data_); - return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, first, last)); + /// \brief Copy n elements to a position in small array + constexpr iterator insert(const_iterator position, size_type n, const value_type &x) { + size_t p = position - begin(); + reserve(size() + n); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + return iterator(&*data_as_array.insert(data_as_array.begin() + p, n, x)); + } else { + auto &data_as_vector = std::get(data_); + return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, n, x)); + } } - } - /// \brief Copy elements from initializer list to a position in small array - constexpr iterator insert(const_iterator position, std::initializer_list il) { - size_t p = position - begin(); - reserve(size() + il.size()); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - return iterator(&*data_as_array.insert(data_as_array.begin() + p, il)); - } else { - auto &data_as_vector = std::get(data_); - return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, il)); + /// \brief Copy element range stating at a position in small array + template + constexpr iterator insert(const_iterator position, InputIterator first, + enable_if_iterator_t last) { + size_t p = position - begin(); + reserve(size() + std::distance(first, last)); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + return iterator(&*data_as_array.insert(data_as_array.begin() + p, first, last)); + } else { + auto &data_as_vector = std::get(data_); + return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, first, last)); + } } - } - /// \brief Erase element at a position in small array - constexpr iterator erase(const_iterator position) { - size_t p = position - begin(); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - return iterator(&*data_as_array.erase(data_as_array.begin() + p)); - } else { - auto &data_as_vector = std::get(data_); - return iterator(&*data_as_vector.erase(data_as_vector.begin() + p)); + /// \brief Copy elements from initializer list to a position in small array + constexpr iterator insert(const_iterator position, std::initializer_list il) { + size_t p = position - begin(); + reserve(size() + il.size()); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + return iterator(&*data_as_array.insert(data_as_array.begin() + p, il)); + } else { + auto &data_as_vector = std::get(data_); + return iterator(&*data_as_vector.insert(data_as_vector.begin() + p, il)); + } } - } - /// \brief Erase range of elements in the small array - constexpr iterator erase(const_iterator first, const_iterator last) { - size_t p_first = first - begin(); - size_t p_last = last - begin(); - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - return iterator(&*data_as_array.erase(data_as_array.begin() + p_first, data_as_array.begin() + p_last)); - } else { - auto &data_as_vector = std::get(data_); - return iterator( - &*data_as_vector.erase(data_as_vector.begin() + p_first, data_as_vector.begin() + p_last)); + /// \brief Erase element at a position in small array + constexpr iterator erase(const_iterator position) { + size_t p = position - begin(); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + return iterator(&*data_as_array.erase(data_as_array.begin() + p)); + } else { + auto &data_as_vector = std::get(data_); + return iterator(&*data_as_vector.erase(data_as_vector.begin() + p)); + } } - } - /// \brief Clear elements in the small array - constexpr void clear() noexcept { resize(0); } - - /// \brief Resize the small array - /// If we are using a vector to store the data, resize will not - /// move the data back to the stack even if the new size is less - /// than the small_vector capacity - constexpr void resize(size_type n) { - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - if (n > data_as_array.max_size()) { - large_vector_type tmp(data_as_array.begin(), data_as_array.end(), alloc_); - tmp.resize(n); - data_ = std::move(tmp); + /// \brief Erase range of elements in the small array + constexpr iterator erase(const_iterator first, const_iterator last) { + size_t p_first = first - begin(); + size_t p_last = last - begin(); + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + return iterator( + &*data_as_array.erase(data_as_array.begin() + p_first, data_as_array.begin() + p_last)); } else { - data_as_array.resize(n); + auto &data_as_vector = std::get(data_); + return iterator( + &*data_as_vector.erase(data_as_vector.begin() + p_first, data_as_vector.begin() + p_last)); } - } else { - auto &data_as_vector = std::get(data_); - data_as_vector.resize(n); } - } - /// \brief Resize and fill the small array - constexpr void resize(size_type n, const value_type &c) { - if (std::holds_alternative(data_)) { - auto &data_as_array = std::get(data_); - if (n > data_as_array.max_size()) { - large_vector_type tmp(data_as_array.begin(), data_as_array.end(), alloc_); - tmp.resize(n, c); - data_ = std::move(tmp); + /// \brief Clear elements in the small array + constexpr void clear() noexcept { resize(0); } + + /// \brief Resize the small array + /// If we are using a vector to store the data, resize will not + /// move the data back to the stack even if the new size is less + /// than the small_vector capacity + constexpr void resize(size_type n) { + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + if (n > data_as_array.max_size()) { + large_vector_type tmp(data_as_array.begin(), data_as_array.end(), alloc_); + tmp.resize(n); + data_ = std::move(tmp); + } else { + data_as_array.resize(n); + } } else { - data_as_array.resize(n, c); + auto &data_as_vector = std::get(data_); + data_as_vector.resize(n); } - } else { - auto &data_as_vector = std::get(data_); - data_as_vector.resize(n, c); } - } - private: - /// \brief Check if small array invariants are ok - [[nodiscard]] constexpr bool invariants() const { - if (size() > capacity()) { - return false; - } - if (begin().base() == nullptr) { - return false; + /// \brief Resize and fill the small array + constexpr void resize(size_type n, const value_type &c) { + if (std::holds_alternative(data_)) { + auto &data_as_array = std::get(data_); + if (n > data_as_array.max_size()) { + large_vector_type tmp(data_as_array.begin(), data_as_array.end(), alloc_); + tmp.resize(n, c); + data_ = std::move(tmp); + } else { + data_as_array.resize(n, c); + } + } else { + auto &data_as_vector = std::get(data_); + data_as_vector.resize(n, c); + } } - if (end().base() == nullptr) { - return false; + + private: + /// \brief Check if small array invariants are ok + [[nodiscard]] constexpr bool invariants() const { + if (size() > capacity()) { + return false; + } + if (begin().base() == nullptr) { + return false; + } + if (end().base() == nullptr) { + return false; + } + if (begin() > end()) { + return false; + } + if (end() > begin() + capacity()) { + return false; + } + return true; } - if (begin() > end()) { - return false; + + /// \brief Throw an out of range error + template void throw_out_of_range(const char *what_arg, const Args &...args) { + throw_error_code(small_vector_error_code::out_of_range, what_arg, args...); } - if (end() > begin() + capacity()) { - return false; + + /// \brief Throw any error related to small vectors + template + void throw_error_code(small_vector_error_code e, const char *what_arg, const Args &...args) { + throw fmt_error(e, small_vector_error_category(), what_arg, args...); } - return true; + + private: + /// \brief A copy of the allocator so we can allocate vectors if needed + allocator_type alloc_{}; + + /// \brief Internal array or vector + variant_type data_{}; + }; + + /// Type deduction + template small_vector(T, U...) -> small_vector; + + /// \brief operator== for small arrays + template + constexpr bool operator==(const small_vector &x, const small_vector &y) { + return std::equal(x.begin(), x.end(), y.begin(), y.end()); + } + + /// \brief operator!= for small arrays + template + constexpr bool operator!=(const small_vector &x, const small_vector &y) { + return !(x == y); + } + + /// \brief operator< for small arrays + template + constexpr bool operator<(const small_vector &x, const small_vector &y) { + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); + } + + /// \brief operator> for small arrays + template + constexpr bool operator>(const small_vector &x, const small_vector &y) { + return y < x; + } + + /// \brief operator<= for small arrays + template + constexpr bool operator<=(const small_vector &x, const small_vector &y) { + return !(y < x); + } + + /// \brief operator>= for small arrays + template + constexpr bool operator>=(const small_vector &x, const small_vector &y) { + return !(x < y); } - /// \brief Throw an out of range error - template void throw_out_of_range(const char *what_arg, const Args &...args) { - throw_error_code(small_vector_error_code::out_of_range, what_arg, args...); + /// \brief swap the contents of two small arrays + template + void swap(small_vector &x, small_vector &y) noexcept(noexcept(x.swap(y))) { + x.swap(y); } - /// \brief Throw any error related to small vectors - template - void throw_error_code(small_vector_error_code e, const char *what_arg, const Args &...args) { - throw fmt_error(e, small_vector_error_category(), what_arg, args...); + /// \brief create small array from raw array + template + constexpr small_vector, N_OUTPUT> to_small_vector(T (&a)[N_INPUT]) { + return small_vector, N_OUTPUT>(a, a + N_INPUT); } - private: - /// \brief A copy of the allocator so we can allocate vectors if needed - allocator_type alloc_{}; - - /// \brief Internal array or vector - variant_type data_{}; - }; - - /// Type deduction - template small_vector(T, U...) -> small_vector; - - /// \brief operator== for small arrays - template constexpr bool operator==(const small_vector &x, const small_vector &y) { - return std::equal(x.begin(), x.end(), y.begin(), y.end()); - } - - /// \brief operator!= for small arrays - template constexpr bool operator!=(const small_vector &x, const small_vector &y) { - return !(x == y); - } - - /// \brief operator< for small arrays - template constexpr bool operator<(const small_vector &x, const small_vector &y) { - return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); - } - - /// \brief operator> for small arrays - template constexpr bool operator>(const small_vector &x, const small_vector &y) { - return y < x; - } - - /// \brief operator<= for small arrays - template constexpr bool operator<=(const small_vector &x, const small_vector &y) { - return !(y < x); - } - - /// \brief operator>= for small arrays - template constexpr bool operator>=(const small_vector &x, const small_vector &y) { - return !(x < y); - } - - /// \brief swap the contents of two small arrays - template void swap(small_vector &x, small_vector &y) noexcept(noexcept(x.swap(y))) { - x.swap(y); - } - - /// \brief create small array from raw array - template - constexpr small_vector, N_OUTPUT> to_small_vector(T (&a)[N_INPUT]) { - return small_vector, N_OUTPUT>(a, a + N_INPUT); - } - - /// \brief create small array from raw array - template - constexpr small_vector, N_OUTPUT> to_small_vector(T(&&a)[N_INPUT]) { - return small_vector, N_OUTPUT>(a, a + N_INPUT); - } + /// \brief create small array from raw array + template + constexpr small_vector, N_OUTPUT> to_small_vector(T (&&a)[N_INPUT]) { + return small_vector, N_OUTPUT>(a, a + N_INPUT); + } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_CONTAINER_VARIANT_VECTOR_H diff --git a/source/small/detail/exception/scope_guard.h b/source/small/detail/exception/scope_guard.h index 6f62168..0c18a68 100644 --- a/source/small/detail/exception/scope_guard.h +++ b/source/small/detail/exception/scope_guard.h @@ -5,13 +5,12 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_EXCEPTION_SCOPE_GUARD_H #define SMALL_DETAIL_EXCEPTION_SCOPE_GUARD_H -#include #include #include +#include #include "throw.h" diff --git a/source/small/detail/exception/throw.h b/source/small/detail/exception/throw.h index 4000d5b..d623a26 100644 --- a/source/small/detail/exception/throw.h +++ b/source/small/detail/exception/throw.h @@ -5,49 +5,50 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_EXCEPTION_THROW_H #define SMALL_DETAIL_EXCEPTION_THROW_H +#include "../traits/cpp_version.h" #include #include #include -#include "../traits/cpp_version.h" #ifndef cpp_exceptions #define SMALL_DISABLE_EXCEPTIONS #endif namespace small { + namespace detail { - /// \brief Throw an exception but terminate if we can't throw - template [[noreturn]] void throw_exception(Ex &&ex) { + /// \brief Throw an exception but terminate if we can't throw + template [[noreturn]] void throw_exception(Ex &&ex) { #ifndef SMALL_DISABLE_EXCEPTIONS - throw static_cast(ex); + throw static_cast(ex); #else - (void)ex; - std::terminate(); + (void)ex; + std::terminate(); #endif - } + } - /// \brief Construct and throw an exception but terminate otherwise - template [[noreturn]] void throw_exception(Args &&...args) { - throw_exception(Ex(std::forward(args)...)); - } + /// \brief Construct and throw an exception but terminate otherwise + template [[noreturn]] void throw_exception(Args &&...args) { + throw_exception(Ex(std::forward(args)...)); + } - /// \brief Throw an exception but terminate if we can't throw - template void catch_exception(ThrowFn &&thrower, CatchFn &&catcher) { + /// \brief Throw an exception but terminate if we can't throw + template void catch_exception(ThrowFn &&thrower, CatchFn &&catcher) { #ifndef SMALL_DISABLE_EXCEPTIONS - try { - return static_cast(thrower)(); - } catch (std::exception &) { - return static_cast(catcher)(); - } + try { + return static_cast(thrower)(); + } catch (std::exception &) { + return static_cast(catcher)(); + } #else - return static_cast(thrower)(); + return static_cast(thrower)(); #endif - } + } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_EXCEPTION_THROW_H diff --git a/source/small/detail/iterator/codepoint_iterator.h b/source/small/detail/iterator/codepoint_iterator.h index 5fc773b..88bcf69 100644 --- a/source/small/detail/iterator/codepoint_iterator.h +++ b/source/small/detail/iterator/codepoint_iterator.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ITERATOR_CODEPOINT_ITERATOR_H #define SMALL_DETAIL_ITERATOR_CODEPOINT_ITERATOR_H @@ -18,637 +17,647 @@ #include "../exception/throw.h" namespace small { - /// \brief This iterator class represents an iterator for utf8 codepoints - /// The codepoints are represented by a span from 1 to 4 bytes - /// The iterator needs to have access to: - /// - its underlying string, which allows it to identify the size of a codepoint - /// - a lookup table, which makes it random access namespace detail { - /// \brief Type to indirectly represent a codepoint reference in a string container - /// - /// The codepoint reference only needs to know where the codepoint starts (its byte index), - /// so that we know how many bytes we need to consider to lazily dereference it as a wide char. - /// - /// However, to be able to change the codepoint value, we need to have access to the underlying - /// container so that we can call a function to update this reference value. This is what - /// makes this complicated. So, in practice, this will only work efficiently with any string - /// class with support for the our lookup_table_view. - /// - /// Like with iterators, we use templates to define the mutable and constant versions at once. - /// - template struct codepoint_reference_impl { - public: - /// \brief The string type on which we are working - using string_type = std::conditional_t; - - /// \brief The type being used represent the UTF8 codepoints - /// Although we make this class work correctly for wide chars, this is really meant to be 1-byte chars - using value_type = typename string_type::value_type; - - /// \brief The char type to which the codepoints get converted when we dereference them - using wide_value_type = typename string_type::wide_value_type; - - /// \brief The type our container uses for indexes - using size_type = typename string_type::size_type; - - /// \brief Constant to make code clearer - /// Everything that's 1-byte is considered to be utf8 - constexpr static bool is_utf8 = sizeof(value_type) == 1; - - public: - /// \brief The constructor containers iterators should use to create a reference - codepoint_reference_impl(string_type *container, size_type codepoint_index, - size_type byte_index_hint) noexcept - : container_(container), codepoint_index_(codepoint_index), byte_index_(byte_index_hint) {} - - /// \brief Get the codepoint size of this reference - constexpr size_type size() const { - if constexpr (sizeof(value_type) == 1) { - return utf8_size(*(container_->begin() + byte_index_), container_->size() - byte_index_); - } else { - return utf8_size(container_->operator[](byte_index_)); - } - } - - /// \brief Cast to the wide char type if we need to access the value - /// This should work in O(1) time because we have a hint to the byte index - operator typename String::wide_value_type() const noexcept { - if constexpr (not is_utf32_v) { - // Get reference to element and convert from utf8 to wide type - wide_value_type v; - to_utf32(container_->begin() + byte_index_, size(), &v, 1); - return v; - } else { - // Just cast at that position - return static_cast(container_->operator[](byte_index_)); - } - } - - /// \brief Streaming a codepoint to the console - /// In POSIX systems, the console usually expects a span of UTF8 chars. Sending a wide value - /// to the console will usually show its integer value. - /// In Windows, as usual, things are a little more complicated. For now, we convert the value - /// to a wide value, which might work with wcout. A more consistent solution would be - /// calling something like `SetConsoleOutputCP(CP_UTF8);` or `_setmode(..., _O_U16TEXT)` if - /// we identify this codepoint has more than 1 byte and the console hasn't been set to unicode - /// yet. We would also need to ensure `os` is cout or wcout. - /// It seems like fmt implements some similar solution. - /// Once we find a consistent solution, we can apply that to the small::string operator<<. - friend std::ostream &operator<<(std::ostream &os, const codepoint_reference_impl &impl) { - if constexpr (not is_utf32_v) { - if (impl.size() == 1) { - os << impl.container_->operator[](impl.byte_index_); + /// \brief This iterator class represents an iterator for utf8 codepoints + /// The codepoints are represented by a span from 1 to 4 bytes + /// The iterator needs to have access to: + /// - its underlying string, which allows it to identify the size of a codepoint + /// - a lookup table, which makes it random access + namespace detail { + /// \brief Type to indirectly represent a codepoint reference in a string container + /// + /// The codepoint reference only needs to know where the codepoint starts (its byte index), + /// so that we know how many bytes we need to consider to lazily dereference it as a wide char. + /// + /// However, to be able to change the codepoint value, we need to have access to the underlying + /// container so that we can call a function to update this reference value. This is what + /// makes this complicated. So, in practice, this will only work efficiently with any string + /// class with support for the our lookup_table_view. + /// + /// Like with iterators, we use templates to define the mutable and constant versions at once. + /// + template struct codepoint_reference_impl { + public: + /// \brief The string type on which we are working + using string_type = std::conditional_t; + + /// \brief The type being used represent the UTF8 codepoints + /// Although we make this class work correctly for wide chars, this is really meant to be 1-byte chars + using value_type = typename string_type::value_type; + + /// \brief The char type to which the codepoints get converted when we dereference them + using wide_value_type = typename string_type::wide_value_type; + + /// \brief The type our container uses for indexes + using size_type = typename string_type::size_type; + + /// \brief Constant to make code clearer + /// Everything that's 1-byte is considered to be utf8 + constexpr static bool is_utf8 = sizeof(value_type) == 1; + + public: + /// \brief The constructor containers iterators should use to create a reference + codepoint_reference_impl(string_type *container, size_type codepoint_index, + size_type byte_index_hint) noexcept + : container_(container), codepoint_index_(codepoint_index), byte_index_(byte_index_hint) {} + + /// \brief Get the codepoint size of this reference + constexpr size_type size() const { + if constexpr (sizeof(value_type) == 1) { + return utf8_size(*(container_->begin() + byte_index_), container_->size() - byte_index_); } else { - console_unicode_guard g(os, impl.size(), 1); - os << std::string_view(impl.container_->data() + impl.byte_index_, impl.size()); + return utf8_size(container_->operator[](byte_index_)); } - } else { - // If the underlying container is utf32, just cast the code unit at that position - os << static_cast(impl.container_->operator[](impl.byte_index_)); - } - return os; - } - - /// \brief Assignment operator from a char - /// The char might be of the same type or another type. It might even be - /// an array with a list of code units. - /// In any case, this is just something for which we can replace in the - /// original string. If required, the string is responsible for shifting items - /// and doing all the hard work. - /// - /// This function should not be available for const references. - template codepoint_reference_impl &operator=(Char codepoint) { - static_assert(!IS_CONST, "Cannot assign to a constant reference"); - // Replace using the codepoint index as a hint for the replace operation. - // This hint makes it faster for the string to find the elements in the lookup - // table that might require an update. - container_->replace(byte_index_, codepoint, codepoint_index_); - return *this; - } - - /// \brief Assignment operator from another codepoint reference - template - codepoint_reference_impl &operator=(const codepoint_reference_impl &rhs) { - static_assert(!IS_CONST, "Cannot assign to a constant reference"); - // Replace using the codepoint index as a hint for the replace operation. - // This hint makes it faster for the string to find the elements in the lookup - // table that might require an update. - container_->replace(byte_index_, rhs.operator wide_value_type(), codepoint_index_); - return *this; - } - - /// \brief Compare this reference to another reference - template - bool operator==(const codepoint_reference_impl &rhs) const { - return this->operator wide_value_type() == rhs.operator wide_value_type(); - } - - /// \brief Compare this reference to another char of any type - template , int> = 0> - friend bool operator==(const codepoint_reference_impl &lhs, const WChar &rhs) { - return lhs.operator wide_value_type() == static_cast(rhs); - } - - /// \brief Compare this reference to a sequence of chars representing another codepoint - template friend bool operator==(const codepoint_reference_impl &lhs, const WChar *rhs) { - constexpr bool rhs_is_utf8 = sizeof(WChar) == 1; - if constexpr (rhs_is_utf8) { - // RHS is code units, something like: `if (ref == "😀")` - // Find its size, but don't look for more than we need - size_t rhs_min_size = strlen(rhs, 10); - if (rhs_min_size == 0) { - return false; + } + + /// \brief Cast to the wide char type if we need to access the value + /// This should work in O(1) time because we have a hint to the byte index + operator typename String::wide_value_type() const noexcept { + if constexpr (not is_utf32_v) { + // Get reference to element and convert from utf8 to wide type + wide_value_type v; + to_utf32(container_->begin() + byte_index_, size(), &v, 1); + return v; + } else { + // Just cast at that position + return static_cast(container_->operator[](byte_index_)); } - // Find its codepoint size - size_t rhs_utf8_size = utf8_size(*rhs, rhs_min_size); - if (lhs.size() != rhs_utf8_size) { - return false; + } + + /// \brief Streaming a codepoint to the console + /// In POSIX systems, the console usually expects a span of UTF8 chars. Sending a wide value + /// to the console will usually show its integer value. + /// In Windows, as usual, things are a little more complicated. For now, we convert the value + /// to a wide value, which might work with wcout. A more consistent solution would be + /// calling something like `SetConsoleOutputCP(CP_UTF8);` or `_setmode(..., _O_U16TEXT)` if + /// we identify this codepoint has more than 1 byte and the console hasn't been set to unicode + /// yet. We would also need to ensure `os` is cout or wcout. + /// It seems like fmt implements some similar solution. + /// Once we find a consistent solution, we can apply that to the small::string operator<<. + friend std::ostream &operator<<(std::ostream &os, const codepoint_reference_impl &impl) { + if constexpr (not is_utf32_v) { + if (impl.size() == 1) { + os << impl.container_->operator[](impl.byte_index_); + } else { + console_unicode_guard g(os, impl.size(), 1); + os << std::string_view(impl.container_->data() + impl.byte_index_, impl.size()); + } + } else { + // If the underlying container is utf32, just cast the code unit at that position + os << static_cast(impl.container_->operator[](impl.byte_index_)); } - // Compare codepoints now - for (size_type i = 0; i < rhs_utf8_size; ++i) { - if (lhs.container_->operator[](lhs.byte_index_ + i) != rhs[i]) { + return os; + } + + /// \brief Assignment operator from a char + /// The char might be of the same type or another type. It might even be + /// an array with a list of code units. + /// In any case, this is just something for which we can replace in the + /// original string. If required, the string is responsible for shifting items + /// and doing all the hard work. + /// + /// This function should not be available for const references. + template codepoint_reference_impl &operator=(Char codepoint) { + static_assert(!IS_CONST, "Cannot assign to a constant reference"); + // Replace using the codepoint index as a hint for the replace operation. + // This hint makes it faster for the string to find the elements in the lookup + // table that might require an update. + container_->replace(byte_index_, codepoint, codepoint_index_); + return *this; + } + + /// \brief Assignment operator from another codepoint reference + template + codepoint_reference_impl &operator=(const codepoint_reference_impl &rhs) { + static_assert(!IS_CONST, "Cannot assign to a constant reference"); + // Replace using the codepoint index as a hint for the replace operation. + // This hint makes it faster for the string to find the elements in the lookup + // table that might require an update. + container_->replace(byte_index_, rhs.operator wide_value_type(), codepoint_index_); + return *this; + } + + /// \brief Compare this reference to another reference + template + bool operator==(const codepoint_reference_impl &rhs) const { + return this->operator wide_value_type() == rhs.operator wide_value_type(); + } + + /// \brief Compare this reference to another char of any type + template , int> = 0> + friend bool operator==(const codepoint_reference_impl &lhs, const WChar &rhs) { + return lhs.operator wide_value_type() == static_cast(rhs); + } + + /// \brief Compare this reference to a sequence of chars representing another codepoint + template + friend bool operator==(const codepoint_reference_impl &lhs, const WChar *rhs) { + constexpr bool rhs_is_utf8 = sizeof(WChar) == 1; + if constexpr (rhs_is_utf8) { + // RHS is code units, something like: `if (ref == "😀")` + // Find its size, but don't look for more than we need + size_t rhs_min_size = strlen(rhs, 10); + if (rhs_min_size == 0) { return false; } + // Find its codepoint size + size_t rhs_utf8_size = utf8_size(*rhs, rhs_min_size); + if (lhs.size() != rhs_utf8_size) { + return false; + } + // Compare codepoints now + for (size_type i = 0; i < rhs_utf8_size; ++i) { + if (lhs.container_->operator[](lhs.byte_index_ + i) != rhs[i]) { + return false; + } + } + return true; + } else { + // Rhs is not code units, something like: `if (ref == U"😀")` + // In this case, we compare the codepoint with the string iff + // this is a string with a single codepoint + size_t rhs_min_size = strlen(rhs, 2); + if (rhs_min_size != 1) { + return false; + } + return lhs.operator wide_value_type() != *rhs; } - return true; - } else { - // Rhs is not code units, something like: `if (ref == U"😀")` - // In this case, we compare the codepoint with the string iff - // this is a string with a single codepoint - size_t rhs_min_size = strlen(rhs, 2); - if (rhs_min_size != 1) { - return false; - } - return lhs.operator wide_value_type() != *rhs; } - } - private: - /// \brief A pointer to the container so we can update its values - string_type *container_; + private: + /// \brief A pointer to the container so we can update its values + string_type *container_; - /// \brief A hint of the codepoint index - /// This helps us with the assignment operation - size_type codepoint_index_{0}; + /// \brief A hint of the codepoint index + /// This helps us with the assignment operation + size_type codepoint_index_{0}; - /// \brief A hint of the byte index - size_type byte_index_{0}; - }; + /// \brief A hint of the byte index + size_type byte_index_{0}; + }; - } // namespace detail + } // namespace detail - /// \section Final aliases for references - template using external_codepoint_reference = detail::codepoint_reference_impl; - template using const_external_codepoint_reference = detail::codepoint_reference_impl; + /// \section Final aliases for references + template using external_codepoint_reference = detail::codepoint_reference_impl; + template + using const_external_codepoint_reference = detail::codepoint_reference_impl; - namespace detail { - /// \brief An iterator for accessing codepoints in a string - /// - /// The basic functions for the codepoint iterator and const codepoint iterator. - /// - /// Although we could implement a _bidirectional_ codepoint iterator with - /// no reference to the underlying container, this class needs this reference - /// so that we can use the look up table to find elements more efficiently - /// and make _random access_ codepoint iterators possible. - /// - /// Unlike other utf8 iterators with O(m) random access, the lookup table - /// allows us to find these elements in constant time through codepoint - /// index hints spread through the lookup table. A detailed description - /// is in the lookup table container header file. - /// - template struct codepoint_iterator_impl { - public: - using string_type = std::conditional_t; - - friend codepoint_iterator_impl; - - using string_view_type = - std::basic_string_view; - - using lookup_table_type = - lookup_table_view; - - using const_lookup_table_type = - const_lookup_table_view; - - public: - /// \section The common types come from the underlying string container - typedef std::random_access_iterator_tag iterator_category; - - /// \brief The iterator type dereferences to the wide from the string - typedef typename string_type::wide_value_type value_type; - - /// \brief The difference types is the same as the string uses for its indexes - typedef typename string_type::difference_type difference_type; - - /// \brief Its address is the address of the char in the string - /// It might be also a wide type if this is a wstring - typedef typename string_type::pointer pointer; - - /// \brief Our reference type is the proxy object that represents a reference to the char as wide char - typedef codepoint_reference_impl reference; - - /// \brief Our reference type to code units - typedef std::conditional_t - codeunit_reference; - - /// \brief The size type comes from the string - typedef typename string_type::size_type size_type; - - public: - /// \brief Construct default iterator - constexpr codepoint_iterator_impl() noexcept : container_(nullptr), codepoint_index_(0), byte_index_(0) {} - - /// \brief Constructor - /// An iterator, like the reference, needs to have access to the string (with its lookup table), - /// and its byte/codepoint indexes, which provide hints to allow random access in the string. - constexpr codepoint_iterator_impl(string_type *container, size_type codepoint_index, - size_type byte_index_hint) noexcept - : container_(container), codepoint_index_(codepoint_index), byte_index_(byte_index_hint) {} - - /// \brief Copy constructor - /// Const iterators can be created from mutable iterators but not the other way around - template = 0> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr codepoint_iterator_impl(const codepoint_iterator_impl &rhs) noexcept - : container_(rhs.container_), codepoint_index_(rhs.codepoint_index_), byte_index_(rhs.byte_index_) {} - - /// \brief Default constructors - constexpr codepoint_iterator_impl(const codepoint_iterator_impl &) noexcept = default; - constexpr codepoint_iterator_impl &operator=(const codepoint_iterator_impl &) noexcept = default; - - public: - /// \brief Getter for the iterator index - [[nodiscard]] constexpr size_type index() const noexcept { return codepoint_index_; } - - /// \brief Get the index of the codepoint the iterator points to - [[nodiscard]] constexpr size_type byte_index() const noexcept { return byte_index_; } - - /// \brief Get the wide char for the codepoint at this position - [[nodiscard]] constexpr value_type wide_value() const noexcept { - // Create a reference and dereference it - return static_cast(this->operator*()); - } - - /// \brief Get the char value that the iterator points to - [[nodiscard]] constexpr typename string_type::value_type byte_value() const noexcept { - // Dereference the byte value in the string - return container_->operator[](byte_index_); - } - - /// \brief Get the wide char for the codepoint at this position - [[nodiscard]] constexpr reference wide_reference() const noexcept { - return reference(container_, codepoint_index_, byte_index_); - } - - /// \brief Get the char value that the iterator points to - [[nodiscard]] constexpr codeunit_reference byte_reference() const noexcept { - return container_->operator[](byte_index_); - } - - public: - /// \section Common iterator functions - - /// \brief Prefix ++iter - codepoint_iterator_impl &operator++() noexcept { - this->increment(); - return *this; - } - - /// \brief Postfix iter++ - codepoint_iterator_impl operator++(int) noexcept { - codepoint_iterator_impl tmp{*this}; - this->increment(); - return tmp; - } - - /// \brief Prefix --iter - /// Decrease the codepoint_iterator by one with - codepoint_iterator_impl &operator--() noexcept { - this->decrement(); - return *this; - } - - /// \brief Postfix iter-- - /// Decrease the codepoint_iterator by one with - codepoint_iterator_impl operator--(int) noexcept { - codepoint_iterator_impl tmp{*this}; - this->decrement(); - return tmp; - } - - /// \brief Advance the by n positions in place - codepoint_iterator_impl &operator+=(typename codepoint_iterator_impl::difference_type n) noexcept { - this->advance(n); - return *this; - } - - /// \brief Decrease the Iterator n times in place - codepoint_iterator_impl &operator-=(typename codepoint_iterator_impl::difference_type n) noexcept { - this->advance(-n); - return *this; - } - - /// \brief Returns the value of the codepoint behind the codepoint_iterator - reference operator*() const noexcept { return this->wide_reference(); } - - public: - /// \section Relational operators declared inline - /// These operators consider the codepoint indexes although the byte indexes would have the same results - - friend constexpr bool operator==(const codepoint_iterator_impl &a, - const codepoint_iterator_impl &b) noexcept { - return a.codepoint_index_ == b.codepoint_index_; - } - - friend constexpr bool operator!=(const codepoint_iterator_impl &a, - const codepoint_iterator_impl &b) noexcept { - return a.codepoint_index_ != b.codepoint_index_; - } - - friend constexpr bool operator<(const codepoint_iterator_impl &a, - const codepoint_iterator_impl &b) noexcept { - return a.codepoint_index_ < b.codepoint_index_; - } - - friend constexpr bool operator<=(const codepoint_iterator_impl &a, - const codepoint_iterator_impl &b) noexcept { - return a.codepoint_index_ <= b.codepoint_index_; - } - - friend constexpr bool operator>(const codepoint_iterator_impl &a, - const codepoint_iterator_impl &b) noexcept { - return a.codepoint_index_ > b.codepoint_index_; - } - - friend constexpr bool operator>=(const codepoint_iterator_impl &a, - const codepoint_iterator_impl &b) noexcept { - return a.codepoint_index_ >= b.codepoint_index_; - } - - /// \section Relational operators with size_type and symmetry for convenience - - friend constexpr bool operator==(const codepoint_iterator_impl &a, size_type b) noexcept { - return a.codepoint_index_ == b; - } - - friend constexpr bool operator==(size_type a, const codepoint_iterator_impl &b) noexcept { - return a == b.codepoint_index_; - } - - friend constexpr bool operator!=(const codepoint_iterator_impl &a, size_type b) noexcept { - return a.codepoint_index_ != b; - } - - friend constexpr bool operator!=(size_type a, const codepoint_iterator_impl &b) noexcept { - return a != b.codepoint_index_; - } - - friend constexpr bool operator<(const codepoint_iterator_impl &a, size_type b) noexcept { - return a.codepoint_index_ < b; - } - - friend constexpr bool operator<(size_type a, const codepoint_iterator_impl &b) noexcept { - return a < b.codepoint_index_; - } - - friend constexpr bool operator<=(const codepoint_iterator_impl &a, size_type b) noexcept { - return a.codepoint_index_ <= b; - } - - friend constexpr bool operator<=(size_type a, const codepoint_iterator_impl &b) noexcept { - return a <= b.codepoint_index_; - } - - friend constexpr bool operator>(const codepoint_iterator_impl &a, size_type b) noexcept { - return a.codepoint_index_ > b; - } - - friend constexpr bool operator>(size_type a, const codepoint_iterator_impl &b) noexcept { - return a > b.codepoint_index_; - } - - friend constexpr bool operator>=(const codepoint_iterator_impl &a, size_type b) noexcept { - return a.codepoint_index_ >= b; - } - - friend constexpr bool operator>=(size_type a, const codepoint_iterator_impl &b) noexcept { - return a >= b.codepoint_index_; - } - - public: - /// \section Arithmetic operations declared inline - - friend constexpr codepoint_iterator_impl operator+(codepoint_iterator_impl a, - const codepoint_iterator_impl &b) noexcept { - a -= b.codepoint_index_; - return a; - } - - friend constexpr codepoint_iterator_impl operator+(codepoint_iterator_impl a, size_type b) noexcept { - a += b; - return a; - } - - /// \section Arithmetic operations with size_type and symmetry for convenience - friend constexpr codepoint_iterator_impl operator-(codepoint_iterator_impl a, size_type b) noexcept { - a -= b; - return a; - } - - friend constexpr difference_type operator-(const codepoint_iterator_impl &a, - const codepoint_iterator_impl &b) noexcept { - return a.codepoint_index_ - b.codepoint_index_; - } - - protected: - /// \section Members - - /// \brief Reference to the container to allow random access - string_type *container_ = nullptr; - - /// \brief Codepoint counter - size_type codepoint_index_; - - /// \brief Codepoint byte, as a hint for random access - size_type byte_index_; - - protected: - /// \section Moving iterators - /// This is where the complex operations come in because we need to check the lookup table - /// correctly to update the byte_index hint in constant time. + namespace detail { + /// \brief An iterator for accessing codepoints in a string + /// + /// The basic functions for the codepoint iterator and const codepoint iterator. /// + /// Although we could implement a _bidirectional_ codepoint iterator with + /// no reference to the underlying container, this class needs this reference + /// so that we can use the look up table to find elements more efficiently + /// and make _random access_ codepoint iterators possible. + /// + /// Unlike other utf8 iterators with O(m) random access, the lookup table + /// allows us to find these elements in constant time through codepoint + /// index hints spread through the lookup table. A detailed description + /// is in the lookup table container header file. + /// + template struct codepoint_iterator_impl { + public: + using string_type = std::conditional_t; + + friend codepoint_iterator_impl; + + using string_view_type = + std::basic_string_view; + + using lookup_table_type = + lookup_table_view; + + using const_lookup_table_type = + const_lookup_table_view; + + public: + /// \section The common types come from the underlying string container + typedef std::random_access_iterator_tag iterator_category; + + /// \brief The iterator type dereferences to the wide from the string + typedef typename string_type::wide_value_type value_type; + + /// \brief The difference types is the same as the string uses for its indexes + typedef typename string_type::difference_type difference_type; + + /// \brief Its address is the address of the char in the string + /// It might be also a wide type if this is a wstring + typedef typename string_type::pointer pointer; + + /// \brief Our reference type is the proxy object that represents a reference to the char as wide char + typedef codepoint_reference_impl reference; + + /// \brief Our reference type to code units + typedef std::conditional_t + codeunit_reference; + + /// \brief The size type comes from the string + typedef typename string_type::size_type size_type; + + public: + /// \brief Construct default iterator + constexpr codepoint_iterator_impl() noexcept + : container_(nullptr), codepoint_index_(0), byte_index_(0) {} + + /// \brief Constructor + /// An iterator, like the reference, needs to have access to the string (with its lookup table), + /// and its byte/codepoint indexes, which provide hints to allow random access in the string. + constexpr codepoint_iterator_impl(string_type *container, size_type codepoint_index, + size_type byte_index_hint) noexcept + : container_(container), codepoint_index_(codepoint_index), byte_index_(byte_index_hint) {} + + /// \brief Copy constructor + /// Const iterators can be created from mutable iterators but not the other way around + template = 0> + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr codepoint_iterator_impl(const codepoint_iterator_impl &rhs) noexcept + : container_(rhs.container_), codepoint_index_(rhs.codepoint_index_), byte_index_(rhs.byte_index_) { + } - /// \brief Move the iterator one codepoint ahead - /// Incrementing is the easiest operation, as it doesn't depend on the lookup table for constant time - void increment() { - constexpr bool string_is_utf8 = sizeof(typename string_type::value_type) == 1; - if constexpr (string_is_utf8) { - if (container_->empty()) { - throw_exception("codepoint_iterator: cannot increment on an empty string"); - return; - } - if (byte_index_ == container_->size()) { - throw_exception("codepoint_iterator: cannot increment the end() iterator"); - return; - } - const codeunit_reference &first_code_unit = byte_reference(); - const size_type bytes_left = container_->size() - byte_index_; - const uint8_t codepoint_size = utf8_size(first_code_unit, bytes_left); - byte_index_ += codepoint_size; - } else { - ++byte_index_; - } - ++codepoint_index_; - } - - /// \brief Move the iterator one codepoint backwards - /// Incrementing and decrementing are easier operations, as they don't depend - /// on the lookup table for constant time - void decrement() { - // We have 4 candidates for the previous bytecode, depending on the size of the - // previous codepoint - constexpr bool string_is_utf8 = sizeof(typename string_type::value_type) == 1; - if constexpr (string_is_utf8) { - if (container_->empty()) { - throw_exception( - "codepoint_iterator::decrement: cannot decrement on an empty string"); - return; + /// \brief Default constructors + constexpr codepoint_iterator_impl(const codepoint_iterator_impl &) noexcept = default; + constexpr codepoint_iterator_impl &operator=(const codepoint_iterator_impl &) noexcept = default; + + public: + /// \brief Getter for the iterator index + [[nodiscard]] constexpr size_type index() const noexcept { return codepoint_index_; } + + /// \brief Get the index of the codepoint the iterator points to + [[nodiscard]] constexpr size_type byte_index() const noexcept { return byte_index_; } + + /// \brief Get the wide char for the codepoint at this position + [[nodiscard]] constexpr value_type wide_value() const noexcept { + // Create a reference and dereference it + return static_cast(this->operator*()); + } + + /// \brief Get the char value that the iterator points to + [[nodiscard]] constexpr typename string_type::value_type byte_value() const noexcept { + // Dereference the byte value in the string + return container_->operator[](byte_index_); + } + + /// \brief Get the wide char for the codepoint at this position + [[nodiscard]] constexpr reference wide_reference() const noexcept { + return reference(container_, codepoint_index_, byte_index_); + } + + /// \brief Get the char value that the iterator points to + [[nodiscard]] constexpr codeunit_reference byte_reference() const noexcept { + return container_->operator[](byte_index_); + } + + public: + /// \section Common iterator functions + + /// \brief Prefix ++iter + codepoint_iterator_impl &operator++() noexcept { + this->increment(); + return *this; + } + + /// \brief Postfix iter++ + codepoint_iterator_impl operator++(int) noexcept { + codepoint_iterator_impl tmp{*this}; + this->increment(); + return tmp; + } + + /// \brief Prefix --iter + /// Decrease the codepoint_iterator by one with + codepoint_iterator_impl &operator--() noexcept { + this->decrement(); + return *this; + } + + /// \brief Postfix iter-- + /// Decrease the codepoint_iterator by one with + codepoint_iterator_impl operator--(int) noexcept { + codepoint_iterator_impl tmp{*this}; + this->decrement(); + return tmp; + } + + /// \brief Advance the by n positions in place + codepoint_iterator_impl &operator+=(typename codepoint_iterator_impl::difference_type n) noexcept { + this->advance(n); + return *this; + } + + /// \brief Decrease the Iterator n times in place + codepoint_iterator_impl &operator-=(typename codepoint_iterator_impl::difference_type n) noexcept { + this->advance(-n); + return *this; + } + + /// \brief Returns the value of the codepoint behind the codepoint_iterator + reference operator*() const noexcept { return this->wide_reference(); } + + public: + /// \section Relational operators declared inline + /// These operators consider the codepoint indexes although the byte indexes would have the same results + + friend constexpr bool operator==(const codepoint_iterator_impl &a, + const codepoint_iterator_impl &b) noexcept { + return a.codepoint_index_ == b.codepoint_index_; + } + + friend constexpr bool operator!=(const codepoint_iterator_impl &a, + const codepoint_iterator_impl &b) noexcept { + return a.codepoint_index_ != b.codepoint_index_; + } + + friend constexpr bool operator<(const codepoint_iterator_impl &a, + const codepoint_iterator_impl &b) noexcept { + return a.codepoint_index_ < b.codepoint_index_; + } + + friend constexpr bool operator<=(const codepoint_iterator_impl &a, + const codepoint_iterator_impl &b) noexcept { + return a.codepoint_index_ <= b.codepoint_index_; + } + + friend constexpr bool operator>(const codepoint_iterator_impl &a, + const codepoint_iterator_impl &b) noexcept { + return a.codepoint_index_ > b.codepoint_index_; + } + + friend constexpr bool operator>=(const codepoint_iterator_impl &a, + const codepoint_iterator_impl &b) noexcept { + return a.codepoint_index_ >= b.codepoint_index_; + } + + /// \section Relational operators with size_type and symmetry for convenience + + friend constexpr bool operator==(const codepoint_iterator_impl &a, size_type b) noexcept { + return a.codepoint_index_ == b; + } + + friend constexpr bool operator==(size_type a, const codepoint_iterator_impl &b) noexcept { + return a == b.codepoint_index_; + } + + friend constexpr bool operator!=(const codepoint_iterator_impl &a, size_type b) noexcept { + return a.codepoint_index_ != b; + } + + friend constexpr bool operator!=(size_type a, const codepoint_iterator_impl &b) noexcept { + return a != b.codepoint_index_; + } + + friend constexpr bool operator<(const codepoint_iterator_impl &a, size_type b) noexcept { + return a.codepoint_index_ < b; + } + + friend constexpr bool operator<(size_type a, const codepoint_iterator_impl &b) noexcept { + return a < b.codepoint_index_; + } + + friend constexpr bool operator<=(const codepoint_iterator_impl &a, size_type b) noexcept { + return a.codepoint_index_ <= b; + } + + friend constexpr bool operator<=(size_type a, const codepoint_iterator_impl &b) noexcept { + return a <= b.codepoint_index_; + } + + friend constexpr bool operator>(const codepoint_iterator_impl &a, size_type b) noexcept { + return a.codepoint_index_ > b; + } + + friend constexpr bool operator>(size_type a, const codepoint_iterator_impl &b) noexcept { + return a > b.codepoint_index_; + } + + friend constexpr bool operator>=(const codepoint_iterator_impl &a, size_type b) noexcept { + return a.codepoint_index_ >= b; + } + + friend constexpr bool operator>=(size_type a, const codepoint_iterator_impl &b) noexcept { + return a >= b.codepoint_index_; + } + + public: + /// \section Arithmetic operations declared inline + + friend constexpr codepoint_iterator_impl operator+(codepoint_iterator_impl a, + const codepoint_iterator_impl &b) noexcept { + a -= b.codepoint_index_; + return a; + } + + friend constexpr codepoint_iterator_impl operator+(codepoint_iterator_impl a, size_type b) noexcept { + a += b; + return a; + } + + /// \section Arithmetic operations with size_type and symmetry for convenience + friend constexpr codepoint_iterator_impl operator-(codepoint_iterator_impl a, size_type b) noexcept { + a -= b; + return a; + } + + friend constexpr difference_type operator-(const codepoint_iterator_impl &a, + const codepoint_iterator_impl &b) noexcept { + return a.codepoint_index_ - b.codepoint_index_; + } + + protected: + /// \section Members + + /// \brief Reference to the container to allow random access + string_type *container_ = nullptr; + + /// \brief Codepoint counter + size_type codepoint_index_; + + /// \brief Codepoint byte, as a hint for random access + size_type byte_index_; + + protected: + /// \section Moving iterators + /// This is where the complex operations come in because we need to check the lookup table + /// correctly to update the byte_index hint in constant time. + /// + + /// \brief Move the iterator one codepoint ahead + /// Incrementing is the easiest operation, as it doesn't depend on the lookup table for constant time + void increment() { + constexpr bool string_is_utf8 = sizeof(typename string_type::value_type) == 1; + if constexpr (string_is_utf8) { + if (container_->empty()) { + throw_exception( + "codepoint_iterator: cannot increment on an empty string"); + return; + } + if (byte_index_ == container_->size()) { + throw_exception( + "codepoint_iterator: cannot increment the end() iterator"); + return; + } + const codeunit_reference &first_code_unit = byte_reference(); + const size_type bytes_left = container_->size() - byte_index_; + const uint8_t codepoint_size = utf8_size(first_code_unit, bytes_left); + byte_index_ += codepoint_size; + } else { + ++byte_index_; } - if (byte_index_ == 0) { - throw_exception( - "codepoint_iterator::decrement: cannot decrement the begin() iterator"); - return; + ++codepoint_index_; + } + + /// \brief Move the iterator one codepoint backwards + /// Incrementing and decrementing are easier operations, as they don't depend + /// on the lookup table for constant time + void decrement() { + // We have 4 candidates for the previous bytecode, depending on the size of the + // previous codepoint + constexpr bool string_is_utf8 = sizeof(typename string_type::value_type) == 1; + if constexpr (string_is_utf8) { + if (container_->empty()) { + throw_exception( + "codepoint_iterator::decrement: cannot decrement on an empty string"); + return; + } + if (byte_index_ == 0) { + throw_exception( + "codepoint_iterator::decrement: cannot decrement the begin() iterator"); + return; + } + + // Check which previous byte is the multibyte first char + size_type code_units_before = 1; + typename string_type::value_type current_byte = + container_->operator[](byte_index_ - code_units_before); + while (is_utf8_continuation(current_byte) && code_units_before < byte_index_) { + ++code_units_before; + current_byte = container_->operator[](byte_index_ - code_units_before); + } + if (code_units_before > byte_index_) { + throw_exception( + "codepoint_iterator::decrement: only continuation bytes were found"); + return; + } + byte_index_ -= code_units_before; + } else { + --byte_index_; } + --codepoint_index_; + } - // Check which previous byte is the multibyte first char - size_type code_units_before = 1; - typename string_type::value_type current_byte = - container_->operator[](byte_index_ - code_units_before); - while (is_utf8_continuation(current_byte) && code_units_before < byte_index_) { - ++code_units_before; - current_byte = container_->operator[](byte_index_ - code_units_before); + /// \brief Advance the iterator n times + void advance(difference_type n) noexcept { + // Handle the trivial cases + if (n == 0) { + return; } - if (code_units_before > byte_index_) { - throw_exception( - "codepoint_iterator::decrement: only continuation bytes were found"); + if (n == 1) { + increment(); return; } - byte_index_ -= code_units_before; - } else { - --byte_index_; - } - --codepoint_index_; - } - - /// \brief Advance the iterator n times - void advance(difference_type n) noexcept { - // Handle the trivial cases - if (n == 0) { - return; - } - if (n == 1) { - increment(); - return; - } - if (n == -1) { - decrement(); - return; - } - // Advance the current codepoint index. This is what really requires the lookup table. - constexpr bool string_is_utf8 = sizeof(typename string_type::value_type) == 1; - if constexpr (string_is_utf8) { - // Trivial case, empty string - if (container_->empty()) { - // Impossible to advance - throw_exception( - "codepoint_iterator::advance: cannot advance on an empty container"); + if (n == -1) { + decrement(); return; } + // Advance the current codepoint index. This is what really requires the lookup table. + constexpr bool string_is_utf8 = sizeof(typename string_type::value_type) == 1; + if constexpr (string_is_utf8) { + // Trivial case, empty string + if (container_->empty()) { + // Impossible to advance + throw_exception( + "codepoint_iterator::advance: cannot advance on an empty container"); + return; + } - // Our final destination - const size_type new_codepoint_index = codepoint_index_ + n; - assert(new_codepoint_index <= container_->size_codepoints()); + // Our final destination + const size_type new_codepoint_index = codepoint_index_ + n; + assert(new_codepoint_index <= container_->size_codepoints()); - // Create a lookup table view for this string - // note: don't include container_->size()+1 in the sv! - // - the lookup table depends on sv.size() matching string.size() - typename string_type::const_pointer first_ptr = container_->data(); - string_view_type sv(first_ptr, container_->size()); + // Create a lookup table view for this string + // note: don't include container_->size()+1 in the sv! + // - the lookup table depends on sv.size() matching string.size() + typename string_type::const_pointer first_ptr = container_->data(); + string_view_type sv(first_ptr, container_->size()); - const size_type full_size = container_->buffer_capacity(); - const size_type main_str_size = container_->size() + 1; - const size_type lookup_table_capacity = full_size - main_str_size; - const_lookup_table_type table(container_->data() + main_str_size, lookup_table_capacity, sv); + const size_type full_size = container_->buffer_capacity(); + const size_type main_str_size = container_->size() + 1; + const size_type lookup_table_capacity = full_size - main_str_size; + const_lookup_table_type table(container_->data() + main_str_size, lookup_table_capacity, sv); - // Trivial case, no multibyte codepoints - if (table.empty()) { - byte_index_ += n; - } else { - // Increment or decrement the byte index with the lookup table - // using lookup_iterator = typename const_lookup_table_type::iterator; - auto [it, codepoint_idx] = table.lower_bound_codepoint(new_codepoint_index); - if (new_codepoint_index == codepoint_idx) { - // The destination codepoint is a multibyte codepoint whose codepoint index - // is already what we looking for - byte_index_ = it.byte_index(); - } else if (it == table.begin()) { - // The first multibyte codepoint comes after what we are looking for - // This means we are in that initial region where the codepoints match the bytes - byte_index_ = new_codepoint_index; + // Trivial case, no multibyte codepoints + if (table.empty()) { + byte_index_ += n; } else { - // We found the closest multibyte codepoint, but this was not what we - // are looking for yet. Because of how lower bound functions work, this - // codepoint_idx we found must be greater than what we are looking for. - // So our target codepoint must be between the multibyte codepoint we found - // and the multibyte codepoint before. - - // Get the codepoint of the multibyte before without using its expensive - // codepoint_index() function. - const size_type multibyte_bytes_idx = - it != table.end() ? it.byte_index() : container_->size(); - const size_type multibyte_codepoint_idx = - it != table.end() ? codepoint_idx : container_->size_codepoints(); - - // Find the multibyte codepoint and byte indexes before that - auto multibyte_before = std::prev(it); - const size_type multibyte_before_bytes_idx = multibyte_before.byte_index(); - const size_type byte_distance = multibyte_bytes_idx - multibyte_before_bytes_idx; - const uint8_t multibyte_before_utf8_size = multibyte_before.utf8_size(); - const size_type codepoint_distance = byte_distance - multibyte_before_utf8_size + 1; - const size_type multibyte_before_codepoint_idx = - multibyte_codepoint_idx - codepoint_distance; - - // Find the codepoint and byte index of the next codepoint now - const size_type next_unibyte_byte_idx = - multibyte_before_bytes_idx + multibyte_before_utf8_size; - const size_type next_unibyte_codepoint_idx = multibyte_before_codepoint_idx + 1; - - // The range between next_unibyte and the unibyte we are searching is now composed of - // only unibyte codepoints so their distance is finally trivial - const size_type unibyte_codepoint_distance = - new_codepoint_index - next_unibyte_codepoint_idx; - byte_index_ = next_unibyte_byte_idx + unibyte_codepoint_distance; + // Increment or decrement the byte index with the lookup table + // using lookup_iterator = typename const_lookup_table_type::iterator; + auto [it, codepoint_idx] = table.lower_bound_codepoint(new_codepoint_index); + if (new_codepoint_index == codepoint_idx) { + // The destination codepoint is a multibyte codepoint whose codepoint index + // is already what we looking for + byte_index_ = it.byte_index(); + } else if (it == table.begin()) { + // The first multibyte codepoint comes after what we are looking for + // This means we are in that initial region where the codepoints match the bytes + byte_index_ = new_codepoint_index; + } else { + // We found the closest multibyte codepoint, but this was not what we + // are looking for yet. Because of how lower bound functions work, this + // codepoint_idx we found must be greater than what we are looking for. + // So our target codepoint must be between the multibyte codepoint we found + // and the multibyte codepoint before. + + // Get the codepoint of the multibyte before without using its expensive + // codepoint_index() function. + const size_type multibyte_bytes_idx = + it != table.end() ? it.byte_index() : container_->size(); + const size_type multibyte_codepoint_idx = + it != table.end() ? codepoint_idx : container_->size_codepoints(); + + // Find the multibyte codepoint and byte indexes before that + auto multibyte_before = std::prev(it); + const size_type multibyte_before_bytes_idx = multibyte_before.byte_index(); + const size_type byte_distance = multibyte_bytes_idx - multibyte_before_bytes_idx; + const uint8_t multibyte_before_utf8_size = multibyte_before.utf8_size(); + const size_type codepoint_distance = byte_distance - multibyte_before_utf8_size + 1; + const size_type multibyte_before_codepoint_idx = + multibyte_codepoint_idx - codepoint_distance; + + // Find the codepoint and byte index of the next codepoint now + const size_type next_unibyte_byte_idx = + multibyte_before_bytes_idx + multibyte_before_utf8_size; + const size_type next_unibyte_codepoint_idx = multibyte_before_codepoint_idx + 1; + + // The range between next_unibyte and the unibyte we are searching is now composed of + // only unibyte codepoints so their distance is finally trivial + const size_type unibyte_codepoint_distance = + new_codepoint_index - next_unibyte_codepoint_idx; + byte_index_ = next_unibyte_byte_idx + unibyte_codepoint_distance; + } } + codepoint_index_ = new_codepoint_index; + } else { + byte_index_ += n; + codepoint_index_ += n; } - codepoint_index_ = new_codepoint_index; - } else { - byte_index_ += n; - codepoint_index_ += n; } - } - }; - } // namespace detail + }; + } // namespace detail - template using external_codepoint_iterator = detail::codepoint_iterator_impl; - template using const_external_codepoint_iterator = detail::codepoint_iterator_impl; - template - using reverse_external_codepoint_iterator = std::reverse_iterator>; - template - using const_reverse_external_codepoint_iterator = std::reverse_iterator>; + template using external_codepoint_iterator = detail::codepoint_iterator_impl; + template using const_external_codepoint_iterator = detail::codepoint_iterator_impl; + template + using reverse_external_codepoint_iterator = std::reverse_iterator>; + template + using const_reverse_external_codepoint_iterator = + std::reverse_iterator>; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ITERATOR_CODEPOINT_ITERATOR_H diff --git a/source/small/detail/iterator/const_key_iterator.h b/source/small/detail/iterator/const_key_iterator.h index 24f1dd9..b0c5fa7 100644 --- a/source/small/detail/iterator/const_key_iterator.h +++ b/source/small/detail/iterator/const_key_iterator.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ITERATOR_CONST_KEY_ITERATOR_H #define SMALL_DETAIL_ITERATOR_CONST_KEY_ITERATOR_H @@ -17,242 +16,255 @@ #include "../traits/is_pair.h" namespace small { - /// \brief Iterator wrapper that makes the key of the underlying pair constant - template class const_key_iterator { - public: - // Base iterator - typedef ITERATOR base_iterator_type; - typedef typename std::iterator_traits::value_type base_value_type; - - static_assert((is_pair_v), "const_key_iterator: base_value_type must be std::pair"); - - // Wrapped types - typedef typename std::iterator_traits::iterator_category iterator_category; - typedef typename add_key_const::type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::add_pointer_t pointer; - typedef typename std::add_lvalue_reference_t reference; - - public /* constructors */: - /// \brief Construct empty iterator wrapper - constexpr const_key_iterator() noexcept : base_(nullptr) {} - - /// \brief Construct iterator wrapper from pointer x - constexpr explicit const_key_iterator(base_iterator_type x) noexcept : base_(x) {} - - /// \brief Construct const iterator wrapper from another wrapper u, which might be another type - template - constexpr const_key_iterator( // NOLINT(google-explicit-constructor): expected for iterators - const const_key_iterator &u, - typename std::enable_if_t> * = 0) noexcept - : base_(u.base()) {} - - public /* element access */: - /// \brief Dereference iterator - constexpr reference operator*() const noexcept { return *(operator->()); } - - /// \brief Dereference iterator and get member - constexpr pointer operator->() const noexcept { - const auto base_pointer = std::addressof(*base_); - auto mutable_base_pointer = - const_cast>>(base_pointer); - return reinterpret_cast(mutable_base_pointer); + namespace detail { + /// \brief Iterator wrapper that makes the key of the underlying pair constant + template class const_key_iterator { + public: + // Base iterator + typedef ITERATOR base_iterator_type; + typedef typename std::iterator_traits::value_type base_value_type; + + static_assert((is_pair_v), "const_key_iterator: base_value_type must be std::pair"); + + // Wrapped types + typedef typename std::iterator_traits::iterator_category iterator_category; + typedef typename add_key_const::type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::add_pointer_t pointer; + typedef typename std::add_lvalue_reference_t reference; + + public /* constructors */: + /// \brief Construct empty iterator wrapper + constexpr const_key_iterator() noexcept : base_(nullptr) {} + + /// \brief Construct iterator wrapper from pointer x + constexpr explicit const_key_iterator(base_iterator_type x) noexcept : base_(x) {} + + /// \brief Construct const iterator wrapper from another wrapper u, which might be another type + template + constexpr const_key_iterator( // NOLINT(google-explicit-constructor): expected for iterators + const const_key_iterator &u, + typename std::enable_if_t> * = 0) noexcept + : base_(u.base()) {} + + public /* element access */: + /// \brief Dereference iterator + constexpr reference operator*() const noexcept { return *(operator->()); } + + /// \brief Dereference iterator and get member + constexpr pointer operator->() const noexcept { + const auto base_pointer = std::addressof(*base_); + auto mutable_base_pointer = + const_cast>>(base_pointer); + return reinterpret_cast(mutable_base_pointer); + } + + /// \brief Dereference iterator n positions ahead + constexpr reference operator[](difference_type n) const noexcept { + return reinterpret_cast(base_[n]); + } + + /// \brief Get base pointer + constexpr base_iterator_type base() const noexcept { return base_; } + + public /* modifiers */: + /// \brief Advance iterator + constexpr const_key_iterator &operator++() noexcept { + ++base_; + return *this; + } + + /// \brief Advance iterator (postfix) + constexpr const_key_iterator operator++(int) noexcept { // NOLINT(cert-dcl21-cpp) + const_key_iterator tmp(*this); + ++(*this); + return tmp; + } + + /// \brief Rewind iterator + constexpr const_key_iterator &operator--() noexcept { + --base_; + return *this; + } + + /// \brief Rewind iterator (postfix) + constexpr const_key_iterator operator--(int) noexcept { // NOLINT(cert-dcl21-cpp) + const_key_iterator tmp(*this); + --(*this); + return tmp; + } + + /// \brief Return copy of iterator advanced by n positions + constexpr const_key_iterator operator+(difference_type n) const noexcept { + const_key_iterator w(*this); + w += n; + return w; + } + + /// \brief Advance iterator by n positions + constexpr const_key_iterator &operator+=(difference_type n) noexcept { + base_ += n; + return *this; + } + + /// \brief Return copy of iterator n positions behind + constexpr const_key_iterator operator-(difference_type n) const noexcept { return *this + (-n); } + + /// \brief Rewind iterator by n positions + constexpr const_key_iterator &operator-=(difference_type n) noexcept { + *this += -n; + return *this; + } + + public /* relational operators */: + /// Make any other iterator wrapper a friend + template friend class const_key_iterator; + + public /* friends */: + /// \brief Get distance between iterators + template + constexpr friend auto operator-(const const_key_iterator &x, + const const_key_iterator &y) noexcept + -> decltype(x.base() - y.base()); + + /// \brief Sum iterators + template + constexpr friend const_key_iterator operator+(typename const_key_iterator::difference_type, + const_key_iterator) noexcept; + + private: + /// Base pointer + base_iterator_type base_; + }; + + template + inline constexpr bool operator==(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return x.base() == y.base(); + } + + template + inline constexpr bool operator!=(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return !(x == y); + } + + template + inline constexpr bool operator<(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return x.base() < y.base(); + } + + template + inline constexpr bool operator>(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return y < x; + } + + template + inline constexpr bool operator>=(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return !(x < y); + } + + template + inline constexpr bool operator<=(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return !(y < x); + } + + template + inline constexpr bool operator==(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return x.base() == y.base(); + } + + template + inline constexpr bool operator!=(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return !(x == y); + } + + template + inline constexpr bool operator>(const const_key_iterator &x, const const_key_iterator &y) noexcept { + return y < x; } - /// \brief Dereference iterator n positions ahead - constexpr reference operator[](difference_type n) const noexcept { - return reinterpret_cast(base_[n]); + template + inline constexpr bool operator>=(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return !(x < y); } - /// \brief Get base pointer - constexpr base_iterator_type base() const noexcept { return base_; } + template + inline constexpr bool operator<=(const const_key_iterator &x, + const const_key_iterator &y) noexcept { + return !(y < x); + } + + template + inline constexpr bool operator==(const const_key_iterator &x, const Pointer &y) noexcept { + return x.base() == y; + } - public /* modifiers */: - /// \brief Advance iterator - constexpr const_key_iterator &operator++() noexcept { - ++base_; - return *this; + template + inline constexpr bool operator!=(const const_key_iterator &x, const Pointer &y) noexcept { + return !(x == y); } - /// \brief Advance iterator (postfix) - constexpr const_key_iterator operator++(int) noexcept { // NOLINT(cert-dcl21-cpp) - const_key_iterator tmp(*this); - ++(*this); - return tmp; + template + inline constexpr bool operator>(const const_key_iterator &x, const Pointer &y) noexcept { + return y < x; } - /// \brief Rewind iterator - constexpr const_key_iterator &operator--() noexcept { - --base_; - return *this; + template + inline constexpr bool operator>=(const const_key_iterator &x, const Pointer &y) noexcept { + return !(x < y); } - /// \brief Rewind iterator (postfix) - constexpr const_key_iterator operator--(int) noexcept { // NOLINT(cert-dcl21-cpp) - const_key_iterator tmp(*this); - --(*this); - return tmp; + template + inline constexpr bool operator<=(const const_key_iterator &x, const Pointer &y) noexcept { + return !(y < x); } - /// \brief Return copy of iterator advanced by n positions - constexpr const_key_iterator operator+(difference_type n) const noexcept { - const_key_iterator w(*this); - w += n; - return w; + template + inline constexpr bool operator==(const Pointer &x, const const_key_iterator &y) noexcept { + return x.base() == y.base(); } - /// \brief Advance iterator by n positions - constexpr const_key_iterator &operator+=(difference_type n) noexcept { - base_ += n; - return *this; + template + inline constexpr bool operator!=(const Pointer &x, const const_key_iterator &y) noexcept { + return !(x == y); } - /// \brief Return copy of iterator n positions behind - constexpr const_key_iterator operator-(difference_type n) const noexcept { return *this + (-n); } + template + inline constexpr bool operator>(const Pointer &x, const const_key_iterator &y) noexcept { + return y < x; + } - /// \brief Rewind iterator by n positions - constexpr const_key_iterator &operator-=(difference_type n) noexcept { - *this += -n; - return *this; + template + inline constexpr bool operator>=(const Pointer &x, const const_key_iterator &y) noexcept { + return !(x < y); } - public /* relational operators */: - /// Make any other iterator wrapper a friend - template friend class const_key_iterator; + template + inline constexpr bool operator<=(const Pointer &x, const const_key_iterator &y) noexcept { + return !(y < x); + } - public /* friends */: - /// \brief Get distance between iterators template - constexpr friend auto operator-(const const_key_iterator &x, const const_key_iterator &y) noexcept - -> decltype(x.base() - y.base()); - - /// \brief Sum iterators - template - constexpr friend const_key_iterator operator+(typename const_key_iterator::difference_type, - const_key_iterator) noexcept; - - private: - /// Base pointer - base_iterator_type base_; - }; - - template - inline constexpr bool operator==(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return x.base() == y.base(); - } - - template - inline constexpr bool operator!=(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator<(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return x.base() < y.base(); - } - - template - inline constexpr bool operator>(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return !(y < x); - } - - template - inline constexpr bool operator==(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return x.base() == y.base(); - } - - template - inline constexpr bool operator!=(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator>(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const const_key_iterator &x, const const_key_iterator &y) noexcept { - return !(y < x); - } - - template - inline constexpr bool operator==(const const_key_iterator &x, const Pointer &y) noexcept { - return x.base() == y; - } - - template - inline constexpr bool operator!=(const const_key_iterator &x, const Pointer &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator>(const const_key_iterator &x, const Pointer &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const const_key_iterator &x, const Pointer &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const const_key_iterator &x, const Pointer &y) noexcept { - return !(y < x); - } - - template - inline constexpr bool operator==(const Pointer &x, const const_key_iterator &y) noexcept { - return x.base() == y.base(); - } - - template - inline constexpr bool operator!=(const Pointer &x, const const_key_iterator &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator>(const Pointer &x, const const_key_iterator &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const Pointer &x, const const_key_iterator &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const Pointer &x, const const_key_iterator &y) noexcept { - return !(y < x); - } - - template - inline constexpr auto operator-(const const_key_iterator &x, const const_key_iterator &y) noexcept - -> decltype(x.base() - y.base()) { - return x.base() - y.base(); - } - - template - inline constexpr const_key_iterator operator+(typename const_key_iterator::difference_type n, - const_key_iterator x) noexcept { - x += n; - return x; - } + inline constexpr auto operator-(const const_key_iterator &x, const const_key_iterator &y) noexcept + -> decltype(x.base() - y.base()) { + return x.base() - y.base(); + } + + template + inline constexpr const_key_iterator operator+(typename const_key_iterator::difference_type n, + const_key_iterator x) noexcept { + x += n; + return x; + } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ITERATOR_CONST_KEY_ITERATOR_H diff --git a/source/small/detail/iterator/iterator_type_traits.h b/source/small/detail/iterator/iterator_type_traits.h index 5b0a864..2211e03 100644 --- a/source/small/detail/iterator/iterator_type_traits.h +++ b/source/small/detail/iterator/iterator_type_traits.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ITERATOR_ITERATOR_TYPE_TRAITS_H #define SMALL_DETAIL_ITERATOR_ITERATOR_TYPE_TRAITS_H @@ -14,106 +13,110 @@ #include "../traits/cpp_version.h" namespace small { - /// Difference type for a custom iterator - /// \note Adapted from https://github.com/danra/shift_proposal/ - template using difference_type_type = typename std::iterator_traits::difference_type; - - /// Category type for a custom iterator - /// \note Adapted from https://github.com/danra/shift_proposal/ - template using iterator_category_type = typename std::iterator_traits::iterator_category; - - /// Whether iterator is in a category Tag (base case = false) - /// \note Adapted from https://github.com/danra/shift_proposal/ - template static constexpr bool is_category_convertible = false; - - /// Whether iterator is in a category Tag (usual case) - /// \note Adapted from https://github.com/danra/shift_proposal/ - template - static constexpr bool - is_category_convertible, Tag>>> = true; - - /// Check if a type has an iterator category - template struct has_iterator_category { - private: - /// An arbitrary type of size == 2 - struct two { - char lx; - char lxx; + namespace detail { + /// Difference type for a custom iterator + /// \note Adapted from https://github.com/danra/shift_proposal/ + template using difference_type_type = typename std::iterator_traits::difference_type; + + /// Category type for a custom iterator + /// \note Adapted from https://github.com/danra/shift_proposal/ + template using iterator_category_type = typename std::iterator_traits::iterator_category; + + /// Whether iterator is in a category Tag (base case = false) + /// \note Adapted from https://github.com/danra/shift_proposal/ + template static constexpr bool is_category_convertible = false; + + /// Whether iterator is in a category Tag (usual case) + /// \note Adapted from https://github.com/danra/shift_proposal/ + template + static constexpr bool + is_category_convertible, Tag>>> = + true; + + /// Check if a type has an iterator category + template struct has_iterator_category { + private: + /// An arbitrary type of size == 2 + struct two { + char lx; + char lxx; + }; + + /// Return type of size == 2 when UP doesn't has iterator category + template static two test(...) { return two{char(), char()}; } + + /// Return type of size == 1 when UP has iterator category + template static char test(typename UP::iterator_category * = 0) { return char(); } + + public: + /// Indicates if I has a category iterator (when return type of test has size == 1) + static const bool value = sizeof(test(0)) == 1; }; - /// Return type of size == 2 when UP doesn't has iterator category - template static two test(...) { return two{char(), char()}; } - - /// Return type of size == 1 when UP has iterator category - template static char test(typename UP::iterator_category * = 0) { return char(); } - - public: - /// Indicates if I has a category iterator (when return type of test has size == 1) - static const bool value = sizeof(test(0)) == 1; - }; - - /// Check if type has an iterator category convertible to UP - template >::value> - struct has_iterator_category_convertible_to - : public std::integral_constant< - bool, std::is_convertible::iterator_category, UP>::value> {}; - - /// Check if type has an iterator category convertible to UP - template struct has_iterator_category_convertible_to : public std::false_type {}; - - /// Check if type is convertible to input_iterator - template - struct is_input_iterator : public has_iterator_category_convertible_to {}; - - /// Type that is only valid if input type is convertible to an input iterator - template - using enable_if_iterator_t = typename std::enable_if_t< - is_input_iterator::value && - std::is_constructible::reference>::value, - I>; - - template constexpr bool is_input_iterator_v = is_input_iterator::value; - - /// Common iterator category primary template. - /// A variant iterator will always have the minimal iterator category requirements for its final type. - /// The implementation should always fall into one of the specializations though. - template struct common_iterator_tag; - - /// Base iterator: 1 Iterator type - template struct common_iterator_tag { using type = Tag1; }; - - /// Base iterator: 2 Iterator types - template struct common_iterator_tag { - template - static constexpr bool both_base_of_v = std::is_base_of_v &&std::is_base_of_v; - - static constexpr bool both_input = both_base_of_v; - static constexpr bool both_forward = both_base_of_v; - static constexpr bool both_bidirectional = both_base_of_v; - static constexpr bool both_random_access = both_base_of_v; - static constexpr bool both_output = both_base_of_v; - - using type = std::conditional_t< - std::is_same_v, Tag1, - std::conditional_t< - both_random_access, std::random_access_iterator_tag, + /// Check if type has an iterator category convertible to UP + template >::value> + struct has_iterator_category_convertible_to + : public std::integral_constant< + bool, std::is_convertible::iterator_category, UP>::value> {}; + + /// Check if type has an iterator category convertible to UP + template + struct has_iterator_category_convertible_to : public std::false_type {}; + + /// Check if type is convertible to input_iterator + template + struct is_input_iterator : public has_iterator_category_convertible_to {}; + + /// Type that is only valid if input type is convertible to an input iterator + template + using enable_if_iterator_t = typename std::enable_if_t< + is_input_iterator::value && + std::is_constructible::reference>::value, + I>; + + template constexpr bool is_input_iterator_v = is_input_iterator::value; + + /// Common iterator category primary template. + /// A variant iterator will always have the minimal iterator category requirements for its final type. + /// The implementation should always fall into one of the specializations though. + template struct common_iterator_tag; + + /// Base iterator: 1 Iterator type + template struct common_iterator_tag { using type = Tag1; }; + + /// Base iterator: 2 Iterator types + template struct common_iterator_tag { + template + static constexpr bool both_base_of_v = std::is_base_of_v &&std::is_base_of_v; + + static constexpr bool both_input = both_base_of_v; + static constexpr bool both_forward = both_base_of_v; + static constexpr bool both_bidirectional = both_base_of_v; + static constexpr bool both_random_access = both_base_of_v; + static constexpr bool both_output = both_base_of_v; + + using type = std::conditional_t< + std::is_same_v, Tag1, std::conditional_t< - both_bidirectional, std::bidirectional_iterator_tag, + both_random_access, std::random_access_iterator_tag, std::conditional_t< - both_forward, std::forward_iterator_tag, - std::conditional_t>>>>>; - }; + both_bidirectional, std::bidirectional_iterator_tag, + std::conditional_t< + both_forward, std::forward_iterator_tag, + std::conditional_t>>>>>; + }; - /// Base iterator: > 2 Iterator types - template struct common_iterator_tag { - using type = typename common_iterator_tag::type, - typename common_iterator_tag::type>::type; - }; + /// Base iterator: > 2 Iterator types + template struct common_iterator_tag { + using type = typename common_iterator_tag::type, + typename common_iterator_tag::type>::type; + }; - /// Base iterator type - template using common_iterator_tag_t = typename common_iterator_tag::type; + /// Base iterator type + template using common_iterator_tag_t = typename common_iterator_tag::type; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ITERATOR_ITERATOR_TYPE_TRAITS_H diff --git a/source/small/detail/iterator/ordered_concat_iterator.h b/source/small/detail/iterator/ordered_concat_iterator.h index 85010e7..695b55a 100644 --- a/source/small/detail/iterator/ordered_concat_iterator.h +++ b/source/small/detail/iterator/ordered_concat_iterator.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ITERATOR_ORDERED_CONCAT_ITERATOR_H #define SMALL_DETAIL_ITERATOR_ORDERED_CONCAT_ITERATOR_H @@ -16,311 +15,313 @@ #include namespace small { - /// \brief Iterator that iterates two ordered containers as one - template class ordered_concat_iterator { - public: - // Base iterator - typedef ITERATOR1 base_iterator_type1; - typedef typename std::iterator_traits::value_type base_value_type1; - typedef ITERATOR2 base_iterator_type2; - typedef typename std::iterator_traits::value_type base_value_type2; - - // Wrapped types - typedef std::bidirectional_iterator_tag iterator_category; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::add_pointer_t pointer; - typedef typename std::add_lvalue_reference_t reference; - - static_assert((std::is_same_v::value_type, - typename std::iterator_traits::value_type>), - "ordered_concat_iterator: iterators should have the same value type"); - - public /* constructors */: - /// \brief Construct empty iterator wrapper - constexpr ordered_concat_iterator() noexcept : base1_(), base2_(), begin1_(), begin2_(), end1_(), end2_() {} - - /// \brief Construct iterator wrapper from pointer x - constexpr explicit ordered_concat_iterator(base_iterator_type1 x1, base_iterator_type2 x2, - base_iterator_type1 begin1, base_iterator_type2 begin2, - base_iterator_type1 end1, base_iterator_type2 end2) noexcept - : base1_(x1), base2_(x2), begin1_(begin1), begin2_(begin2), end1_(end1), end2_(end2) {} - - /// \brief Construct const iterator wrapper from another wrapper u, which might be another type - template - constexpr ordered_concat_iterator( // NOLINT(google-explicit-constructor): expected for iterators - const ordered_concat_iterator &u, - typename std::enable_if_t && - std::is_convertible_v> * = 0) noexcept - : base1_(u.base1()), base2_(u.base2()), begin1_(u.begin1_), begin2_(u.begin2_), end1_(u.end1_), - end2_(u.end2_) {} - - public /* element access */: - /// \brief Dereference iterator - constexpr reference operator*() const noexcept { return *(operator->()); } - - /// \brief Dereference iterator and get member - constexpr pointer operator->() const noexcept { - const bool can_dereference_first = base1_ != end1_; - const bool dereference_first = can_dereference_first && (base2_ == end2_ || *base1_ < *base2_); - if (dereference_first) { - const auto base_pointer = std::addressof(*base1_); - auto mutable_base_pointer = - const_cast>>(base_pointer); - return reinterpret_cast(mutable_base_pointer); - } else { - const auto base_pointer = std::addressof(*base2_); - auto mutable_base_pointer = - const_cast>>(base_pointer); - return reinterpret_cast(mutable_base_pointer); + namespace detail { + /// \brief Iterator that iterates two ordered containers as one + template class ordered_concat_iterator { + public: + // Base iterator + typedef ITERATOR1 base_iterator_type1; + typedef typename std::iterator_traits::value_type base_value_type1; + typedef ITERATOR2 base_iterator_type2; + typedef typename std::iterator_traits::value_type base_value_type2; + + // Wrapped types + typedef std::bidirectional_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::add_pointer_t pointer; + typedef typename std::add_lvalue_reference_t reference; + + static_assert((std::is_same_v::value_type, + typename std::iterator_traits::value_type>), + "ordered_concat_iterator: iterators should have the same value type"); + + public /* constructors */: + /// \brief Construct empty iterator wrapper + constexpr ordered_concat_iterator() noexcept : base1_(), base2_(), begin1_(), begin2_(), end1_(), end2_() {} + + /// \brief Construct iterator wrapper from pointer x + constexpr explicit ordered_concat_iterator(base_iterator_type1 x1, base_iterator_type2 x2, + base_iterator_type1 begin1, base_iterator_type2 begin2, + base_iterator_type1 end1, base_iterator_type2 end2) noexcept + : base1_(x1), base2_(x2), begin1_(begin1), begin2_(begin2), end1_(end1), end2_(end2) {} + + /// \brief Construct const iterator wrapper from another wrapper u, which might be another type + template + constexpr ordered_concat_iterator( // NOLINT(google-explicit-constructor): expected for iterators + const ordered_concat_iterator &u, + typename std::enable_if_t && + std::is_convertible_v> * = 0) noexcept + : base1_(u.base1()), base2_(u.base2()), begin1_(u.begin1_), begin2_(u.begin2_), end1_(u.end1_), + end2_(u.end2_) {} + + public /* element access */: + /// \brief Dereference iterator + constexpr reference operator*() const noexcept { return *(operator->()); } + + /// \brief Dereference iterator and get member + constexpr pointer operator->() const noexcept { + const bool can_dereference_first = base1_ != end1_; + const bool dereference_first = can_dereference_first && (base2_ == end2_ || *base1_ < *base2_); + if (dereference_first) { + const auto base_pointer = std::addressof(*base1_); + auto mutable_base_pointer = + const_cast>>(base_pointer); + return reinterpret_cast(mutable_base_pointer); + } else { + const auto base_pointer = std::addressof(*base2_); + auto mutable_base_pointer = + const_cast>>(base_pointer); + return reinterpret_cast(mutable_base_pointer); + } + } + + /// \brief Dereference iterator n positions ahead + constexpr reference operator[](difference_type n) const noexcept { + auto it = *this; + std::advance(it, n); + return it; + } + + /// \brief Get base pointer + constexpr base_iterator_type1 base1() const noexcept { return base1_; } + constexpr base_iterator_type2 base2() const noexcept { return base2_; } + + public /* modifiers */: + /// \brief Advance iterator + constexpr ordered_concat_iterator &operator++() noexcept { + const bool can_advance_first = base1_ != end1_; + const bool can_advance_second = base2_ != end2_; + const bool should_advance_first = can_advance_first && (!can_advance_second || *base1_ < *base2_); + if (should_advance_first) { + base1_.operator++(); + } else { + base2_.operator++(); + } + return *this; + } + + /// \brief Advance iterator (postfix) + constexpr ordered_concat_iterator operator++(int) noexcept { // NOLINT(cert-dcl21-cpp) + ordered_concat_iterator tmp(*this); + ++(*this); + return tmp; } + + /// \brief Decrement iterator + /// This will undo the post-condition of operator++ + constexpr ordered_concat_iterator &operator--() noexcept { + const bool can_decrement_first = base1_ != begin1_; + const bool can_decrement_second = base2_ != begin2_; + const bool can_dereference_first = base1_ != end1_; + const bool can_dereference_second = base2_ != end2_; + const auto prev_base1 = std::prev(base1_); + const auto prev_base2 = std::prev(base2_); + const bool should_decrement_first = + can_decrement_first && + (!can_decrement_second || (can_dereference_second && *prev_base1 < *base2_) || + (can_dereference_first && !(*base1_ < *prev_base2)) || !(*prev_base1 < *prev_base2)); + // i.e.: if std::prev(base1_) is the iterator to which we applied operator++ last time + if (should_decrement_first) { + // Then we should undo that + base1_.operator--(); + } else { + base2_.operator--(); + } + return *this; + } + + /// \brief Rewind iterator (postfix) + constexpr ordered_concat_iterator operator--(int) noexcept { // NOLINT(cert-dcl21-cpp) + ordered_concat_iterator tmp(*this); + --(*this); + return tmp; + } + + /// \brief Return copy of iterator advanced by n positions + constexpr ordered_concat_iterator operator+(difference_type n) const noexcept { + ordered_concat_iterator w(*this); + w += n; + return w; + } + + /// \brief Advance iterator by n positions + constexpr ordered_concat_iterator &operator+=(difference_type n) noexcept { + auto it = *this; + std::advance(it, n); + return *this; + } + + /// \brief Return copy of iterator n positions behind + constexpr ordered_concat_iterator operator-(difference_type n) const noexcept { return *this + (-n); } + + /// \brief Rewind iterator by n positions + constexpr ordered_concat_iterator &operator-=(difference_type n) noexcept { + *this += -n; + return *this; + } + + public /* relational operators */: + /// Make any other iterator wrapper a friend + template friend class ordered_concat_iterator; + + public /* friends */: + /// \brief Get distance between iterators + template + constexpr friend auto operator-(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept + -> decltype(x.base() - y.base()); + + /// \brief Sum iterators + template + constexpr friend ordered_concat_iterator + operator+(typename ordered_concat_iterator::difference_type, + ordered_concat_iterator) noexcept; + + private: + /// Base pointer + base_iterator_type1 base1_; + base_iterator_type2 base2_; + + /// We need to know where std::begin and std::end are so that we know which iterators + /// we can/should advance + base_iterator_type1 begin1_; + base_iterator_type2 begin2_; + base_iterator_type1 end1_; + base_iterator_type2 end2_; + }; + + template + inline constexpr bool operator==(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return x.base1() == y.base1() && x.base2() == y.base2(); } - /// \brief Dereference iterator n positions ahead - constexpr reference operator[](difference_type n) const noexcept { - auto it = *this; - std::advance(it, n); - return it; + template + inline constexpr bool operator!=(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return !(x == y); } - /// \brief Get base pointer - constexpr base_iterator_type1 base1() const noexcept { return base1_; } - constexpr base_iterator_type2 base2() const noexcept { return base2_; } - - public /* modifiers */: - /// \brief Advance iterator - constexpr ordered_concat_iterator &operator++() noexcept { - const bool can_advance_first = base1_ != end1_; - const bool can_advance_second = base2_ != end2_; - const bool should_advance_first = can_advance_first && (!can_advance_second || *base1_ < *base2_); - if (should_advance_first) { - base1_.operator++(); - } else { - base2_.operator++(); - } - return *this; + template + inline constexpr bool operator<(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return x.base() < y.base(); } - /// \brief Advance iterator (postfix) - constexpr ordered_concat_iterator operator++(int) noexcept { // NOLINT(cert-dcl21-cpp) - ordered_concat_iterator tmp(*this); - ++(*this); - return tmp; + template + inline constexpr bool operator>(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return y < x; } - /// \brief Decrement iterator - /// This will undo the post-condition of operator++ - constexpr ordered_concat_iterator &operator--() noexcept { - const bool can_decrement_first = base1_ != begin1_; - const bool can_decrement_second = base2_ != begin2_; - const bool can_dereference_first = base1_ != end1_; - const bool can_dereference_second = base2_ != end2_; - const auto prev_base1 = std::prev(base1_); - const auto prev_base2 = std::prev(base2_); - const bool should_decrement_first = - can_decrement_first && - (!can_decrement_second || (can_dereference_second && *prev_base1 < *base2_) || - (can_dereference_first && !(*base1_ < *prev_base2)) || !(*prev_base1 < *prev_base2)); - // i.e.: if std::prev(base1_) is the iterator to which we applied operator++ last time - if (should_decrement_first) { - // Then we should undo that - base1_.operator--(); - } else { - base2_.operator--(); - } - return *this; + template + inline constexpr bool operator>=(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return !(x < y); } - /// \brief Rewind iterator (postfix) - constexpr ordered_concat_iterator operator--(int) noexcept { // NOLINT(cert-dcl21-cpp) - ordered_concat_iterator tmp(*this); - --(*this); - return tmp; + template + inline constexpr bool operator<=(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return !(y < x); + } + + template + inline constexpr bool operator==(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return x.base1() == y.base1() && x.base2() == y.base2(); + } + + template + inline constexpr bool operator!=(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return !(x == y); + } + + template + inline constexpr bool operator>(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return y < x; + } + + template + inline constexpr bool operator>=(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return !(x < y); + } + + template + inline constexpr bool operator<=(const ordered_concat_iterator &x, + const ordered_concat_iterator &y) noexcept { + return !(y < x); + } + + template + inline constexpr bool operator==(const ordered_concat_iterator &x, const Pointer &y) noexcept { + return x.base() == y; } - /// \brief Return copy of iterator advanced by n positions - constexpr ordered_concat_iterator operator+(difference_type n) const noexcept { - ordered_concat_iterator w(*this); - w += n; - return w; + template + inline constexpr bool operator!=(const ordered_concat_iterator &x, const Pointer &y) noexcept { + return !(x == y); } - /// \brief Advance iterator by n positions - constexpr ordered_concat_iterator &operator+=(difference_type n) noexcept { - auto it = *this; - std::advance(it, n); - return *this; + template + inline constexpr bool operator>(const ordered_concat_iterator &x, const Pointer &y) noexcept { + return y < x; } - /// \brief Return copy of iterator n positions behind - constexpr ordered_concat_iterator operator-(difference_type n) const noexcept { return *this + (-n); } + template + inline constexpr bool operator>=(const ordered_concat_iterator &x, const Pointer &y) noexcept { + return !(x < y); + } + + template + inline constexpr bool operator<=(const ordered_concat_iterator &x, const Pointer &y) noexcept { + return !(y < x); + } - /// \brief Rewind iterator by n positions - constexpr ordered_concat_iterator &operator-=(difference_type n) noexcept { - *this += -n; - return *this; + template + inline constexpr bool operator==(const Pointer &x, const ordered_concat_iterator &y) noexcept { + return x.base() == y.base(); } - public /* relational operators */: - /// Make any other iterator wrapper a friend - template friend class ordered_concat_iterator; + template + inline constexpr bool operator!=(const Pointer &x, const ordered_concat_iterator &y) noexcept { + return !(x == y); + } + + template + inline constexpr bool operator>(const Pointer &x, const ordered_concat_iterator &y) noexcept { + return y < x; + } + + template + inline constexpr bool operator>=(const Pointer &x, const ordered_concat_iterator &y) noexcept { + return !(x < y); + } + + template + inline constexpr bool operator<=(const Pointer &x, const ordered_concat_iterator &y) noexcept { + return !(y < x); + } - public /* friends */: - /// \brief Get distance between iterators template - constexpr friend auto operator-(const ordered_concat_iterator &x, + inline constexpr auto operator-(const ordered_concat_iterator &x, const ordered_concat_iterator &y) noexcept - -> decltype(x.base() - y.base()); - - /// \brief Sum iterators - template - constexpr friend ordered_concat_iterator - operator+(typename ordered_concat_iterator::difference_type, - ordered_concat_iterator) noexcept; - - private: - /// Base pointer - base_iterator_type1 base1_; - base_iterator_type2 base2_; - - /// We need to know where std::begin and std::end are so that we know which iterators - /// we can/should advance - base_iterator_type1 begin1_; - base_iterator_type2 begin2_; - base_iterator_type1 end1_; - base_iterator_type2 end2_; - }; - - template - inline constexpr bool operator==(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return x.base1() == y.base1() && x.base2() == y.base2(); - } - - template - inline constexpr bool operator!=(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator<(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return x.base() < y.base(); - } - - template - inline constexpr bool operator>(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return !(y < x); - } - - template - inline constexpr bool operator==(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return x.base1() == y.base1() && x.base2() == y.base2(); - } - - template - inline constexpr bool operator!=(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator>(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept { - return !(y < x); - } - - template - inline constexpr bool operator==(const ordered_concat_iterator &x, const Pointer &y) noexcept { - return x.base() == y; - } - - template - inline constexpr bool operator!=(const ordered_concat_iterator &x, const Pointer &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator>(const ordered_concat_iterator &x, const Pointer &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const ordered_concat_iterator &x, const Pointer &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const ordered_concat_iterator &x, const Pointer &y) noexcept { - return !(y < x); - } - - template - inline constexpr bool operator==(const Pointer &x, const ordered_concat_iterator &y) noexcept { - return x.base() == y.base(); - } - - template - inline constexpr bool operator!=(const Pointer &x, const ordered_concat_iterator &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator>(const Pointer &x, const ordered_concat_iterator &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const Pointer &x, const ordered_concat_iterator &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const Pointer &x, const ordered_concat_iterator &y) noexcept { - return !(y < x); - } - - template - inline constexpr auto operator-(const ordered_concat_iterator &x, - const ordered_concat_iterator &y) noexcept - -> decltype(x.base() - y.base()) { - return x.base() - y.base(); - } - - template - inline constexpr ordered_concat_iterator - operator+(typename ordered_concat_iterator::difference_type n, - ordered_concat_iterator x) noexcept { - x += n; - return x; - } + -> decltype(x.base() - y.base()) { + return x.base() - y.base(); + } + + template + inline constexpr ordered_concat_iterator + operator+(typename ordered_concat_iterator::difference_type n, + ordered_concat_iterator x) noexcept { + x += n; + return x; + } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ITERATOR_ORDERED_CONCAT_ITERATOR_H diff --git a/source/small/detail/iterator/pointer_wrapper.h b/source/small/detail/iterator/pointer_wrapper.h index a00b12e..433a210 100644 --- a/source/small/detail/iterator/pointer_wrapper.h +++ b/source/small/detail/iterator/pointer_wrapper.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_ITERATOR_POINTER_WRAPPER_H #define SMALL_DETAIL_ITERATOR_POINTER_WRAPPER_H @@ -14,232 +13,233 @@ #include namespace small { + namespace detail { + + /// \brief Wraps a pointer as an iterator + template class pointer_wrapper { + public: + static_assert(std::is_pointer_v, "pointer_wrapper can only wrap pointers"); + typedef POINTER iterator_type; + typedef typename std::iterator_traits::iterator_category iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::pointer pointer; + typedef typename std::iterator_traits::reference reference; + + public /* constructors */: + /// \brief Construct empty pointer wrapper + constexpr pointer_wrapper() noexcept : base_(nullptr) {} + + /// \brief Construct pointer wrapper from pointer x + constexpr explicit pointer_wrapper(iterator_type x) noexcept : base_(x) {} + + /// \brief Construct pointer wrapper from pointer wrapper u, which might be another type + template + constexpr pointer_wrapper( // NOLINT(google-explicit-constructor): expected for iterators + const pointer_wrapper &u, + typename std::enable_if_t> * = 0) noexcept + : base_(u.base()) {} + + public /* element access */: + /// \brief Dereference iterator + constexpr reference operator*() const noexcept { return *base_; } + + /// \brief Dereference iterator and get member + constexpr pointer operator->() const noexcept { return static_cast(std::addressof(*base_)); } + + /// \brief Dereference iterator n positions ahead + constexpr reference operator[](difference_type n) const noexcept { return base_[n]; } + + /// \brief Get base pointer + constexpr iterator_type base() const noexcept { return base_; } + + public /* modifiers */: + /// \brief Advance iterator + constexpr pointer_wrapper &operator++() noexcept { + ++base_; + return *this; + } + + /// \brief Advance iterator (postfix) + constexpr pointer_wrapper operator++(int) noexcept { // NOLINT(cert-dcl21-cpp) + pointer_wrapper tmp(*this); + ++(*this); + return tmp; + } + + /// \brief Rewind iterator + constexpr pointer_wrapper &operator--() noexcept { + --base_; + return *this; + } + + /// \brief Rewind iterator (postfix) + constexpr pointer_wrapper operator--(int) noexcept { // NOLINT(cert-dcl21-cpp) + pointer_wrapper tmp(*this); + --(*this); + return tmp; + } + + /// \brief Return copy of iterator advanced by n positions + constexpr pointer_wrapper operator+(difference_type n) const noexcept { + pointer_wrapper w(*this); + w += n; + return w; + } + + /// \brief Advance iterator by n positions + constexpr pointer_wrapper &operator+=(difference_type n) noexcept { + base_ += n; + return *this; + } + + /// \brief Return copy of iterator n positions behind + constexpr pointer_wrapper operator-(difference_type n) const noexcept { return *this + (-n); } + + /// \brief Rewind iterator by n positions + constexpr pointer_wrapper &operator-=(difference_type n) noexcept { + *this += -n; + return *this; + } + + public /* relational operators */: + /// Make any other pointer wrapper a friend + template friend class pointer_wrapper; + + public /* friends */: + /// \brief Get distance between iterators + template + constexpr friend auto operator-(const pointer_wrapper &x, const pointer_wrapper &y) noexcept + -> decltype(x.base() - y.base()); + + /// \brief Sum iterators + template + constexpr friend pointer_wrapper operator+(typename pointer_wrapper::difference_type, + pointer_wrapper) noexcept; + + private: + /// Base pointer + iterator_type base_; + }; - /// \brief Wraps a pointer as an iterator - template class pointer_wrapper { - public: - static_assert(std::is_pointer_v, "pointer_wrapper can only wrap pointers"); - typedef POINTER iterator_type; - typedef typename std::iterator_traits::iterator_category iterator_category; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::pointer pointer; - typedef typename std::iterator_traits::reference reference; + template + inline constexpr bool operator==(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return x.base() == y.base(); + } - public /* constructors */: - /// \brief Construct empty pointer wrapper - constexpr pointer_wrapper() noexcept : base_(nullptr) {} + template + inline constexpr bool operator!=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return !(x == y); + } - /// \brief Construct pointer wrapper from pointer x - constexpr explicit pointer_wrapper(iterator_type x) noexcept : base_(x) {} + template + inline constexpr bool operator<(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return x.base() < y.base(); + } - /// \brief Construct pointer wrapper from pointer wrapper u, which might be another type - template - constexpr pointer_wrapper( // NOLINT(google-explicit-constructor): expected for iterators - const pointer_wrapper &u, - typename std::enable_if_t> * = 0) noexcept - : base_(u.base()) {} + template + inline constexpr bool operator>(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return y < x; + } - public /* element access */: - /// \brief Dereference iterator - constexpr reference operator*() const noexcept { return *base_; } + template + inline constexpr bool operator>=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return !(x < y); + } - /// \brief Dereference iterator and get member - constexpr pointer operator->() const noexcept { return static_cast(std::addressof(*base_)); } + template + inline constexpr bool operator<=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return !(y < x); + } - /// \brief Dereference iterator n positions ahead - constexpr reference operator[](difference_type n) const noexcept { return base_[n]; } + template + inline constexpr bool operator==(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return x.base() == y.base(); + } - /// \brief Get base pointer - constexpr iterator_type base() const noexcept { return base_; } + template + inline constexpr bool operator!=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return !(x == y); + } + + template + inline constexpr bool operator>(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return y < x; + } - public /* modifiers */: - /// \brief Advance iterator - constexpr pointer_wrapper &operator++() noexcept { - ++base_; - return *this; + template + inline constexpr bool operator>=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return !(x < y); } - /// \brief Advance iterator (postfix) - constexpr pointer_wrapper operator++(int) noexcept { // NOLINT(cert-dcl21-cpp) - pointer_wrapper tmp(*this); - ++(*this); - return tmp; + template + inline constexpr bool operator<=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { + return !(y < x); } - /// \brief Rewind iterator - constexpr pointer_wrapper &operator--() noexcept { - --base_; - return *this; + template + inline constexpr bool operator==(const pointer_wrapper &x, const BaseIter &y) noexcept { + return x.base() == y; } - /// \brief Rewind iterator (postfix) - constexpr pointer_wrapper operator--(int) noexcept { // NOLINT(cert-dcl21-cpp) - pointer_wrapper tmp(*this); - --(*this); - return tmp; + template + inline constexpr bool operator!=(const pointer_wrapper &x, const BaseIter &y) noexcept { + return !(x == y); } - /// \brief Return copy of iterator advanced by n positions - constexpr pointer_wrapper operator+(difference_type n) const noexcept { - pointer_wrapper w(*this); - w += n; - return w; + template + inline constexpr bool operator>(const pointer_wrapper &x, const BaseIter &y) noexcept { + return y < x; } - /// \brief Advance iterator by n positions - constexpr pointer_wrapper &operator+=(difference_type n) noexcept { - base_ += n; - return *this; + template + inline constexpr bool operator>=(const pointer_wrapper &x, const BaseIter &y) noexcept { + return !(x < y); } - /// \brief Return copy of iterator n positions behind - constexpr pointer_wrapper operator-(difference_type n) const noexcept { return *this + (-n); } + template + inline constexpr bool operator<=(const pointer_wrapper &x, const BaseIter &y) noexcept { + return !(y < x); + } - /// \brief Rewind iterator by n positions - constexpr pointer_wrapper &operator-=(difference_type n) noexcept { - *this += -n; - return *this; + template + inline constexpr bool operator==(const BaseIter &x, const pointer_wrapper &y) noexcept { + return x.base() == y.base(); } - public /* relational operators */: - /// Make any other pointer wrapper a friend - template friend class pointer_wrapper; + template + inline constexpr bool operator!=(const BaseIter &x, const pointer_wrapper &y) noexcept { + return !(x == y); + } + + template + inline constexpr bool operator>(const BaseIter &x, const pointer_wrapper &y) noexcept { + return y < x; + } + + template + inline constexpr bool operator>=(const BaseIter &x, const pointer_wrapper &y) noexcept { + return !(x < y); + } + + template + inline constexpr bool operator<=(const BaseIter &x, const pointer_wrapper &y) noexcept { + return !(y < x); + } - public /* friends */: - /// \brief Get distance between iterators template - constexpr friend auto operator-(const pointer_wrapper &x, const pointer_wrapper &y) noexcept - -> decltype(x.base() - y.base()); - - /// \brief Sum iterators - template - constexpr friend pointer_wrapper operator+(typename pointer_wrapper::difference_type, - pointer_wrapper) noexcept; - - private: - /// Base pointer - iterator_type base_; - }; - - template - inline constexpr bool operator==(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return x.base() == y.base(); - } - - template - inline constexpr bool operator!=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator<(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return x.base() < y.base(); - } - - template - inline constexpr bool operator>(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return !(y < x); - } - - template - inline constexpr bool operator==(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return x.base() == y.base(); - } - - template - inline constexpr bool operator!=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator>(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const pointer_wrapper &x, const pointer_wrapper &y) noexcept { - return !(y < x); - } - - template - inline constexpr bool operator==(const pointer_wrapper &x, const BaseIter &y) noexcept { - return x.base() == y; - } - - template - inline constexpr bool operator!=(const pointer_wrapper &x, const BaseIter &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator>(const pointer_wrapper &x, const BaseIter &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const pointer_wrapper &x, const BaseIter &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const pointer_wrapper &x, const BaseIter &y) noexcept { - return !(y < x); - } - - template - inline constexpr bool operator==(const BaseIter &x, const pointer_wrapper &y) noexcept { - return x.base() == y.base(); - } - - template - inline constexpr bool operator!=(const BaseIter &x, const pointer_wrapper &y) noexcept { - return !(x == y); - } - - template - inline constexpr bool operator>(const BaseIter &x, const pointer_wrapper &y) noexcept { - return y < x; - } - - template - inline constexpr bool operator>=(const BaseIter &x, const pointer_wrapper &y) noexcept { - return !(x < y); - } - - template - inline constexpr bool operator<=(const BaseIter &x, const pointer_wrapper &y) noexcept { - return !(y < x); - } - - template - inline constexpr auto operator-(const pointer_wrapper &x, const pointer_wrapper &y) noexcept - -> decltype(x.base() - y.base()) { - return x.base() - y.base(); - } - - template - inline constexpr pointer_wrapper operator+(typename pointer_wrapper::difference_type n, - pointer_wrapper x) noexcept { - x += n; - return x; - } + inline constexpr auto operator-(const pointer_wrapper &x, const pointer_wrapper &y) noexcept + -> decltype(x.base() - y.base()) { + return x.base() - y.base(); + } + template + inline constexpr pointer_wrapper operator+(typename pointer_wrapper::difference_type n, + pointer_wrapper x) noexcept { + x += n; + return x; + } + } // namespace detail } // namespace small #endif // SMALL_DETAIL_ITERATOR_POINTER_WRAPPER_H diff --git a/source/small/detail/traits/add_key_const.h b/source/small/detail/traits/add_key_const.h index 1d3d01c..dbdc21c 100644 --- a/source/small/detail/traits/add_key_const.h +++ b/source/small/detail/traits/add_key_const.h @@ -5,32 +5,33 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_ADD_KEY_CONST_H #define SMALL_DETAIL_TRAITS_ADD_KEY_CONST_H #include namespace small { - /// Make pair key constant - template struct add_key_const : std::add_const {}; + namespace detail { + /// Make pair key constant + template struct add_key_const : std::add_const {}; - template struct add_key_const> { - typedef std::pair, U> type; - }; + template struct add_key_const> { + typedef std::pair, U> type; + }; - /// Make pair key constant from pointer to pair - template struct add_key_const { typedef typename add_key_const::type *type; }; + /// Make pair key constant from pointer to pair + template struct add_key_const { typedef typename add_key_const::type *type; }; - /// Make pair key constant from reference to pair - template struct add_key_const { typedef typename add_key_const::type &type; }; + /// Make pair key constant from reference to pair + template struct add_key_const { typedef typename add_key_const::type &type; }; - /// Check if pair has a const key - template struct is_key_const : std::false_type {}; + /// Check if pair has a const key + template struct is_key_const : std::false_type {}; - template struct is_key_const> : std::is_const {}; + template struct is_key_const> : std::is_const {}; - template constexpr bool is_key_const_v = is_key_const::value; + template constexpr bool is_key_const_v = is_key_const::value; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_TRAITS_ADD_KEY_CONST_H diff --git a/source/small/detail/traits/cpp_version.h b/source/small/detail/traits/cpp_version.h index 3a88813..c64c931 100644 --- a/source/small/detail/traits/cpp_version.h +++ b/source/small/detail/traits/cpp_version.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_CPP_VERSION_H #define SMALL_DETAIL_TRAITS_CPP_VERSION_H @@ -89,7 +88,6 @@ #define cpp_feature_testing 201911L #endif - #ifdef cpp_feature_testing #ifdef __cpp_aggregate_bases #define cpp_aggregate_bases __cpp_aggregate_bases @@ -201,7 +199,7 @@ #endif #if defined(do_constexpr) -# undef do_constexpr +#undef do_constexpr #endif #ifdef HEDLEY_CONSTEXPR #define do_constexpr HEDLEY_CONSTEXPR @@ -627,7 +625,6 @@ #define cpp_variadic_using 201611L #endif - /* * C++ attributes */ @@ -691,35 +688,35 @@ * Macros to use C++ attributes even if there are not formally available yet */ #if defined(warn_nodiscard) -# undef warn_nodiscard +#undef warn_nodiscard #endif #ifdef HEDLEY_WARN_UNUSED_RESULT #define warn_nodiscard HEDLEY_WARN_UNUSED_RESULT #endif #if defined(warn_noreturn) -# undef warn_noreturn +#undef warn_noreturn #endif #ifdef HEDLEY_NO_RETURN #define warn_noreturn HEDLEY_NO_RETURN #endif #if defined(do_fallthrough) -# undef do_fallthrough +#undef do_fallthrough #endif #ifdef HEDLEY_FALL_THROUGH #define do_fallthrough HEDLEY_FALL_THROUGH #endif #if defined(do_likely) -# undef do_likely +#undef do_likely #endif #ifdef HEDLEY_LIKELY #define do_likely(expr) HEDLEY_LIKELY(expr) #endif #if defined(do_unlikely) -# undef do_unlikely +#undef do_unlikely #endif #ifdef HEDLEY_UNLIKELY #define do_unlikely(expr) HEDLEY_UNLIKELY(expr) @@ -738,28 +735,28 @@ * Macros to use compiler attributes if they are available */ #if defined(warn_return_non_null) -# undef warn_return_non_null +#undef warn_return_non_null #endif #ifdef HEDLEY_RETURNS_NON_NULL #define warn_return_non_null HEDLEY_RETURNS_NON_NULL #endif #if defined(warn_non_null) -# undef warn_non_null +#undef warn_non_null #endif #ifdef HEDLEY_RETURNS_NON_NULL #define warn_non_null(...) HEDLEY_NON_NULL(__VA_ARGS__) #endif #if defined(warn_bit_flags) -# undef warn_bit_flags +#undef warn_bit_flags #endif #ifdef HEDLEY_RETURNS_NON_NULL #define warn_bit_flags HEDLEY_FLAGS #endif #if defined(do_predict) -# undef do_predict +#undef do_predict #endif #ifdef HEDLEY_PREDICT #define do_predict(expr, expected, probability) HEDLEY_PREDICT(expr, expected, probability) @@ -778,7 +775,6 @@ #define cpp_lib_chrono_udls 201304L #endif - #if __has_include() #ifdef __cpp_lib_complex_udls #define cpp_lib_complex_udls __cpp_lib_complex_udls @@ -787,7 +783,6 @@ #define cpp_lib_complex_udls 201309L #endif - #if __has_include() #ifdef __cpp_lib_exchange_function #define cpp_lib_exchange_function __cpp_lib_exchange_function @@ -804,7 +799,6 @@ #define cpp_lib_generic_associative_lookup 201304L #endif - #if __has_include() #ifdef __cpp_lib_integer_sequence #define cpp_lib_integer_sequence __cpp_lib_integer_sequence @@ -813,7 +807,6 @@ #define cpp_lib_integer_sequence 201304L #endif - #if __has_include() #ifdef __cpp_lib_integral_constant_callable #define cpp_lib_integral_constant_callable __cpp_lib_integral_constant_callable @@ -822,7 +815,6 @@ #define cpp_lib_integral_constant_callable 201304L #endif - #if __has_include() #ifdef __cpp_lib_is_final #define cpp_lib_is_final __cpp_lib_is_final @@ -831,7 +823,6 @@ #define cpp_lib_is_final 201402L #endif - #if __has_include() #ifdef __cpp_lib_is_null_pointer #define cpp_lib_is_null_pointer __cpp_lib_is_null_pointer @@ -840,7 +831,6 @@ #define cpp_lib_is_null_pointer 201309L #endif - #if __has_include() #ifdef __cpp_lib_make_reverse_iterator #define cpp_lib_make_reverse_iterator __cpp_lib_make_reverse_iterator @@ -849,7 +839,6 @@ #define cpp_lib_make_reverse_iterator 201402L #endif - #if __has_include() #ifdef __cpp_lib_make_unique #define cpp_lib_make_unique __cpp_lib_make_unique @@ -858,7 +847,6 @@ #define cpp_lib_make_unique 201304L #endif - #if __has_include() #ifdef __cpp_lib_null_iterators #define cpp_lib_null_iterators __cpp_lib_null_iterators @@ -867,7 +855,6 @@ #define cpp_lib_null_iterators 201304L #endif - #if __has_include() #ifdef __cpp_lib_quoted_string_io #define cpp_lib_quoted_string_io __cpp_lib_quoted_string_io @@ -876,7 +863,6 @@ #define cpp_lib_quoted_string_io 201304L #endif - #if __has_include() #ifdef __cpp_lib_result_of_sfinae #define cpp_lib_result_of_sfinae __cpp_lib_result_of_sfinae @@ -885,7 +871,6 @@ #define cpp_lib_result_of_sfinae 201210L #endif - #if __has_include() #ifdef __cpp_lib_robust_nonmodifying_seq_ops #define cpp_lib_robust_nonmodifying_seq_ops __cpp_lib_robust_nonmodifying_seq_ops @@ -894,7 +879,6 @@ #define cpp_lib_robust_nonmodifying_seq_ops 201304L #endif - #if __has_include() #ifdef __cpp_lib_shared_timed_mutex #define cpp_lib_shared_timed_mutex __cpp_lib_shared_timed_mutex @@ -903,7 +887,6 @@ #define cpp_lib_shared_timed_mutex 201402L #endif - #if __has_include() #ifdef __cpp_lib_string_udls #define cpp_lib_string_udls __cpp_lib_string_udls @@ -912,7 +895,6 @@ #define cpp_lib_string_udls 201304L #endif - #if __has_include() #ifdef __cpp_lib_transformation_trait_aliases #define cpp_lib_transformation_trait_aliases __cpp_lib_transformation_trait_aliases @@ -921,7 +903,6 @@ #define cpp_lib_transformation_trait_aliases 201304L #endif - #if __has_include() #ifdef __cpp_lib_transparent_operators #define cpp_lib_transparent_operators __cpp_lib_transparent_operators @@ -930,7 +911,6 @@ #define cpp_lib_transparent_operators 201210L #endif - #if __has_include() #ifdef __cpp_lib_tuple_element_t #define cpp_lib_tuple_element_t __cpp_lib_tuple_element_t @@ -939,7 +919,6 @@ #define cpp_lib_tuple_element_t 201402L #endif - #if __has_include() #ifdef __cpp_lib_tuples_by_type #define cpp_lib_tuples_by_type __cpp_lib_tuples_by_type @@ -948,8 +927,6 @@ #define cpp_lib_tuples_by_type 201304L #endif - - #if __has_include() #ifdef __cpp_lib_addressof_constexpr #define cpp_lib_addressof_constexpr __cpp_lib_addressof_constexpr @@ -958,7 +935,6 @@ #define cpp_lib_addressof_constexpr 201603L #endif - #if __has_include() #ifdef __cpp_lib_allocator_traits_is_always_equal #define cpp_lib_allocator_traits_is_always_equal __cpp_lib_allocator_traits_is_always_equal @@ -967,7 +943,6 @@ #define cpp_lib_allocator_traits_is_always_equal 201411L #endif - #if __has_include() #ifdef __cpp_lib_any #define cpp_lib_any __cpp_lib_any @@ -976,7 +951,6 @@ #define cpp_lib_any 201606L #endif - #if __has_include() #ifdef __cpp_lib_apply #define cpp_lib_apply __cpp_lib_apply @@ -985,7 +959,6 @@ #define cpp_lib_apply 201603L #endif - #if __has_include() #ifdef __cpp_lib_array_constexpr #define cpp_lib_array_constexpr __cpp_lib_array_constexpr @@ -994,7 +967,6 @@ #define cpp_lib_array_constexpr 201603L #endif - #if __has_include() #ifdef __cpp_lib_as_const #define cpp_lib_as_const __cpp_lib_as_const @@ -1003,7 +975,6 @@ #define cpp_lib_as_const 201510L #endif - #if __has_include() #ifdef __cpp_lib_atomic_is_always_lock_free #define cpp_lib_atomic_is_always_lock_free __cpp_lib_atomic_is_always_lock_free @@ -1012,7 +983,6 @@ #define cpp_lib_atomic_is_always_lock_free 201603L #endif - #if __has_include() #ifdef __cpp_lib_bool_constant #define cpp_lib_bool_constant __cpp_lib_bool_constant @@ -1021,7 +991,6 @@ #define cpp_lib_bool_constant 201505L #endif - #if __has_include() #ifdef __cpp_lib_boyer_moore_searcher #define cpp_lib_boyer_moore_searcher __cpp_lib_boyer_moore_searcher @@ -1030,7 +999,6 @@ #define cpp_lib_boyer_moore_searcher 201603L #endif - #if __has_include() #ifdef __cpp_lib_byte #define cpp_lib_byte __cpp_lib_byte @@ -1039,7 +1007,6 @@ #define cpp_lib_byte 201603L #endif - #if __has_include() #ifdef __cpp_lib_chrono #define cpp_lib_chrono __cpp_lib_chrono @@ -1048,7 +1015,6 @@ #define cpp_lib_chrono 201611L #endif - #if __has_include() #ifdef __cpp_lib_clamp #define cpp_lib_clamp __cpp_lib_clamp @@ -1057,7 +1023,6 @@ #define cpp_lib_clamp 201603L #endif - #if __has_include() #ifdef __cpp_lib_enable_shared_from_this #define cpp_lib_enable_shared_from_this __cpp_lib_enable_shared_from_this @@ -1066,7 +1031,6 @@ #define cpp_lib_enable_shared_from_this 201603L #endif - #if __has_include() #ifdef __cpp_lib_execution #define cpp_lib_execution __cpp_lib_execution @@ -1075,7 +1039,6 @@ #define cpp_lib_execution 201603L #endif - #if __has_include() #ifdef __cpp_lib_filesystem #define cpp_lib_filesystem __cpp_lib_filesystem @@ -1084,7 +1047,6 @@ #define cpp_lib_filesystem 201703L #endif - #if __has_include() #ifdef __cpp_lib_gcd_lcm #define cpp_lib_gcd_lcm __cpp_lib_gcd_lcm @@ -1093,7 +1055,6 @@ #define cpp_lib_gcd_lcm 201606L #endif - #if __has_include() #ifdef __cpp_lib_hardware_interference_size #define cpp_lib_hardware_interference_size __cpp_lib_hardware_interference_size @@ -1102,7 +1063,6 @@ #define cpp_lib_hardware_interference_size 201703L #endif - #if __has_include() #ifdef __cpp_lib_has_unique_object_representations #define cpp_lib_has_unique_object_representations __cpp_lib_has_unique_object_representations @@ -1111,7 +1071,6 @@ #define cpp_lib_has_unique_object_representations 201606L #endif - #if __has_include() #ifdef __cpp_lib_hypot #define cpp_lib_hypot __cpp_lib_hypot @@ -1120,7 +1079,6 @@ #define cpp_lib_hypot 201603L #endif - #if __has_include() #ifdef __cpp_lib_incomplete_container_elements #define cpp_lib_incomplete_container_elements __cpp_lib_incomplete_container_elements @@ -1129,7 +1087,6 @@ #define cpp_lib_incomplete_container_elements 201505L #endif - #if __has_include() #ifdef __cpp_lib_invoke #define cpp_lib_invoke __cpp_lib_invoke @@ -1138,7 +1095,6 @@ #define cpp_lib_invoke 201411L #endif - #if __has_include() #ifdef __cpp_lib_is_aggregate #define cpp_lib_is_aggregate __cpp_lib_is_aggregate @@ -1147,7 +1103,6 @@ #define cpp_lib_is_aggregate 201703L #endif - #if __has_include() #ifdef __cpp_lib_is_invocable #define cpp_lib_is_invocable __cpp_lib_is_invocable @@ -1156,7 +1111,6 @@ #define cpp_lib_is_invocable 201703L #endif - #if __has_include() #ifdef __cpp_lib_is_swappable #define cpp_lib_is_swappable __cpp_lib_is_swappable @@ -1165,7 +1119,6 @@ #define cpp_lib_is_swappable 201603L #endif - #if __has_include() #ifdef __cpp_lib_launder #define cpp_lib_launder __cpp_lib_launder @@ -1174,7 +1127,6 @@ #define cpp_lib_launder 201606L #endif - #if __has_include() #ifdef __cpp_lib_logical_traits #define cpp_lib_logical_traits __cpp_lib_logical_traits @@ -1183,7 +1135,6 @@ #define cpp_lib_logical_traits 201510L #endif - #if __has_include() #ifdef __cpp_lib_make_from_tuple #define cpp_lib_make_from_tuple __cpp_lib_make_from_tuple @@ -1192,7 +1143,6 @@ #define cpp_lib_make_from_tuple 201606L #endif - #if __has_include() #ifdef __cpp_lib_map_try_emplace #define cpp_lib_map_try_emplace __cpp_lib_map_try_emplace @@ -1201,7 +1151,6 @@ #define cpp_lib_map_try_emplace 201411L #endif - #if __has_include() #ifdef __cpp_lib_math_special_functions #define cpp_lib_math_special_functions __cpp_lib_math_special_functions @@ -1210,7 +1159,6 @@ #define cpp_lib_math_special_functions 201603L #endif - #if __has_include() #ifdef __cpp_lib_memory_resource #define cpp_lib_memory_resource __cpp_lib_memory_resource @@ -1219,7 +1167,6 @@ #define cpp_lib_memory_resource 201603L #endif - #if __has_include() #ifdef __cpp_lib_node_extract #define cpp_lib_node_extract __cpp_lib_node_extract @@ -1228,7 +1175,6 @@ #define cpp_lib_node_extract 201606L #endif - #if __has_include() #ifdef __cpp_lib_nonmember_container_access #define cpp_lib_nonmember_container_access __cpp_lib_nonmember_container_access @@ -1237,7 +1183,6 @@ #define cpp_lib_nonmember_container_access 201411L #endif - #if __has_include() #ifdef __cpp_lib_not_fn #define cpp_lib_not_fn __cpp_lib_not_fn @@ -1246,7 +1191,6 @@ #define cpp_lib_not_fn 201603L #endif - #if __has_include() #ifdef __cpp_lib_optional #define cpp_lib_optional __cpp_lib_optional @@ -1255,7 +1199,6 @@ #define cpp_lib_optional 201606L #endif - #if __has_include() #ifdef __cpp_lib_parallel_algorithm #define cpp_lib_parallel_algorithm __cpp_lib_parallel_algorithm @@ -1264,7 +1207,6 @@ #define cpp_lib_parallel_algorithm 201603L #endif - #if __has_include() #ifdef __cpp_lib_raw_memory_algorithms #define cpp_lib_raw_memory_algorithms __cpp_lib_raw_memory_algorithms @@ -1273,7 +1215,6 @@ #define cpp_lib_raw_memory_algorithms 201606L #endif - #if __has_include() #ifdef __cpp_lib_sample #define cpp_lib_sample __cpp_lib_sample @@ -1282,7 +1223,6 @@ #define cpp_lib_sample 201603L #endif - #if __has_include() #ifdef __cpp_lib_scoped_lock #define cpp_lib_scoped_lock __cpp_lib_scoped_lock @@ -1291,7 +1231,6 @@ #define cpp_lib_scoped_lock 201703L #endif - #if __has_include() #ifdef __cpp_lib_shared_mutex #define cpp_lib_shared_mutex __cpp_lib_shared_mutex @@ -1300,7 +1239,6 @@ #define cpp_lib_shared_mutex 201505L #endif - #if __has_include() #ifdef __cpp_lib_shared_ptr_arrays #define cpp_lib_shared_ptr_arrays __cpp_lib_shared_ptr_arrays @@ -1309,7 +1247,6 @@ #define cpp_lib_shared_ptr_arrays 201611L #endif - #if __has_include() #ifdef __cpp_lib_shared_ptr_weak_type #define cpp_lib_shared_ptr_weak_type __cpp_lib_shared_ptr_weak_type @@ -1318,7 +1255,6 @@ #define cpp_lib_shared_ptr_weak_type 201606L #endif - #if __has_include() #ifdef __cpp_lib_string_view #define cpp_lib_string_view __cpp_lib_string_view @@ -1327,7 +1263,6 @@ #define cpp_lib_string_view 201606L #endif - #if __has_include() #ifdef __cpp_lib_to_chars #define cpp_lib_to_chars __cpp_lib_to_chars @@ -1336,7 +1271,6 @@ #define cpp_lib_to_chars 201611L #endif - #if __has_include() #ifdef __cpp_lib_type_trait_variable_templates #define cpp_lib_type_trait_variable_templates __cpp_lib_type_trait_variable_templates @@ -1345,7 +1279,6 @@ #define cpp_lib_type_trait_variable_templates 201510L #endif - #if __has_include() #ifdef __cpp_lib_uncaught_exceptions #define cpp_lib_uncaught_exceptions __cpp_lib_uncaught_exceptions @@ -1354,7 +1287,6 @@ #define cpp_lib_uncaught_exceptions 201411L #endif - #if __has_include() #ifdef __cpp_lib_unordered_map_try_emplace #define cpp_lib_unordered_map_try_emplace __cpp_lib_unordered_map_try_emplace @@ -1363,7 +1295,6 @@ #define cpp_lib_unordered_map_try_emplace 201411L #endif - #if __has_include() #ifdef __cpp_lib_variant #define cpp_lib_variant __cpp_lib_variant @@ -1372,7 +1303,6 @@ #define cpp_lib_variant 201606L #endif - #if __has_include() #ifdef __cpp_lib_void_t #define cpp_lib_void_t __cpp_lib_void_t @@ -1381,8 +1311,6 @@ #define cpp_lib_void_t 201411L #endif - - #if __has_include() #ifdef __cpp_lib_assume_aligned #define cpp_lib_assume_aligned __cpp_lib_assume_aligned @@ -1391,7 +1319,6 @@ #define cpp_lib_assume_aligned 201811L #endif - #if __has_include() #ifdef __cpp_lib_atomic_flag_test #define cpp_lib_atomic_flag_test __cpp_lib_atomic_flag_test @@ -1400,7 +1327,6 @@ #define cpp_lib_atomic_flag_test 201907L #endif - #if __has_include() #ifdef __cpp_lib_atomic_float #define cpp_lib_atomic_float __cpp_lib_atomic_float @@ -1409,7 +1335,6 @@ #define cpp_lib_atomic_float 201711L #endif - #if __has_include() #ifdef __cpp_lib_atomic_lock_free_type_aliases #define cpp_lib_atomic_lock_free_type_aliases __cpp_lib_atomic_lock_free_type_aliases @@ -1418,7 +1343,6 @@ #define cpp_lib_atomic_lock_free_type_aliases 201907L #endif - #if __has_include() #ifdef __cpp_lib_atomic_ref #define cpp_lib_atomic_ref __cpp_lib_atomic_ref @@ -1427,7 +1351,6 @@ #define cpp_lib_atomic_ref 201806L #endif - #if __has_include() #ifdef __cpp_lib_atomic_shared_ptr #define cpp_lib_atomic_shared_ptr __cpp_lib_atomic_shared_ptr @@ -1436,7 +1359,6 @@ #define cpp_lib_atomic_shared_ptr 201711L #endif - #if __has_include() #ifdef __cpp_lib_atomic_value_initialization #define cpp_lib_atomic_value_initialization __cpp_lib_atomic_value_initialization @@ -1445,7 +1367,6 @@ #define cpp_lib_atomic_value_initialization 201911L #endif - #if __has_include() #ifdef __cpp_lib_atomic_wait #define cpp_lib_atomic_wait __cpp_lib_atomic_wait @@ -1454,7 +1375,6 @@ #define cpp_lib_atomic_wait 201907L #endif - #if __has_include() #ifdef __cpp_lib_barrier #define cpp_lib_barrier __cpp_lib_barrier @@ -1463,7 +1383,6 @@ #define cpp_lib_barrier 201907L #endif - #if __has_include() #ifdef __cpp_lib_bind_front #define cpp_lib_bind_front __cpp_lib_bind_front @@ -1472,7 +1391,6 @@ #define cpp_lib_bind_front 201907L #endif - #if __has_include() #ifdef __cpp_lib_bit_cast #define cpp_lib_bit_cast __cpp_lib_bit_cast @@ -1481,7 +1399,6 @@ #define cpp_lib_bit_cast 201806L #endif - #if __has_include() #ifdef __cpp_lib_bitops #define cpp_lib_bitops __cpp_lib_bitops @@ -1490,7 +1407,6 @@ #define cpp_lib_bitops 201907L #endif - #if __has_include() #ifdef __cpp_lib_bounded_array_traits #define cpp_lib_bounded_array_traits __cpp_lib_bounded_array_traits @@ -1499,7 +1415,6 @@ #define cpp_lib_bounded_array_traits 201902L #endif - #if __has_include() #ifdef __cpp_lib_char8_t #define cpp_lib_char8_t __cpp_lib_char8_t @@ -1508,7 +1423,6 @@ #define cpp_lib_char8_t 201811L #endif - #if __has_include() #ifdef __cpp_lib_concepts #define cpp_lib_concepts __cpp_lib_concepts @@ -1517,7 +1431,6 @@ #define cpp_lib_concepts 202002L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_algorithms #define cpp_lib_constexpr_algorithms __cpp_lib_constexpr_algorithms @@ -1526,7 +1439,6 @@ #define cpp_lib_constexpr_algorithms 201806L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_complex #define cpp_lib_constexpr_complex __cpp_lib_constexpr_complex @@ -1535,7 +1447,6 @@ #define cpp_lib_constexpr_complex 201711L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_dynamic_alloc #define cpp_lib_constexpr_dynamic_alloc __cpp_lib_constexpr_dynamic_alloc @@ -1544,7 +1455,6 @@ #define cpp_lib_constexpr_dynamic_alloc 201907L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_functional #define cpp_lib_constexpr_functional __cpp_lib_constexpr_functional @@ -1553,7 +1463,6 @@ #define cpp_lib_constexpr_functional 201907L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_iterator #define cpp_lib_constexpr_iterator __cpp_lib_constexpr_iterator @@ -1562,7 +1471,6 @@ #define cpp_lib_constexpr_iterator 201811L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_memory #define cpp_lib_constexpr_memory __cpp_lib_constexpr_memory @@ -1571,7 +1479,6 @@ #define cpp_lib_constexpr_memory 201811L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_numeric #define cpp_lib_constexpr_numeric __cpp_lib_constexpr_numeric @@ -1580,7 +1487,6 @@ #define cpp_lib_constexpr_numeric 201911L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_string #define cpp_lib_constexpr_string __cpp_lib_constexpr_string @@ -1589,7 +1495,6 @@ #define cpp_lib_constexpr_string 201907L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_string_view #define cpp_lib_constexpr_string_view __cpp_lib_constexpr_string_view @@ -1598,7 +1503,6 @@ #define cpp_lib_constexpr_string_view 201811L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_tuple #define cpp_lib_constexpr_tuple __cpp_lib_constexpr_tuple @@ -1607,7 +1511,6 @@ #define cpp_lib_constexpr_tuple 201811L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_utility #define cpp_lib_constexpr_utility __cpp_lib_constexpr_utility @@ -1616,7 +1519,6 @@ #define cpp_lib_constexpr_utility 201811L #endif - #if __has_include() #ifdef __cpp_lib_constexpr_vector #define cpp_lib_constexpr_vector __cpp_lib_constexpr_vector @@ -1625,7 +1527,6 @@ #define cpp_lib_constexpr_vector 201907L #endif - #if __has_include() #ifdef __cpp_lib_coroutine #define cpp_lib_coroutine __cpp_lib_coroutine @@ -1634,7 +1535,6 @@ #define cpp_lib_coroutine 201902L #endif - #if __has_include() #ifdef __cpp_lib_destroying_delete #define cpp_lib_destroying_delete __cpp_lib_destroying_delete @@ -1643,7 +1543,6 @@ #define cpp_lib_destroying_delete 201806L #endif - #if __has_include() #ifdef __cpp_lib_endian #define cpp_lib_endian __cpp_lib_endian @@ -1652,7 +1551,6 @@ #define cpp_lib_endian 201907L #endif - #if __has_include() #ifdef __cpp_lib_erase_if #define cpp_lib_erase_if __cpp_lib_erase_if @@ -1661,7 +1559,6 @@ #define cpp_lib_erase_if 202002L #endif - #if __has_include() #ifdef __cpp_lib_generic_unordered_lookup #define cpp_lib_generic_unordered_lookup __cpp_lib_generic_unordered_lookup @@ -1670,7 +1567,6 @@ #define cpp_lib_generic_unordered_lookup 201811L #endif - #if __has_include() #ifdef __cpp_lib_int_pow2 #define cpp_lib_int_pow2 __cpp_lib_int_pow2 @@ -1679,7 +1575,6 @@ #define cpp_lib_int_pow2 202002L #endif - #if __has_include() #ifdef __cpp_lib_integer_comparison_functions #define cpp_lib_integer_comparison_functions __cpp_lib_integer_comparison_functions @@ -1688,7 +1583,6 @@ #define cpp_lib_integer_comparison_functions 202002L #endif - #if __has_include() #ifdef __cpp_lib_interpolate #define cpp_lib_interpolate __cpp_lib_interpolate @@ -1697,7 +1591,6 @@ #define cpp_lib_interpolate 201902L #endif - #if __has_include() #ifdef __cpp_lib_is_constant_evaluated #define cpp_lib_is_constant_evaluated __cpp_lib_is_constant_evaluated @@ -1706,7 +1599,6 @@ #define cpp_lib_is_constant_evaluated 201811L #endif - #if __has_include() #ifdef __cpp_lib_is_layout_compatible #define cpp_lib_is_layout_compatible __cpp_lib_is_layout_compatible @@ -1715,7 +1607,6 @@ #define cpp_lib_is_layout_compatible 201907L #endif - #if __has_include() #ifdef __cpp_lib_is_nothrow_convertible #define cpp_lib_is_nothrow_convertible __cpp_lib_is_nothrow_convertible @@ -1724,7 +1615,6 @@ #define cpp_lib_is_nothrow_convertible 201806L #endif - #if __has_include() #ifdef __cpp_lib_is_pointer_interconvertible #define cpp_lib_is_pointer_interconvertible __cpp_lib_is_pointer_interconvertible @@ -1733,7 +1623,6 @@ #define cpp_lib_is_pointer_interconvertible 201907L #endif - #if __has_include() #ifdef __cpp_lib_jthread #define cpp_lib_jthread __cpp_lib_jthread @@ -1742,7 +1631,6 @@ #define cpp_lib_jthread 201911L #endif - #if __has_include() #ifdef __cpp_lib_latch #define cpp_lib_latch __cpp_lib_latch @@ -1751,7 +1639,6 @@ #define cpp_lib_latch 201907L #endif - #if __has_include() #ifdef __cpp_lib_list_remove_return_type #define cpp_lib_list_remove_return_type __cpp_lib_list_remove_return_type @@ -1760,7 +1647,6 @@ #define cpp_lib_list_remove_return_type 201806L #endif - #if __has_include() #ifdef __cpp_lib_math_constants #define cpp_lib_math_constants __cpp_lib_math_constants @@ -1769,7 +1655,6 @@ #define cpp_lib_math_constants 201907L #endif - #if __has_include() #ifdef __cpp_lib_polymorphic_allocator #define cpp_lib_polymorphic_allocator __cpp_lib_polymorphic_allocator @@ -1778,7 +1663,6 @@ #define cpp_lib_polymorphic_allocator 201902L #endif - #if __has_include() #ifdef __cpp_lib_ranges #define cpp_lib_ranges __cpp_lib_ranges @@ -1787,7 +1671,6 @@ #define cpp_lib_ranges 201811L #endif - #if __has_include() #ifdef __cpp_lib_remove_cvref #define cpp_lib_remove_cvref __cpp_lib_remove_cvref @@ -1796,7 +1679,6 @@ #define cpp_lib_remove_cvref 201711L #endif - #if __has_include() #ifdef __cpp_lib_semaphore #define cpp_lib_semaphore __cpp_lib_semaphore @@ -1805,7 +1687,6 @@ #define cpp_lib_semaphore 201907L #endif - #if __has_include() #ifdef __cpp_lib_shift #define cpp_lib_shift __cpp_lib_shift @@ -1814,7 +1695,6 @@ #define cpp_lib_shift 201806L #endif - #if __has_include() #ifdef __cpp_lib_smart_ptr_for_overwrite #define cpp_lib_smart_ptr_for_overwrite __cpp_lib_smart_ptr_for_overwrite @@ -1823,7 +1703,6 @@ #define cpp_lib_smart_ptr_for_overwrite 202002L #endif - #if __has_include() #ifdef __cpp_lib_source_location #define cpp_lib_source_location __cpp_lib_source_location @@ -1832,7 +1711,6 @@ #define cpp_lib_source_location 201907L #endif - #if __has_include() #ifdef __cpp_lib_span #define cpp_lib_span __cpp_lib_span @@ -1841,7 +1719,6 @@ #define cpp_lib_span 202002L #endif - #if __has_include() #ifdef __cpp_lib_ssize #define cpp_lib_ssize __cpp_lib_ssize @@ -1850,7 +1727,6 @@ #define cpp_lib_ssize 201902L #endif - #if __has_include() #ifdef __cpp_lib_starts_ends_with #define cpp_lib_starts_ends_with __cpp_lib_starts_ends_with @@ -1859,7 +1735,6 @@ #define cpp_lib_starts_ends_with 201711L #endif - #if __has_include() #ifdef __cpp_lib_syncbuf #define cpp_lib_syncbuf __cpp_lib_syncbuf @@ -1868,7 +1743,6 @@ #define cpp_lib_syncbuf 201803L #endif - #if __has_include() #ifdef __cpp_lib_three_way_comparison #define cpp_lib_three_way_comparison __cpp_lib_three_way_comparison @@ -1877,7 +1751,6 @@ #define cpp_lib_three_way_comparison 201907L #endif - #if __has_include() #ifdef __cpp_lib_to_address #define cpp_lib_to_address __cpp_lib_to_address @@ -1886,7 +1759,6 @@ #define cpp_lib_to_address 201711L #endif - #if __has_include() #ifdef __cpp_lib_to_array #define cpp_lib_to_array __cpp_lib_to_array @@ -1895,7 +1767,6 @@ #define cpp_lib_to_array 201907L #endif - #if __has_include() #ifdef __cpp_lib_unwrap_ref #define cpp_lib_unwrap_ref __cpp_lib_unwrap_ref @@ -1904,8 +1775,6 @@ #define cpp_lib_unwrap_ref 201811L #endif - - #if __has_include() #ifdef __cpp_lib_is_scoped_enum #define cpp_lib_is_scoped_enum __cpp_lib_is_scoped_enum @@ -1914,7 +1783,6 @@ #define cpp_lib_is_scoped_enum 202011L #endif - #if __has_include() #ifdef __cpp_lib_stacktrace #define cpp_lib_stacktrace __cpp_lib_stacktrace @@ -1923,7 +1791,6 @@ #define cpp_lib_stacktrace 202011L #endif - #if __has_include() #ifdef __cpp_lib_stdatomic_h #define cpp_lib_stdatomic_h __cpp_lib_stdatomic_h @@ -1932,7 +1799,6 @@ #define cpp_lib_stdatomic_h 202011L #endif - #if __has_include() #ifdef __cpp_lib_string_contains #define cpp_lib_string_contains __cpp_lib_string_contains @@ -1941,5 +1807,4 @@ #define cpp_lib_string_contains 202011L #endif - #endif // SMALL_DETAIL_TRAITS_CPP_VERSION_H diff --git a/source/small/detail/traits/default_inline_storage.h b/source/small/detail/traits/default_inline_storage.h index c93f1e1..ffd9adf 100644 --- a/source/small/detail/traits/default_inline_storage.h +++ b/source/small/detail/traits/default_inline_storage.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_DEFAULT_INLINE_STORAGE_H #define SMALL_DETAIL_TRAITS_DEFAULT_INLINE_STORAGE_H diff --git a/source/small/detail/traits/enable_allocator_from_this.h b/source/small/detail/traits/enable_allocator_from_this.h index b428bc9..b9e7299 100644 --- a/source/small/detail/traits/enable_allocator_from_this.h +++ b/source/small/detail/traits/enable_allocator_from_this.h @@ -5,43 +5,44 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_ENABLE_ALLOCATOR_FROM_THIS_H #define SMALL_DETAIL_TRAITS_ENABLE_ALLOCATOR_FROM_THIS_H namespace small { - /// \brief A class to enable empty base optimization for allocators - template class enable_allocator_from_this {}; - - /// \brief Store nothing when allocator is empty - template class enable_allocator_from_this { - public: - constexpr enable_allocator_from_this() = default; - constexpr explicit enable_allocator_from_this(const Allocator &) {} - constexpr Allocator get_allocator() const noexcept { return Allocator(); } - - protected: - constexpr void set_allocator(const Allocator &) const noexcept {} - constexpr void set_allocator(Allocator &&) const noexcept {} - constexpr void swap_allocator(Allocator &&) const noexcept {} - }; - - /// \brief Store allocator when allocator is not empty - template class enable_allocator_from_this { - public: - constexpr enable_allocator_from_this() : alloc_(Allocator()) {} - constexpr explicit enable_allocator_from_this(const Allocator &alloc) : alloc_(alloc) {} - constexpr Allocator get_allocator() const noexcept { return alloc_; } - - protected: - constexpr void set_allocator(const Allocator &alloc) const noexcept { alloc_ = alloc; } - constexpr void set_allocator(Allocator &&alloc) const noexcept { alloc_ = std::move(alloc); } - constexpr void swap_allocator(Allocator &&alloc) const noexcept { std::swap(alloc_, alloc); } - - private: - Allocator alloc_; - }; - + namespace detail { + /// \brief A class to enable empty base optimization for allocators + template class enable_allocator_from_this {}; + + /// \brief Store nothing when allocator is empty + template class enable_allocator_from_this { + public: + constexpr enable_allocator_from_this() = default; + constexpr explicit enable_allocator_from_this(const Allocator &) {} + constexpr Allocator get_allocator() const noexcept { return Allocator(); } + + protected: + constexpr void set_allocator(const Allocator &) const noexcept {} + constexpr void set_allocator(Allocator &&) const noexcept {} + constexpr void swap_allocator(Allocator &&) const noexcept {} + }; + + /// \brief Store allocator when allocator is not empty + template class enable_allocator_from_this { + public: + constexpr enable_allocator_from_this() : alloc_(Allocator()) {} + constexpr explicit enable_allocator_from_this(const Allocator &alloc) : alloc_(alloc) {} + constexpr Allocator get_allocator() const noexcept { return alloc_; } + + protected: + constexpr void set_allocator(const Allocator &alloc) const noexcept { alloc_ = alloc; } + constexpr void set_allocator(Allocator &&alloc) const noexcept { alloc_ = std::move(alloc); } + constexpr void swap_allocator(Allocator &&alloc) const noexcept { std::swap(alloc_, alloc); } + + private: + Allocator alloc_; + }; + + } // namespace detail } // namespace small #endif // SMALL_DETAIL_TRAITS_ENABLE_ALLOCATOR_FROM_THIS_H diff --git a/source/small/detail/traits/extract_value_type.h b/source/small/detail/traits/extract_value_type.h index 2bb708c..26a1650 100644 --- a/source/small/detail/traits/extract_value_type.h +++ b/source/small/detail/traits/extract_value_type.h @@ -5,20 +5,21 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_EXTRACT_VALUE_TYPE_H #define SMALL_DETAIL_TRAITS_EXTRACT_VALUE_TYPE_H namespace small { - /// \struct Get value type from T, if present - template struct extract_value_type { using type = void; }; + namespace detail { + /// \struct Get value type from T, if present + template struct extract_value_type { using type = void; }; - template struct extract_value_type> { - using type = typename T::value_type; - }; + template struct extract_value_type> { + using type = typename T::value_type; + }; - template using extract_value_type_t = typename extract_value_type::type; + template using extract_value_type_t = typename extract_value_type::type; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_TRAITS_EXTRACT_VALUE_TYPE_H diff --git a/source/small/detail/traits/has_allocator.h b/source/small/detail/traits/has_allocator.h index 41765aa..c1bb979 100644 --- a/source/small/detail/traits/has_allocator.h +++ b/source/small/detail/traits/has_allocator.h @@ -5,20 +5,21 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_HAS_ALLOCATOR_H #define SMALL_DETAIL_TRAITS_HAS_ALLOCATOR_H namespace small { - /// Check if type has an associated allocator type - template struct has_allocator : std::false_type {}; + namespace detail { + /// Check if type has an associated allocator type + template struct has_allocator : std::false_type {}; - template - struct has_allocator().get_allocator()), typename T::allocator_type>> - : std::true_type {}; + template + struct has_allocator().get_allocator()), typename T::allocator_type>> + : std::true_type {}; - template static constexpr bool has_allocator_v = has_allocator::value; + template static constexpr bool has_allocator_v = has_allocator::value; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_TRAITS_HAS_ALLOCATOR_H diff --git a/source/small/detail/traits/hedley.h b/source/small/detail/traits/hedley.h index bcb62a0..a4a69d2 100644 --- a/source/small/detail/traits/hedley.h +++ b/source/small/detail/traits/hedley.h @@ -12,2030 +12,1812 @@ #if !defined(HEDLEY_VERSION) || (HEDLEY_VERSION < 15) #if defined(HEDLEY_VERSION) -# undef HEDLEY_VERSION +#undef HEDLEY_VERSION #endif #define HEDLEY_VERSION 15 #if defined(HEDLEY_STRINGIFY_EX) -# undef HEDLEY_STRINGIFY_EX +#undef HEDLEY_STRINGIFY_EX #endif #define HEDLEY_STRINGIFY_EX(x) #x #if defined(HEDLEY_STRINGIFY) -# undef HEDLEY_STRINGIFY +#undef HEDLEY_STRINGIFY #endif #define HEDLEY_STRINGIFY(x) HEDLEY_STRINGIFY_EX(x) #if defined(HEDLEY_CONCAT_EX) -# undef HEDLEY_CONCAT_EX +#undef HEDLEY_CONCAT_EX #endif -#define HEDLEY_CONCAT_EX(a,b) a##b +#define HEDLEY_CONCAT_EX(a, b) a##b #if defined(HEDLEY_CONCAT) -# undef HEDLEY_CONCAT +#undef HEDLEY_CONCAT #endif -#define HEDLEY_CONCAT(a,b) HEDLEY_CONCAT_EX(a,b) +#define HEDLEY_CONCAT(a, b) HEDLEY_CONCAT_EX(a, b) #if defined(HEDLEY_CONCAT3_EX) -# undef HEDLEY_CONCAT3_EX +#undef HEDLEY_CONCAT3_EX #endif -#define HEDLEY_CONCAT3_EX(a,b,c) a##b##c +#define HEDLEY_CONCAT3_EX(a, b, c) a##b##c #if defined(HEDLEY_CONCAT3) -# undef HEDLEY_CONCAT3 +#undef HEDLEY_CONCAT3 #endif -#define HEDLEY_CONCAT3(a,b,c) HEDLEY_CONCAT3_EX(a,b,c) +#define HEDLEY_CONCAT3(a, b, c) HEDLEY_CONCAT3_EX(a, b, c) #if defined(HEDLEY_VERSION_ENCODE) -# undef HEDLEY_VERSION_ENCODE +#undef HEDLEY_VERSION_ENCODE #endif -#define HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) +#define HEDLEY_VERSION_ENCODE(major, minor, revision) (((major)*1000000) + ((minor)*1000) + (revision)) #if defined(HEDLEY_VERSION_DECODE_MAJOR) -# undef HEDLEY_VERSION_DECODE_MAJOR +#undef HEDLEY_VERSION_DECODE_MAJOR #endif #define HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) #if defined(HEDLEY_VERSION_DECODE_MINOR) -# undef HEDLEY_VERSION_DECODE_MINOR +#undef HEDLEY_VERSION_DECODE_MINOR #endif #define HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) #if defined(HEDLEY_VERSION_DECODE_REVISION) -# undef HEDLEY_VERSION_DECODE_REVISION +#undef HEDLEY_VERSION_DECODE_REVISION #endif #define HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) #if defined(HEDLEY_GNUC_VERSION) -# undef HEDLEY_GNUC_VERSION +#undef HEDLEY_GNUC_VERSION #endif #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) -# define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #elif defined(__GNUC__) -# define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) #endif #if defined(HEDLEY_GNUC_VERSION_CHECK) -# undef HEDLEY_GNUC_VERSION_CHECK +#undef HEDLEY_GNUC_VERSION_CHECK #endif #if defined(HEDLEY_GNUC_VERSION) -# define HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (HEDLEY_GNUC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_GNUC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_MSVC_VERSION) -# undef HEDLEY_MSVC_VERSION +#undef HEDLEY_MSVC_VERSION #endif #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) -# define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#define HEDLEY_MSVC_VERSION \ + HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) #elif defined(_MSC_FULL_VER) && !defined(__ICL) -# define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#define HEDLEY_MSVC_VERSION \ + HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) #elif defined(_MSC_VER) && !defined(__ICL) -# define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) #endif #if defined(HEDLEY_MSVC_VERSION_CHECK) -# undef HEDLEY_MSVC_VERSION_CHECK +#undef HEDLEY_MSVC_VERSION_CHECK #endif #if !defined(HEDLEY_MSVC_VERSION) -# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (0) #elif defined(_MSC_VER) && (_MSC_VER >= 1400) -# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) #elif defined(_MSC_VER) && (_MSC_VER >= 1200) -# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) #else -# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (_MSC_VER >= ((major * 100) + (minor))) #endif #if defined(HEDLEY_INTEL_VERSION) -# undef HEDLEY_INTEL_VERSION +#undef HEDLEY_INTEL_VERSION #endif #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) -# define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#define HEDLEY_INTEL_VERSION \ + HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) #elif defined(__INTEL_COMPILER) && !defined(__ICL) -# define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) #endif #if defined(HEDLEY_INTEL_VERSION_CHECK) -# undef HEDLEY_INTEL_VERSION_CHECK +#undef HEDLEY_INTEL_VERSION_CHECK #endif #if defined(HEDLEY_INTEL_VERSION) -# define HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (HEDLEY_INTEL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_INTEL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_INTEL_CL_VERSION) -# undef HEDLEY_INTEL_CL_VERSION +#undef HEDLEY_INTEL_CL_VERSION #endif #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) -# define HEDLEY_INTEL_CL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#define HEDLEY_INTEL_CL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) #endif #if defined(HEDLEY_INTEL_CL_VERSION_CHECK) -# undef HEDLEY_INTEL_CL_VERSION_CHECK +#undef HEDLEY_INTEL_CL_VERSION_CHECK #endif #if defined(HEDLEY_INTEL_CL_VERSION) -# define HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (HEDLEY_INTEL_CL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_INTEL_CL_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_INTEL_CL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_INTEL_CL_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_PGI_VERSION) -# undef HEDLEY_PGI_VERSION +#undef HEDLEY_PGI_VERSION #endif #if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) -# define HEDLEY_PGI_VERSION HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#define HEDLEY_PGI_VERSION HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) #endif #if defined(HEDLEY_PGI_VERSION_CHECK) -# undef HEDLEY_PGI_VERSION_CHECK +#undef HEDLEY_PGI_VERSION_CHECK #endif #if defined(HEDLEY_PGI_VERSION) -# define HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (HEDLEY_PGI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_PGI_VERSION_CHECK(major, minor, patch) (HEDLEY_PGI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_PGI_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_SUNPRO_VERSION) -# undef HEDLEY_SUNPRO_VERSION +#undef HEDLEY_SUNPRO_VERSION #endif #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) -# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#define HEDLEY_SUNPRO_VERSION \ + HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \ + (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) #elif defined(__SUNPRO_C) -# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C)&0xf) #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) -# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#define HEDLEY_SUNPRO_VERSION \ + HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \ + (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) #elif defined(__SUNPRO_CC) -# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#define HEDLEY_SUNPRO_VERSION \ + HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC)&0xf) #endif #if defined(HEDLEY_SUNPRO_VERSION_CHECK) -# undef HEDLEY_SUNPRO_VERSION_CHECK +#undef HEDLEY_SUNPRO_VERSION_CHECK #endif #if defined(HEDLEY_SUNPRO_VERSION) -# define HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (HEDLEY_SUNPRO_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_SUNPRO_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_EMSCRIPTEN_VERSION) -# undef HEDLEY_EMSCRIPTEN_VERSION +#undef HEDLEY_EMSCRIPTEN_VERSION #endif #if defined(__EMSCRIPTEN__) -# define HEDLEY_EMSCRIPTEN_VERSION HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#define HEDLEY_EMSCRIPTEN_VERSION HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) #endif #if defined(HEDLEY_EMSCRIPTEN_VERSION_CHECK) -# undef HEDLEY_EMSCRIPTEN_VERSION_CHECK +#undef HEDLEY_EMSCRIPTEN_VERSION_CHECK #endif #if defined(HEDLEY_EMSCRIPTEN_VERSION) -# define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (HEDLEY_EMSCRIPTEN_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_EMSCRIPTEN_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_ARM_VERSION) -# undef HEDLEY_ARM_VERSION +#undef HEDLEY_ARM_VERSION #endif #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) -# define HEDLEY_ARM_VERSION HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#define HEDLEY_ARM_VERSION \ + HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, \ + (__ARMCOMPILER_VERSION % 10000) / 100) #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) -# define HEDLEY_ARM_VERSION HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#define HEDLEY_ARM_VERSION \ + HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, \ + (__ARMCC_VERSION % 10000) / 100) #endif #if defined(HEDLEY_ARM_VERSION_CHECK) -# undef HEDLEY_ARM_VERSION_CHECK +#undef HEDLEY_ARM_VERSION_CHECK #endif #if defined(HEDLEY_ARM_VERSION) -# define HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (HEDLEY_ARM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_ARM_VERSION_CHECK(major, minor, patch) (HEDLEY_ARM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_ARM_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_IBM_VERSION) -# undef HEDLEY_IBM_VERSION +#undef HEDLEY_IBM_VERSION #endif #if defined(__ibmxl__) -# define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) #elif defined(__xlC__) && defined(__xlC_ver__) -# define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) #elif defined(__xlC__) -# define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) #endif #if defined(HEDLEY_IBM_VERSION_CHECK) -# undef HEDLEY_IBM_VERSION_CHECK +#undef HEDLEY_IBM_VERSION_CHECK #endif #if defined(HEDLEY_IBM_VERSION) -# define HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (HEDLEY_IBM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_IBM_VERSION_CHECK(major, minor, patch) (HEDLEY_IBM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_IBM_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TI_VERSION) -# undef HEDLEY_TI_VERSION +#undef HEDLEY_TI_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && \ + (defined(__TMS470__) || defined(__TI_ARM__) || defined(__MSP430__) || defined(__TMS320C2000__)) +#if (__TI_COMPILER_VERSION__ >= 16000000) +#define HEDLEY_TI_VERSION \ + HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) #endif -#if \ -defined(__TI_COMPILER_VERSION__) && \ -( \ -defined(__TMS470__) || defined(__TI_ARM__) || \ -defined(__MSP430__) || \ -defined(__TMS320C2000__) \ -) -# if (__TI_COMPILER_VERSION__ >= 16000000) -# define HEDLEY_TI_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -# endif #endif #if defined(HEDLEY_TI_VERSION_CHECK) -# undef HEDLEY_TI_VERSION_CHECK +#undef HEDLEY_TI_VERSION_CHECK #endif #if defined(HEDLEY_TI_VERSION) -# define HEDLEY_TI_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TI_VERSION_CHECK(major, minor, patch) (HEDLEY_TI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TI_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TI_CL2000_VERSION) -# undef HEDLEY_TI_CL2000_VERSION +#undef HEDLEY_TI_CL2000_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) -# define HEDLEY_TI_CL2000_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#define HEDLEY_TI_CL2000_VERSION \ + HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(HEDLEY_TI_CL2000_VERSION_CHECK) -# undef HEDLEY_TI_CL2000_VERSION_CHECK +#undef HEDLEY_TI_CL2000_VERSION_CHECK #endif #if defined(HEDLEY_TI_CL2000_VERSION) -# define HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_CL2000_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TI_CL2000_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_TI_CL2000_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TI_CL2000_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TI_CL430_VERSION) -# undef HEDLEY_TI_CL430_VERSION +#undef HEDLEY_TI_CL430_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) -# define HEDLEY_TI_CL430_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#define HEDLEY_TI_CL430_VERSION \ + HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(HEDLEY_TI_CL430_VERSION_CHECK) -# undef HEDLEY_TI_CL430_VERSION_CHECK +#undef HEDLEY_TI_CL430_VERSION_CHECK #endif #if defined(HEDLEY_TI_CL430_VERSION) -# define HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_CL430_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TI_CL430_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_TI_CL430_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TI_CL430_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TI_ARMCL_VERSION) -# undef HEDLEY_TI_ARMCL_VERSION +#undef HEDLEY_TI_ARMCL_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) -# define HEDLEY_TI_ARMCL_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#define HEDLEY_TI_ARMCL_VERSION \ + HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(HEDLEY_TI_ARMCL_VERSION_CHECK) -# undef HEDLEY_TI_ARMCL_VERSION_CHECK +#undef HEDLEY_TI_ARMCL_VERSION_CHECK #endif #if defined(HEDLEY_TI_ARMCL_VERSION) -# define HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_ARMCL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TI_ARMCL_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_TI_ARMCL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TI_ARMCL_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TI_CL6X_VERSION) -# undef HEDLEY_TI_CL6X_VERSION +#undef HEDLEY_TI_CL6X_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) -# define HEDLEY_TI_CL6X_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#define HEDLEY_TI_CL6X_VERSION \ + HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(HEDLEY_TI_CL6X_VERSION_CHECK) -# undef HEDLEY_TI_CL6X_VERSION_CHECK +#undef HEDLEY_TI_CL6X_VERSION_CHECK #endif #if defined(HEDLEY_TI_CL6X_VERSION) -# define HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_CL6X_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TI_CL6X_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_TI_CL6X_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TI_CL6X_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TI_CL7X_VERSION) -# undef HEDLEY_TI_CL7X_VERSION +#undef HEDLEY_TI_CL7X_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) -# define HEDLEY_TI_CL7X_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#define HEDLEY_TI_CL7X_VERSION \ + HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(HEDLEY_TI_CL7X_VERSION_CHECK) -# undef HEDLEY_TI_CL7X_VERSION_CHECK +#undef HEDLEY_TI_CL7X_VERSION_CHECK #endif #if defined(HEDLEY_TI_CL7X_VERSION) -# define HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_CL7X_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TI_CL7X_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_TI_CL7X_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TI_CL7X_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TI_CLPRU_VERSION) -# undef HEDLEY_TI_CLPRU_VERSION +#undef HEDLEY_TI_CLPRU_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) -# define HEDLEY_TI_CLPRU_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#define HEDLEY_TI_CLPRU_VERSION \ + HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(HEDLEY_TI_CLPRU_VERSION_CHECK) -# undef HEDLEY_TI_CLPRU_VERSION_CHECK +#undef HEDLEY_TI_CLPRU_VERSION_CHECK #endif #if defined(HEDLEY_TI_CLPRU_VERSION) -# define HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_CLPRU_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TI_CLPRU_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_TI_CLPRU_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TI_CLPRU_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_CRAY_VERSION) -# undef HEDLEY_CRAY_VERSION +#undef HEDLEY_CRAY_VERSION #endif #if defined(_CRAYC) -# if defined(_RELEASE_PATCHLEVEL) -# define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) -# else -# define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) -# endif +#if defined(_RELEASE_PATCHLEVEL) +#define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) +#else +#define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) +#endif #endif #if defined(HEDLEY_CRAY_VERSION_CHECK) -# undef HEDLEY_CRAY_VERSION_CHECK +#undef HEDLEY_CRAY_VERSION_CHECK #endif #if defined(HEDLEY_CRAY_VERSION) -# define HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (HEDLEY_CRAY_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_CRAY_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_IAR_VERSION) -# undef HEDLEY_IAR_VERSION +#undef HEDLEY_IAR_VERSION #endif #if defined(__IAR_SYSTEMS_ICC__) -# if __VER__ > 1000 -# define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) -# else -# define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) -# endif +#if __VER__ > 1000 +#define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) +#else +#define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) +#endif #endif #if defined(HEDLEY_IAR_VERSION_CHECK) -# undef HEDLEY_IAR_VERSION_CHECK +#undef HEDLEY_IAR_VERSION_CHECK #endif #if defined(HEDLEY_IAR_VERSION) -# define HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (HEDLEY_IAR_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_IAR_VERSION_CHECK(major, minor, patch) (HEDLEY_IAR_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_IAR_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TINYC_VERSION) -# undef HEDLEY_TINYC_VERSION +#undef HEDLEY_TINYC_VERSION #endif #if defined(__TINYC__) -# define HEDLEY_TINYC_VERSION HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#define HEDLEY_TINYC_VERSION HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) #endif #if defined(HEDLEY_TINYC_VERSION_CHECK) -# undef HEDLEY_TINYC_VERSION_CHECK +#undef HEDLEY_TINYC_VERSION_CHECK #endif #if defined(HEDLEY_TINYC_VERSION) -# define HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (HEDLEY_TINYC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_TINYC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_DMC_VERSION) -# undef HEDLEY_DMC_VERSION +#undef HEDLEY_DMC_VERSION #endif #if defined(__DMC__) -# define HEDLEY_DMC_VERSION HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#define HEDLEY_DMC_VERSION HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) #endif #if defined(HEDLEY_DMC_VERSION_CHECK) -# undef HEDLEY_DMC_VERSION_CHECK +#undef HEDLEY_DMC_VERSION_CHECK #endif #if defined(HEDLEY_DMC_VERSION) -# define HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (HEDLEY_DMC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_DMC_VERSION_CHECK(major, minor, patch) (HEDLEY_DMC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_DMC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_COMPCERT_VERSION) -# undef HEDLEY_COMPCERT_VERSION +#undef HEDLEY_COMPCERT_VERSION #endif #if defined(__COMPCERT_VERSION__) -# define HEDLEY_COMPCERT_VERSION HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#define HEDLEY_COMPCERT_VERSION \ + HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) #endif #if defined(HEDLEY_COMPCERT_VERSION_CHECK) -# undef HEDLEY_COMPCERT_VERSION_CHECK +#undef HEDLEY_COMPCERT_VERSION_CHECK #endif #if defined(HEDLEY_COMPCERT_VERSION) -# define HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (HEDLEY_COMPCERT_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_COMPCERT_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_PELLES_VERSION) -# undef HEDLEY_PELLES_VERSION +#undef HEDLEY_PELLES_VERSION #endif #if defined(__POCC__) -# define HEDLEY_PELLES_VERSION HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#define HEDLEY_PELLES_VERSION HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) #endif #if defined(HEDLEY_PELLES_VERSION_CHECK) -# undef HEDLEY_PELLES_VERSION_CHECK +#undef HEDLEY_PELLES_VERSION_CHECK #endif #if defined(HEDLEY_PELLES_VERSION) -# define HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (HEDLEY_PELLES_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_PELLES_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_MCST_LCC_VERSION) -# undef HEDLEY_MCST_LCC_VERSION +#undef HEDLEY_MCST_LCC_VERSION #endif #if defined(__LCC__) && defined(__LCC_MINOR__) -# define HEDLEY_MCST_LCC_VERSION HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#define HEDLEY_MCST_LCC_VERSION HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) #endif #if defined(HEDLEY_MCST_LCC_VERSION_CHECK) -# undef HEDLEY_MCST_LCC_VERSION_CHECK +#undef HEDLEY_MCST_LCC_VERSION_CHECK #endif #if defined(HEDLEY_MCST_LCC_VERSION) -# define HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (HEDLEY_MCST_LCC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_MCST_LCC_VERSION_CHECK(major, minor, patch) \ + (HEDLEY_MCST_LCC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_MCST_LCC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_GCC_VERSION) -# undef HEDLEY_GCC_VERSION -#endif -#if \ -defined(HEDLEY_GNUC_VERSION) && \ -!defined(__clang__) && \ -!defined(HEDLEY_INTEL_VERSION) && \ -!defined(HEDLEY_PGI_VERSION) && \ -!defined(HEDLEY_ARM_VERSION) && \ -!defined(HEDLEY_CRAY_VERSION) && \ -!defined(HEDLEY_TI_VERSION) && \ -!defined(HEDLEY_TI_ARMCL_VERSION) && \ -!defined(HEDLEY_TI_CL430_VERSION) && \ -!defined(HEDLEY_TI_CL2000_VERSION) && \ -!defined(HEDLEY_TI_CL6X_VERSION) && \ -!defined(HEDLEY_TI_CL7X_VERSION) && \ -!defined(HEDLEY_TI_CLPRU_VERSION) && \ -!defined(__COMPCERT__) && \ -!defined(HEDLEY_MCST_LCC_VERSION) -# define HEDLEY_GCC_VERSION HEDLEY_GNUC_VERSION +#undef HEDLEY_GCC_VERSION +#endif +#if defined(HEDLEY_GNUC_VERSION) && !defined(__clang__) && !defined(HEDLEY_INTEL_VERSION) && \ + !defined(HEDLEY_PGI_VERSION) && !defined(HEDLEY_ARM_VERSION) && !defined(HEDLEY_CRAY_VERSION) && \ + !defined(HEDLEY_TI_VERSION) && !defined(HEDLEY_TI_ARMCL_VERSION) && !defined(HEDLEY_TI_CL430_VERSION) && \ + !defined(HEDLEY_TI_CL2000_VERSION) && !defined(HEDLEY_TI_CL6X_VERSION) && !defined(HEDLEY_TI_CL7X_VERSION) && \ + !defined(HEDLEY_TI_CLPRU_VERSION) && !defined(__COMPCERT__) && !defined(HEDLEY_MCST_LCC_VERSION) +#define HEDLEY_GCC_VERSION HEDLEY_GNUC_VERSION #endif #if defined(HEDLEY_GCC_VERSION_CHECK) -# undef HEDLEY_GCC_VERSION_CHECK +#undef HEDLEY_GCC_VERSION_CHECK #endif #if defined(HEDLEY_GCC_VERSION) -# define HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (HEDLEY_GCC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_GCC_VERSION_CHECK(major, minor, patch) (HEDLEY_GCC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_GCC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_HAS_ATTRIBUTE) -# undef HEDLEY_HAS_ATTRIBUTE +#undef HEDLEY_HAS_ATTRIBUTE #endif -#if \ -defined(__has_attribute) && \ -( \ -(!defined(HEDLEY_IAR_VERSION) || HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ -) -# define HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#if defined(__has_attribute) && ((!defined(HEDLEY_IAR_VERSION) || HEDLEY_IAR_VERSION_CHECK(8, 5, 9))) +#define HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) #else -# define HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#define HEDLEY_HAS_ATTRIBUTE(attribute) (0) #endif #if defined(HEDLEY_GNUC_HAS_ATTRIBUTE) -# undef HEDLEY_GNUC_HAS_ATTRIBUTE +#undef HEDLEY_GNUC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) -# define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_HAS_ATTRIBUTE(attribute) +#define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_HAS_ATTRIBUTE(attribute) #else -# define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_ATTRIBUTE) -# undef HEDLEY_GCC_HAS_ATTRIBUTE +#undef HEDLEY_GCC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) -# define HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_HAS_ATTRIBUTE(attribute) +#define HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_HAS_ATTRIBUTE(attribute) #else -# define HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_CPP_ATTRIBUTE) -# undef HEDLEY_HAS_CPP_ATTRIBUTE +#undef HEDLEY_HAS_CPP_ATTRIBUTE #endif -#if \ -defined(__has_cpp_attribute) && \ -defined(__cplusplus) && \ -(!defined(HEDLEY_SUNPRO_VERSION) || HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) -# define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#if defined(__has_cpp_attribute) && defined(__cplusplus) && \ + (!defined(HEDLEY_SUNPRO_VERSION) || HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0)) +#define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) #else -# define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) #endif #if defined(HEDLEY_HAS_CPP_ATTRIBUTE_NS) -# undef HEDLEY_HAS_CPP_ATTRIBUTE_NS +#undef HEDLEY_HAS_CPP_ATTRIBUTE_NS #endif #if !defined(__cplusplus) || !defined(__has_cpp_attribute) -# define HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) -#elif \ -!defined(HEDLEY_PGI_VERSION) && \ -!defined(HEDLEY_IAR_VERSION) && \ -(!defined(HEDLEY_SUNPRO_VERSION) || HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ -(!defined(HEDLEY_MSVC_VERSION) || HEDLEY_MSVC_VERSION_CHECK(19,20,0)) -# define HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#define HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns, attribute) (0) +#elif !defined(HEDLEY_PGI_VERSION) && !defined(HEDLEY_IAR_VERSION) && \ + (!defined(HEDLEY_SUNPRO_VERSION) || HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0)) && \ + (!defined(HEDLEY_MSVC_VERSION) || HEDLEY_MSVC_VERSION_CHECK(19, 20, 0)) +#define HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns, attribute) HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) #else -# define HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#define HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns, attribute) (0) #endif #if defined(HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) -# undef HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#undef HEDLEY_GNUC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) -# define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) __has_cpp_attribute(attribute) #else -# define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_CPP_ATTRIBUTE) -# undef HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#undef HEDLEY_GCC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) -# define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) __has_cpp_attribute(attribute) #else -# define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_BUILTIN) -# undef HEDLEY_HAS_BUILTIN +#undef HEDLEY_HAS_BUILTIN #endif #if defined(__has_builtin) -# define HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#define HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) #else -# define HEDLEY_HAS_BUILTIN(builtin) (0) +#define HEDLEY_HAS_BUILTIN(builtin) (0) #endif #if defined(HEDLEY_GNUC_HAS_BUILTIN) -# undef HEDLEY_GNUC_HAS_BUILTIN +#undef HEDLEY_GNUC_HAS_BUILTIN #endif #if defined(__has_builtin) -# define HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#define HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) __has_builtin(builtin) #else -# define HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_BUILTIN) -# undef HEDLEY_GCC_HAS_BUILTIN +#undef HEDLEY_GCC_HAS_BUILTIN #endif #if defined(__has_builtin) -# define HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#define HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) __has_builtin(builtin) #else -# define HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_FEATURE) -# undef HEDLEY_HAS_FEATURE +#undef HEDLEY_HAS_FEATURE #endif #if defined(__has_feature) -# define HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#define HEDLEY_HAS_FEATURE(feature) __has_feature(feature) #else -# define HEDLEY_HAS_FEATURE(feature) (0) +#define HEDLEY_HAS_FEATURE(feature) (0) #endif #if defined(HEDLEY_GNUC_HAS_FEATURE) -# undef HEDLEY_GNUC_HAS_FEATURE +#undef HEDLEY_GNUC_HAS_FEATURE #endif #if defined(__has_feature) -# define HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#define HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) __has_feature(feature) #else -# define HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_FEATURE) -# undef HEDLEY_GCC_HAS_FEATURE +#undef HEDLEY_GCC_HAS_FEATURE #endif #if defined(__has_feature) -# define HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#define HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) __has_feature(feature) #else -# define HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_EXTENSION) -# undef HEDLEY_HAS_EXTENSION +#undef HEDLEY_HAS_EXTENSION #endif #if defined(__has_extension) -# define HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#define HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) #else -# define HEDLEY_HAS_EXTENSION(extension) (0) +#define HEDLEY_HAS_EXTENSION(extension) (0) #endif #if defined(HEDLEY_GNUC_HAS_EXTENSION) -# undef HEDLEY_GNUC_HAS_EXTENSION +#undef HEDLEY_GNUC_HAS_EXTENSION #endif #if defined(__has_extension) -# define HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#define HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) __has_extension(extension) #else -# define HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_EXTENSION) -# undef HEDLEY_GCC_HAS_EXTENSION +#undef HEDLEY_GCC_HAS_EXTENSION #endif #if defined(__has_extension) -# define HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#define HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) __has_extension(extension) #else -# define HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_DECLSPEC_ATTRIBUTE) -# undef HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#undef HEDLEY_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) -# define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) #else -# define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) #endif #if defined(HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) -# undef HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#undef HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) -# define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) __has_declspec_attribute(attribute) #else -# define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) \ + HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) -# undef HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#undef HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) -# define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) __has_declspec_attribute(attribute) #else -# define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_WARNING) -# undef HEDLEY_HAS_WARNING +#undef HEDLEY_HAS_WARNING #endif #if defined(__has_warning) -# define HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#define HEDLEY_HAS_WARNING(warning) __has_warning(warning) #else -# define HEDLEY_HAS_WARNING(warning) (0) +#define HEDLEY_HAS_WARNING(warning) (0) #endif #if defined(HEDLEY_GNUC_HAS_WARNING) -# undef HEDLEY_GNUC_HAS_WARNING +#undef HEDLEY_GNUC_HAS_WARNING #endif #if defined(__has_warning) -# define HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#define HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) __has_warning(warning) #else -# define HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_WARNING) -# undef HEDLEY_GCC_HAS_WARNING +#undef HEDLEY_GCC_HAS_WARNING #endif #if defined(__has_warning) -# define HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) -#else -# define HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if \ -(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ -defined(__clang__) || \ -HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ -HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ -HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ -HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ -HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ -(HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) -# define HEDLEY_PRAGMA(value) _Pragma(#value) -#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) -# define HEDLEY_PRAGMA(value) __pragma(value) -#else -# define HEDLEY_PRAGMA(value) +#define HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) __has_warning(warning) +#else +#define HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__clang__) || \ + HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || \ + HEDLEY_PGI_VERSION_CHECK(18, 4, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(4, 7, 0) || HEDLEY_TI_CL430_VERSION_CHECK(2, 0, 1) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 1, 0) || HEDLEY_TI_CL6X_VERSION_CHECK(7, 0, 0) || \ + HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) || HEDLEY_TINYC_VERSION_CHECK(0, 9, 17) || \ + HEDLEY_SUNPRO_VERSION_CHECK(8, 0, 0) || (HEDLEY_IBM_VERSION_CHECK(10, 1, 0) && defined(__C99_PRAGMA_OPERATOR)) +#define HEDLEY_PRAGMA(value) _Pragma(#value) +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define HEDLEY_PRAGMA(value) __pragma(value) +#else +#define HEDLEY_PRAGMA(value) #endif #if defined(HEDLEY_DIAGNOSTIC_PUSH) -# undef HEDLEY_DIAGNOSTIC_PUSH +#undef HEDLEY_DIAGNOSTIC_PUSH #endif #if defined(HEDLEY_DIAGNOSTIC_POP) -# undef HEDLEY_DIAGNOSTIC_POP +#undef HEDLEY_DIAGNOSTIC_POP #endif #if defined(__clang__) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") -#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#elif HEDLEY_GCC_VERSION_CHECK(4,6,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") -#elif \ -HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) -# define HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) -#elif HEDLEY_ARM_VERSION_CHECK(5,6,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("pop") -#elif \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") -#elif HEDLEY_PELLES_VERSION_CHECK(2,90,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#else -# define HEDLEY_DIAGNOSTIC_PUSH -# define HEDLEY_DIAGNOSTIC_POP +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif HEDLEY_GCC_VERSION_CHECK(4, 6, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) +#define HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif HEDLEY_ARM_VERSION_CHECK(5, 6, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif HEDLEY_TI_VERSION_CHECK(15, 12, 0) || HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 4, 0) || HEDLEY_TI_CL6X_VERSION_CHECK(8, 1, 0) || \ + HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else +#define HEDLEY_DIAGNOSTIC_PUSH +#define HEDLEY_DIAGNOSTIC_POP #endif /* HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) -# undef HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#undef HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ #endif #if defined(__cplusplus) -# if HEDLEY_HAS_WARNING("-Wc++98-compat") -# if HEDLEY_HAS_WARNING("-Wc++17-extensions") -# if HEDLEY_HAS_WARNING("-Wc++1z-extensions") -# define HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ -HEDLEY_DIAGNOSTIC_PUSH \ -_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ -_Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ -_Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ -xpr \ -HEDLEY_DIAGNOSTIC_POP -# else -# define HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ -HEDLEY_DIAGNOSTIC_PUSH \ -_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ -_Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ -xpr \ -HEDLEY_DIAGNOSTIC_POP -# endif -# else -# define HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ -HEDLEY_DIAGNOSTIC_PUSH \ -_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ -xpr \ -HEDLEY_DIAGNOSTIC_POP -# endif -# endif +#if HEDLEY_HAS_WARNING("-Wc++98-compat") +#if HEDLEY_HAS_WARNING("-Wc++17-extensions") +#if HEDLEY_HAS_WARNING("-Wc++1z-extensions") +#define HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") xpr HEDLEY_DIAGNOSTIC_POP +#else +#define HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr HEDLEY_DIAGNOSTIC_POP +#endif +#else +#define HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") xpr HEDLEY_DIAGNOSTIC_POP +#endif +#endif #endif #if !defined(HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) -# define HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#define HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x #endif #if defined(HEDLEY_CONST_CAST) -# undef HEDLEY_CONST_CAST +#undef HEDLEY_CONST_CAST #endif #if defined(__cplusplus) -# define HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) -#elif \ -HEDLEY_HAS_WARNING("-Wcast-qual") || \ -HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ -HEDLEY_DIAGNOSTIC_PUSH \ -HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ -((T) (expr)); \ -HEDLEY_DIAGNOSTIC_POP \ -})) +#define HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif HEDLEY_HAS_WARNING("-Wcast-qual") || HEDLEY_GCC_VERSION_CHECK(4, 6, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_CONST_CAST(T, expr) \ + (__extension__({ \ + HEDLEY_DIAGNOSTIC_PUSH \ + HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL((T)(expr)); \ + HEDLEY_DIAGNOSTIC_POP \ + })) #else -# define HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#define HEDLEY_CONST_CAST(T, expr) ((T)(expr)) #endif #if defined(HEDLEY_REINTERPRET_CAST) -# undef HEDLEY_REINTERPRET_CAST +#undef HEDLEY_REINTERPRET_CAST #endif #if defined(__cplusplus) -# define HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#define HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) #else -# define HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#define HEDLEY_REINTERPRET_CAST(T, expr) ((T)(expr)) #endif #if defined(HEDLEY_STATIC_CAST) -# undef HEDLEY_STATIC_CAST +#undef HEDLEY_STATIC_CAST #endif #if defined(__cplusplus) -# define HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#define HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) #else -# define HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#define HEDLEY_STATIC_CAST(T, expr) ((T)(expr)) #endif #if defined(HEDLEY_CPP_CAST) -# undef HEDLEY_CPP_CAST +#undef HEDLEY_CPP_CAST #endif #if defined(__cplusplus) -# if HEDLEY_HAS_WARNING("-Wold-style-cast") -# define HEDLEY_CPP_CAST(T, expr) \ -HEDLEY_DIAGNOSTIC_PUSH \ -_Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ -((T) (expr)) \ -HEDLEY_DIAGNOSTIC_POP -# elif HEDLEY_IAR_VERSION_CHECK(8,3,0) -# define HEDLEY_CPP_CAST(T, expr) \ -HEDLEY_DIAGNOSTIC_PUSH \ -_Pragma("diag_suppress=Pe137") \ -HEDLEY_DIAGNOSTIC_POP -# else -# define HEDLEY_CPP_CAST(T, expr) ((T) (expr)) -# endif +#if HEDLEY_HAS_WARNING("-Wold-style-cast") +#define HEDLEY_CPP_CAST(T, expr) \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"")((T)(expr)) HEDLEY_DIAGNOSTIC_POP +#elif HEDLEY_IAR_VERSION_CHECK(8, 3, 0) +#define HEDLEY_CPP_CAST(T, expr) \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") HEDLEY_DIAGNOSTIC_POP +#else +#define HEDLEY_CPP_CAST(T, expr) ((T)(expr)) +#endif #else -# define HEDLEY_CPP_CAST(T, expr) (expr) +#define HEDLEY_CPP_CAST(T, expr) (expr) #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) -# undef HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#undef HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if HEDLEY_HAS_WARNING("-Wdeprecated-declarations") -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") -#elif HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) -#elif HEDLEY_PGI_VERSION_CHECK(20,7,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") -#elif HEDLEY_PGI_VERSION_CHECK(17,10,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif HEDLEY_GCC_VERSION_CHECK(4,3,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) -#elif HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") -#elif HEDLEY_PELLES_VERSION_CHECK(2,90,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") -#else -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable : 1478 1786)) +#elif HEDLEY_PGI_VERSION_CHECK(20, 7, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif HEDLEY_GCC_VERSION_CHECK(4, 3, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable : 4996)) +#elif HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && !defined(__cplusplus) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && defined(__cplusplus) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) -# undef HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#undef HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") -#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") -#elif HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) -#elif HEDLEY_PGI_VERSION_CHECK(17,10,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") -#elif HEDLEY_GCC_VERSION_CHECK(4,3,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") -#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) -#elif \ -HEDLEY_TI_VERSION_CHECK(16,9,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") -#elif HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") -#else -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable : 161)) +#elif HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif HEDLEY_GCC_VERSION_CHECK(4, 3, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable : 4068)) +#elif HEDLEY_TI_VERSION_CHECK(16, 9, 0) || HEDLEY_TI_CL6X_VERSION_CHECK(8, 0, 0) || \ + HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || HEDLEY_TI_CLPRU_VERSION_CHECK(2, 3, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif HEDLEY_TI_CL6X_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") +#else +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) -# undef HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#undef HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #endif #if HEDLEY_HAS_WARNING("-Wunknown-attributes") -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") -#elif HEDLEY_GCC_VERSION_CHECK(4,6,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif HEDLEY_INTEL_VERSION_CHECK(17,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") -#elif HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) -#elif HEDLEY_MSVC_VERSION_CHECK(19,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) -#elif HEDLEY_PGI_VERSION_CHECK(20,7,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") -#elif HEDLEY_PGI_VERSION_CHECK(17,10,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") -#elif \ -HEDLEY_TI_VERSION_CHECK(18,1,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") -#elif HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#else -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif HEDLEY_GCC_VERSION_CHECK(4, 6, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif HEDLEY_INTEL_VERSION_CHECK(17, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable : 1292)) +#elif HEDLEY_MSVC_VERSION_CHECK(19, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable : 5030)) +#elif HEDLEY_PGI_VERSION_CHECK(20, 7, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif HEDLEY_TI_VERSION_CHECK(18, 1, 0) || HEDLEY_TI_CL6X_VERSION_CHECK(8, 3, 0) || \ + HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) -# undef HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#undef HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if HEDLEY_HAS_WARNING("-Wcast-qual") -# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") -#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") -#elif HEDLEY_GCC_VERSION_CHECK(3,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif HEDLEY_GCC_VERSION_CHECK(3, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") #else -# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) -# undef HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#undef HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION #endif #if HEDLEY_HAS_WARNING("-Wunused-function") -# define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") -#elif HEDLEY_GCC_VERSION_CHECK(3,4,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") -#elif HEDLEY_MSVC_VERSION_CHECK(1,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) -#elif HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif HEDLEY_GCC_VERSION_CHECK(3, 4, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif HEDLEY_MSVC_VERSION_CHECK(1, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable : 4505)) +#elif HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") #else -# define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#define HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION #endif #if defined(HEDLEY_DEPRECATED) -# undef HEDLEY_DEPRECATED +#undef HEDLEY_DEPRECATED #endif #if defined(HEDLEY_DEPRECATED_FOR) -# undef HEDLEY_DEPRECATED_FOR -#endif -#if \ -HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) -# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) -#elif \ -(HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(HEDLEY_IAR_VERSION)) || \ -HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ -HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ -HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ -HEDLEY_TI_VERSION_CHECK(18,1,0) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) -# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#undef HEDLEY_DEPRECATED_FOR +#endif +#if HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " #since)) +#define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif (HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(HEDLEY_IAR_VERSION)) || \ + HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) || HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + HEDLEY_TI_VERSION_CHECK(18, 1, 0) || HEDLEY_TI_ARMCL_VERSION_CHECK(18, 1, 0) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(8, 3, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 3, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) +#define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) #elif defined(__cplusplus) && (__cplusplus >= 201402L) -# define HEDLEY_DEPRECATED(since) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) -# define HEDLEY_DEPRECATED_FOR(since, replacement) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) -#elif \ -HEDLEY_HAS_ATTRIBUTE(deprecated) || \ -HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ -HEDLEY_IAR_VERSION_CHECK(8,10,0) -# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) -# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) -#elif \ -HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ -HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_DEPRECATED(since) __declspec(deprecated) -# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_DEPRECATED(since) _Pragma("deprecated") -# define HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") -#else -# define HEDLEY_DEPRECATED(since) -# define HEDLEY_DEPRECATED_FOR(since, replacement) +#define HEDLEY_DEPRECATED(since) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) +#define HEDLEY_DEPRECATED_FOR(since, replacement) \ + HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif HEDLEY_HAS_ATTRIBUTE(deprecated) || HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) || \ + HEDLEY_IAR_VERSION_CHECK(8, 10, 0) +#define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) +#define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || HEDLEY_PELLES_VERSION_CHECK(6, 50, 0) || \ + HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_DEPRECATED(since) __declspec(deprecated) +#define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DEPRECATED(since) _Pragma("deprecated") +#define HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else +#define HEDLEY_DEPRECATED(since) +#define HEDLEY_DEPRECATED_FOR(since, replacement) #endif #if defined(HEDLEY_UNAVAILABLE) -# undef HEDLEY_UNAVAILABLE +#undef HEDLEY_UNAVAILABLE #endif -#if \ -HEDLEY_HAS_ATTRIBUTE(warning) || \ -HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#if HEDLEY_HAS_ATTRIBUTE(warning) || HEDLEY_GCC_VERSION_CHECK(4, 3, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) #else -# define HEDLEY_UNAVAILABLE(available_since) +#define HEDLEY_UNAVAILABLE(available_since) #endif #if defined(HEDLEY_WARN_UNUSED_RESULT) -# undef HEDLEY_WARN_UNUSED_RESULT +#undef HEDLEY_WARN_UNUSED_RESULT #endif #if defined(HEDLEY_WARN_UNUSED_RESULT_MSG) -# undef HEDLEY_WARN_UNUSED_RESULT_MSG -#endif -#if \ -HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ -HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -(HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ -HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) -# define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#undef HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || (HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || \ + HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) #elif (HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) -# define HEDLEY_WARN_UNUSED_RESULT HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) -# define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#define HEDLEY_WARN_UNUSED_RESULT HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) #elif HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) -# define HEDLEY_WARN_UNUSED_RESULT HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) -# define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#define HEDLEY_WARN_UNUSED_RESULT HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) #elif defined(_Check_return_) /* SAL */ -# define HEDLEY_WARN_UNUSED_RESULT _Check_return_ -# define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#define HEDLEY_WARN_UNUSED_RESULT _Check_return_ +#define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ #else -# define HEDLEY_WARN_UNUSED_RESULT -# define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#define HEDLEY_WARN_UNUSED_RESULT +#define HEDLEY_WARN_UNUSED_RESULT_MSG(msg) #endif #if defined(HEDLEY_SENTINEL) -# undef HEDLEY_SENTINEL +#undef HEDLEY_SENTINEL #endif -#if \ -HEDLEY_HAS_ATTRIBUTE(sentinel) || \ -HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#if HEDLEY_HAS_ATTRIBUTE(sentinel) || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_ARM_VERSION_CHECK(5, 4, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) #else -# define HEDLEY_SENTINEL(position) +#define HEDLEY_SENTINEL(position) #endif #if defined(HEDLEY_NO_RETURN) -# undef HEDLEY_NO_RETURN -#endif -#if HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_NO_RETURN __noreturn -#elif \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#undef HEDLEY_NO_RETURN +#endif +#if HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_NO_RETURN __noreturn +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -# define HEDLEY_NO_RETURN _Noreturn +#define HEDLEY_NO_RETURN _Noreturn #elif defined(__cplusplus) && (__cplusplus >= 201103L) -# define HEDLEY_NO_RETURN HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) -#elif \ -HEDLEY_HAS_ATTRIBUTE(noreturn) || \ -HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ -HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_IAR_VERSION_CHECK(8,10,0) -# define HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) -# define HEDLEY_NO_RETURN _Pragma("does_not_return") -#elif \ -HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_NO_RETURN __declspec(noreturn) -#elif HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) -# define HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") -#elif HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) -# define HEDLEY_NO_RETURN __attribute((noreturn)) -#elif HEDLEY_PELLES_VERSION_CHECK(9,0,0) -# define HEDLEY_NO_RETURN __declspec(noreturn) -#else -# define HEDLEY_NO_RETURN +#define HEDLEY_NO_RETURN HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif HEDLEY_HAS_ATTRIBUTE(noreturn) || HEDLEY_GCC_VERSION_CHECK(3, 2, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || HEDLEY_IAR_VERSION_CHECK(8, 10, 0) +#define HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_NO_RETURN __declspec(noreturn) +#elif HEDLEY_TI_CL6X_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) +#define HEDLEY_NO_RETURN __attribute((noreturn)) +#elif HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) +#define HEDLEY_NO_RETURN __declspec(noreturn) +#else +#define HEDLEY_NO_RETURN #endif #if defined(HEDLEY_NO_ESCAPE) -# undef HEDLEY_NO_ESCAPE +#undef HEDLEY_NO_ESCAPE #endif #if HEDLEY_HAS_ATTRIBUTE(noescape) -# define HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#define HEDLEY_NO_ESCAPE __attribute__((__noescape__)) #else -# define HEDLEY_NO_ESCAPE +#define HEDLEY_NO_ESCAPE #endif #if defined(HEDLEY_UNREACHABLE) -# undef HEDLEY_UNREACHABLE +#undef HEDLEY_UNREACHABLE #endif #if defined(HEDLEY_UNREACHABLE_RETURN) -# undef HEDLEY_UNREACHABLE_RETURN +#undef HEDLEY_UNREACHABLE_RETURN #endif #if defined(HEDLEY_ASSUME) -# undef HEDLEY_ASSUME +#undef HEDLEY_ASSUME #endif -#if \ -HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_ASSUME(expr) __assume(expr) +#if HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_ASSUME(expr) __assume(expr) #elif HEDLEY_HAS_BUILTIN(__builtin_assume) -# define HEDLEY_ASSUME(expr) __builtin_assume(expr) -#elif \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) -# if defined(__cplusplus) -# define HEDLEY_ASSUME(expr) std::_nassert(expr) -# else -# define HEDLEY_ASSUME(expr) _nassert(expr) -# endif -#endif -#if \ -(HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(HEDLEY_ARM_VERSION))) || \ -HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ -HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ -HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_UNREACHABLE() __builtin_unreachable() +#define HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif HEDLEY_TI_CL2000_VERSION_CHECK(6, 2, 0) || HEDLEY_TI_CL6X_VERSION_CHECK(4, 0, 0) +#if defined(__cplusplus) +#define HEDLEY_ASSUME(expr) std::_nassert(expr) +#else +#define HEDLEY_ASSUME(expr) _nassert(expr) +#endif +#endif +#if (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(HEDLEY_ARM_VERSION))) || \ + HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || HEDLEY_PGI_VERSION_CHECK(18, 10, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 5) || \ + HEDLEY_CRAY_VERSION_CHECK(10, 0, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_UNREACHABLE() __builtin_unreachable() #elif defined(HEDLEY_ASSUME) -# define HEDLEY_UNREACHABLE() HEDLEY_ASSUME(0) +#define HEDLEY_UNREACHABLE() HEDLEY_ASSUME(0) #endif #if !defined(HEDLEY_ASSUME) -# if defined(HEDLEY_UNREACHABLE) -# define HEDLEY_ASSUME(expr) HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (HEDLEY_UNREACHABLE(), 1))) -# else -# define HEDLEY_ASSUME(expr) HEDLEY_STATIC_CAST(void, expr) -# endif +#if defined(HEDLEY_UNREACHABLE) +#define HEDLEY_ASSUME(expr) HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (HEDLEY_UNREACHABLE(), 1))) +#else +#define HEDLEY_ASSUME(expr) HEDLEY_STATIC_CAST(void, expr) +#endif #endif #if defined(HEDLEY_UNREACHABLE) -# if \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) -# define HEDLEY_UNREACHABLE_RETURN(value) return (HEDLEY_STATIC_CAST(void, HEDLEY_ASSUME(0)), (value)) -# else -# define HEDLEY_UNREACHABLE_RETURN(value) HEDLEY_UNREACHABLE() -# endif +#if HEDLEY_TI_CL2000_VERSION_CHECK(6, 2, 0) || HEDLEY_TI_CL6X_VERSION_CHECK(4, 0, 0) +#define HEDLEY_UNREACHABLE_RETURN(value) return (HEDLEY_STATIC_CAST(void, HEDLEY_ASSUME(0)), (value)) +#else +#define HEDLEY_UNREACHABLE_RETURN(value) HEDLEY_UNREACHABLE() +#endif #else -# define HEDLEY_UNREACHABLE_RETURN(value) return (value) +#define HEDLEY_UNREACHABLE_RETURN(value) return (value) #endif #if !defined(HEDLEY_UNREACHABLE) -# define HEDLEY_UNREACHABLE() HEDLEY_ASSUME(0) +#define HEDLEY_UNREACHABLE() HEDLEY_ASSUME(0) #endif HEDLEY_DIAGNOSTIC_PUSH #if HEDLEY_HAS_WARNING("-Wpedantic") -# pragma clang diagnostic ignored "-Wpedantic" +#pragma clang diagnostic ignored "-Wpedantic" #endif #if HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) -# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros", 4, 0, 0) +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wvariadic-macros" +#elif defined(HEDLEY_GCC_VERSION) +#pragma GCC diagnostic ignored "-Wvariadic-macros" #endif -#if HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) -# if defined(__clang__) -# pragma clang diagnostic ignored "-Wvariadic-macros" -# elif defined(HEDLEY_GCC_VERSION) -# pragma GCC diagnostic ignored "-Wvariadic-macros" -# endif #endif #if defined(HEDLEY_NON_NULL) -# undef HEDLEY_NON_NULL +#undef HEDLEY_NON_NULL #endif -#if \ -HEDLEY_HAS_ATTRIBUTE(nonnull) || \ -HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) -# define HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#if HEDLEY_HAS_ATTRIBUTE(nonnull) || HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) +#define HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) #else -# define HEDLEY_NON_NULL(...) +#define HEDLEY_NON_NULL(...) #endif HEDLEY_DIAGNOSTIC_POP #if defined(HEDLEY_PRINTF_FORMAT) -# undef HEDLEY_PRINTF_FORMAT -#endif -#if defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) -#elif defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) -#elif \ -HEDLEY_HAS_ATTRIBUTE(format) || \ -HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ -HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) -#elif HEDLEY_PELLES_VERSION_CHECK(6,0,0) -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) -#else -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#undef HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && !defined(__USE_MINGW_ANSI_STDIO) +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && defined(__USE_MINGW_ANSI_STDIO) +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif HEDLEY_HAS_ATTRIBUTE(format) || HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif HEDLEY_PELLES_VERSION_CHECK(6, 0, 0) +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) __declspec(vaformat(printf, string_idx, first_to_check)) +#else +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) #endif #if defined(HEDLEY_CONSTEXPR) -# undef HEDLEY_CONSTEXPR +#undef HEDLEY_CONSTEXPR #endif #if defined(__cplusplus) -# if __cplusplus >= 201103L -# define HEDLEY_CONSTEXPR HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) -# endif +#if __cplusplus >= 201103L +#define HEDLEY_CONSTEXPR HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) +#endif #endif #if !defined(HEDLEY_CONSTEXPR) -# define HEDLEY_CONSTEXPR +#define HEDLEY_CONSTEXPR #endif #if defined(HEDLEY_PREDICT) -# undef HEDLEY_PREDICT +#undef HEDLEY_PREDICT #endif #if defined(HEDLEY_LIKELY) -# undef HEDLEY_LIKELY +#undef HEDLEY_LIKELY #endif #if defined(HEDLEY_UNLIKELY) -# undef HEDLEY_UNLIKELY +#undef HEDLEY_UNLIKELY #endif #if defined(HEDLEY_UNPREDICTABLE) -# undef HEDLEY_UNPREDICTABLE +#undef HEDLEY_UNPREDICTABLE #endif #if HEDLEY_HAS_BUILTIN(__builtin_unpredictable) -# define HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) -#endif -#if \ -(HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(HEDLEY_PGI_VERSION)) || \ -HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) -# define HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) -# define HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) -# define HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) -# define HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) -#elif \ -(HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(HEDLEY_INTEL_CL_VERSION)) || \ -HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -(HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ -HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ -HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_PREDICT(expr, expected, probability) \ -(((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (HEDLEY_STATIC_CAST(void, expected), (expr))) -# define HEDLEY_PREDICT_TRUE(expr, probability) \ -(__extension__ ({ \ -double hedley_probability_ = (probability); \ -((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ -})) -# define HEDLEY_PREDICT_FALSE(expr, probability) \ -(__extension__ ({ \ -double hedley_probability_ = (probability); \ -((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ -})) -# define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) -#else -# define HEDLEY_PREDICT(expr, expected, probability) (HEDLEY_STATIC_CAST(void, expected), (expr)) -# define HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) -# define HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) -# define HEDLEY_LIKELY(expr) (!!(expr)) -# define HEDLEY_UNLIKELY(expr) (!!(expr)) +#define HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if (HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(HEDLEY_PGI_VERSION)) || \ + HEDLEY_GCC_VERSION_CHECK(9, 0, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability((expr), (value), (probability)) +#define HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, (probability)) +#define HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, (probability)) +#define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +#define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#elif (HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(HEDLEY_INTEL_CL_VERSION)) || \ + HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + (HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(4, 7, 0) || HEDLEY_TI_CL430_VERSION_CHECK(3, 1, 0) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 1, 0) || HEDLEY_TI_CL6X_VERSION_CHECK(6, 1, 0) || \ + HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ + HEDLEY_TINYC_VERSION_CHECK(0, 9, 27) || HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || \ + HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (HEDLEY_STATIC_CAST(void, expected), (expr))) +#define HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) \ + : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +#define HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) \ + : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +#define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +#define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +#define HEDLEY_PREDICT(expr, expected, probability) (HEDLEY_STATIC_CAST(void, expected), (expr)) +#define HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +#define HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +#define HEDLEY_LIKELY(expr) (!!(expr)) +#define HEDLEY_UNLIKELY(expr) (!!(expr)) #endif #if !defined(HEDLEY_UNPREDICTABLE) -# define HEDLEY_UNPREDICTABLE(expr) HEDLEY_PREDICT(expr, 1, 0.5) +#define HEDLEY_UNPREDICTABLE(expr) HEDLEY_PREDICT(expr, 1, 0.5) #endif #if defined(HEDLEY_MALLOC) -# undef HEDLEY_MALLOC -#endif -#if \ -HEDLEY_HAS_ATTRIBUTE(malloc) || \ -HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_MALLOC __attribute__((__malloc__)) -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) -# define HEDLEY_MALLOC _Pragma("returns_new_memory") -#elif \ -HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_MALLOC __declspec(restrict) -#else -# define HEDLEY_MALLOC +#undef HEDLEY_MALLOC +#endif +#if HEDLEY_HAS_ATTRIBUTE(malloc) || HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_MALLOC __attribute__((__malloc__)) +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_MALLOC __declspec(restrict) +#else +#define HEDLEY_MALLOC #endif #if defined(HEDLEY_PURE) -# undef HEDLEY_PURE -#endif -#if \ -HEDLEY_HAS_ATTRIBUTE(pure) || \ -HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_PURE __attribute__((__pure__)) -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) -# define HEDLEY_PURE _Pragma("does_not_write_global_data") -#elif defined(__cplusplus) && \ -( \ -HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ -) -# define HEDLEY_PURE _Pragma("FUNC_IS_PURE;") -#else -# define HEDLEY_PURE +#undef HEDLEY_PURE +#endif +#if HEDLEY_HAS_ATTRIBUTE(pure) || HEDLEY_GCC_VERSION_CHECK(2, 96, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_PURE __attribute__((__pure__)) +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && (HEDLEY_TI_CL430_VERSION_CHECK(2, 0, 1) || HEDLEY_TI_CL6X_VERSION_CHECK(4, 0, 0) || \ + HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0)) +#define HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +#define HEDLEY_PURE #endif #if defined(HEDLEY_CONST) -# undef HEDLEY_CONST -#endif -#if \ -HEDLEY_HAS_ATTRIBUTE(const) || \ -HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_CONST __attribute__((__const__)) -#elif \ -HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) -# define HEDLEY_CONST _Pragma("no_side_effect") -#else -# define HEDLEY_CONST HEDLEY_PURE +#undef HEDLEY_CONST +#endif +#if HEDLEY_HAS_ATTRIBUTE(const) || HEDLEY_GCC_VERSION_CHECK(2, 5, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_CONST __attribute__((__const__)) +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define HEDLEY_CONST _Pragma("no_side_effect") +#else +#define HEDLEY_CONST HEDLEY_PURE #endif #if defined(HEDLEY_RESTRICT) -# undef HEDLEY_RESTRICT +#undef HEDLEY_RESTRICT #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) -# define HEDLEY_RESTRICT restrict -#elif \ -HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ -HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ -HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -(HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ -HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ -defined(__clang__) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_RESTRICT __restrict -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) -# define HEDLEY_RESTRICT _Restrict -#else -# define HEDLEY_RESTRICT +#define HEDLEY_RESTRICT restrict +#elif HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || HEDLEY_TI_CL2000_VERSION_CHECK(6, 2, 4) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(8, 1, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + (HEDLEY_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus)) || HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || \ + defined(__clang__) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_RESTRICT __restrict +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus) +#define HEDLEY_RESTRICT _Restrict +#else +#define HEDLEY_RESTRICT #endif #if defined(HEDLEY_INLINE) -# undef HEDLEY_INLINE -#endif -#if \ -(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ -(defined(__cplusplus) && (__cplusplus >= 199711L)) -# define HEDLEY_INLINE inline -#elif \ -defined(HEDLEY_GCC_VERSION) || \ -HEDLEY_ARM_VERSION_CHECK(6,2,0) -# define HEDLEY_INLINE __inline__ -#elif \ -HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ -HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_INLINE __inline -#else -# define HEDLEY_INLINE +#undef HEDLEY_INLINE +#endif +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined(__cplusplus) && (__cplusplus >= 199711L)) +#define HEDLEY_INLINE inline +#elif defined(HEDLEY_GCC_VERSION) || HEDLEY_ARM_VERSION_CHECK(6, 2, 0) +#define HEDLEY_INLINE __inline__ +#elif HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_TI_ARMCL_VERSION_CHECK(5, 1, 0) || \ + HEDLEY_TI_CL430_VERSION_CHECK(3, 1, 0) || HEDLEY_TI_CL2000_VERSION_CHECK(6, 2, 0) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(8, 0, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_INLINE __inline +#else +#define HEDLEY_INLINE #endif #if defined(HEDLEY_ALWAYS_INLINE) -# undef HEDLEY_ALWAYS_INLINE -#endif -#if \ -HEDLEY_HAS_ATTRIBUTE(always_inline) || \ -HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ -HEDLEY_IAR_VERSION_CHECK(8,10,0) -# define HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) HEDLEY_INLINE -#elif \ -HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_ALWAYS_INLINE __forceinline -#elif defined(__cplusplus) && \ -( \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ -) -# define HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") -#else -# define HEDLEY_ALWAYS_INLINE HEDLEY_INLINE +#undef HEDLEY_ALWAYS_INLINE +#endif +#if HEDLEY_HAS_ATTRIBUTE(always_inline) || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) || \ + HEDLEY_IAR_VERSION_CHECK(8, 10, 0) +#define HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) HEDLEY_INLINE +#elif HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && (HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || HEDLEY_TI_CL6X_VERSION_CHECK(6, 1, 0) || \ + HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0)) +#define HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +#define HEDLEY_ALWAYS_INLINE HEDLEY_INLINE #endif #if defined(HEDLEY_NEVER_INLINE) -# undef HEDLEY_NEVER_INLINE -#endif -#if \ -HEDLEY_HAS_ATTRIBUTE(noinline) || \ -HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ -HEDLEY_TI_VERSION_CHECK(15,12,0) || \ -(HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ -(HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ -(HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ -HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ -HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ -HEDLEY_IAR_VERSION_CHECK(8,10,0) -# define HEDLEY_NEVER_INLINE __attribute__((__noinline__)) -#elif \ -HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_NEVER_INLINE __declspec(noinline) -#elif HEDLEY_PGI_VERSION_CHECK(10,2,0) -# define HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) -# define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_NEVER_INLINE _Pragma("inline=never") -#elif HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) -# define HEDLEY_NEVER_INLINE __attribute((noinline)) -#elif HEDLEY_PELLES_VERSION_CHECK(9,0,0) -# define HEDLEY_NEVER_INLINE __declspec(noinline) -#else -# define HEDLEY_NEVER_INLINE +#undef HEDLEY_NEVER_INLINE +#endif +#if HEDLEY_HAS_ATTRIBUTE(noinline) || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ + HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) || \ + HEDLEY_IAR_VERSION_CHECK(8, 10, 0) +#define HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_NEVER_INLINE __declspec(noinline) +#elif HEDLEY_PGI_VERSION_CHECK(10, 2, 0) +#define HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif HEDLEY_TI_CL6X_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) +#define HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) +#define HEDLEY_NEVER_INLINE __declspec(noinline) +#else +#define HEDLEY_NEVER_INLINE #endif #if defined(HEDLEY_PRIVATE) -# undef HEDLEY_PRIVATE +#undef HEDLEY_PRIVATE #endif #if defined(HEDLEY_PUBLIC) -# undef HEDLEY_PUBLIC +#undef HEDLEY_PUBLIC #endif #if defined(HEDLEY_IMPORT) -# undef HEDLEY_IMPORT +#undef HEDLEY_IMPORT #endif #if defined(_WIN32) || defined(__CYGWIN__) -# define HEDLEY_PRIVATE -# define HEDLEY_PUBLIC __declspec(dllexport) -# define HEDLEY_IMPORT __declspec(dllimport) -#else -# if \ -HEDLEY_HAS_ATTRIBUTE(visibility) || \ -HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ -HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ -( \ -defined(__TI_EABI__) && \ -( \ -(HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ -) \ -) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) -# define HEDLEY_PUBLIC __attribute__((__visibility__("default"))) -# else -# define HEDLEY_PRIVATE -# define HEDLEY_PUBLIC -# endif -# define HEDLEY_IMPORT extern +#define HEDLEY_PRIVATE +#define HEDLEY_PUBLIC __declspec(dllexport) +#define HEDLEY_IMPORT __declspec(dllimport) +#else +#if HEDLEY_HAS_ATTRIBUTE(visibility) || HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + (defined(__TI_EABI__) && ((HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0))) || \ + HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +#define HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +#else +#define HEDLEY_PRIVATE +#define HEDLEY_PUBLIC +#endif +#define HEDLEY_IMPORT extern #endif #if defined(HEDLEY_NO_THROW) -# undef HEDLEY_NO_THROW +#undef HEDLEY_NO_THROW #endif -#if \ -HEDLEY_HAS_ATTRIBUTE(nothrow) || \ -HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_NO_THROW __attribute__((__nothrow__)) -#elif \ -HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) -# define HEDLEY_NO_THROW __declspec(nothrow) +#if HEDLEY_HAS_ATTRIBUTE(nothrow) || HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif HEDLEY_MSVC_VERSION_CHECK(13, 1, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) +#define HEDLEY_NO_THROW __declspec(nothrow) #else -# define HEDLEY_NO_THROW +#define HEDLEY_NO_THROW #endif #if defined(HEDLEY_FALL_THROUGH) -# undef HEDLEY_FALL_THROUGH -#endif -#if \ -HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ -HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) -#elif HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) -# define HEDLEY_FALL_THROUGH HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#undef HEDLEY_FALL_THROUGH +#endif +#if HEDLEY_HAS_ATTRIBUTE(fallthrough) || HEDLEY_GCC_VERSION_CHECK(7, 0, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang, fallthrough) +#define HEDLEY_FALL_THROUGH HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) #elif HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) -# define HEDLEY_FALL_THROUGH HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#define HEDLEY_FALL_THROUGH HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) #elif defined(__fallthrough) /* SAL */ -# define HEDLEY_FALL_THROUGH __fallthrough +#define HEDLEY_FALL_THROUGH __fallthrough #else -# define HEDLEY_FALL_THROUGH +#define HEDLEY_FALL_THROUGH #endif #if defined(HEDLEY_RETURNS_NON_NULL) -# undef HEDLEY_RETURNS_NON_NULL +#undef HEDLEY_RETURNS_NON_NULL #endif -#if \ -HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ -HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#if HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || HEDLEY_GCC_VERSION_CHECK(4, 9, 0) || \ + HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) #elif defined(_Ret_notnull_) /* SAL */ -# define HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#define HEDLEY_RETURNS_NON_NULL _Ret_notnull_ #else -# define HEDLEY_RETURNS_NON_NULL +#define HEDLEY_RETURNS_NON_NULL #endif #if defined(HEDLEY_ARRAY_PARAM) -# undef HEDLEY_ARRAY_PARAM +#undef HEDLEY_ARRAY_PARAM #endif -#if \ -defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ -!defined(__STDC_NO_VLA__) && \ -!defined(__cplusplus) && \ -!defined(HEDLEY_PGI_VERSION) && \ -!defined(HEDLEY_TINYC_VERSION) -# define HEDLEY_ARRAY_PARAM(name) (name) +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && !defined(HEDLEY_PGI_VERSION) && !defined(HEDLEY_TINYC_VERSION) +#define HEDLEY_ARRAY_PARAM(name) (name) #else -# define HEDLEY_ARRAY_PARAM(name) +#define HEDLEY_ARRAY_PARAM(name) #endif #if defined(HEDLEY_IS_CONSTANT) -# undef HEDLEY_IS_CONSTANT +#undef HEDLEY_IS_CONSTANT #endif #if defined(HEDLEY_REQUIRE_CONSTEXPR) -# undef HEDLEY_REQUIRE_CONSTEXPR +#undef HEDLEY_REQUIRE_CONSTEXPR #endif /* HEDLEY_IS_CONSTEXPR_ is for HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(HEDLEY_IS_CONSTEXPR_) -# undef HEDLEY_IS_CONSTEXPR_ -#endif -#if \ -HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ -HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ -HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ -HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ -HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ -(HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ -HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ -HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#undef HEDLEY_IS_CONSTEXPR_ +#endif +#if HEDLEY_HAS_BUILTIN(__builtin_constant_p) || HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_TINYC_VERSION_CHECK(0, 9, 19) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + HEDLEY_TI_CL6X_VERSION_CHECK(6, 1, 0) || (HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) && !defined(__cplusplus)) || \ + HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) +#define HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) #endif #if !defined(__cplusplus) -# if \ -HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ -HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ -HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ -HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ -HEDLEY_TINYC_VERSION_CHECK(0,9,24) -# if defined(__INTPTR_TYPE__) -# define HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) -# else -# include -# define HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) -# endif -# elif \ -( \ -defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ -!defined(HEDLEY_SUNPRO_VERSION) && \ -!defined(HEDLEY_PGI_VERSION) && \ -!defined(HEDLEY_IAR_VERSION)) || \ -(HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(HEDLEY_IAR_VERSION)) || \ -HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ -HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ -HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ -HEDLEY_ARM_VERSION_CHECK(5,3,0) -# if defined(__INTPTR_TYPE__) -# define HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) -# else -# include -# define HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) -# endif -# elif \ -defined(HEDLEY_GCC_VERSION) || \ -defined(HEDLEY_INTEL_VERSION) || \ -defined(HEDLEY_TINYC_VERSION) || \ -defined(HEDLEY_TI_ARMCL_VERSION) || \ -HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ -defined(HEDLEY_TI_CL2000_VERSION) || \ -defined(HEDLEY_TI_CL6X_VERSION) || \ -defined(HEDLEY_TI_CL7X_VERSION) || \ -defined(HEDLEY_TI_CLPRU_VERSION) || \ -defined(__clang__) -# define HEDLEY_IS_CONSTEXPR_(expr) ( \ -sizeof(void) != \ -sizeof(*( \ -1 ? \ -((void*) ((expr) * 0L) ) : \ -((struct { char v[sizeof(void) * 2]; } *) 1) \ -) \ -) \ -) -# endif +#if HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || HEDLEY_ARM_VERSION_CHECK(5, 4, 0) || HEDLEY_TINYC_VERSION_CHECK(0, 9, 24) +#if defined(__INTPTR_TYPE__) +#define HEDLEY_IS_CONSTEXPR_(expr) \ + __builtin_types_compatible_p(__typeof__((1 ? (void *)((__INTPTR_TYPE__)((expr)*0)) : (int *)0)), int *) +#else +#include +#define HEDLEY_IS_CONSTEXPR_(expr) \ + __builtin_types_compatible_p(__typeof__((1 ? (void *)((intptr_t)((expr)*0)) : (int *)0)), int *) +#endif +#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(HEDLEY_SUNPRO_VERSION) && \ + !defined(HEDLEY_PGI_VERSION) && !defined(HEDLEY_IAR_VERSION)) || \ + (HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(HEDLEY_IAR_VERSION)) || \ + HEDLEY_GCC_VERSION_CHECK(4, 9, 0) || HEDLEY_INTEL_VERSION_CHECK(17, 0, 0) || HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || \ + HEDLEY_ARM_VERSION_CHECK(5, 3, 0) +#if defined(__INTPTR_TYPE__) +#define HEDLEY_IS_CONSTEXPR_(expr) \ + _Generic((1 ? (void *)((__INTPTR_TYPE__)((expr)*0)) : (int *)0), int * : 1, void * : 0) +#else +#include +#define HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void *)((intptr_t)*0) : (int *)0), int * : 1, void * : 0) +#endif +#elif defined(HEDLEY_GCC_VERSION) || defined(HEDLEY_INTEL_VERSION) || defined(HEDLEY_TINYC_VERSION) || \ + defined(HEDLEY_TI_ARMCL_VERSION) || HEDLEY_TI_CL430_VERSION_CHECK(18, 12, 0) || \ + defined(HEDLEY_TI_CL2000_VERSION) || defined(HEDLEY_TI_CL6X_VERSION) || defined(HEDLEY_TI_CL7X_VERSION) || \ + defined(HEDLEY_TI_CLPRU_VERSION) || defined(__clang__) +#define HEDLEY_IS_CONSTEXPR_(expr) \ + (sizeof(void) != sizeof(*(1 ? ((void *)((expr)*0L)) : ((struct { char v[sizeof(void) * 2]; } *)1)))) +#endif #endif #if defined(HEDLEY_IS_CONSTEXPR_) -# if !defined(HEDLEY_IS_CONSTANT) -# define HEDLEY_IS_CONSTANT(expr) HEDLEY_IS_CONSTEXPR_(expr) -# endif -# define HEDLEY_REQUIRE_CONSTEXPR(expr) (HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#if !defined(HEDLEY_IS_CONSTANT) +#define HEDLEY_IS_CONSTANT(expr) HEDLEY_IS_CONSTEXPR_(expr) +#endif +#define HEDLEY_REQUIRE_CONSTEXPR(expr) (HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) #else -# if !defined(HEDLEY_IS_CONSTANT) -# define HEDLEY_IS_CONSTANT(expr) (0) -# endif -# define HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#if !defined(HEDLEY_IS_CONSTANT) +#define HEDLEY_IS_CONSTANT(expr) (0) +#endif +#define HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) #endif #if defined(HEDLEY_BEGIN_C_DECLS) -# undef HEDLEY_BEGIN_C_DECLS +#undef HEDLEY_BEGIN_C_DECLS #endif #if defined(HEDLEY_END_C_DECLS) -# undef HEDLEY_END_C_DECLS +#undef HEDLEY_END_C_DECLS #endif #if defined(HEDLEY_C_DECL) -# undef HEDLEY_C_DECL +#undef HEDLEY_C_DECL #endif #if defined(__cplusplus) -# define HEDLEY_BEGIN_C_DECLS extern "C" { -# define HEDLEY_END_C_DECLS } -# define HEDLEY_C_DECL extern "C" +#define HEDLEY_BEGIN_C_DECLS extern "C" { +#define HEDLEY_END_C_DECLS } +#define HEDLEY_C_DECL extern "C" #else -# define HEDLEY_BEGIN_C_DECLS -# define HEDLEY_END_C_DECLS -# define HEDLEY_C_DECL +#define HEDLEY_BEGIN_C_DECLS +#define HEDLEY_END_C_DECLS +#define HEDLEY_C_DECL #endif #if defined(HEDLEY_STATIC_ASSERT) -# undef HEDLEY_STATIC_ASSERT -#endif -#if \ -!defined(__cplusplus) && ( \ -(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ -(HEDLEY_HAS_FEATURE(c_static_assert) && !defined(HEDLEY_INTEL_CL_VERSION)) || \ -HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ -defined(_Static_assert) \ -) -# define HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) -#elif \ -(defined(__cplusplus) && (__cplusplus >= 201103L)) || \ -HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_STATIC_ASSERT(expr, message) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) -#else -# define HEDLEY_STATIC_ASSERT(expr, message) +#undef HEDLEY_STATIC_ASSERT +#endif +#if !defined(__cplusplus) && \ + ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (HEDLEY_HAS_FEATURE(c_static_assert) && !defined(HEDLEY_INTEL_CL_VERSION)) || \ + HEDLEY_GCC_VERSION_CHECK(6, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || defined(_Static_assert)) +#define HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif (defined(__cplusplus) && (__cplusplus >= 201103L)) || HEDLEY_MSVC_VERSION_CHECK(16, 0, 0) || \ + HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_STATIC_ASSERT(expr, message) HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +#define HEDLEY_STATIC_ASSERT(expr, message) #endif #if defined(HEDLEY_NULL) -# undef HEDLEY_NULL +#undef HEDLEY_NULL #endif #if defined(__cplusplus) -# if __cplusplus >= 201103L -# define HEDLEY_NULL HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) -# elif defined(NULL) -# define HEDLEY_NULL NULL -# else -# define HEDLEY_NULL HEDLEY_STATIC_CAST(void*, 0) -# endif +#if __cplusplus >= 201103L +#define HEDLEY_NULL HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) +#elif defined(NULL) +#define HEDLEY_NULL NULL +#else +#define HEDLEY_NULL HEDLEY_STATIC_CAST(void *, 0) +#endif #elif defined(NULL) -# define HEDLEY_NULL NULL +#define HEDLEY_NULL NULL #else -# define HEDLEY_NULL ((void*) 0) +#define HEDLEY_NULL ((void *)0) #endif #if defined(HEDLEY_MESSAGE) -# undef HEDLEY_MESSAGE +#undef HEDLEY_MESSAGE #endif #if HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define HEDLEY_MESSAGE(msg) \ -HEDLEY_DIAGNOSTIC_PUSH \ -HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ -HEDLEY_PRAGMA(message msg) \ -HEDLEY_DIAGNOSTIC_POP -#elif \ -HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message msg) -#elif HEDLEY_CRAY_VERSION_CHECK(5,0,0) -# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(_CRI message msg) -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) -#elif HEDLEY_PELLES_VERSION_CHECK(2,0,0) -# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) -#else -# define HEDLEY_MESSAGE(msg) +#define HEDLEY_MESSAGE(msg) \ + HEDLEY_DIAGNOSTIC_PUSH \ + HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + HEDLEY_PRAGMA(message msg) \ + HEDLEY_DIAGNOSTIC_POP +#elif HEDLEY_GCC_VERSION_CHECK(4, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message msg) +#elif HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) +#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(_CRI message msg) +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) +#elif HEDLEY_PELLES_VERSION_CHECK(2, 0, 0) +#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) +#else +#define HEDLEY_MESSAGE(msg) #endif #if defined(HEDLEY_WARNING) -# undef HEDLEY_WARNING +#undef HEDLEY_WARNING #endif #if HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define HEDLEY_WARNING(msg) \ -HEDLEY_DIAGNOSTIC_PUSH \ -HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ -HEDLEY_PRAGMA(clang warning msg) \ -HEDLEY_DIAGNOSTIC_POP -#elif \ -HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ -HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ -HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(GCC warning msg) -#elif \ -HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(message(msg)) +#define HEDLEY_WARNING(msg) \ + HEDLEY_DIAGNOSTIC_PUSH \ + HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + HEDLEY_PRAGMA(clang warning msg) \ + HEDLEY_DIAGNOSTIC_POP +#elif HEDLEY_GCC_VERSION_CHECK(4, 8, 0) || HEDLEY_PGI_VERSION_CHECK(18, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(GCC warning msg) +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) || HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(message(msg)) #else -# define HEDLEY_WARNING(msg) HEDLEY_MESSAGE(msg) +#define HEDLEY_WARNING(msg) HEDLEY_MESSAGE(msg) #endif #if defined(HEDLEY_REQUIRE) -# undef HEDLEY_REQUIRE +#undef HEDLEY_REQUIRE #endif #if defined(HEDLEY_REQUIRE_MSG) -# undef HEDLEY_REQUIRE_MSG +#undef HEDLEY_REQUIRE_MSG #endif #if HEDLEY_HAS_ATTRIBUTE(diagnose_if) -# if HEDLEY_HAS_WARNING("-Wgcc-compat") -# define HEDLEY_REQUIRE(expr) \ -HEDLEY_DIAGNOSTIC_PUSH \ -_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ -__attribute__((diagnose_if(!(expr), #expr, "error"))) \ -HEDLEY_DIAGNOSTIC_POP -# define HEDLEY_REQUIRE_MSG(expr,msg) \ -HEDLEY_DIAGNOSTIC_PUSH \ -_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ -__attribute__((diagnose_if(!(expr), msg, "error"))) \ -HEDLEY_DIAGNOSTIC_POP -# else -# define HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) -# define HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) -# endif +#if HEDLEY_HAS_WARNING("-Wgcc-compat") +#define HEDLEY_REQUIRE(expr) \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + HEDLEY_DIAGNOSTIC_POP +#define HEDLEY_REQUIRE_MSG(expr, msg) \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") __attribute__((diagnose_if(!(expr), msg, "error"))) \ + HEDLEY_DIAGNOSTIC_POP +#else +#define HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +#define HEDLEY_REQUIRE_MSG(expr, msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +#endif #else -# define HEDLEY_REQUIRE(expr) -# define HEDLEY_REQUIRE_MSG(expr,msg) +#define HEDLEY_REQUIRE(expr) +#define HEDLEY_REQUIRE_MSG(expr, msg) #endif #if defined(HEDLEY_FLAGS) -# undef HEDLEY_FLAGS +#undef HEDLEY_FLAGS #endif #if HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) -# define HEDLEY_FLAGS __attribute__((__flag_enum__)) +#define HEDLEY_FLAGS __attribute__((__flag_enum__)) #else -# define HEDLEY_FLAGS +#define HEDLEY_FLAGS #endif #if defined(HEDLEY_FLAGS_CAST) -# undef HEDLEY_FLAGS_CAST +#undef HEDLEY_FLAGS_CAST #endif -#if HEDLEY_INTEL_VERSION_CHECK(19,0,0) -# define HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ -HEDLEY_DIAGNOSTIC_PUSH \ -_Pragma("warning(disable:188)") \ -((T) (expr)); \ -HEDLEY_DIAGNOSTIC_POP \ -})) +#if HEDLEY_INTEL_VERSION_CHECK(19, 0, 0) +#define HEDLEY_FLAGS_CAST(T, expr) \ + (__extension__({ \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)")((T)(expr)); \ + HEDLEY_DIAGNOSTIC_POP \ + })) #else -# define HEDLEY_FLAGS_CAST(T, expr) HEDLEY_STATIC_CAST(T, expr) +#define HEDLEY_FLAGS_CAST(T, expr) HEDLEY_STATIC_CAST(T, expr) #endif #if defined(HEDLEY_EMPTY_BASES) -# undef HEDLEY_EMPTY_BASES +#undef HEDLEY_EMPTY_BASES #endif -#if \ -(HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ -HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define HEDLEY_EMPTY_BASES __declspec(empty_bases) +#if (HEDLEY_MSVC_VERSION_CHECK(19, 0, 23918) && !HEDLEY_MSVC_VERSION_CHECK(20, 0, 0)) || \ + HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) +#define HEDLEY_EMPTY_BASES __declspec(empty_bases) #else -# define HEDLEY_EMPTY_BASES +#define HEDLEY_EMPTY_BASES #endif /* Remaining macros are deprecated. */ #if defined(HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) -# undef HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#undef HEDLEY_GCC_NOT_CLANG_VERSION_CHECK #endif #if defined(__clang__) -# define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) (0) #else -# define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_CLANG_HAS_ATTRIBUTE) -# undef HEDLEY_CLANG_HAS_ATTRIBUTE +#undef HEDLEY_CLANG_HAS_ATTRIBUTE #endif #define HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) HEDLEY_HAS_ATTRIBUTE(attribute) #if defined(HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) -# undef HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#undef HEDLEY_CLANG_HAS_CPP_ATTRIBUTE #endif #define HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) HEDLEY_HAS_CPP_ATTRIBUTE(attribute) #if defined(HEDLEY_CLANG_HAS_BUILTIN) -# undef HEDLEY_CLANG_HAS_BUILTIN +#undef HEDLEY_CLANG_HAS_BUILTIN #endif #define HEDLEY_CLANG_HAS_BUILTIN(builtin) HEDLEY_HAS_BUILTIN(builtin) #if defined(HEDLEY_CLANG_HAS_FEATURE) -# undef HEDLEY_CLANG_HAS_FEATURE +#undef HEDLEY_CLANG_HAS_FEATURE #endif #define HEDLEY_CLANG_HAS_FEATURE(feature) HEDLEY_HAS_FEATURE(feature) #if defined(HEDLEY_CLANG_HAS_EXTENSION) -# undef HEDLEY_CLANG_HAS_EXTENSION +#undef HEDLEY_CLANG_HAS_EXTENSION #endif #define HEDLEY_CLANG_HAS_EXTENSION(extension) HEDLEY_HAS_EXTENSION(extension) #if defined(HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) -# undef HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#undef HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE #endif #define HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) #if defined(HEDLEY_CLANG_HAS_WARNING) -# undef HEDLEY_CLANG_HAS_WARNING +#undef HEDLEY_CLANG_HAS_WARNING #endif #define HEDLEY_CLANG_HAS_WARNING(warning) HEDLEY_HAS_WARNING(warning) diff --git a/source/small/detail/traits/is_pair.h b/source/small/detail/traits/is_pair.h index bbe9742..c3c5c85 100644 --- a/source/small/detail/traits/is_pair.h +++ b/source/small/detail/traits/is_pair.h @@ -5,19 +5,20 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_IS_PAIR_H #define SMALL_DETAIL_TRAITS_IS_PAIR_H #include namespace small { - /// Check if type is a pair - template struct is_pair : std::false_type {}; + namespace detail { + /// Check if type is a pair + template struct is_pair : std::false_type {}; - template struct is_pair> : std::true_type {}; + template struct is_pair> : std::true_type {}; - template constexpr bool is_pair_v = is_pair::value; + template constexpr bool is_pair_v = is_pair::value; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_TRAITS_IS_PAIR_H diff --git a/source/small/detail/traits/is_range.h b/source/small/detail/traits/is_range.h index 1c6f07c..75e53cf 100644 --- a/source/small/detail/traits/is_range.h +++ b/source/small/detail/traits/is_range.h @@ -5,22 +5,21 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_IS_RANGE_H #define SMALL_DETAIL_TRAITS_IS_RANGE_H namespace small { - /// Check if type is a range (has begin() and end() functions) - template struct is_range : std::false_type {}; - - template - struct is_range< - T, std::void_t().begin()), decltype(std::declval().end()), typename T::value_type>> - : std::true_type {}; + namespace detail { + /// Check if type is a range (has begin() and end() functions) + template struct is_range : std::false_type {}; - /// True if type is a range (has begin() and end() functions) - template constexpr bool is_range_v = is_range>::value; + template + struct is_range().begin()), decltype(std::declval().end()), + typename T::value_type>> : std::true_type {}; + /// True if type is a range (has begin() and end() functions) + template constexpr bool is_range_v = is_range>::value; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_TRAITS_IS_RANGE_H diff --git a/source/small/detail/traits/is_relocatable.h b/source/small/detail/traits/is_relocatable.h index 486fc08..ae4322c 100644 --- a/source/small/detail/traits/is_relocatable.h +++ b/source/small/detail/traits/is_relocatable.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_IS_RELOCATABLE_H #define SMALL_DETAIL_TRAITS_IS_RELOCATABLE_H @@ -21,7 +20,6 @@ namespace small { }; template constexpr bool is_relocatable_v = is_relocatable::value; - } // namespace small #endif // SMALL_DETAIL_TRAITS_IS_RELOCATABLE_H diff --git a/source/small/detail/traits/little_endian.h b/source/small/detail/traits/little_endian.h index b4eb468..9c789ff 100644 --- a/source/small/detail/traits/little_endian.h +++ b/source/small/detail/traits/little_endian.h @@ -5,34 +5,35 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_DETAIL_TRAITS_LITTLE_ENDIAN_H #define SMALL_DETAIL_TRAITS_LITTLE_ENDIAN_H namespace small { - /// \brief Helper to detect little endian - class is_little_endian { - constexpr static std::uint32_t u4 = 1; - constexpr static std::uint8_t u1 = (const std::uint8_t &)u4; + namespace detail { + /// \brief Helper to detect little endian + class is_little_endian { + constexpr static std::uint32_t u4 = 1; + constexpr static std::uint8_t u1 = (const std::uint8_t &)u4; - public: - constexpr static bool value = u1; - }; + public: + constexpr static bool value = u1; + }; - /// \brief Helper to modify the last (address-wise) byte of a little endian value of type 'T' - template union last_byte { - T number; - struct { - char dummy[sizeof(T) - 1]; - char last; - } bytes; - }; - template union last_byte { - T number; - struct { - char last; - } bytes; - }; + /// \brief Helper to modify the last (address-wise) byte of a little endian value of type 'T' + template union last_byte { + T number; + struct { + char dummy[sizeof(T) - 1]; + char last; + } bytes; + }; + template union last_byte { + T number; + struct { + char last; + } bytes; + }; + } // namespace detail } // namespace small #endif // SMALL_DETAIL_TRAITS_LITTLE_ENDIAN_H diff --git a/source/small/map.h b/source/small/map.h index acc11f6..4059028 100644 --- a/source/small/map.h +++ b/source/small/map.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_MAP_H #define SMALL_MAP_H @@ -17,33 +16,37 @@ namespace small { template >, class Compare = std::less<>, class Allocator = std::allocator>> - using map = associative_vector, N, Allocator>, Compare>; + using map = detail::associative_vector, N, Allocator>, Compare>; template >, class Compare = std::less<>> - using max_size_map = small::associative_vector, N>, Compare>; + using max_size_map = + small::detail::associative_vector, N>, Compare>; template >, class Compare = std::less<>, class Allocator = std::allocator>> - using multimap = associative_vector, N, Allocator>, Compare>; + using multimap = detail::associative_vector, N, Allocator>, Compare>; template >, class Compare = std::less<>> - using max_size_multimap = small::associative_vector, N>, Compare>; + using max_size_multimap = + small::detail::associative_vector, N>, Compare>; template >, class Compare = std::less<>, class Allocator = std::allocator>> - using unordered_map = associative_vector, N, Allocator>, Compare>; + using unordered_map = + detail::associative_vector, N, Allocator>, Compare>; template >, class Compare = std::less<>> using max_size_unordered_map = - small::associative_vector, N>, Compare>; + small::detail::associative_vector, N>, Compare>; template >, class Compare = std::less<>, class Allocator = std::allocator>> - using unordered_multimap = associative_vector, N, Allocator>, Compare>; + using unordered_multimap = + detail::associative_vector, N, Allocator>, Compare>; template >, class Compare = std::less<>> using max_size_unordered_multimap = - small::associative_vector, N>, Compare>; + small::detail::associative_vector, N>, Compare>; } // namespace small diff --git a/source/small/queue.h b/source/small/queue.h index 315b055..3d25acc 100644 --- a/source/small/queue.h +++ b/source/small/queue.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_QUEUE_H #define SMALL_QUEUE_H diff --git a/source/small/set.h b/source/small/set.h index 41c1702..02bbf76 100644 --- a/source/small/set.h +++ b/source/small/set.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_SET_H #define SMALL_SET_H @@ -17,31 +16,33 @@ namespace small { template , class Compare = std::less<>, class Allocator = std::allocator> - using set = associative_vector, Compare>; + using set = detail::associative_vector, Compare>; template , class Compare = std::less<>> - using max_size_set = small::associative_vector, Compare>; + using max_size_set = small::detail::associative_vector, Compare>; template , class Compare = std::less<>, class Allocator = std::allocator> - using multiset = associative_vector, Compare>; + using multiset = detail::associative_vector, Compare>; template , class Compare = std::less<>> - using max_size_multiset = small::associative_vector, Compare>; + using max_size_multiset = small::detail::associative_vector, Compare>; template , class Compare = std::less<>, class Allocator = std::allocator> - using unordered_set = associative_vector, Compare>; + using unordered_set = detail::associative_vector, Compare>; template , class Compare = std::less<>> - using max_size_unordered_set = small::associative_vector, Compare>; + using max_size_unordered_set = + small::detail::associative_vector, Compare>; template , class Compare = std::less<>, class Allocator = std::allocator> - using unordered_multiset = associative_vector, Compare>; + using unordered_multiset = detail::associative_vector, Compare>; template , class Compare = std::less<>> - using max_size_unordered_multiset = small::associative_vector, Compare>; + using max_size_unordered_multiset = + small::detail::associative_vector, Compare>; } // namespace small diff --git a/source/small/stack.h b/source/small/stack.h index 0ee3e55..8b365c3 100644 --- a/source/small/stack.h +++ b/source/small/stack.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_STACK_H #define SMALL_STACK_H diff --git a/source/small/string.h b/source/small/string.h index 8761ea1..6a21950 100644 --- a/source/small/string.h +++ b/source/small/string.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_STRING_H #define SMALL_STRING_H @@ -91,8 +90,8 @@ namespace small { typedef const value_type &const_reference; typedef typename std::allocator_traits::pointer pointer; typedef typename std::allocator_traits::const_pointer const_pointer; - typedef pointer_wrapper iterator; - typedef pointer_wrapper const_iterator; + typedef detail::pointer_wrapper iterator; + typedef detail::pointer_wrapper const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; enum : size_type { npos = (size_type)-1 }; @@ -111,9 +110,10 @@ namespace small { /// \section Type we use for the lookup table, if it exists /// The type of codepoint map view for accessing the byte and codepoint indexes of multibyte chars /// The table will use the codepoint hint defined above - using lookup_table_type = lookup_table_view; + using lookup_table_type = + detail::lookup_table_view; using const_lookup_table_type = - const_lookup_table_view; + detail::const_lookup_table_view; /// \brief We string view type for this string type using string_view_type = std::basic_string_view; @@ -122,12 +122,12 @@ namespace small { using self_type = basic_string; /// \section Types for iterating codepoints - using codepoint_reference = external_codepoint_reference; - using const_codepoint_reference = const_external_codepoint_reference; - using codepoint_iterator = external_codepoint_iterator; - using const_codepoint_iterator = const_external_codepoint_iterator; - using reverse_codepoint_iterator = reverse_external_codepoint_iterator; - using const_reverse_codepoint_iterator = const_reverse_external_codepoint_iterator; + using codepoint_reference = detail::external_codepoint_reference; + using const_codepoint_reference = detail::const_external_codepoint_reference; + using codepoint_iterator = detail::external_codepoint_iterator; + using const_codepoint_iterator = detail::const_external_codepoint_iterator; + using reverse_codepoint_iterator = detail::reverse_external_codepoint_iterator; + using const_reverse_codepoint_iterator = detail::const_reverse_external_codepoint_iterator; /// \brief A strong integer type for representing code point indexes /// Although it's a strong type, it still includes most operations to work with size_type @@ -148,10 +148,10 @@ namespace small { /// The difference here is that we accept string views of any char type template using is_api_string_view = std::conjunction< - std::negation, void>>, - std::is_convertible< - const T &, std::basic_string_view, std::char_traits>>>, - std::negation *>>>; + std::negation, void>>, + std::is_convertible, + std::char_traits>>>, + std::negation *>>>; template static constexpr bool is_api_string_view_v = is_api_string_view::value; @@ -194,7 +194,7 @@ namespace small { constexpr bool input_is_wide = sizeof(InputChar) > 1; uint8_t codeunits_per_codepoint = 1; if constexpr (input_is_wide) { - codeunits_per_codepoint = utf_size_as(&cp, 1); + codeunits_per_codepoint = detail::utf_size_as(&cp, 1); } size_.codeunit_size() = codeunits_per_codepoint * count; if constexpr (store_codepoint_size) { @@ -209,11 +209,11 @@ namespace small { buffer_.resize(buffer_.capacity()); // Fill the buffer - if constexpr (!is_same_utf_encoding_v) { + if constexpr (!detail::is_same_utf_encoding_v) { if (codeunits_per_codepoint == 1) { std::fill(buffer_.begin(), buffer_.begin() + count, static_cast(cp)); } else { - to_utf(&cp, 1, buffer_.data(), codeunits_per_codepoint); + detail::to_utf(&cp, 1, buffer_.data(), codeunits_per_codepoint); size_type n_to_copy = count; for (value_type *it = buffer_.data(); --n_to_copy > 0;) { std::memcpy(it += codeunits_per_codepoint, buffer_.data(), codeunits_per_codepoint); @@ -279,8 +279,8 @@ namespace small { for (InputIt input_code_unit_it = first; input_code_unit_it != last && *input_code_unit_it;) { // Get code point sizes const size_type input_cu_left = last - input_code_unit_it; - uint8_t it_input_code_units = utf_size(*input_code_unit_it, input_cu_left); - uint8_t it_output_code_units = utf_size_as(input_code_unit_it, input_cu_left); + uint8_t it_input_code_units = detail::utf_size(*input_code_unit_it, input_cu_left); + uint8_t it_output_code_units = detail::utf_size_as(input_code_unit_it, input_cu_left); // Count code points we will have in the output if (it_output_code_units > 1) { @@ -304,7 +304,7 @@ namespace small { buffer_.resize(buffer_.capacity()); // Fill the buffer - if constexpr (is_same_utf_encoding_v) { + if constexpr (detail::is_same_utf_encoding_v) { if constexpr (std::is_pointer_v) { std::memcpy(buffer_.data(), first, input_code_units); } else /* if (is iterator) */ { @@ -317,10 +317,11 @@ namespace small { // Get sizes const size_type input_cu_left = last - input_code_unit_it; const size_type output_cu_left = output_code_units - buffer_idx; - const size_type it_input_code_units = utf_size(*input_code_unit_it, input_cu_left); - const size_type it_output_code_units = utf_size_as(input_code_unit_it, input_cu_left); + const size_type it_input_code_units = detail::utf_size(*input_code_unit_it, input_cu_left); + const size_type it_output_code_units = + detail::utf_size_as(input_code_unit_it, input_cu_left); // Convert - to_utf(input_code_unit_it, input_cu_left, buffer_.data() + buffer_idx, output_cu_left); + detail::to_utf(input_code_unit_it, input_cu_left, buffer_.data() + buffer_idx, output_cu_left); // Next input_code_unit_it += it_input_code_units; buffer_idx += it_output_code_units; @@ -339,7 +340,7 @@ namespace small { size_type multibyte_idx = 0; while (codeunit_idx < size_.codeunit_size()) { const size_type n_code_units = - utf_size(buffer_[codeunit_idx], size_.codeunit_size() - codeunit_idx); + detail::utf_size(buffer_[codeunit_idx], size_.codeunit_size() - codeunit_idx); if (n_code_units > 1) { t.insert_or_assign(multibyte_idx, codeunit_idx, codepoint_idx); ++multibyte_idx; @@ -363,14 +364,14 @@ namespace small { /// \brief Constructs the string with the first count characters of character string pointed to by s. template constexpr basic_string(const InputChar *s, size_type count, const allocator_type &alloc = allocator_type()) - : basic_string(s, count != npos ? (s + count) : s + strlen(s), alloc) {} + : basic_string(s, count != npos ? (s + count) : s + detail::strlen(s), alloc) {} /// \brief Constructs the string with the contents initialized with a copy of the null-terminated character /// string pointed to by s. template /// NOLINTNEXTLINE(google-explicit-constructor): replicating the std::string constructor constexpr basic_string(const InputChar *s, const allocator_type &alloc = allocator_type()) - : basic_string(s, strlen(s), alloc) {} + : basic_string(s, detail::strlen(s), alloc) {} /// \brief Copy constructor. Constructs the string with a copy of the contents of other. constexpr basic_string(const basic_string &other) : buffer_(other.buffer_), size_(other.size_) {} @@ -558,7 +559,7 @@ namespace small { constexpr reference at(size_type byte_index) { const size_type size = this->size(); if (byte_index >= size) { - throw_exception("basic_string::at: index out of bounds"); + detail::throw_exception("basic_string::at: index out of bounds"); } return operator[](byte_index); } @@ -574,7 +575,7 @@ namespace small { constexpr codepoint_reference at(codepoint_index index) { const size_type size = this->size_.codepoint_size(); if (index >= size) { - throw_exception("basic_string::at: index out of bounds"); + detail::throw_exception("basic_string::at: index out of bounds"); } return operator[](index); } @@ -843,7 +844,7 @@ namespace small { const_lookup_table_type t = const_lookup_table(); const size_type look_size_in_bytes = lookup_table_type::size_for(buffer_.capacity(), t.size()); return buffer_.capacity() - null_char_size - - static_cast(div_ceil(look_size_in_bytes, sizeof(value_type))); + static_cast(detail::div_ceil(look_size_in_bytes, sizeof(value_type))); } else { return buffer_.capacity() - null_char_size; } @@ -964,7 +965,7 @@ namespace small { /// \throws std::out_of_range if index > size() template constexpr basic_string &insert(size_type index, size_type count, Char ch) { if (index > size()) { - throw_exception("basic_string::insert: index > size()"); + detail::throw_exception("basic_string::insert: index > size()"); } insert(begin() + index, count, ch); return *this; @@ -972,7 +973,7 @@ namespace small { template constexpr basic_string &insert(codepoint_index index, size_type count, Char ch) { if (index > size_codepoints()) { - throw_exception("basic_string::insert: index > size_codepoints()"); + detail::throw_exception("basic_string::insert: index > size_codepoints()"); } codepoint_iterator it = begin_codepoint() + index; return insert(it.byte_index(), count, ch); @@ -983,7 +984,7 @@ namespace small { /// The length of the string is determined by the first null character using Traits::length(s) template constexpr basic_string &insert(size_type index, const Char *s) { if (index > size()) { - throw_exception("basic_string::insert: index > size()"); + detail::throw_exception("basic_string::insert: index > size()"); } insert(begin() + index, s, s + std::char_traits::length(s)); return *this; @@ -991,7 +992,7 @@ namespace small { template constexpr basic_string &insert(codepoint_index index, const Char *s) { if (index > size_codepoints()) { - throw_exception("basic_string::insert: index > size_codepoints()"); + detail::throw_exception("basic_string::insert: index > size_codepoints()"); } insert(begin_codepoint() + index, s, s + std::char_traits::length(s)); return *this; @@ -1002,7 +1003,7 @@ namespace small { /// \throws std::out_of_range if index > size() template constexpr basic_string &insert(size_type index, const Char *s, size_type count) { if (index > size()) { - throw_exception("basic_string::insert: index > size()"); + detail::throw_exception("basic_string::insert: index > size()"); } insert(begin() + index, s, s + count); return *this; @@ -1010,7 +1011,7 @@ namespace small { template constexpr basic_string &insert(codepoint_index index, const Char *s, size_type count) { if (index > size_codepoints()) { - throw_exception("basic_string::insert: index > size_codepoints()"); + detail::throw_exception("basic_string::insert: index > size_codepoints()"); } insert(begin_codepoint() + index, s, s + count); return *this; @@ -1020,7 +1021,7 @@ namespace small { /// \throws std::out_of_range if index > size() constexpr basic_string &insert(size_type index, const basic_string &str) { if (index > size()) { - throw_exception("basic_string::insert: index > size()"); + detail::throw_exception("basic_string::insert: index > size()"); } insert(begin() + index, str.begin(), str.end()); return *this; @@ -1028,7 +1029,7 @@ namespace small { constexpr basic_string &insert(codepoint_index index, const basic_string &str) { if (index > size_codepoints()) { - throw_exception("basic_string::insert: index > size_codepoints()"); + detail::throw_exception("basic_string::insert: index > size_codepoints()"); } insert(begin_codepoint() + index, str.begin(), str.end()); return *this; @@ -1039,10 +1040,10 @@ namespace small { constexpr basic_string &insert(size_type index, const basic_string &str, size_type index_str, size_type count = npos) { if (index > size()) { - throw_exception("basic_string::insert: index > size()"); + detail::throw_exception("basic_string::insert: index > size()"); } if (index_str > str.size()) { - throw_exception("basic_string::insert: index_str > str.size()"); + detail::throw_exception("basic_string::insert: index_str > str.size()"); } const_iterator str_first = str.begin() + index_str; const_iterator str_last = count != npos ? str_first + count : str.end(); @@ -1053,10 +1054,10 @@ namespace small { constexpr basic_string &insert(size_type index, const basic_string &str, codepoint_index index_str, codepoint_index count = codepoint_index(npos)) { if (index > size()) { - throw_exception("basic_string::insert: index > size()"); + detail::throw_exception("basic_string::insert: index > size()"); } if (index_str > str.size_codepoints()) { - throw_exception("basic_string::insert: index_str > str.size_codepoints()"); + detail::throw_exception("basic_string::insert: index_str > str.size_codepoints()"); } const_codepoint_iterator str_codepoint_first = str.begin_codepoint() + index_str; const_codepoint_iterator str_codepoint_last = @@ -1070,10 +1071,10 @@ namespace small { constexpr basic_string &insert(codepoint_index index, const basic_string &str, size_type index_str, size_type count = npos) { if (index > size_codepoints()) { - throw_exception("basic_string::insert: index > size_codepoints()"); + detail::throw_exception("basic_string::insert: index > size_codepoints()"); } if (index_str > str.size()) { - throw_exception("basic_string::insert: index_str > str.size()"); + detail::throw_exception("basic_string::insert: index_str > str.size()"); } codepoint_iterator this_cp_pos = begin_codepoint() + index; const_iterator str_first = str.begin() + index_str; @@ -1085,10 +1086,10 @@ namespace small { constexpr basic_string &insert(codepoint_index index, const basic_string &str, codepoint_index index_str, codepoint_index count = codepoint_index(npos)) { if (index > size_codepoints()) { - throw_exception("basic_string::insert: index > size_codepoints()"); + detail::throw_exception("basic_string::insert: index > size_codepoints()"); } if (index_str > str.size_codepoints()) { - throw_exception("basic_string::insert: index_str > str.size_codepoints()"); + detail::throw_exception("basic_string::insert: index_str > str.size_codepoints()"); } codepoint_iterator this_cp_pos = begin_codepoint() + index; const_codepoint_iterator str_codepoint_first = str.begin_codepoint() + index_str; @@ -1122,7 +1123,7 @@ namespace small { } // Input properties - uint8_t codeunits_per_codepoint = utf_size_as(&ch, 1); + uint8_t codeunits_per_codepoint = detail::utf_size_as(&ch, 1); const size_type count_code_units = count * codeunits_per_codepoint; const size_type count_code_points = count; @@ -1144,11 +1145,11 @@ namespace small { } // Fill the buffer with new elements - if constexpr (!is_same_utf_encoding_v) { + if constexpr (!detail::is_same_utf_encoding_v) { if (codeunits_per_codepoint == 1) { std::fill(begin() + pos_idx, new_pos, static_cast(ch)); } else { - to_utf(&ch, 1, buffer_.data() + pos_idx, codeunits_per_codepoint); + detail::to_utf(&ch, 1, buffer_.data() + pos_idx, codeunits_per_codepoint); size_type n_to_copy = count_code_points; for (value_type *it = buffer_.data() + pos_idx; --n_to_copy > 0;) { std::memcpy(it += codeunits_per_codepoint, buffer_.data() + pos_idx, codeunits_per_codepoint); @@ -1171,7 +1172,7 @@ namespace small { constexpr codepoint_iterator insert(const_codepoint_iterator pos, size_type count, Char ch) { size_type pos_offset = pos.index(); if (pos.index() > size_codepoints()) { - throw_exception("basic_string::insert: pos.index() > size_codepoints()"); + detail::throw_exception("basic_string::insert: pos.index() > size_codepoints()"); } insert(begin() + pos.byte_index(), count, ch); return begin_codepoint() + pos_offset; @@ -1208,8 +1209,8 @@ namespace small { auto it = first; while (it != last) { const size_type bytes_left = last - it; - const uint8_t it_input_code_units = utf_size(*it, bytes_left); - const uint8_t it_output_code_units = utf_size_as(it, bytes_left); + const uint8_t it_input_code_units = detail::utf_size(*it, bytes_left); + const uint8_t it_output_code_units = detail::utf_size_as(it, bytes_left); output_code_units += it_output_code_units; it += it_input_code_units; if (it_output_code_units > 1) { @@ -1237,13 +1238,13 @@ namespace small { } // Fill the buffer with new elements - if constexpr (!is_same_utf_encoding_v) { + if constexpr (!detail::is_same_utf_encoding_v) { auto from_it = first; auto to_it = begin() + pos_idx; while (from_it != last) { - uint8_t input_codepoint_size = utf_size(*from_it, last - from_it); - uint8_t output_codepoint_size = utf_size_as(from_it, last - from_it); - to_utf(from_it, input_codepoint_size, to_it.base(), output_codepoint_size); + uint8_t input_codepoint_size = detail::utf_size(*from_it, last - from_it); + uint8_t output_codepoint_size = detail::utf_size_as(from_it, last - from_it); + detail::to_utf(from_it, input_codepoint_size, to_it.base(), output_codepoint_size); from_it += input_codepoint_size; to_it += output_codepoint_size; } @@ -1264,7 +1265,7 @@ namespace small { constexpr codepoint_iterator insert(const_codepoint_iterator pos, InputIt first, InputIt last) { const size_type pos_offset = pos.index(); if (pos > end_codepoint()) { - throw_exception("basic_string::insert: pos > end_codepoint()"); + detail::throw_exception("basic_string::insert: pos > end_codepoint()"); } insert(begin() + pos.byte_index(), first, last); return begin_codepoint() + pos_offset; @@ -1318,10 +1319,10 @@ namespace small { constexpr basic_string &insert(size_type index, const T &t, size_type index_str, size_type count = npos) { std::basic_string_view> sv(t); if (index > size()) { - throw_exception("basic_string::insert: index > size()"); + detail::throw_exception("basic_string::insert: index > size()"); } if (index_str > sv.size()) { - throw_exception("basic_string::insert: index_str > str.size()"); + detail::throw_exception("basic_string::insert: index_str > str.size()"); } auto substr = sv.substr(index_str, count); insert(begin() + index, substr.begin(), substr.end()); @@ -1332,10 +1333,10 @@ namespace small { constexpr basic_string &insert(codepoint_index index, const T &t, size_type index_str, size_type count = npos) { std::basic_string_view> sv(t); if (index > size_codepoints()) { - throw_exception("basic_string::insert: index > size_codepoints()"); + detail::throw_exception("basic_string::insert: index > size_codepoints()"); } if (index_str > sv.size()) { - throw_exception("basic_string::insert: index_str > str.size()"); + detail::throw_exception("basic_string::insert: index_str > str.size()"); } auto substr = sv.substr(index_str, count); insert(begin_codepoint() + index, substr.begin(), substr.end()); @@ -1349,7 +1350,7 @@ namespace small { /// \throws std::out_of_range if index > size() constexpr basic_string &erase(size_type index = 0, size_type count = npos) { if (index > size()) { - throw_exception("basic_string::erase: index > size()"); + detail::throw_exception("basic_string::erase: index > size()"); } iterator first = begin() + index; iterator last = first + std::min(count, size() - index); @@ -1359,7 +1360,7 @@ namespace small { constexpr basic_string &erase(codepoint_index index = 0, codepoint_index count = codepoint_index(npos)) { if (index > size_codepoints()) { - throw_exception("basic_string::erase: index > size_codepoints()"); + detail::throw_exception("basic_string::erase: index > size_codepoints()"); } codepoint_iterator first_codepoint = begin_codepoint() + index; size_type count_codepoint = std::min(count.value_of(), size_codepoints() - index); @@ -1403,7 +1404,7 @@ namespace small { } value_type *new_code_unit_begin = buffer_.data() + first_offset; value_type *code_unit_end_pos = buffer_.data() + size(); - shift::shift_left(new_code_unit_begin, code_unit_end_pos, count_codeunit); + detail::shift::shift_left(new_code_unit_begin, code_unit_end_pos, count_codeunit); // Set null char value_type *new_code_unit_end_pos = code_unit_end_pos - count_codeunit; @@ -1558,15 +1559,15 @@ namespace small { if (sv.empty()) { return true; } - if constexpr (!is_same_utf_encoding_v) { + if constexpr (!detail::is_same_utf_encoding_v) { auto this_first = begin(); auto this_last = end(); auto other_first = sv.begin(); auto other_last = sv.end(); while (this_first != this_last && other_first != other_last) { - const uint8_t buf_size = utf_size_as(other_first, other_last - other_first); + const uint8_t buf_size = detail::utf_size_as(other_first, other_last - other_first); value_type buf[8]; - to_utf(other_first, other_last - other_first, buf, buf_size); + detail::to_utf(other_first, other_last - other_first, buf, buf_size); const size_type this_code_units_left = this_last - this_first; if (this_code_units_left < buf_size) { return false; @@ -1574,7 +1575,7 @@ namespace small { if (!std::equal(this_first, this_first + buf_size, buf, buf + buf_size)) { return false; } - other_first += utf_size(*other_first, other_last - other_first); + other_first += detail::utf_size(*other_first, other_last - other_first); this_first += buf_size; } return !*other_first; @@ -1593,10 +1594,10 @@ namespace small { if (empty()) { return false; } - if constexpr (!is_same_utf_encoding_v) { - const uint8_t s = utf_size_as(&c, 1); + if constexpr (!detail::is_same_utf_encoding_v) { + const uint8_t s = detail::utf_size_as(&c, 1); value_type buf[8]; - to_utf(&c, 1, buf, s); + detail::to_utf(&c, 1, buf, s); return size() >= s && std::equal(begin(), begin() + s, buf, buf + s); } else { return front() == c; @@ -1613,16 +1614,16 @@ namespace small { if (!*s) { return true; } - if constexpr (!is_same_utf_encoding_v) { + if constexpr (!detail::is_same_utf_encoding_v) { auto this_first = begin(); auto this_last = end(); auto other_first = s; auto other_last = s + std::char_traits::length(s); while (this_first != this_last && *other_first) { const size_type other_values_left = other_last - other_first; - const uint8_t buf_size = utf_size_as(other_first, other_values_left); + const uint8_t buf_size = detail::utf_size_as(other_first, other_values_left); value_type buf[8]; - to_utf(other_first, other_values_left, buf, buf_size); + detail::to_utf(other_first, other_values_left, buf, buf_size); const size_type this_bytes_left = this_last - this_first; if (this_bytes_left < buf_size) { return false; @@ -1630,7 +1631,7 @@ namespace small { if (!std::equal(this_first, this_first + buf_size, buf, buf + buf_size)) { return false; } - other_first += utf_size(*other_first, other_values_left); + other_first += detail::utf_size(*other_first, other_values_left); this_first += buf_size; } return !*other_first; @@ -1654,12 +1655,12 @@ namespace small { if (sv.empty()) { return true; } - if constexpr (!is_same_utf_encoding_v) { + if constexpr (!detail::is_same_utf_encoding_v) { // Count code points in other auto it_other = sv.begin(); size_type other_code_points = 0; while (it_other != sv.end()) { - auto it_cp_size = utf_size(*it_other, sv.end() - it_other); + auto it_cp_size = detail::utf_size(*it_other, sv.end() - it_other); other_code_points += it_cp_size; it_other += it_cp_size; } @@ -1674,10 +1675,10 @@ namespace small { while (this_first != this_last && other_first != other_last) { // Find other code point auto other_entries_left = sv.end() - other_first; - auto other_cp_size = utf_size(*other_first, other_entries_left); + auto other_cp_size = detail::utf_size(*other_first, other_entries_left); // Convert other codepoint to utf32 - utf32_char_type r{}; - auto ok = to_utf32(other_first, other_cp_size, &r, 1); + detail::utf32_char_type r{}; + auto ok = detail::to_utf32(other_first, other_cp_size, &r, 1); if (!ok) { break; } @@ -1705,7 +1706,7 @@ namespace small { if (empty()) { return false; } - if constexpr (!is_same_utf_encoding_v) { + if constexpr (!detail::is_same_utf_encoding_v) { return *rbegin_codepoint() == c; } else { return back() == c; @@ -1754,10 +1755,10 @@ namespace small { constexpr basic_string &replace(size_type pos, size_type count, const basic_string &str, size_type pos2, size_type count2 = npos) { if (pos > size()) { - throw_exception("string::replace: pos > size()"); + detail::throw_exception("string::replace: pos > size()"); } if (pos2 > str.size()) { - throw_exception("string::replace: pos2 > str.size()"); + detail::throw_exception("string::replace: pos2 > str.size()"); } return replace(begin() + pos, begin() + pos + std::min(count, size() - pos), str.begin() + pos2, str.begin() + pos2 + std::min(count2, str.size() - pos2)); @@ -1766,10 +1767,10 @@ namespace small { constexpr basic_string &replace(size_type pos, size_type count, const basic_string &str, codepoint_index pos2, codepoint_index count2 = codepoint_index(npos)) { if (pos > size()) { - throw_exception("string::replace: pos > size()"); + detail::throw_exception("string::replace: pos > size()"); } if (pos2 > str.size_codepoints()) { - throw_exception("string::replace: pos2 > str.size_codepoints()"); + detail::throw_exception("string::replace: pos2 > str.size_codepoints()"); } const_codepoint_iterator other_first_code_point = str.begin_codepoint() + pos2; const_codepoint_iterator other_last_code_point = @@ -1783,10 +1784,10 @@ namespace small { constexpr basic_string &replace(codepoint_index pos, codepoint_index count, const basic_string &str, size_type pos2, size_type count2 = npos) { if (pos > size_codepoints()) { - throw_exception("string::replace: pos > size_codepoints()"); + detail::throw_exception("string::replace: pos > size_codepoints()"); } if (pos2 > str.size()) { - throw_exception("string::replace: pos2 > str.size()"); + detail::throw_exception("string::replace: pos2 > str.size()"); } codepoint_iterator first_code_point = begin_codepoint() + pos; codepoint_iterator last_code_point = @@ -1800,10 +1801,10 @@ namespace small { constexpr basic_string &replace(codepoint_index pos, codepoint_index count, const basic_string &str, codepoint_index pos2, codepoint_index count2 = codepoint_index(npos)) { if (pos > size_codepoints()) { - throw_exception("string::replace: pos > size_codepoints()"); + detail::throw_exception("string::replace: pos > size_codepoints()"); } if (pos2 > str.size_codepoints()) { - throw_exception("string::replace: pos2 > str.size_codepoints()"); + detail::throw_exception("string::replace: pos2 > str.size_codepoints()"); } codepoint_iterator first_code_point = begin_codepoint() + pos; codepoint_iterator last_code_point = @@ -1847,8 +1848,8 @@ namespace small { [](auto ch) { return static_cast(ch); }); const size_type new_codepoint = size_codepoints(first, last); if constexpr (has_lookup_table) { - const bool prev_had_multibyte = cmp_not_equal(prev_codepoint, d1); - const bool new_has_multibyte = cmp_not_equal(new_codepoint, d1); + const bool prev_had_multibyte = detail::cmp_not_equal(prev_codepoint, d1); + const bool new_has_multibyte = detail::cmp_not_equal(new_codepoint, d1); if (prev_had_multibyte || new_has_multibyte) { index_multibyte_codepoints(first, end()); } @@ -1875,7 +1876,7 @@ namespace small { template , int> = 0> constexpr basic_string &replace(size_type pos, size_type count, const Char *cstr, size_type count2) { if (pos > size()) { - throw_exception("string::replace: pos > size()"); + detail::throw_exception("string::replace: pos > size()"); } return replace(begin() + pos, begin() + pos + std::min(count, size() - pos), cstr, cstr + count2); } @@ -1884,7 +1885,7 @@ namespace small { constexpr basic_string &replace(codepoint_index pos, codepoint_index count, const Char *cstr, size_type count2) { if (pos > size_codepoints()) { - throw_exception("string::replace: pos > size_codepoints()"); + detail::throw_exception("string::replace: pos > size_codepoints()"); } codepoint_iterator first_code_point = begin_codepoint() + pos; codepoint_iterator last_code_point = @@ -1911,7 +1912,7 @@ namespace small { /// \brief Replaces the part of the string with cstr template constexpr basic_string &replace(size_type pos, size_type count, const Char *cstr) { if (pos > size()) { - throw_exception("string::replace: pos > size()"); + detail::throw_exception("string::replace: pos > size()"); } return replace(begin() + pos, begin() + pos + std::min(count, size() - count), cstr, std::char_traits::length(cstr)); @@ -1920,7 +1921,7 @@ namespace small { template constexpr basic_string &replace(codepoint_index pos, codepoint_index count, const Char *cstr) { if (pos > size_codepoints()) { - throw_exception("string::replace: pos > size_codepoints()"); + detail::throw_exception("string::replace: pos > size_codepoints()"); } codepoint_iterator first_code_point = begin_codepoint() + pos; codepoint_iterator last_code_point = @@ -1948,7 +1949,7 @@ namespace small { template constexpr basic_string &replace(size_type pos, size_type count, size_type count2, Char ch) { if (pos > size()) { - throw_exception("string::replace: pos > size()"); + detail::throw_exception("string::replace: pos > size()"); } return replace(begin() + pos, begin() + pos + std::min(count, size() - pos), count2, ch); } @@ -1956,7 +1957,7 @@ namespace small { template , int> = 0> constexpr basic_string &replace(codepoint_index pos, codepoint_index count, size_type count2, Char ch) { if (pos > size_codepoints()) { - throw_exception("string::replace: pos > size_codepoints()"); + detail::throw_exception("string::replace: pos > size_codepoints()"); } codepoint_iterator first_code_point = begin_codepoint() + pos; codepoint_iterator last_code_point = @@ -2000,7 +2001,7 @@ namespace small { template , int> = 0> constexpr basic_string &replace(size_type pos, size_type count, const T &t) { if (pos > size()) { - throw_exception("string::replace: pos > size()"); + detail::throw_exception("string::replace: pos > size()"); } std::basic_string_view sv(t); return replace(begin() + pos, begin() + pos + std::min(count, size() - pos), sv.begin(), sv.end()); @@ -2009,7 +2010,7 @@ namespace small { template , int> = 0> constexpr basic_string &replace(codepoint_index pos, codepoint_index count, const T &t) { if (pos > size_codepoints()) { - throw_exception("string::replace: pos > size_codepoints()"); + detail::throw_exception("string::replace: pos > size_codepoints()"); } std::basic_string_view sv(t); codepoint_iterator first_code_point = begin_codepoint() + pos; @@ -2040,7 +2041,7 @@ namespace small { constexpr basic_string &replace(size_type pos, size_type count, const T &t, size_type pos2, size_type count2 = npos) { if (pos > size()) { - throw_exception("string::replace: pos > size()"); + detail::throw_exception("string::replace: pos > size()"); } std::basic_string_view sv(t); sv = sv.substr(pos2, count2); @@ -2051,7 +2052,7 @@ namespace small { constexpr basic_string &replace(codepoint_index pos, codepoint_index count, const T &t, size_type pos2, size_type count2 = npos) { if (pos > size_codepoints()) { - throw_exception("string::replace: pos > size_codepoints()"); + detail::throw_exception("string::replace: pos > size_codepoints()"); } std::basic_string_view sv(t); sv = sv.substr(pos2, count2); @@ -2087,7 +2088,7 @@ namespace small { /// \throws If pos > size(), std::out_of_range is thrown template constexpr size_type copy(Char *dest, size_type count, size_type pos = 0) const { if (pos > size()) { - throw_exception("string::copy: pos > size()"); + detail::throw_exception("string::copy: pos > size()"); } const_iterator first = begin() + pos; const_iterator last = first + std::min(count, size() - pos); @@ -2105,7 +2106,7 @@ namespace small { template constexpr size_type copy(Char *dest, codepoint_index count, codepoint_index pos = codepoint_index(0)) const { if (pos > size_codepoints()) { - throw_exception("string::copy: pos > size_codepoints()"); + detail::throw_exception("string::copy: pos > size_codepoints()"); } const const_codepoint_iterator first_cp = begin_codepoint() + pos; const const_codepoint_iterator last_cp = @@ -2142,7 +2143,7 @@ namespace small { downsize(count); } else if (count > size_codepoints()) { size_type codepoint_increase = count - size_codepoints(); - uint8_t code_units_per_code_point = utf_size_as(&ch, 1); + uint8_t code_units_per_code_point = detail::utf_size_as(&ch, 1); size_type code_unit_increase = codepoint_increase * code_units_per_code_point; upsize(size() + code_unit_increase, ch); } @@ -2176,7 +2177,7 @@ namespace small { /// that begins before code_unit_index. [[nodiscard]] codepoint_iterator find_codepoint(size_type code_unit_index) { // Decrement to a codepoint start - while (is_utf8_continuation(buffer_[code_unit_index]) && code_unit_index > 0) { + while (detail::is_utf8_continuation(buffer_[code_unit_index]) && code_unit_index > 0) { --code_unit_index; } // Find first multibyte >= this code unit and get its codepoint @@ -2189,7 +2190,7 @@ namespace small { if (byte_distance == 0) { return begin_codepoint() + first_multibyte_after_codepoint; } else { - const size_type this_size = utf8_size(buffer_[code_unit_index], size() - code_unit_index); + const size_type this_size = detail::utf8_size(buffer_[code_unit_index], size() - code_unit_index); const size_type codepoint_distance = byte_distance - this_size + 1; const size_type this_codepoint_index = first_multibyte_after_codepoint - codepoint_distance; return begin_codepoint() + this_codepoint_index; @@ -2225,7 +2226,7 @@ namespace small { if (pos >= size()) { return npos; } - constexpr bool same_encoding = is_same_utf_encoding_v; + constexpr bool same_encoding = detail::is_same_utf_encoding_v; if constexpr (same_encoding) { // Sequential search const_iterator it = std::search(begin() + pos, end(), s, s + count); @@ -2311,7 +2312,7 @@ namespace small { if (pos >= size()) { return npos; } - constexpr bool same_encoding = is_same_utf_encoding_v; + constexpr bool same_encoding = detail::is_same_utf_encoding_v; if constexpr (same_encoding) { const_iterator it = begin() + pos; if (std::equal(it, it + count, s, s + count)) { @@ -2331,7 +2332,7 @@ namespace small { const_codepoint_iterator this_cp_first = find_codepoint(pos); const_codepoint_iterator end = end_codepoint(); auto d_to_end = end - this_cp_first; - if (cmp_less(d_to_end, count)) { + if (detail::cmp_less(d_to_end, count)) { this_cp_first -= (count - d_to_end); } const_codepoint_iterator this_cp_last = this_cp_first + count; @@ -2568,7 +2569,7 @@ namespace small { const value_type *this_it = data(); auto *this_end = this_it + size(); while (this_it != this_end && first != last && *first) { - if constexpr (is_same_utf_encoding_v) { + if constexpr (detail::is_same_utf_encoding_v) { if (*this_it != *first) { return *this_it < *first ? -1 : 1; } @@ -2578,9 +2579,9 @@ namespace small { // Encode to "this" utf type value_type buf[8]; std::memset(buf, '\0', 8); - width_type other_code_units = utf_size(*first, last - first); - width_type this_code_units = utf_size_as(first, other_code_units); - to_utf(first, other_code_units, buf, this_code_units); + width_type other_code_units = detail::utf_size(*first, last - first); + width_type this_code_units = detail::utf_size_as(first, other_code_units); + detail::to_utf(first, other_code_units, buf, this_code_units); // Compare the encoded arrays value_type *encoded_first = buf; value_type *encoded_last = buf + this_code_units; @@ -2599,13 +2600,15 @@ namespace small { } /// \brief Compare this string with a range of chars - template , int> = 0> + template , int> = 0> constexpr int compare(Range &&r) const noexcept { return compare(r.begin(), r.end()); } /// \brief Compare this string with a null terminated char array - template constexpr int compare(const Char *s) const { return compare(s, s + strlen(s)); } + template constexpr int compare(const Char *s) const { + return compare(s, s + detail::strlen(s)); + } /// \brief Compare this string with a null terminated std::string template @@ -2656,7 +2659,7 @@ namespace small { // other small basic string type is_small_basic_string, // range of chars - is_range, + detail::is_range, // std::string is_std_basic_string, // CharT* @@ -2716,7 +2719,7 @@ namespace small { } template >, int> = 0> - constexpr friend bool operator<(T &&lhs, const basic_string &rhs) noexcept { + constexpr friend bool operator<(T && lhs, const basic_string &rhs) noexcept { return rhs.compare(lhs) > 0; } @@ -2877,7 +2880,8 @@ namespace small { // 2) Then stores each character from the resulting sequence (the contents of str plus padding) to the // output stream os as if by calling os.rdbuf()->sputn(seq, n), where n=std::max(os.width(), str.size()) 3) // Finally, calls os.width(0) to cancel the effects of std::setw, if any - console_unicode_guard g(os, str.size(), str.size_codepoints(), (str.size() - str.size_codepoints()) > 2); + detail::console_unicode_guard g(os, str.size(), str.size_codepoints(), + (str.size() - str.size_codepoints()) > 2); os << str.c_str(); return os; } @@ -3035,9 +3039,9 @@ namespace small { /// \brief True if this string type supports utf8 /// We use utf8 for the string whenever the char size is 1. - static constexpr bool is_utf8_string = is_utf8_v; - static constexpr bool is_utf16_string = is_utf16_v; - static constexpr bool is_utf32_string = is_utf32_v; + static constexpr bool is_utf8_string = detail::is_utf8_v; + static constexpr bool is_utf16_string = detail::is_utf16_v; + static constexpr bool is_utf32_string = detail::is_utf32_v; static_assert(is_utf8_string || is_utf16_string || is_utf32_string, "string: A unicode char type is required"); @@ -3069,7 +3073,7 @@ namespace small { assert(count > size()); // Calculate increments - uint8_t code_units_per_char = utf_size_as(&ch, 1); + uint8_t code_units_per_char = detail::utf_size_as(&ch, 1); size_type code_unit_increment = count - size(); size_type code_point_increment = code_unit_increment / code_units_per_char; const_lookup_table_type ct = const_lookup_table(); @@ -3080,12 +3084,12 @@ namespace small { // Fill the buffer value_type *fill_begin = (buffer_.begin() + size()).base(); value_type *fill_end = fill_begin + code_unit_increment; - if constexpr (!is_same_utf_encoding_v) { + if constexpr (!detail::is_same_utf_encoding_v) { if (code_units_per_char == 1) { std::fill(fill_begin, fill_end, static_cast(ch)); } else { // Fill buffer - to_utf(&ch, 1, fill_begin, code_unit_increment); + detail::to_utf(&ch, 1, fill_begin, code_unit_increment); if (code_units_per_char < code_unit_increment) { for (size_type i = 1; i < code_point_increment; ++i) { std::memcpy(fill_begin + i * code_units_per_char, fill_begin, code_units_per_char); @@ -3226,7 +3230,7 @@ namespace small { size_type input_multibytes_in_range = 0; auto it = first; while (it < last) { - uint8_t s = utf8_size(*it, end() - it); + uint8_t s = detail::utf8_size(*it, end() - it); if (s > 1) { ++input_multibytes_in_range; } @@ -3260,7 +3264,7 @@ namespace small { // Iterate and reindex codepoints from first to end() while (codeunit_idx < size_.codeunit_size()) { const size_type utf8_code_units = - utf8_size(buffer_[codeunit_idx], size_.codeunit_size() - codeunit_idx); + detail::utf8_size(buffer_[codeunit_idx], size_.codeunit_size() - codeunit_idx); if (utf8_code_units > 1) { t.insert_or_assign(multibyte_idx, codeunit_idx, codepoint_idx); ++multibyte_idx; @@ -3464,10 +3468,10 @@ namespace small { }; /// \brief Typedef of string (data type: char) - using string = basic_string; + using string = basic_string; /// \brief Typedef of u8string (data type char8_t) - using u8string = basic_string; + using u8string = basic_string; /// \brief Forms a string literal of the desired type /// returns std::string{str, len} @@ -3483,11 +3487,11 @@ namespace small { char *p_end; const long i = std::strtol(str.c_str(), &p_end, base); if (str.c_str() == p_end) { - throw_exception("stoi(small::string): no conversion could be performed"); + detail::throw_exception("stoi(small::string): no conversion could be performed"); } - if (errno == ERANGE || cmp_greater(i, std::numeric_limits::max()) || - cmp_less(i, std::numeric_limits::min())) { - throw_exception( + if (errno == ERANGE || detail::cmp_greater(i, std::numeric_limits::max()) || + detail::cmp_less(i, std::numeric_limits::min())) { + detail::throw_exception( "stoi(small::string): converted value falls out of the range of the result type"); } if (pos) { @@ -3506,10 +3510,10 @@ namespace small { char *p_end; const long i = std::strtol(str.c_str(), &p_end, base); if (str.c_str() == p_end) { - throw_exception("stol(small::string): no conversion could be performed"); + detail::throw_exception("stol(small::string): no conversion could be performed"); } if (errno == ERANGE) { - throw_exception( + detail::throw_exception( "stol(small::string): converted value falls out of the range of the result type"); } if (pos) { @@ -3528,10 +3532,10 @@ namespace small { char *p_end; const long long i = std::strtoll(str.c_str(), &p_end, base); if (str.c_str() == p_end) { - throw_exception("stoll(small::string): no conversion could be performed"); + detail::throw_exception("stoll(small::string): no conversion could be performed"); } if (errno == ERANGE) { - throw_exception( + detail::throw_exception( "stoll(small::string): converted value falls out of the range of the result type"); } if (pos) { @@ -3550,10 +3554,10 @@ namespace small { char *p_end; const unsigned long i = std::strtoul(str.c_str(), &p_end, base); if (str.c_str() == p_end) { - throw_exception("stoul(small::string): no conversion could be performed"); + detail::throw_exception("stoul(small::string): no conversion could be performed"); } if (errno == ERANGE) { - throw_exception( + detail::throw_exception( "stoul(small::string): converted value falls out of the range of the result type"); } if (pos) { @@ -3572,10 +3576,10 @@ namespace small { char *p_end; const unsigned long long i = std::strtoull(str.c_str(), &p_end, base); if (str.c_str() == p_end) { - throw_exception("stoull(small::string): no conversion could be performed"); + detail::throw_exception("stoull(small::string): no conversion could be performed"); } if (errno == ERANGE) { - throw_exception( + detail::throw_exception( "stoull(small::string): converted value falls out of the range of the result type"); } if (pos) { @@ -3594,10 +3598,10 @@ namespace small { char *p_end; const float i = std::strtof(str.c_str(), &p_end); if (str.c_str() == p_end) { - throw_exception("stof(small::string): no conversion could be performed"); + detail::throw_exception("stof(small::string): no conversion could be performed"); } if (errno == ERANGE) { - throw_exception( + detail::throw_exception( "stof(small::string): converted value falls out of the range of the result type"); } if (pos) { @@ -3616,10 +3620,10 @@ namespace small { char *p_end; const double i = std::strtod(str.c_str(), &p_end); if (str.c_str() == p_end) { - throw_exception("stod(small::string): no conversion could be performed"); + detail::throw_exception("stod(small::string): no conversion could be performed"); } if (errno == ERANGE) { - throw_exception( + detail::throw_exception( "stod(small::string): converted value falls out of the range of the result type"); } if (pos) { @@ -3638,10 +3642,10 @@ namespace small { char *p_end; const long double i = std::strtold(str.c_str(), &p_end); if (str.c_str() == p_end) { - throw_exception("stold(small::string): no conversion could be performed"); + detail::throw_exception("stold(small::string): no conversion could be performed"); } if (errno == ERANGE) { - throw_exception( + detail::throw_exception( "stold(small::string): converted value falls out of the range of the result type"); } if (pos) { @@ -3670,17 +3674,17 @@ namespace small { [[nodiscard]] constexpr bool is_malformed( const small::basic_string &string) noexcept { using string_type = small::basic_string; - if constexpr (!is_utf32_v) { + if constexpr (!detail::is_utf32_v) { auto first = string.begin(); auto last = string.end(); while (first != last) { - if (is_utf_continuation(*first)) { + if (::small::detail::is_utf_continuation(*first)) { return true; } else { - uint8_t codepoint_size = utf_size(*first, 8); + uint8_t codepoint_size = detail::utf_size(*first, 8); ++first; for (uint8_t i = 1; i < codepoint_size; ++i) { - if (!is_utf_continuation(*first)) { + if (!detail::is_utf_continuation(*first)) { return true; } ++first; diff --git a/source/small/vector.h b/source/small/vector.h index 3aa78a7..fb95859 100644 --- a/source/small/vector.h +++ b/source/small/vector.h @@ -5,7 +5,6 @@ // https://www.boost.org/LICENSE_1_0.txt // - #ifndef SMALL_VECTOR_H #define SMALL_VECTOR_H @@ -70,9 +69,9 @@ namespace small { /// \tparam N Array maximum expected size template , class Allocator = std::allocator, class AllowHeap = std::true_type, class SizeType = size_t, class GrowthFactor = std::ratio<3, 2>> - class vector : public enable_allocator_from_this, Allocator> { + class vector : public detail::enable_allocator_from_this, Allocator> { private: - using enable_allocator_type = enable_allocator_from_this, Allocator>; + using enable_allocator_type = detail::enable_allocator_from_this, Allocator>; public: /// \section Common container types @@ -84,8 +83,8 @@ namespace small { typedef ptrdiff_t difference_type; typedef value_type *pointer; typedef const value_type *const_pointer; - typedef pointer_wrapper iterator; - typedef pointer_wrapper const_iterator; + typedef detail::pointer_wrapper iterator; + typedef detail::pointer_wrapper const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; @@ -351,7 +350,7 @@ namespace small { assert(invariants()); } - public /* constructors */: + public /* constructors */: /// \section Initialization constructors /// \brief Construct empty small array @@ -375,7 +374,7 @@ namespace small { /// \brief Construct small array from a pair of iterators template - constexpr vector(Iterator first, enable_if_iterator_t last, + constexpr vector(Iterator first, detail::enable_if_iterator_t last, const allocator_type &alloc = allocator_type()) { enable_allocator_type::set_allocator(alloc); // Handle input iterators @@ -414,7 +413,7 @@ namespace small { /// \brief Construct small array from a range /// This range might also be a std::vector - template , int> = 0> + template , int> = 0> constexpr explicit vector(Range &&r, const allocator_type &alloc = allocator_type()) : vector(r.begin(), r.end(), alloc) {} @@ -426,7 +425,7 @@ namespace small { /// \brief Assign small array from iterators template - constexpr void assign(InputIterator first, enable_if_iterator_t last) { + constexpr void assign(InputIterator first, detail::enable_if_iterator_t last) { clear(); insert(end(), first, last); } @@ -556,7 +555,7 @@ namespace small { assert(invariants()); } - public /* iterators */: + public /* iterators */: /// \brief Get iterator to first element constexpr iterator begin() noexcept { return iterator(data()); } @@ -601,7 +600,7 @@ namespace small { return std::reverse_iterator(cbegin()); } - public /* capacity */: + public /* capacity */: /// \brief Get small array size [[nodiscard]] constexpr size_type size() const noexcept { return get_unmasked_size(); } @@ -655,7 +654,7 @@ namespace small { tmp.swap(*this); } - public /* element access */: + public /* element access */: /// \brief Get reference to n-th element in small array constexpr reference operator[](size_type n) { assert(n < size() && "vector::operator[] index out of bounds"); @@ -671,7 +670,7 @@ namespace small { /// \brief Check bounds and get reference to n-th element in small array constexpr reference at(size_type n) { if (n >= size()) { - throw_exception("at: cannot access element after vector::size()"); + detail::throw_exception("at: cannot access element after vector::size()"); } return (*this)[n]; } @@ -679,7 +678,7 @@ namespace small { /// \brief Check bounds and get constant reference to n-th element in small array constexpr const_reference at(size_type n) const { if (n >= size()) { - throw_exception("at const: cannot access element after vector::size()"); + detail::throw_exception("at const: cannot access element after vector::size()"); } return (*this)[n]; } @@ -714,7 +713,7 @@ namespace small { /// \brief Get constant reference to internal pointer to small array data constexpr const T *data() const noexcept { return this->is_external() ? data_.heap() : data_.buffer(); } - public /* modifiers */: + public /* modifiers */: /// \brief Copy element to end of small array constexpr void push_back(const value_type &v) { emplace_back(v); } @@ -730,7 +729,7 @@ namespace small { return *(data_.buffer() + size_); } else { if constexpr (!should_use_heap) { - throw_exception("emplace_back: max_size exceeded in small_vector"); + detail::throw_exception("emplace_back: max_size exceeded in small_vector"); } else { // Handle external vectors size_type old_size = size(); @@ -807,7 +806,7 @@ namespace small { /// \brief Copy element range stating at a position in small array template constexpr iterator insert(const_iterator position, Iterator first, - enable_if_iterator_t last) { + detail::enable_if_iterator_t last) { // Handle input iterators using category = typename std::iterator_traits::iterator_category; using it_ref = typename std::iterator_traits::reference; @@ -996,8 +995,8 @@ namespace small { return; } make_size_internal( - new_size, [](void *) { throw_exception("Should not emplace when changing size"); }, - 0); + new_size, + [](void *) { detail::throw_exception("Should not emplace when changing size"); }, 0); } /// \brief Change the size and emplace the elements as we go @@ -1014,7 +1013,7 @@ namespace small { void make_size_internal(size_type new_size, EmplaceFunc &&emplace_func, size_type new_emplaced_size) { // Invariants if (new_size > max_size()) { - throw_exception("make_size: max_size exceeded in small_vector"); + detail::throw_exception("make_size: max_size exceeded in small_vector"); } else { if constexpr (!should_use_heap) { return; @@ -1402,7 +1401,7 @@ namespace small { /// \brief Create a vector from a raw array /// This is similar to std::to_array template , N_INPUT)> - constexpr vector, N_OUTPUT> to_vector(T(&&a)[N_INPUT]) { + constexpr vector, N_OUTPUT> to_vector(T (&&a)[N_INPUT]) { return vector, N_OUTPUT>(a, a + N_INPUT); } diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 2f91b64..a2cd58e 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -152,21 +152,21 @@ if (SMALL_BUILD_TESTS_WITH_PCH) ut_small_string_const_algorithms ut_small_string_non_member) target_precompile_headers(${string_target} - PRIVATE - - - - - - - + PRIVATE + + + + + + + - + - - - ) - endforeach() + + + ) + endforeach () target_precompile_headers(ut_small_set PRIVATE diff --git a/tests/unit_tests/custom_small_vector.cpp b/tests/unit_tests/custom_small_vector.cpp index 0912ace..1b1f88c 100644 --- a/tests/unit_tests/custom_small_vector.cpp +++ b/tests/unit_tests/custom_small_vector.cpp @@ -368,7 +368,7 @@ TEST_CASE("Custom Vector") { auto it = a.emplace(a.begin() + 2, "ten"); REQUIRE(it == a.begin() + 2); - auto& b = a.back(); + auto &b = a.back(); REQUIRE(b == "four"); REQUIRE(a.size() == 5); REQUIRE(a.max_size() > 5); diff --git a/tests/unit_tests/ptr_wrapper.cpp b/tests/unit_tests/ptr_wrapper.cpp index 89c74ad..271bfe1 100644 --- a/tests/unit_tests/ptr_wrapper.cpp +++ b/tests/unit_tests/ptr_wrapper.cpp @@ -23,6 +23,7 @@ TEST_CASE("Pointer wrapper") { using namespace small; + using namespace small::detail; SECTION("Constructor") { SECTION("Empty") { [[maybe_unused]] pointer_wrapper p; } diff --git a/tests/unit_tests/small_map.cpp b/tests/unit_tests/small_map.cpp index aa758df..b14d8cf 100644 --- a/tests/unit_tests/small_map.cpp +++ b/tests/unit_tests/small_map.cpp @@ -35,7 +35,8 @@ TEST_CASE("Small Map") { SECTION("Allocator") { std::allocator alloc; - associative_vector, 5, std::allocator>>> + detail::associative_vector, 5, std::allocator>>> a(alloc); REQUIRE(a.empty()); REQUIRE(equal_il(a, {})); @@ -353,7 +354,8 @@ TEST_CASE("Max Size Map") { SECTION("Allocator") { std::allocator alloc; - associative_vector, 5, std::allocator>>> + detail::associative_vector, 5, std::allocator>>> a(alloc); REQUIRE(a.empty()); REQUIRE(equal_il(a, {})); diff --git a/tests/unit_tests/small_set.cpp b/tests/unit_tests/small_set.cpp index 374e472..097b699 100644 --- a/tests/unit_tests/small_set.cpp +++ b/tests/unit_tests/small_set.cpp @@ -35,7 +35,7 @@ TEST_CASE("Small Set") { SECTION("Allocator") { std::allocator alloc; - associative_vector>> a(alloc); + detail::associative_vector>> a(alloc); REQUIRE(a.empty()); REQUIRE(equal_il(a, {})); REQUIRE(a.get_allocator() == alloc); @@ -348,7 +348,7 @@ TEST_CASE("Max Size Set") { SECTION("Allocator") { std::allocator alloc; - associative_vector>> a(alloc); + detail::associative_vector>> a(alloc); REQUIRE(a.empty()); REQUIRE(equal_il(a, {})); REQUIRE(a.get_allocator() == alloc); diff --git a/tests/unit_tests/small_string_const_algorithms.cpp b/tests/unit_tests/small_string_const_algorithms.cpp index da8f021..97bda11 100644 --- a/tests/unit_tests/small_string_const_algorithms.cpp +++ b/tests/unit_tests/small_string_const_algorithms.cpp @@ -97,14 +97,14 @@ TEST_CASE("String Const Algorithms") { SECTION("To UTF32") { SECTION("Copy count") { string a("😐🙂😀🙂😀😐😐🙂😀🙂😀😐"); - utf32_char_type b[7]{}; + detail::utf32_char_type b[7]{}; a.copy(b, string::codepoint_index(7)); REQUIRE(std::u32string_view(b, 7) == U"😐🙂😀🙂😀😐😐"); } SECTION("From pos") { string a("😐🙂😀🙂😀😐😐🙂😀🙂😀😐"); - utf32_char_type b[7]{}; + detail::utf32_char_type b[7]{}; a.copy(b, string::codepoint_index(7), string::codepoint_index(3)); REQUIRE(std::u32string_view(b, 7) == U"🙂😀😐😐🙂😀🙂"); } diff --git a/tests/unit_tests/small_string_modify.cpp b/tests/unit_tests/small_string_modify.cpp index 86c565c..33e437d 100644 --- a/tests/unit_tests/small_string_modify.cpp +++ b/tests/unit_tests/small_string_modify.cpp @@ -824,5 +824,4 @@ TEST_CASE("String Modify") { REQUIRE(a == "🙂😀🙂😀😐"); } } - } \ No newline at end of file diff --git a/tests/unit_tests/unicode_functions.cpp b/tests/unit_tests/unicode_functions.cpp index 0060b80..04291f9 100644 --- a/tests/unit_tests/unicode_functions.cpp +++ b/tests/unit_tests/unicode_functions.cpp @@ -22,6 +22,7 @@ TEST_CASE("Unicode") { using namespace small; + using namespace small::detail; SECTION("UTF8") { utf8_char_type a = 'g';