diff --git a/include/fmt/core.h b/include/fmt/core.h index 1e8ecad1..e6c36675 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -130,6 +130,18 @@ # define FMT_CONSTEXPR_CHAR_TRAITS #endif +#ifndef FMT_NO_ALLOCATIONS +# define FMT_NO_ALLOCATIONS 0 +#endif + +#if FMT_NO_ALLOCATIONS +# define FMT_EXCEPTIONS 0 +# define FMT_STATIC_THOUSANDS_SEPARATOR 1 +# define FMT_USE_FLOAT 0 +# define FMT_USE_DOUBLE 0 +# define FMT_USE_LONG_DOUBLE 0 +#endif + // Check if exceptions are disabled. #ifndef FMT_EXCEPTIONS # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 8391aa9b..c0e21d0e 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -32,15 +32,22 @@ FMT_BEGIN_NAMESPACE namespace detail { FMT_FUNC void assert_fail(const char* file, int line, const char* message) { +#if FMT_NO_ALLOCATIONS + (void)file; + (void)line; + (void)message; +#else // Use unchecked std::fprintf to avoid triggering another assertion when // writing to stderr fails std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); +#endif // Chosen instead of std::abort to satisfy Clang in CUDA mode during device // code pass. std::terminate(); } FMT_FUNC void throw_format_error(const char* message) { + (void)message; FMT_THROW(format_error(message)); } @@ -121,11 +128,13 @@ template FMT_FUNC Char decimal_point_impl(locale_ref) { FMT_API FMT_FUNC format_error::~format_error() noexcept = default; #endif +#if !FMT_NO_ALLOCATIONS FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str, format_args args) { auto ec = std::error_code(error_code, std::generic_category()); return std::system_error(ec, vformat(format_str, args)); } +#endif namespace detail { @@ -1449,6 +1458,7 @@ FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { buffer_.push_back(0); } +#if !FMT_NO_ALLOCATIONS FMT_FUNC void format_system_error(detail::buffer& out, int error_code, const char* message) noexcept { FMT_TRY { @@ -1464,6 +1474,7 @@ FMT_FUNC void report_system_error(int error_code, const char* message) noexcept { report_error(format_system_error, error_code, message); } +#endif // !FMT_NO_ALLOCATIONS FMT_FUNC std::string vformat(string_view fmt, format_args args) { // Don't optimize the "{}" case to keep the binary size small and because it diff --git a/include/fmt/format.h b/include/fmt/format.h index 83b2a222..59f56d8a 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -77,6 +77,8 @@ # define FMT_MSC_DEFAULT #endif +#define FMT_STRINGIZE(T) #T + #ifndef FMT_THROW # if FMT_EXCEPTIONS # if FMT_MSC_VERSION || defined(__NVCC__) @@ -94,6 +96,12 @@ FMT_END_NAMESPACE # else # define FMT_THROW(x) throw x # endif +# elif FMT_NO_ALLOCATIONS +# define FMT_THROW(x) \ + do { \ + FMT_ASSERT(false, "ERROR THROWN AT " FMT_STRINGIZE( \ + __FILE__) " : " FMT_STRINGIZE(__LINE__)); \ + } while (false) # else # define FMT_THROW(x) \ do { \ @@ -894,6 +902,10 @@ template FMT_CONSTEXPR20 void basic_memory_buffer::grow( size_t size) { detail::abort_fuzzing_if(size > 5000); +#if FMT_NO_ALLOCATIONS + detail::assert_fail(__FILE__, __LINE__, "dynamic allocations disabled"); + return; +#endif const size_t max_size = std::allocator_traits::max_size(alloc_); size_t old_capacity = this->capacity(); size_t new_capacity = old_capacity + old_capacity / 2; @@ -2029,11 +2041,15 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, switch (specs.type) { case presentation_type::none: case presentation_type::dec: { +#if FMT_NO_ALLOCATIONS + (void)loc; +#else if (specs.localized && write_int_localized(out, static_cast>(abs_value), prefix, specs, loc)) { return out; } +#endif auto num_digits = count_digits(abs_value); return write_int( out, num_digits, prefix, specs, [=](reserve_iterator it) { @@ -3160,6 +3176,12 @@ template specs, locale_ref loc = {}) -> OutputIt { +#if FMT_NO_ALLOCATIONS + (void)value; + (void)specs; + (void)loc; + return out; +#endif if (const_check(!is_supported_floating_point(value))) return out; float_specs fspecs = parse_float_type_spec(specs); fspecs.sign = specs.sign; @@ -3209,6 +3231,10 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value, template ::value)> FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { +#if FMT_NO_ALLOCATIONS + (void)value; + return out; +#endif if (is_constant_evaluated()) return write(out, value, basic_format_specs()); if (const_check(!is_supported_floating_point(value))) return out; @@ -3571,6 +3597,7 @@ FMT_API void report_error(format_func func, int error_code, const char* message) noexcept; FMT_END_DETAIL_NAMESPACE +#if !FMT_NO_ALLOCATIONS FMT_API auto vsystem_error(int error_code, string_view format_str, format_args args) -> std::system_error; @@ -3619,6 +3646,7 @@ FMT_API void format_system_error(detail::buffer& out, int error_code, // Reports a system error without throwing an exception. // Can be used to report errors from destructors. FMT_API void report_system_error(int error_code, const char* message) noexcept; +#endif // !FMT_NO_ALLOCATIONS /** Fast integer formatter. */ class format_int {