diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e050b8..3af230d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,9 +93,9 @@ if(NOT WIN32 OR MINGW) endif() if(UNIX AND NOT APPLE) - check_support(HAS_DL_FIND_OBJECT has_dl_find_object.cpp "" "" "") + check_support(HAS_DL_FIND_OBJECT has_dl_find_object.cpp "" "dl" "") if(NOT HAS_DL_FIND_OBJECT) - check_support(HAS_DLADDR1 has_dladdr1.cpp "" "" "") + check_support(HAS_DLADDR1 has_dladdr1.cpp "" "dl" "") endif() endif() diff --git a/cmake/has_dladdr1.cpp b/cmake/has_dladdr1.cpp index b92aad0..fd069a5 100644 --- a/cmake/has_dladdr1.cpp +++ b/cmake/has_dladdr1.cpp @@ -1,4 +1,5 @@ #include +#include int main() { Dl_info info; diff --git a/src/utils/microfmt.hpp b/src/utils/microfmt.hpp index 572f26d..cc8d9b1 100644 --- a/src/utils/microfmt.hpp +++ b/src/utils/microfmt.hpp @@ -1,33 +1,24 @@ #ifndef MICROFMT_HPP #define MICROFMT_HPP -// Copyright (c) 2024 Jeremy Rifkin; MIT License - #include #include #include -#include #include #include #include #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) -#include + #include #endif #ifdef _MSC_VER -#include + #include #endif -// {[[align][width]:[fill][base]]} -// width: number or {} +// https://github.com/jeremy-rifkin/microfmt +// Format: {[align][width][:[fill][base]]} # width: number or {} namespace microfmt { namespace detail { - #define STR2(x) #x - #define STR(x) STR2(x) - #define MICROFMT_ASSERT(expr) if(!(expr)) { \ - throw std::runtime_error("Microfmt check failed" __FILE__ ":" STR(__LINE__) ": " #expr); \ - } - inline std::uint64_t clz(std::uint64_t value) { #ifdef _MSC_VER unsigned long out = 0; @@ -60,7 +51,6 @@ namespace microfmt { template void do_write(std::string& out, It begin, It end, const format_options& options) { auto size = end - begin; - MICROFMT_ASSERT(size >= 0); if(static_cast(size) >= options.width) { out.append(begin, end); } else { @@ -100,13 +90,11 @@ namespace microfmt { inline std::string to_string(std::uint64_t value, const format_options& options) { switch(options.base) { - case 'd': return std::to_string(value); case 'H': return to_string<4, 0xf>(value, "0123456789ABCDEF"); case 'h': return to_string<4, 0xf>(value); case 'o': return to_string<3, 0x7>(value); case 'b': return to_string<1, 0x1>(value); - default: - MICROFMT_ASSERT(false); + default: return std::to_string(value); // failure: decimal } } @@ -154,7 +142,7 @@ namespace microfmt { switch(value) { case value_type::int64_value: return static_cast(int64_value); case value_type::uint64_value: return static_cast(uint64_value); - default: MICROFMT_ASSERT(false); + default: return 0; // failure: just 0 } } @@ -193,108 +181,84 @@ namespace microfmt { case value_type::c_string_value: do_write(out, c_string_value, c_string_value + std::strlen(c_string_value), options); break; - default: - MICROFMT_ASSERT(false); - } + } // failure: nop } }; - inline int parse_int(const char* begin, const char* end) { - int x = 0; - for(auto it = begin; it != end; it++) { - MICROFMT_ASSERT(isdigit(*it)); - x *= 10; - x += *it - '0'; - } - return x; - } - - template - std::string format(const char* fmt_begin, const char* fmt_end, std::array args) { + template + std::string format(It fmt_begin, It fmt_end, std::array args) { std::string str; std::size_t arg_i = 0; auto it = fmt_begin; auto peek = [&] (std::size_t dist) -> char { // 0 on failure - if(it != fmt_end) { - return *(it + dist); - } else { - return 0; - } + return fmt_end - it > signed(dist) ? *(it + dist) : 0; }; auto read_number = [&] () -> int { // -1 on failure auto scan = it; + int num = 0; while(scan != fmt_end && isdigit(*scan)) { + num *= 10; + num += *scan - '0'; scan++; } if(scan != it) { - int val = parse_int(it, scan); it = scan; - return val; + return num; } else { return -1; } }; - while(it != fmt_end) { - if(*it == '{') { - if(peek(1) == '{') { - // try to handle escape - str += '{'; + for(; it != fmt_end; it++) { + if((*it == '{' || *it == '}') && peek(1) == *it) { // parse {{ and }} escapes + it++; + } else if(*it == '{' && it + 1 != fmt_end) { + auto saved_it = it; + auto handle_formatter = [&] () { it++; - } else { - // parse format string - it++; - MICROFMT_ASSERT(it != fmt_end); format_options options; // try to parse alignment if(*it == '<' || *it == '>') { - options.align = *it == '<' ? alignment::left : alignment::right; - it++; + options.align = *it++ == '<' ? alignment::left : alignment::right; } // try to parse width - auto width = read_number(); + auto width = read_number(); // handles fmt_end check if(width != -1) { options.width = width; - } else if(*it == '{') { // try to parse variable width - MICROFMT_ASSERT(peek(1) == '}'); + } else if(it != fmt_end && *it == '{') { // try to parse variable width + if(peek(1) != '}') { + return false; + } it += 2; - MICROFMT_ASSERT(arg_i < args.size()); - options.width = args[arg_i++].unwrap_int(); + options.width = arg_i < args.size() ? args[arg_i++].unwrap_int() : 0; } // try to parse fill/base - if(*it == ':') { + if(it != fmt_end && *it == ':') { it++; - // try to parse fill - if(*it != '}' && peek(1) != '}') { - // two chars before the }, treat as fill+base + if(fmt_end - it > 1 && *it != '}' && peek(1) != '}') { // two chars before the }, fill+base options.fill = *it++; options.base = *it++; - } else if(*it != '}') { - // one char before the }, treat as base if possible + } else if(it != fmt_end && *it != '}') { // one char before the }, just base if(*it == 'd' || *it == 'h' || *it == 'H' || *it == 'o' || *it == 'b') { options.base = *it++; } else { options.fill = *it++; } - } else { - MICROFMT_ASSERT(false); } } - MICROFMT_ASSERT(*it == '}'); - MICROFMT_ASSERT(arg_i < args.size()); - args[arg_i++].write(str, options); + if(it == fmt_end || *it != '}') { + return false; + } + if(arg_i < args.size()) { + args[arg_i++].write(str, options); + } + return true; + }; + if(handle_formatter()) { + continue; // If reached here, successfully parsed and wrote a formatter. Don't write *it. } - } else if(*it == '}') { - // parse }} escape - if(peek(1) == '}') { - str += '}'; - it++; - } else { - MICROFMT_ASSERT(false); - } - } else { - str += *it; + it = saved_it; // go back } - it++; + str += *it; } return str; } @@ -306,8 +270,9 @@ namespace microfmt { return detail::format(fmt.begin(), fmt.end(), {detail::format_value(args)...}); } + // working around an old msvc bug https://godbolt.org/z/88T8hrzzq mre: https://godbolt.org/z/drd8echbP inline std::string format(std::string_view fmt) { - return std::string(fmt); + return detail::format<1>(fmt.begin(), fmt.end(), {detail::format_value(1)}); } #endif @@ -316,7 +281,6 @@ namespace microfmt { return detail::format(fmt, fmt + std::strlen(fmt), {detail::format_value(args)...}); } - // working around an old msvc bug https://godbolt.org/z/88T8hrzzq mre: https://godbolt.org/z/drd8echbP inline std::string format(const char* fmt) { return detail::format<1>(fmt, fmt + std::strlen(fmt), {detail::format_value(1)}); }