From 462776dafa51bff6f9106ee593883208bb9c6a79 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 14 Apr 2021 10:23:33 +1000 Subject: [PATCH] format: remove in favour of libfmt --- CMakeLists.txt | 4 - cpuid/x86.cpp | 14 +- debug/system.cpp | 15 +- debug/warn.cpp | 2 +- debug_win32.cpp | 2 +- format.cpp.rl | 218 ----------------- format.hpp | 599 ---------------------------------------------- io.cpp | 5 +- log/log.hpp | 60 +++-- log/packet.hpp | 12 +- log/scoped.cpp | 2 +- log/sink/path.cpp | 1 + parse/enum.hpp | 2 +- registrar.hpp | 4 +- tap.hpp | 7 +- test/format.cpp | 223 ----------------- test/ip.cpp | 4 +- test/parse/si.cpp | 2 +- time.cpp | 2 +- 19 files changed, 76 insertions(+), 1102 deletions(-) delete mode 100644 format.cpp.rl delete mode 100644 format.hpp delete mode 100644 test/format.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 18d02a4f..ec400fb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,6 @@ endif() ############################################################################### RAGEL_TARGET(uri uri.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/uri.cpp COMPILE_FLAGS -G2) RAGEL_TARGET(version version.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/version.cpp) -RAGEL_TARGET(format.cpp format.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/format.cpp) RAGEL_TARGET(parse8601 time/parse8601.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/time/parse8601.cpp) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) @@ -337,8 +336,6 @@ list ( fixed_string.hpp float.cpp float.hpp - ${CMAKE_CURRENT_BINARY_DIR}/format.cpp - format.hpp fourcc.cpp fourcc.hpp functor.hpp @@ -703,7 +700,6 @@ if (TESTS) extent fixed float - format geom/aabb geom/ellipse geom/frustum diff --git a/cpuid/x86.cpp b/cpuid/x86.cpp index dd7115bd..ac97a7d3 100644 --- a/cpuid/x86.cpp +++ b/cpuid/x86.cpp @@ -10,9 +10,10 @@ #include "endian.hpp" #include "view.hpp" -#include "format.hpp" #include "bitwise.hpp" +#include + #include #include @@ -158,10 +159,11 @@ cruft::cpu::operator<< (std::ostream &os, const x86 &val) }; }; - return os << cruft::format::printf ( - "{ name: { vendor: '%!', product: '%!' }" - ", cores: { logical: %!, physical: %!, hyper_threading: %! }" - ", simd: { sse: %!, sse2: %!, sse3: %!, ssse3: %!, sse41: %!, sse42: %!, avx: %! }" + fmt::print ( + os, + "{ name: { vendor: '{}', product: '{}' }" + ", cores: { logical: {}, physical: {}, hyper_threading: {} }" + ", simd: { sse: {}, sse2: {}, sse3: {}, ssse3: {}, sse41: {}, sse42: {}, avx: {} }" " }", to_string (val.vendor_name), to_string (val.product_name), @@ -176,4 +178,6 @@ cruft::cpu::operator<< (std::ostream &os, const x86 &val) (val.simd.sse42 ? "true" : "false"), (val.simd.avx ? "true" : "false") ); + + return os; } diff --git a/debug/system.cpp b/debug/system.cpp index 29a916e5..a7388621 100644 --- a/debug/system.cpp +++ b/debug/system.cpp @@ -8,9 +8,10 @@ #include "./system.hpp" -#include "debugger.hpp" -#include "except.hpp" -#include "crash.hpp" +#include "./assert.hpp" +#include "./debugger.hpp" +#include "./except.hpp" +#include "./crash.hpp" #include "../backtrace.hpp" #include "../log.hpp" @@ -44,14 +45,14 @@ static void abort_with_trace (void) try { std::rethrow_exception (ptr); } catch (std::exception const &x) { - LOG_EMERGENCY ("unhandled exception: %!\n%!", x.what (), ::cruft::backtrace {}); + LOG_EMERGENCY ("unhandled exception: {}\n{}", x.what (), ::cruft::backtrace {}); } catch (cruft::error const &x) { - LOG_EMERGENCY ("unhandled exception: %!\n%!", x, ::cruft::backtrace {}); + LOG_EMERGENCY ("unhandled exception: {}\n{}", x, ::cruft::backtrace {}); } catch (...) { - LOG_EMERGENCY ("unhandled exception\n%!", ::cruft::backtrace {}); + LOG_EMERGENCY ("unhandled exception\n{}", ::cruft::backtrace {}); } } else { - LOG_EMERGENCY ("aborting: %!", ::cruft::backtrace {}); + LOG_EMERGENCY ("aborting: {}", ::cruft::backtrace {}); } old_handler (); diff --git a/debug/warn.cpp b/debug/warn.cpp index 4373f406..1292728a 100644 --- a/debug/warn.cpp +++ b/debug/warn.cpp @@ -31,6 +31,6 @@ warn (const std::string &msg) void warn (const char *msg) { - LOG_WARN (msg); + LOG_WARN ("{}", msg); } diff --git a/debug_win32.cpp b/debug_win32.cpp index fe9968c4..18b5d072 100644 --- a/debug_win32.cpp +++ b/debug_win32.cpp @@ -44,7 +44,7 @@ prepare_debugger (void) // as possible. if (nullptr == LoadLibrary("exchndl.dll")) { auto code = GetLastError (); - LOG_WARNING("Emergency debugger not loaded, %s", cruft::win32::error::code_string (code)); + LOG_WARNING("Emergency debugger not loaded, {:s}", cruft::win32::error::code_string (code)); } } diff --git a/format.cpp.rl b/format.cpp.rl deleted file mode 100644 index 6bdf235a..00000000 --- a/format.cpp.rl +++ /dev/null @@ -1,218 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 2017 Danny Robson - */ - -#include "./format.hpp" - -#include - -// We generate some really old style C code via ragel here, so we have to -// disable some noisy warnings (doubly so given -Werror) -#pragma GCC diagnostic ignored "-Wold-style-cast" - -namespace cruft::format { - std::ostream& - operator<< (std::ostream &os, type_t val) - { - switch (val) { - case type_t::LITERAL: return os << "LITERAL"; - case type_t::USER: return os << "USER"; - case type_t::ESCAPE: return os << "ESCAPE"; - case type_t::SIGNED: return os << "SIGNED"; - case type_t::UNSIGNED: return os << "UNSIGNED"; - case type_t::REAL: return os << "REAL"; - case type_t::STRING: return os << "STRING"; - case type_t::CHAR: return os << "CHAR"; - case type_t::POINTER: return os << "POINTER"; - case type_t::COUNT: return os << "COUNT"; - } - - return os << "UNKNOWN_" << static_cast> (val); - } - - - std::ostream& - operator<< (std::ostream &os, const specifier &val) - { - return os << "{ fmt: " << val.fmt << ", type: " << val.type << " }"; - } -} - - -/////////////////////////////////////////////////////////////////////////////// -%%{ - machine printf; - - parameter = digit+ '$'; - - flag = '+' %{ s.flags.plus = true; } - | '-' %{ s.flags.minus = true; } - | ' ' %{ s.flags.space = true; } - | '0' %{ s.flags.zero = true; } - | '#' %{ s.flags.hash = true; } - ; - - width = digit+ >{ s.width = 0; } ${ s.width *= 10; s.width += fc - '0'; }; - - # precision may be zero digits which implies zero precision. - precision = '.' >{ s.precision = 0; } digit* ${ s.precision *= 10; s.precision += fc - '0'; }; - - length = - 'hh' %{ s.length = sizeof (char); } - | 'h' %{ s.length = sizeof (short); } - | 'l' %{ s.length = sizeof (long); } - | 'll' %{ s.length = sizeof (long long); } - | 'L' %{ s.length = sizeof (long double); } - | 'z' %{ s.length = sizeof (size_t); } - | 'j' %{ s.length = sizeof (intmax_t); } - | 't' %{ s.length = sizeof (ptrdiff_t); } - ; - - type = ( - '!' >{ s.type = type_t::USER; } - | '%' >{ s.type = type_t::ESCAPE; } - | ( - 'd' - | 'i' - ) >{ s.type = type_t::SIGNED; } - | ( - 'u' - | 'x' %{ s.base = 16; } - | 'X' %{ s.base = 16; s.upper = true; } - | 'o' %{ s.base = 8; } - ) >{ s.type = type_t::UNSIGNED; } - | ( - ('f' | 'F' %{ s.upper = true; }) %{ s.representation = specifier::FIXED; } - | ('e' | 'E' %{ s.upper = true; }) %{ s.representation = specifier::SCIENTIFIC; } - | ('g' | 'G' %{ s.upper = true; }) %{ s.representation = specifier::DEFAULT; } - | ('a' | 'A' %{ s.upper = true; }) %{ s.representation = specifier::HEX; s.base = 16; } - ) >{ s.type = type_t::REAL; } - | 's' >{ s.type = type_t::STRING; } - | 'c' >{ s.type = type_t::CHAR; } - | 'p' >{ s.type = type_t::POINTER; } - | 'n' >{ s.type = type_t::COUNT; } - ); - - literal = ([^%]+) - >{ - s = specifier {}; - s.fmt = {fpc,fpc}; - s.type = type_t::LITERAL; - } - %{ - s.fmt = {s.fmt.begin(),fpc}; - if (!s.fmt.empty ()) { - specs.push_back (s); - } - }; - - specifier = ( - '%' - parameter? - flag** - width? - precision? - length? - type - ) - >{ - s = specifier {}; - s.fmt = {fpc,fpc}; - } - %{ - s.fmt = {s.fmt.begin(),fpc}; - specs.push_back (s); - }; - - format := literal? (specifier literal?)** - >{ success = false; } - %{ success = true; } - ; - - write data; -}%% - - -/////////////////////////////////////////////////////////////////////////////// -cruft::format::parsed -cruft::format::printf (cruft::view fmt) -{ - std::vector specs; - specifier s; - bool success = false; - (void)s; - - int cs; - - auto p = std::cbegin (fmt); - auto pe = std::cend (fmt); - auto eof = pe; - - %%write init; - %%write exec; - - if (!success) - throw std::runtime_error ("invalid format specification"); - - return parsed { std::move (specs) }; -} - - -/// parses a format specifier in the style of PEP3101 (with the notable -/// exception of named parameters). -/// -/// in the event of a parsing error the function will throw. makes no -/// attempt to cater for constexpr validation. -cruft::format::parsed -cruft::format::python (cruft::view fmt) -{ - std::vector specs; - - const auto *prev = std::begin (fmt); - const auto *cursor = std::begin (fmt); - while (*cursor) { - switch (*cursor) { - case '{': - { - { - specifier s; - s.fmt = { prev, cursor }; - s.type = type_t::LITERAL; - specs.push_back (s); - } - - auto first = cursor; - while (*++cursor != '}') - ; - - ++cursor; - { - specifier s; - s.fmt = {first, cursor}; - s.type = type_t::USER; - specs.push_back (s); - } - - prev = cursor; - break; - } - - default: - ++cursor; - break; - } - } - - { - specifier s; - s.fmt = {prev,cursor}; - s.type = type_t::LITERAL; - specs.push_back (s); - } - - return parsed {std::move (specs)}; -} diff --git a/format.hpp b/format.hpp deleted file mode 100644 index dd3247f7..00000000 --- a/format.hpp +++ /dev/null @@ -1,599 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 2017 Danny Robson - */ - -#ifndef CRUFT_UTIL_FORMAT_HPP -#define CRUFT_UTIL_FORMAT_HPP - -#include "view.hpp" - -#include -#include -#include -#include -#include -#include -#include - -namespace cruft::format { - /// denotes the stated data type of one specifier - enum class type_t { - /// an internal type that indicates a span of literal text to copy - /// from the format specifier string - LITERAL, - /// a type that has implemented an ostream operator - USER, - - /// a literal '%' symbol - ESCAPE, - - /// numeric types - SIGNED, - UNSIGNED, - REAL, - - /// a C style string, or equivalent C++ type (std::string, - /// std::string_view, cruft::view, etc, ...) - STRING, - /// a single character - CHAR, - - /// a raw pointer (rather than value that needs to be dereferenced) - POINTER, - - /// number of characters written - COUNT - }; - - /// formatting information for a single specifier. - /// - /// TODO: investigate using a proper tagged union to compress the data size - struct specifier { - /// the sub-region of the format specifier that we parsed for this - /// information. probably only useful for the LITERAL type as we just - /// copy the view into the output buffer directly. - view fmt = view {nullptr}; - - int parameter = -1; - - struct { - bool plus = false; - bool minus = false; - bool space = false; - bool zero = false; - bool hash = false; - } flags; - - int width = -1; - - int precision = -1; - - int length = -1; - - type_t type = type_t::USER; - - bool upper = false; - int base = 10; - enum { - FIXED, - SCIENTIFIC, - DEFAULT, - HEX, - } representation = DEFAULT; - }; - - - struct parsed; - template class bound; - template class stored; - - /// a sequence of parsed specifiers that can be used to render some - /// collection parameters in the future. - struct parsed { - std::vector m_specifiers; - - auto begin (void) const { return std::begin (m_specifiers); } - auto end (void) const { return std::end (m_specifiers); } - - /// records a complete collection of parameters for rendering in the - /// future. the caller must maintain the 'parsed' object for the - /// lifetime of the return value. - template - bound - operator() (const Args &...args) &; - - /// records a complete collection of parameters for rendering in the - /// future. takes ownership of the specifiers so there is no lifetime - /// requirement. - template - stored - operator() (const Args &...args) &&; - }; - - - template - class bound; - - template - std::string - to_string (const bound&); - - template - class stored; - - template - std::string - to_string (const bound&); - - - /// parameter collection for a non-owning sequence of specifiers - template - class bound { - public: - bound (const parsed &_parsed, const ValueT &...args): - m_parsed {_parsed}, - m_values {args...} - { ; } - - - auto specifiers (void) const - { return view (m_parsed.m_specifiers); } - - - template - auto - get (void) const& { return std::get (m_values); } - - - operator ::std::string () const - { - return to_string (*this); - } - - private: - const parsed &m_parsed; - std::tuple m_values; - }; - - - /// parameter collection for an owning squence of specifiers. - template - class stored { - public: - stored (std::vector &&_specifiers, const ValueT &...args): - m_specifiers {std::move (_specifiers)}, - m_values {args...} - { ; } - - - auto - specifiers (void) const& - { - return view {m_specifiers}; - } - - - template - const auto& - get (void) const& { return std::get (m_values); } - - - operator ::std::string () const - { - return to_string (*this); - } - - private: - std::vector m_specifiers; - std::tuple m_values; - }; - - - template - bound - parsed::operator() (const Args &...args) & - { return bound { *this, args... }; } - - - template - stored - parsed::operator() (const Args &...args) && - { - return stored { std::move (m_specifiers), args... }; - } - - - /// parses a format string in the style of std::printf - /// - /// if the format specifier is invalid the function will throw an error at - /// runtime. specifically does not make allowances for constexpr - /// validation. - parsed printf (view); - - - /// parses a format specifier in the style of PEP3101 (with the notable - /// exception of named parameters). - /// - /// in the event of a parsing error the function will throw. makes no - /// attempt to cater for constexpr validation. - parsed python (view); - - - /// parses a printf format string and binds parameters for rendering. - template - auto - printf (view fmt, Args &&...args) - { - return printf (fmt) (args...); - } - - - /// parses a python format string and binds parameters for rendering. - template - auto - python (view fmt, Args &&...args) - { - return python (fmt) (args...); - } - - - template - struct value { - static std::ostream& - write (std::ostream &os, specifier spec, const ValueT &val) - { - os << std::resetiosflags (~std::ios_base::fmtflags{}); - - switch (spec.type) { - case type_t::REAL: - if (!std::is_floating_point_v) - throw std::runtime_error ("expected real value"); - break; - - case type_t::UNSIGNED: - if (!std::is_unsigned_v) - throw std::runtime_error ("expected unsigned value"); - break; - - case type_t::SIGNED: - if (!std::is_signed_v) - throw std::runtime_error ("expected signed value"); - break; - - case type_t::STRING: - if (std::is_same_v>) - break; - if (std::is_same_v) - break; - if (std::is_same_v) - break; - throw std::runtime_error ("expected string value"); - - case type_t::POINTER: - if (!std::is_pointer_v && !std::is_integral_v) - throw std::runtime_error ("expected pointer value"); - break; - - case type_t::CHAR: - if (!std::is_same_v && - !std::is_same_v && - !std::is_same_v && - !std::is_same_v && - !std::is_same_v && - !std::is_same_v) - throw std::runtime_error ("expected character value"); - break; - - case type_t::COUNT: - if (!std::is_pointer_v && !std::is_reference_v) - if (!std::is_integral_v>>) - throw std::runtime_error ("expected pointer/reference to integral"); - break; - - case type_t::USER: - break; - - case type_t::ESCAPE: - case type_t::LITERAL: - break; - } - - // easy case where we just throw it to ostream - if (spec.type == type_t::USER) - return os << val; - - if (spec.length > 0 && sizeof (val) != spec.length) - throw std::runtime_error ("mismatched argument size"); - - const bool uses_space = std::is_arithmetic_v && spec.flags.space && !spec.flags.plus; - if (uses_space) - os << ' '; - - if (spec.flags.plus) - os << std::showpos; - if (spec.flags.minus) - os << std::left; - if (spec.flags.zero) - os << std::setfill ('0'); - - if (spec.base >= 0) { - switch (spec.base) { - case 10: os << std::dec; break; - case 16: os << std::hex; break; - case 8: os << std::oct; break; - default: - throw std::runtime_error ("unhandled numeric base"); - } - } - - if (spec.precision >= 0) { - os << std::setprecision (spec.precision); - } - - if (spec.width >= 0) - os << std::setw (spec.width - (uses_space ? 1 : 0)); - - if (spec.upper) - os << std::uppercase; - - if (spec.type == type_t::UNSIGNED || spec.type == type_t::SIGNED) - if (spec.flags.hash) - os << std::showbase; - if (spec.type == type_t::REAL) - if (spec.flags.hash) - os << std::showpoint; - - if (spec.type == type_t::REAL) { - switch (spec.representation) { - case specifier::FIXED: os << std::fixed; break; - case specifier::SCIENTIFIC: os << std::scientific; break; - case specifier::DEFAULT: os << std::defaultfloat; break; - case specifier::HEX: os << std::hexfloat; break; - } - } - - if constexpr (std::is_integral_v) { - if (spec.type == type_t::POINTER) { - if (!val) - return os << "(nil)"; - return os << reinterpret_cast (val); - } - } - - if constexpr (std::is_floating_point_v) { - if (spec.type == type_t::REAL) { - if (std::isnan (val)) - return os << (spec.upper ? "NAN" : "nan"); - if (std::isinf (val)) - return os << (spec.upper ? "INF" : "inf"); - } - } - - if constexpr (std::is_integral_v) { - if (spec.type == type_t::SIGNED || spec.type == type_t::UNSIGNED) { - // explicitly handle the zero width case as blank because - // there's no easy way to do this using iomanip. - if (spec.precision == 0 && !val) { - return os; - } - } - } - - if constexpr (std::is_same_v, ValueT>) { - if (spec.precision >= 0) { - std::copy_n ( - std::begin (val), - min (spec.precision, static_cast (val.size ())), - std::ostream_iterator (os) - ); - return os; - } - } - - // the final output calls. we need to use unary plus so that - // chars get promoted to ints for correct stream rendering when - // the intention is to output a number. - if constexpr (std::is_fundamental_v) { - if (spec.type == type_t::CHAR) - return os << val; - if constexpr (!std::is_null_pointer_v) - if (spec.type != type_t::USER) - return os << +val; - } - - return os << val; - } - }; - - - template - struct value { - static std::ostream& - write (std::ostream &os, specifier spec, const ValueT *val) - { - if (spec.type != type_t::POINTER && spec.type != type_t::USER) - throw std::runtime_error ("expected pointer specification"); - - if (!val) - return os << "(nil)"; - return os << reinterpret_cast (val); - } - }; - - - template - struct value { - static std::ostream& - write (std::ostream &os, specifier spec, ValueT *val) { - return value::write (os, spec, val); - } - }; - - - template <> - struct value { - static std::ostream& - write (std::ostream &os, specifier s, const std::nullptr_t &val) - { - if (s.type != type_t::POINTER || s.type == type_t::USER) - throw std::runtime_error ("expected pointer specifier"); - return value::write (os, s, val); - } - }; - - - template - struct value { - static std::ostream& - write (std::ostream &os, specifier spec, const char (&val)[N]) { - if (spec.type == type_t::STRING || spec.type == type_t::USER) - return value>::write (os, spec, view (val)); - throw std::runtime_error ("invalid data type"); - } - }; - - - template - struct value { - static std::ostream& - write (std::ostream &os, specifier spec, const char (&val)[N]) { - return value>::write (os, spec, view (val)); - } - }; - - - template <> - struct value { - static std::ostream& - write (std::ostream &os, specifier spec, char *val) { - if (!val) - return os << "(nil)"; - if (spec.type == type_t::STRING || spec.type == type_t::USER) - return value>::write (os, spec, view { val, val + strlen (val) }); - if (spec.type == type_t::POINTER) - return value::write (os, spec, val); - throw std::runtime_error ("invalid data type"); - } - }; - - - template <> - struct value { - static std::ostream& - write (std::ostream &os, specifier spec, const char *val) { - if (!val) - return os << "(nil)"; - if (spec.type == type_t::STRING || spec.type == type_t::USER) - return value>::write (os, spec, view { val, val + strlen (val) }); - if (spec.type == type_t::POINTER) - return value::write (os, spec, val); - throw std::runtime_error ("invalid data type"); - } - }; - - - template <> - struct value { - static std::ostream& - write (std::ostream &os, specifier spec, const std::string &val) { - return value>::write ( - os, spec, view (val.data (), val.data () + val.size ()) - ); - } - }; - - template <> - struct value { - static std::ostream& - write (std::ostream &os, specifier spec, std::string &val) { - return value::write (os, spec, val); - } - }; - - - /// renders an LITERAL specifiers followed by one parameter, then - /// recurses for any following specifiers. - /// - /// \tparam Index the index of the next parameter to render - /// \tparam SpecifierT a forward iterator container - /// \tparam DataT a tuple-like object template class - /// \tparam Args a paramater pack of all parameter types - /// - /// \param os the ostream that we render to - /// \param specifiers the sequence of all specifiers to be rendered - /// \param data a tuple-like object containing references to all parameters - template class HolderT, typename ...DataT> - static std::ostream& - write (std::ostream &os, const SpecifiersT &specifiers, const HolderT &data) - { - for (auto cursor = std::cbegin (specifiers); cursor != std::cend (specifiers); ++cursor) { - const auto &s = *cursor; - - if (s.type == type_t::LITERAL) { - std::copy (std::begin (s.fmt), std::end (s.fmt), std::ostream_iterator (os)); - continue; - } - - if (s.type == type_t::ESCAPE) { - os << '%'; - continue; - } - - if constexpr (Index < sizeof... (DataT)) { - using value_t = std::tuple_element_t>; - value::write (os, s, data.template get ()); - return write (os, make_view (cursor+1,specifiers.end ()), data); - } else { - throw std::runtime_error ("insufficient data parameters"); - } - } - - return os; - } - - /// dispatches rendering of formats with associated parameters - template < - typename ...Args - > - std::ostream& - operator<< (std::ostream &os, const bound &val) - { - return write<0> (os, val.specifiers (), val); - } - - - /// dispatches rendering of formats with associated parameters - template < - typename ...Args - > - std::ostream& - operator<< (std::ostream &os, const stored &val) - { - return write<0> (os, val.specifiers (), val); - } - - - template - std::string - to_string (const bound &fmt) - { - std::ostringstream os; - os << fmt; - return os.str (); - } - - template - std::string - to_string (const stored &fmt) - { - std::ostringstream os; - os << fmt; - return os.str (); - } -} - -#endif diff --git a/io.cpp b/io.cpp index f851a2b8..f63053aa 100644 --- a/io.cpp +++ b/io.cpp @@ -10,9 +10,10 @@ #include "debug/assert.hpp" #include "cast.hpp" -#include "format.hpp" #include "posix/except.hpp" +#include + #include #include #include @@ -232,7 +233,7 @@ scoped_cwd::~scoped_cwd () /////////////////////////////////////////////////////////////////////////////// path_error::path_error (std::filesystem::path const &_path): - runtime_error (to_string (format::printf ("Unknown path: %!", _path))), + runtime_error (fmt::format ("Unknown path: {}", _path)), m_path (_path) { ; } diff --git a/log/log.hpp b/log/log.hpp index 58a9f710..94bb6f77 100644 --- a/log/log.hpp +++ b/log/log.hpp @@ -11,7 +11,6 @@ #include "level.hpp" #include "packet.hpp" #include "sink/base.hpp" -#include "../format.hpp" #include #include @@ -42,26 +41,41 @@ namespace cruft::log { ) ); } - - - //------------------------------------------------------------------------- - // Various convenience macros for logging specific strings with a well - // known severity. - // - // LOG_DEBUG is treated similarly to assert; if NDEBUG is defined then we - // compile out the statement so as to gain a little runtime efficiency - // speed. - #define LOG_EMERGENCY(...) do { cruft::log::write (cruft::log::EMERGENCY, ##__VA_ARGS__); } while (0) - #define LOG_ALERT(...) do { cruft::log::write (cruft::log::ALERT, ##__VA_ARGS__); } while (0) - #define LOG_CRITICAL(...) do { cruft::log::write (cruft::log::CRITICAL, ##__VA_ARGS__); } while (0) - #define LOG_ERROR(...) do { cruft::log::write (cruft::log::ERROR, ##__VA_ARGS__); } while (0) - #define LOG_WARNING(...) do { cruft::log::write (cruft::log::WARNING, ##__VA_ARGS__); } while (0) - #define LOG_WARN(...) do { cruft::log::write (cruft::log::WARN, ##__VA_ARGS__); } while (0) - #define LOG_NOTICE(...) do { cruft::log::write (cruft::log::NOTICE, ##__VA_ARGS__); } while (0) - #define LOG_INFO(...) do { cruft::log::write (cruft::log::INFO, ##__VA_ARGS__); } while (0) -#if !defined(NDEBUG) - #define LOG_DEBUG(...) do { cruft::log::write (cruft::log::DEBUG, ##__VA_ARGS__); } while (0) -#else - #define LOG_DEBUG(...) do { ; } while (0) -#endif } + + +//------------------------------------------------------------------------- +// Various convenience macros for logging specific strings with a well +// known severity. +// +// The format string _must_ be a compile time literal so that compile time +// checking of strings and arguments is possible. +// +// LOG_DEBUG is treated similarly to assert; if NDEBUG is defined then we +// compile out the statement so as to gain a little runtime efficiency. + +#define LOG(LEVEL, FMT, ...) \ +do { \ + ::cruft::log::write ( \ + (LEVEL), \ + FMT_STRING(FMT) \ + __VA_OPT__(,) \ + __VA_ARGS__ \ + ); \ +} while (0) + +#define LOG_EMERGENCY(FMT, ...) LOG(::cruft::log::EMERGENCY, FMT __VA_OPT__(,) __VA_ARGS__) +#define LOG_ALERT(FMT, ...) LOG(::cruft::log::ALERT, FMT __VA_OPT__(,) __VA_ARGS__) +#define LOG_CRITICAL(FMT, ...) LOG(::cruft::log::CRITICAL, FMT __VA_OPT__(,) __VA_ARGS__) +#define LOG_ERROR(FMT, ...) LOG(::cruft::log::ERROR, FMT __VA_OPT__(,) __VA_ARGS__) +#define LOG_WARNING(FMT, ...) LOG(::cruft::log::WARNING, FMT __VA_OPT__(,) __VA_ARGS__) +#define LOG_NOTICE(FMT, ...) LOG(::cruft::log::NOTICE, FMT __VA_OPT__(,) __VA_ARGS__) +#define LOG_INFO(FMT, ...) LOG(::cruft::log::INFO, FMT __VA_OPT__(,) __VA_ARGS__) + +#if !defined(NDEBUG) +#define LOG_DEBUG(FMT, ...) LOG(::cruft::log::DEBUG, FMT __VA_OPT__(,) __VA_ARGS__) +#else +#define LOG_DEBUG(...) do { ; } while (0) +#endif + +#define LOG_WARN(...) LOG_WARNING(__VA_ARGS__) diff --git a/log/packet.hpp b/log/packet.hpp index a7d49645..79e2fdd7 100644 --- a/log/packet.hpp +++ b/log/packet.hpp @@ -1,7 +1,8 @@ #pragma once #include "level.hpp" -#include "../format.hpp" + +#include #include @@ -26,12 +27,9 @@ namespace cruft::log { ArgsT &&..._args ) : packet ( _level, - cruft::format::to_string ( - cruft::format::printf ( - std::forward (_format) - ) ( - std::forward (_args)... - ) + fmt::format ( + std::forward (_format), + std::forward (_args)... ) ) { ; } diff --git a/log/scoped.cpp b/log/scoped.cpp index 4a93f774..854ff155 100644 --- a/log/scoped.cpp +++ b/log/scoped.cpp @@ -50,7 +50,7 @@ cruft::log::scoped_timer::~scoped_timer () write ( m_level, - "%fs, %s", + "{:f}s, {:s}", float (duration) / 1'000'000'000.f, m_message ); diff --git a/log/sink/path.cpp b/log/sink/path.cpp index 9c9351d9..8f0c0b22 100644 --- a/log/sink/path.cpp +++ b/log/sink/path.cpp @@ -12,6 +12,7 @@ #include "../packet.hpp" #include "../../paths.hpp" #include "../../debug/warn.hpp" +#include "../../cast.hpp" using cruft::log::sink::path; diff --git a/parse/enum.hpp b/parse/enum.hpp index 5e34f5d2..1fb2d830 100644 --- a/parse/enum.hpp +++ b/parse/enum.hpp @@ -184,7 +184,7 @@ namespace cruft::parse::enumeration { if (!success) LOG_WARN ( - "duplicate parse setup for %! was ignored", + "duplicate parse setup for {:s} was ignored", cruft::introspection::name::bare () ); diff --git a/registrar.hpp b/registrar.hpp index b890e842..00995888 100644 --- a/registrar.hpp +++ b/registrar.hpp @@ -59,14 +59,14 @@ namespace cruft { if (success) { LOG_INFO ( - "Registered %! for %!", + "Registered {} for {}", key, cruft::introspection::name::full () ); return cookie { key }; } { LOG_ERROR ( - "Unable to register %! for %!", + "Unable to register {} for {}", key, cruft::introspection::name::full () ); diff --git a/tap.hpp b/tap.hpp index f2b8591c..9be40359 100644 --- a/tap.hpp +++ b/tap.hpp @@ -52,7 +52,6 @@ namespace cruft::TAP { bool expect (const bool test, const char (&fmt)[N], Args&&... args) { - CHECK (!strstr (fmt, "%")); m_output << (test ? "ok " : "not ok ") << ++m_size << " - "; fmt::print (m_output, fmt, std::forward (args)...); @@ -112,7 +111,7 @@ namespace cruft::TAP { if (almost_equal (a, b)) return expect (true, fmt, std::forward (args)...); else - return expect (false, "%! # %! != %!", format::printf (fmt)(std::forward (args)...), a, b); + return expect (false, "{} # {} != {}", format::printf (fmt)(std::forward (args)...), a, b); #endif } @@ -244,9 +243,9 @@ namespace cruft::TAP { function (tap, args...); return tap.status (); } catch (std::exception const &err) { - tap.fail ("no exceptions: %s", err.what ()); + tap.fail ("no exceptions: {:s}", err.what ()); } catch (cruft::error const &err) { - tap.fail ("no exceptions: %s", err); + tap.fail ("no exceptions: {:s}", err); } catch (...) { tap.fail ("no exceptions"); } diff --git a/test/format.cpp b/test/format.cpp deleted file mode 100644 index e7126b19..00000000 --- a/test/format.cpp +++ /dev/null @@ -1,223 +0,0 @@ -#include "format.hpp" - -#include "tap.hpp" - - -/////////////////////////////////////////////////////////////////////////////// -struct userobj { }; - -static std::ostream& -operator<< (std::ostream &os, const userobj&) -{ - return os << "userobj"; -} - - -/////////////////////////////////////////////////////////////////////////////// -int -main (void) -{ - cruft::TAP::logger tap; - - #define CHECK_RENDER(fmt,res,...) do { \ - auto val = to_string (cruft::format::printf (fmt)(__VA_ARGS__)); \ - tap.expect_eq (val, res, "render '{}', # {} == {}", fmt, val, res); \ - } while (0) - - CHECK_RENDER ("foo", "foo"); - - CHECK_RENDER ("%i", "1", 1 ); - CHECK_RENDER ("%3i", " 1", 1 ); - CHECK_RENDER ("%03i", "001", 1 ); - CHECK_RENDER ("%.i", "", 0); - CHECK_RENDER ("% .i", " ", 0); // zero precision still requires a space - - CHECK_RENDER ("%hhi", "1", (signed char){1}); - CHECK_RENDER ("%hi", "1", (signed short){1}); - CHECK_RENDER ("%li", "1", (signed long){1}); - CHECK_RENDER ("%lli", "1", (signed long long){1}); - CHECK_RENDER ("%ji", "1", intmax_t{1}); - CHECK_RENDER ("%zi", "1", ssize_t{1}); - CHECK_RENDER ("%ti", "1", ptrdiff_t{1}); - - CHECK_RENDER ("%u", "1", 1u); - CHECK_RENDER ("%03u", "001", 1u); - CHECK_RENDER ("% u", " 1", 1u); - CHECK_RENDER ("% 3u", " 1", 1u); - CHECK_RENDER ("% 03u", " 01", 1u); - CHECK_RENDER ("%-3u", "1 ", 1u); - CHECK_RENDER ("%64u", " 1", 1u); - - CHECK_RENDER ("%hhu", "1", (unsigned char){1}); - CHECK_RENDER ("%hu", "1", (unsigned short){1}); - CHECK_RENDER ("%lu", "1", (unsigned long){1}); - CHECK_RENDER ("%llu", "1", (unsigned long long){1}); - CHECK_RENDER ("%ju", "1", uintmax_t{1}); - CHECK_RENDER ("%zu", "0", size_t{0}); - CHECK_RENDER ("%zu", "1", size_t{1}); - CHECK_RENDER ("%!", "1", 1u); - - CHECK_RENDER ("%o", "1", 01u); - CHECK_RENDER ("%o", "13", 013u); - CHECK_RENDER ("%o", "13", 013u); - CHECK_RENDER ("%#o", "013", 013u); - - CHECK_RENDER ("%x", "1", 0x1u); - CHECK_RENDER ("%x", "fe", 0xfeu); - CHECK_RENDER ("%X", "FE", 0xFEu); - CHECK_RENDER ("%#x", "0xfe", 0xfeu); - CHECK_RENDER ("%#X", "0XFE", 0xFEu); - - CHECK_RENDER ("%e", "1.000000e+00", 1.); - CHECK_RENDER ("%e", "1.200000e+00", 1.2); - CHECK_RENDER ("%e", "1.234568e+00", 1.2345678); - - CHECK_RENDER ("%E", "1.234568E+00", 1.2345678); - - CHECK_RENDER ("%f", "1.000000", 1.); - CHECK_RENDER ("%f", "1.200000", 1.2); - CHECK_RENDER ("%f", "1.234560", 1.23456); - CHECK_RENDER ("%f", "1.234567", 1.234567); - CHECK_RENDER ("%f", "1.234568", 1.2345678); - - CHECK_RENDER ("%g", "1", 1.); - CHECK_RENDER ("%g", "1.2", 1.2); - CHECK_RENDER ("%g", "1.23457", 1.2345678); - CHECK_RENDER ("%g", "0.000123457", 0.00012345678); - CHECK_RENDER ("%g", "1.23457e-05", 0.000012345678); - CHECK_RENDER ("%G", "1.23457E-05", 0.000012345678); - - CHECK_RENDER ("%+e", "+1.234568e+00", 1.2345678); - CHECK_RENDER ("%+f", "+1.234568", 1.2345678); - CHECK_RENDER ("%+g", "+1.23457", 1.2345678); - -#if !defined(PLATFORM_WIN32) - // msys2#xxx: hexfloat output is broken under msys2 - CHECK_RENDER ("%+a", "+0x1.3c0ca2a5b1d5dp+0", +0x1.3c0ca2a5b1d5dp+0); -#endif - - CHECK_RENDER ("%#.e", "1.e+00", 1.2345678); - CHECK_RENDER ("%#.f", "1.", 1.2345678); - CHECK_RENDER ("%#.g", "1.", 1.2345678); - //CHECK_RENDER ("%#.a", "0x1.p+0", 1.2345678); - -#if !defined(PLATFORM_WIN32) - // msys2#xxx: hexfloat output is broken under msys2 - CHECK_RENDER ("%a", "0x1.3c0ca2a5b1d5dp+0", 0x1.3c0ca2a5b1d5dp+0); - CHECK_RENDER ("%A", "0X1.3C0CA2A5B1D5DP+0", 0X1.3C0CA2A5B1D5DP+0); -#endif - - CHECK_RENDER ("%e", "inf", std::numeric_limits::infinity ()); - CHECK_RENDER ("%E", "INF", std::numeric_limits::infinity ()); - CHECK_RENDER ("%f", "inf", std::numeric_limits::infinity ()); - CHECK_RENDER ("%F", "INF", std::numeric_limits::infinity ()); - CHECK_RENDER ("%g", "inf", std::numeric_limits::infinity ()); - CHECK_RENDER ("%G", "INF", std::numeric_limits::infinity ()); - CHECK_RENDER ("%a", "inf", std::numeric_limits::infinity ()); - CHECK_RENDER ("%A", "INF", std::numeric_limits::infinity ()); - - CHECK_RENDER ("%e", "nan", std::numeric_limits::quiet_NaN ()); - CHECK_RENDER ("%E", "NAN", std::numeric_limits::quiet_NaN ()); - CHECK_RENDER ("%f", "nan", std::numeric_limits::quiet_NaN ()); - CHECK_RENDER ("%F", "NAN", std::numeric_limits::quiet_NaN ()); - CHECK_RENDER ("%g", "nan", std::numeric_limits::quiet_NaN ()); - CHECK_RENDER ("%G", "NAN", std::numeric_limits::quiet_NaN ()); - CHECK_RENDER ("%a", "nan", std::numeric_limits::quiet_NaN ()); - CHECK_RENDER ("%A", "NAN", std::numeric_limits::quiet_NaN ()); - - CHECK_RENDER ("%.f", "1", 1.2345678); - CHECK_RENDER ("%3.f", " 1", 1.2345678); - CHECK_RENDER ("%3.2f", "1.23", 1.2345678); - CHECK_RENDER ("%3.2f", "1234.57", 1234.5678); - - CHECK_RENDER ("%!", "1", 1.); - - CHECK_RENDER ("%c", "A", 'A'); - CHECK_RENDER ("%!", "A", 'A'); - - CHECK_RENDER ("%s", "foo", "foo"); - CHECK_RENDER ("%s", "foo", std::string ("foo")); - CHECK_RENDER ("%s", "foo", const_cast ("foo")); - CHECK_RENDER ("%.s", "", "foo"); - CHECK_RENDER ("%.0s", "", "foo"); - CHECK_RENDER ("%.2s", "fo", "foo"); - CHECK_RENDER ("%.02s", "fo", "foo"); - CHECK_RENDER ("%.64s", "foo", "foo"); - CHECK_RENDER ("%3.1s", " f", "foo"); - CHECK_RENDER ("%-3.1s", "f ", "foo"); - CHECK_RENDER ("%!", "foo", "foo"); - - CHECK_RENDER ("%!", "userobj", userobj {}); - - CHECK_RENDER ("%p", "0x1234567", reinterpret_cast(0x01234567)); - CHECK_RENDER ("%p", "0x1234567", reinterpret_cast (0x01234567)); - CHECK_RENDER ("%p", "0x1234567", reinterpret_cast(0x01234567)); - CHECK_RENDER ("%p", "(nil)", nullptr); - CHECK_RENDER ("%p", "(nil)", NULL); - CHECK_RENDER ("%!", "0x1234567", reinterpret_cast(0x01234567)); - - CHECK_RENDER ("%%", "%"); - CHECK_RENDER ("%10%", "%"); - CHECK_RENDER ("%.%", "%"); - CHECK_RENDER ("% 0-+#12.34%", "%"); // escaped conversions should largely ignore flags, width, and precision. - - // multiple components - CHECK_RENDER ("%%%%", "%%"); - - CHECK_RENDER (" %%", " %"); - CHECK_RENDER ("%% ", "% "); - CHECK_RENDER ("%% %%", "% %"); - CHECK_RENDER (" %% %% ", " % % "); - - CHECK_RENDER ("%%%d%%", "%0%", 0); - - CHECK_RENDER ("%u %u", "1 2", 1u, 2u); - - CHECK_RENDER ("%#o %o", "010 10", 8u, 8u); - CHECK_RENDER ("%#o %o %#o", "010 10 010", 8u, 8u, 8u); - CHECK_RENDER ("%X%x%X", "FfF", 0xfu, 0xfu, 0xfu); - - tap.expect_eq (to_string (cruft::format::printf ("%u\n")(1u)), "1\n", "newline"); - - #define CHECK_THROW(fmt,except,...) do { \ - tap.expect_throw ([&] { \ - to_string (cruft::format::printf (fmt)(__VA_ARGS__)); \ - }, "exception '{:s}' for format '{:s}'", #except, fmt); \ - } while (0) - - CHECK_THROW("%", syntax_error); - CHECK_THROW("%_", syntax_error); - CHECK_THROW("%_u", syntax_error); - - CHECK_THROW("%u", missing_error); - CHECK_THROW("%!", missing_error); - - CHECK_THROW("%d", conversion_error, 1u); - CHECK_THROW("%i", conversion_error, 1u); - CHECK_THROW("%i", conversion_error, nullptr); - - CHECK_THROW("%hhi", length_error, (long long){1}); - CHECK_THROW("%lli", length_error, (signed char){1}); - - CHECK_THROW("%u", conversion_error, 1.); - CHECK_THROW("%u", conversion_error, "foo"); - CHECK_THROW("%u", conversion_error, (void*){0}); - CHECK_THROW("%u", conversion_error, 1); - CHECK_THROW("%u", conversion_error, nullptr); - - CHECK_THROW("%hhu", length_error, (unsigned long long){1}); - CHECK_THROW("%llu", length_error, (unsigned char){1}); - - CHECK_THROW("%f", conversion_error, 1u); - CHECK_THROW("%f", conversion_error, "foo"); - CHECK_THROW("%f", conversion_error, nullptr); - - CHECK_THROW("%s", conversion_error, 1u); - CHECK_THROW("%s", conversion_error, '_'); - CHECK_THROW("%s", conversion_error, nullptr); - - CHECK_THROW("%c", conversion_error, 1u); - CHECK_THROW("%c", conversion_error, "foo"); - - return tap.status (); -} diff --git a/test/ip.cpp b/test/ip.cpp index 1c415bc6..26490b3a 100644 --- a/test/ip.cpp +++ b/test/ip.cpp @@ -24,7 +24,7 @@ test_good (cruft::TAP::logger &tap) }; for (const auto &i: TESTS) - tap.expect_eq (ipv4::ip::parse (i.str), i.ip, "%s", i.msg); + tap.expect_eq (ipv4::ip::parse (i.str), i.ip, "{:s}", i.msg); } @@ -43,7 +43,7 @@ test_bad (cruft::TAP::logger &tap) }; for (const auto &i: TESTS) - tap.expect_throw ([&] { ipv4::ip::parse (i.str); }, "%s", i.msg); + tap.expect_throw ([&] { ipv4::ip::parse (i.str); }, "{:s}", i.msg); } diff --git a/test/parse/si.cpp b/test/parse/si.cpp index 337adcde..efa52bda 100644 --- a/test/parse/si.cpp +++ b/test/parse/si.cpp @@ -23,7 +23,7 @@ int main () for (auto const &t: TESTS) { auto res = cruft::parse::si (t.str); if (!res) { - tap.fail ("SI parsing %!", t.str); + tap.fail ("SI parsing {}", t.str); } else { tap.expect_eq (t.val, *res, "SI parsing '{}'", t.str); } diff --git a/time.cpp b/time.cpp index 69586c2b..b608279e 100644 --- a/time.cpp +++ b/time.cpp @@ -115,7 +115,7 @@ cruft::polled_duration::stop (void) { m_series.add (dt / MILLISECOND); if (m_next < now) { - LOG_DEBUG ("timing: '%s'. %s", m_name, m_series); + LOG_DEBUG ("timing: '{:s}'. {:s}", m_name, m_series); m_series.reset (); m_next = now + m_interval; }