diff options
Diffstat (limited to 'compat')
| -rw-r--r-- | compat/array-size.hpp | 8 | ||||
| -rw-r--r-- | compat/assert.cpp | 38 | ||||
| -rw-r--r-- | compat/assert.hpp | 61 | ||||
| -rw-r--r-- | compat/borrowed-ptr-fwd.hpp | 8 | ||||
| -rw-r--r-- | compat/borrowed-ptr.cpp | 2 | ||||
| -rw-r--r-- | compat/borrowed-ptr.hpp | 8 | ||||
| -rw-r--r-- | compat/borrowed-ptr.inl | 23 | ||||
| -rw-r--r-- | compat/format.hpp | 10 | ||||
| -rw-r--r-- | compat/fpu.hpp | 4 | ||||
| -rw-r--r-- | compat/function2.hpp | 4 | ||||
| -rw-r--r-- | compat/heap.hpp | 48 | ||||
| -rw-r--r-- | compat/intrusive-ptr.hpp | 8 | ||||
| -rw-r--r-- | compat/unroll.hpp | 13 |
13 files changed, 163 insertions, 72 deletions
diff --git a/compat/array-size.hpp b/compat/array-size.hpp index 15eb66ab..98da4d1e 100644 --- a/compat/array-size.hpp +++ b/compat/array-size.hpp @@ -5,15 +5,19 @@ namespace floormat::detail { template<typename T> struct array_size_; template<typename T, size_t N> struct array_size_<T(&)[N]> : std::integral_constant<size_t, N> {}; +template<typename T, size_t N> struct array_size_<T(*)[N]> : std::integral_constant<size_t, N> {}; template<typename T, size_t N> struct array_size_<T[N]> : std::integral_constant<size_t, N> {}; template<typename T, size_t N> struct array_size_<std::array<T, N>> : std::integral_constant<size_t, N> {}; template<typename T, size_t N> struct array_size_<StaticArray<N, T>> : std::integral_constant<size_t, N> {}; +template<typename C, typename T> struct array_size_<T C::*> : std::integral_constant<size_t, array_size_<std::remove_cvref_t<T>>::value> {}; +//template<typename T, typename U, size_t N> struct array_size_< T(U::*)[N] > : std::integral_constant<size_t, N> {}; // should be redundant + } // namespace floormat::detail namespace floormat { -template<typename T> constexpr inline size_t static_array_size = detail::array_size_<T>::value; -template<typename T> constexpr inline size_t array_size(const T&) noexcept { return detail::array_size_<T>::value; } +template<typename T> constexpr inline size_t static_array_size = detail::array_size_<std::remove_cvref_t<T>>::value; +template<typename T> constexpr inline size_t array_size(const T&) noexcept { return detail::array_size_<std::remove_cvref_t<T>>::value; } } // namespace floormat diff --git a/compat/assert.cpp b/compat/assert.cpp index cd6e9af3..3f030b6b 100644 --- a/compat/assert.cpp +++ b/compat/assert.cpp @@ -1,4 +1,5 @@ #include "assert.hpp" +#include "exception.hpp" #include <cstdlib> #include <cstdio> #include <cstdarg> @@ -7,13 +8,15 @@ #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif -namespace floormat { +namespace floormat::debug::detail { namespace { +bool do_soft_assert = false; + template<bool DoPrefix, bool DoSourceLocation> CORRADE_NEVER_INLINE -void fm_emit_debug_(const char* prefix, const char* file, int line, const char* fmt, va_list arg_ptr) +void emit_debug_(const char* prefix, const char* file, int line, const char* fmt, va_list arg_ptr) { std::fflush(stdout); std::fflush(stderr); @@ -29,31 +32,31 @@ void fm_emit_debug_(const char* prefix, const char* file, int line, const char* } // namespace -void fm_emit_debug(const char* prefix, fm_FORMAT_ARG_MSVC const char* fmt, ...) +void emit_debug(const char* prefix, fm_FORMAT_ARG_MSVC const char* fmt, ...) { va_list arg_ptr; va_start(arg_ptr, fmt); - fm_emit_debug_<true, false>(prefix, nullptr, 0, fmt, arg_ptr); + emit_debug_<true, false>(prefix, nullptr, 0, fmt, arg_ptr); va_end(arg_ptr); } -void fm_emit_debug0(fm_FORMAT_ARG_MSVC const char* fmt, ...) +void emit_debug0(fm_FORMAT_ARG_MSVC const char* fmt, ...) { va_list arg_ptr; va_start(arg_ptr, fmt); - fm_emit_debug_<false, false>(nullptr, nullptr, 0, fmt, arg_ptr); + emit_debug_<false, false>(nullptr, nullptr, 0, fmt, arg_ptr); va_end(arg_ptr); } -void CORRADE_NEVER_INLINE fm_emit_debug_loc(const char* prefix, const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) +void CORRADE_NEVER_INLINE emit_debug_loc(const char* prefix, const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) { va_list arg_ptr; va_start(arg_ptr, fmt); - fm_emit_debug_<true, true>(prefix, file, line, fmt, arg_ptr); + emit_debug_<true, true>(prefix, file, line, fmt, arg_ptr); va_end(arg_ptr); } -void fm_emit_assert_fail(const char* expr, const char* file, int line) +void emit_assert_fail(const char* expr, const char* file, int line) { std::fflush(stdout); std::fflush(stderr); @@ -62,20 +65,29 @@ void fm_emit_assert_fail(const char* expr, const char* file, int line) std::abort(); } -void fm_emit_abort(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) +void emit_abort(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) { va_list arg_ptr; va_start(arg_ptr, fmt); - fm_emit_debug_<true, true>("fatal: ", file, line, fmt, arg_ptr); + emit_debug_<true, true>("fatal: ", file, line, fmt, arg_ptr); va_end(arg_ptr); std::abort(); } -void fm_emit_abort() +void emit_abort() { std::fflush(stdout); std::fflush(stderr); std::abort(); } -} // namespace floormat +} // namespace floormat::debug::detail + +using namespace floormat::debug::detail; + +namespace floormat::debug { + +void set_soft_assert_mode(bool value) { do_soft_assert = value; } +bool soft_assert_mode() { return detail::do_soft_assert; } + +} // namespace floormat::debug diff --git a/compat/assert.hpp b/compat/assert.hpp index 8c882b0e..1333c6a6 100644 --- a/compat/assert.hpp +++ b/compat/assert.hpp @@ -12,16 +12,29 @@ #define fm_FORMAT_ARG_MSVC #endif -namespace floormat { +namespace floormat::debug::detail { + +void emit_debug(const char* prefix, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(2); +void emit_debug0(fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(1); +void emit_debug_loc(const char* prefix, const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(4); +void emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(3); + +[[noreturn]] CORRADE_NEVER_INLINE void emit_assert_fail(const char* expr, const char* file, int line); +[[noreturn]] CORRADE_NEVER_INLINE void emit_abort(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(3); +[[noreturn]] CORRADE_NEVER_INLINE void emit_abort(); + +} // namespace floormat::debug::detail + + +namespace floormat::debug { + +void set_soft_assert_mode(bool value); +bool soft_assert_mode(); -void fm_emit_debug(const char* prefix, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(2); -void fm_emit_debug0(fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(1); -void fm_emit_debug_loc(const char* prefix, const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(4); -void fm_emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(3); +} // namespace floormat::debug -[[noreturn]] CORRADE_NEVER_INLINE void fm_emit_assert_fail(const char* expr, const char* file, int line); -[[noreturn]] CORRADE_NEVER_INLINE void fm_emit_abort(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(3); -[[noreturn]] CORRADE_NEVER_INLINE void fm_emit_abort(); + +namespace floormat { } // namespace floormat @@ -30,19 +43,29 @@ void fm_emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const cha #pragma GCC diagnostic ignored "-Wunused-macros" #endif -#define fm_assert(...) ((__VA_ARGS__) ? void() : ::floormat::fm_emit_assert_fail(#__VA_ARGS__, __FILE__, __LINE__)) -#define fm_abort(...) (::floormat::fm_emit_abort(__FILE__, __LINE__, __VA_ARGS__)) -#define fm_warn(...) (::floormat::fm_emit_debug("warning: ", __VA_ARGS__)) -#define fm_error(...) (::floormat::fm_emit_debug("error: ", __VA_ARGS__)) -#define fm_log(...) (::floormat::fm_emit_debug0(__VA_ARGS__)) -#define fm_debug(...) (::floormat::fm_emit_debug0(__VA_ARGS__)) -#define fm_debug_loc(pfx, ...) (::floormat::fm_emit_debug_loc(pfx, __FILE__, __LINE__,__VA_ARGS__)) -#define fm_debug_loc0(...) (::floormat::fm_emit_debug_loc0(__FILE__, __LINE__,__VA_ARGS__)) +#define fm_assert(...) ((__VA_ARGS__) ? void() : ::floormat::debug::detail::emit_assert_fail(#__VA_ARGS__, __FILE__, __LINE__)) +#define fm_abort(...) (::floormat::debug::detail::emit_abort(__FILE__, __LINE__, __VA_ARGS__)) +#define fm_warn(...) (::floormat::debug::detail::emit_debug("warning: ", __VA_ARGS__)) +#define fm_error(...) (::floormat::debug::detail::emit_debug("error: ", __VA_ARGS__)) +#define fm_log(...) (::floormat::debug::detail::emit_debug0(__VA_ARGS__)) +#define fm_debug(...) (::floormat::debug::detail::emit_debug0(__VA_ARGS__)) +#define fm_debug_loc(pfx, ...) (::floormat::debug::detail::emit_debug_loc(pfx, __FILE__, __LINE__,__VA_ARGS__)) +#define fm_debug_loc0(...) (::floormat::debug::detail::emit_debug_loc0(__FILE__, __LINE__,__VA_ARGS__)) + +#if defined FM_NO_DEBUG && !defined FM_NO_DEBUG2 +#define FM_NO_DEBUG2 +#endif #ifndef FM_NO_DEBUG #define fm_debug_assert(...) fm_assert(__VA_ARGS__) #else -#define fm_debug_assert(...) void() +#define fm_debug_assert(...) (void()) +#endif + +#ifndef FM_NO_DEBUG2 +#define fm_debug2_assert(...) fm_assert(__VA_ARGS__) +#else +#define fm_debug2_assert(...) (void()) #endif #define fm_warn_once(...) do { \ @@ -66,7 +89,7 @@ void fm_emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const cha ERR_nospace << #__VA_ARGS__; \ ERR_nospace << " expected: " << a; \ ERR_nospace << " actual: " << b; \ - fm_emit_abort(); \ + ::floormat::debug::detail::emit_abort(); \ } \ })(__VA_ARGS__) @@ -83,7 +106,7 @@ void fm_emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const cha ERR_nospace << #__VA_ARGS__; \ ERR_nospace << "not expected: " << a; \ ERR_nospace << " actual: " << b; \ - fm_emit_abort(); \ + ::floormat::debug::detail::emit_abort(); \ } \ })(__VA_ARGS__) diff --git a/compat/borrowed-ptr-fwd.hpp b/compat/borrowed-ptr-fwd.hpp index 8fcc5dde..48c3e141 100644 --- a/compat/borrowed-ptr-fwd.hpp +++ b/compat/borrowed-ptr-fwd.hpp @@ -2,12 +2,18 @@ namespace floormat { +#define FM_BPTR_DEBUG +//#define FM_NO_WEAK_BPTR + struct bptr_base; template<typename T> class bptr; template<typename T> class weak_bptr; template<typename T> bptr(T* ptr) -> bptr<T>; -template<typename T> bptr(const T* ptr) -> bptr<const T>; + +#ifndef FM_NO_WEAK_BPTR +template<typename T> weak_bptr(const bptr<T>& ptr) -> weak_bptr<T>; +#endif } // namespace floormat diff --git a/compat/borrowed-ptr.cpp b/compat/borrowed-ptr.cpp index 1dded12a..e64468d5 100644 --- a/compat/borrowed-ptr.cpp +++ b/compat/borrowed-ptr.cpp @@ -4,6 +4,8 @@ namespace floormat::detail_bptr { void control_block::decrement(control_block*& blk) noexcept { + if (!blk) + return; auto c2 = --blk->_hard_count; fm_bptr_assert(c2 != (uint32_t)-1); if (c2 == 0) diff --git a/compat/borrowed-ptr.hpp b/compat/borrowed-ptr.hpp index 6a4e79f1..b818154c 100644 --- a/compat/borrowed-ptr.hpp +++ b/compat/borrowed-ptr.hpp @@ -1,9 +1,5 @@ #pragma once #include "borrowed-ptr-fwd.hpp" -#include <compare> - -#define FM_BPTR_DEBUG -#define FM_NO_WEAK_BPTR #ifdef __CLION_IDE__ #define fm_bptr_assert(...) (void(__VA_ARGS__)) @@ -113,10 +109,6 @@ public: bool operator==(const bptr<T>& other) const noexcept requires (!std::is_const_v<T>); bool operator==(const std::nullptr_t& other) const noexcept; - std::strong_ordering operator<=>(const bptr<const T>& other) const noexcept; - std::strong_ordering operator<=>(const bptr<T>& other) const noexcept requires (!std::is_const_v<T>); - std::strong_ordering operator<=>(const std::nullptr_t&) const noexcept; - template<typename U> friend class bptr; template<typename U> friend class weak_bptr; diff --git a/compat/borrowed-ptr.inl b/compat/borrowed-ptr.inl index e1a5f591..d8c561a5 100644 --- a/compat/borrowed-ptr.inl +++ b/compat/borrowed-ptr.inl @@ -9,7 +9,7 @@ namespace floormat { -template<typename T> bptr<T>::~bptr() noexcept { if (blk) detail_bptr::control_block::decrement(blk); } +template<typename T> bptr<T>::~bptr() noexcept { detail_bptr::control_block::decrement(blk); } template<typename T> bptr<T>::bptr(const bptr<std::remove_const_t<T>>& ptr) noexcept requires std::is_const_v<T>: bptr{ptr, nullptr} {} template<typename T> bptr<T>::bptr(bptr<std::remove_const_t<T>>&& ptr) noexcept requires std::is_const_v<T>: bptr{move(ptr), nullptr} {} @@ -41,14 +41,13 @@ template<detail_bptr::DerivedFrom<T> Y> bptr<T>& bptr<T>::operator=(bptr<Y>&& other) noexcept { return _move_assign(move(other)); } -template<typename T> void bptr<T>::reset() noexcept { if (blk) detail_bptr::control_block::decrement(blk); } +template<typename T> void bptr<T>::reset() noexcept { detail_bptr::control_block::decrement(blk); } template<typename T> template<detail_bptr::DerivedFrom<T> Y> void bptr<T>::reset(Y* ptr) noexcept { - if (blk) - detail_bptr::control_block::decrement(blk); + detail_bptr::control_block::decrement(blk); blk = ptr ? new detail_bptr::control_block{const_cast<std::remove_const_t<Y>*>(ptr), 1, #ifndef FM_NO_WEAK_BPTR 1, @@ -95,8 +94,7 @@ bptr<T>& bptr<T>::_copy_assign(const bptr<Y>& other) noexcept { if (blk != other.blk) { - if (blk) - detail_bptr::control_block::decrement(blk); + detail_bptr::control_block::decrement(blk); blk = other.blk; if (blk) { @@ -113,8 +111,7 @@ template<typename T> template<typename Y> bptr<T>& bptr<T>::_move_assign(bptr<Y>&& other) noexcept { - if (blk) - detail_bptr::control_block::decrement(blk); + detail_bptr::control_block::decrement(blk); blk = other.blk; other.blk = nullptr; return *this; @@ -151,16 +148,6 @@ template<typename T> bool bptr<T>::operator==(const bptr<T>& other) const noexce template<typename T> bool bptr<T>::operator==(const std::nullptr_t&) const noexcept { return !blk || !blk->_ptr; } -template<typename T> -std::strong_ordering bptr<T>::operator<=>(const bptr<const T>& other) const noexcept -{ return get() <=> other.get(); } - -template<typename T> std::strong_ordering bptr<T>::operator<=>(const bptr<T>& other) const noexcept requires (!std::is_const_v<T>) -{ return get() <=> other.get(); } - -template<typename T> std::strong_ordering bptr<T>::operator<=>(const std::nullptr_t&) const noexcept -{ return get() <=> (T*)nullptr; } - template<typename T> void bptr<T>::swap(bptr& other) noexcept { floormat::swap(blk, other.blk); } template<typename T> diff --git a/compat/format.hpp b/compat/format.hpp index 1cb4f365..800bce5a 100644 --- a/compat/format.hpp +++ b/compat/format.hpp @@ -9,12 +9,12 @@ namespace fmt { template<> struct formatter<Corrade::Containers::StringView> { template<typename ParseContext> static constexpr auto parse(ParseContext& ctx) { return ctx.begin(); } - template<typename FormatContext> auto format(Corrade::Containers::StringView const& s, FormatContext& ctx); + template<typename FormatContext> auto format(Corrade::Containers::StringView const& s, FormatContext& ctx) const; }; template<> struct formatter<Corrade::Containers::String> { template<typename ParseContext> static constexpr auto parse(ParseContext& ctx) { return ctx.begin(); } - template<typename FormatContext> auto format(Corrade::Containers::String const& s, FormatContext& ctx); + template<typename FormatContext> auto format(Corrade::Containers::String const& s, FormatContext& ctx) const; }; } // namespace fmt @@ -42,7 +42,7 @@ consteval auto operator""_cf() noexcept return FMT_COMPILE(s.data); } #else -using namespace fmt::literals; +using fmt::literals::operator""_cf; #endif namespace floormat { @@ -66,11 +66,11 @@ size_t snformat(char(&buf)[N], Fmt&& fmt, Xs&&... args) } // namespace floormat template<typename FormatContext> -auto fmt::formatter<Corrade::Containers::StringView>::format(Corrade::Containers::StringView const& s, FormatContext& ctx) { +auto fmt::formatter<Corrade::Containers::StringView>::format(Corrade::Containers::StringView const& s, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "{}"_cf, basic_string_view<char>{s.data(), s.size()}); } template<typename FormatContext> -auto fmt::formatter<Corrade::Containers::String>::format(Corrade::Containers::String const& s, FormatContext& ctx) { +auto fmt::formatter<Corrade::Containers::String>::format(Corrade::Containers::String const& s, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "{}"_cf, basic_string_view<char>{s.data(), s.size()}); } diff --git a/compat/fpu.hpp b/compat/fpu.hpp index 9433648a..e72e8fdd 100644 --- a/compat/fpu.hpp +++ b/compat/fpu.hpp @@ -19,7 +19,11 @@ static inline void set_fp_mask() #endif #ifdef __APPLE__ +#if defined __386__ || defined __x86_64__ fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV); +#elif defined __arm64__ + fesetenv(FE_DFL_DISABLE_DENORMS_ENV); +#endif #endif #ifdef _WIN32 diff --git a/compat/function2.hpp b/compat/function2.hpp index 9e6b9b50..f53dcf7f 100644 --- a/compat/function2.hpp +++ b/compat/function2.hpp @@ -1082,8 +1082,8 @@ struct internal_capacity { /// Tag to access the structure in a type-safe way data_accessor accessor_; /// The internal capacity we use to allocate in-place - struct { - alignas(Capacity::alignment) unsigned char data[Capacity::capacity]; + struct alignas(Capacity::alignment) { + unsigned char data[Capacity::capacity]; } capacity_; } type; }; diff --git a/compat/heap.hpp b/compat/heap.hpp index 3d901755..665d11e3 100644 --- a/compat/heap.hpp +++ b/compat/heap.hpp @@ -1,6 +1,54 @@ #pragma once #if defined __GLIBCXX__ && defined _GLIBCXX_DEBUG +// Heap implementation -*- C++ -*- + +// Copyright (C) 2001-2024 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * Copyright (c) 1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ #include <utility> #include <iterator> // regular STL implementation stripped of debug code diff --git a/compat/intrusive-ptr.hpp b/compat/intrusive-ptr.hpp index 8e9b3d6c..c8cf6ff3 100644 --- a/compat/intrusive-ptr.hpp +++ b/compat/intrusive-ptr.hpp @@ -41,10 +41,10 @@ struct refcount_ops using Tref = T*; #endif - static constexpr inline auto incr(T* ptr) noexcept -> size_type; // todo! remove constexpr from everywhere, then move everything to .inl - static constexpr inline auto decr(Tref ptr) noexcept -> size_type; - static constexpr inline auto count(T* ptr) noexcept -> size_type; - static constexpr inline void init_to_1(T* ptr) noexcept; + static constexpr auto incr(T* ptr) noexcept -> size_type; // todo! remove constexpr from everywhere, then move everything to .inl + static constexpr auto decr(Tref ptr) noexcept -> size_type; + static constexpr auto count(T* ptr) noexcept -> size_type; + static constexpr void init_to_1(T* ptr) noexcept; }; template<typename Tag, typename T> diff --git a/compat/unroll.hpp b/compat/unroll.hpp new file mode 100644 index 00000000..2b74ed1a --- /dev/null +++ b/compat/unroll.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace floormat { + +template<uint32_t Max, typename F> +constexpr CORRADE_ALWAYS_INLINE void unroll(F&& fn) +{ + [&]<size_t... Is>(std::index_sequence<Is...>) { + (..., fn(std::integral_constant<size_t, Is>{})); + }(std::make_index_sequence<Max>()); +} + +} // namespace floormat |
