diff --git a/CMakeLists.txt b/CMakeLists.txt index cda1bcb..05c133a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ add_executable(logger src/main.cpp) if(MSVC) target_compile_options(logger PRIVATE /W4 /WX) else() - target_compile_options(logger PRIVATE -Wall -Wextra -pedantic) + target_compile_options(logger PRIVATE -O3 -Wall -Wextra -pedantic -fno-exceptions) endif() diff --git a/inc/format.h b/inc/format.h index e607d5b..690c3e7 100644 --- a/inc/format.h +++ b/inc/format.h @@ -2,9 +2,11 @@ #define LOGGER_FORMAT_H +#include + #include "parse.h" #include "utility.h" -#include +#include "format_impl.h" namespace detail { @@ -32,16 +34,6 @@ constexpr void check_fmt_params() { } -/* - * - * Type-specific formatting functions - * (Most of this code is shamelessly stolen from fmtlib) - */ - - -// TODO - - /* * * Formatting wrapper functions @@ -50,14 +42,12 @@ constexpr void check_fmt_params() { template -constexpr void format_arg(char* dest, fmt_data_t fmt_data, arg_t) { - *(dest + fmt_data.position) = 'i'; - // dest = dest + fmt_data.position; - // format_int(dest, fmt_data.length, arg); +constexpr void format_arg(char* dest, fmt_data_t fmt_data, arg_t arg) { + detail::format_integral(dest, arg, fmt_data); }; + template constexpr void format_arg(char* dest, fmt_data_t fmt_data, arg_t) { - dest = dest + fmt_data.position; *(dest) = 'f'; *(dest + fmt_data.length - fmt_data.precision - 1) = '.'; }; @@ -66,7 +56,7 @@ constexpr void format_arg(char* dest, fmt_data_t fmt_data, const char* arg) { const std::size_t len = const_strlen(arg); if (len > fmt_data.length) return; - dest = dest + fmt_data.position + fmt_data.length - len; + dest = dest + fmt_data.length - len; if (!std::is_constant_evaluated()) { std::memcpy(dest, arg, len); @@ -84,7 +74,7 @@ constexpr void format_args(char*) { template constexpr void format_args(char* dest, first_arg_t first_arg, args_t... args) { - format_arg(dest, fmt_data_array[0], first_arg); + format_arg(dest + fmt_data_array[0].position, fmt_data_array[0], first_arg); format_args(dest, args...); } @@ -117,7 +107,7 @@ consteval std::array()> get_preproc_string() { template -constexpr std::array()> format(args_t... args) { +constexpr auto format(args_t... args) { constexpr auto ast = detail::parse_string().value; constexpr auto fmt_data = detail::get_fmt_data(); @@ -128,6 +118,7 @@ constexpr std::array()> format(args_t... args) { return result; } + template class fmt_literal_obj_t { public: diff --git a/inc/format_impl.h b/inc/format_impl.h new file mode 100644 index 0000000..68f3de7 --- /dev/null +++ b/inc/format_impl.h @@ -0,0 +1,105 @@ +#ifndef LOGGER_FORMAT_IMPL_H +#define LOGGER_FORMAT_IMPL_H + + +/* + * + * **************************************************************** + * Disclaimer: Most of this code is shamelessly stolen from fmtlib + * **************************************************************** + * + */ + + +#include "utility.h" + + +namespace detail { + + +/* + * + * Utility functions + * + */ + + +// Converts value in the range [0, 100) to a string. +constexpr inline const char* digits2(size_t value) { + // GCC generates slightly better code when value is pointer-size. + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; +} + + +constexpr inline void copy2(char* dst, const char* src) { + if (!std::is_constant_evaluated()) { + std::memcpy(dst, src, 2); + return; + } + + *dst++ = static_cast(*src++); + *dst = static_cast(*src); +} + +template +constexpr inline void format_decimal(char* out, UInt value, int size) { + // TODO: Error handling (Maybe calculate "ffff..." as a constant expression + // and then set the out pointer with a branchless statement) + + out += size; + while (value >= 100) { + out -= 2; + copy2(out, digits2(static_cast(value % 100))); + value /= 100; + } + + if (value < 10) *--out = static_cast('0' + value); + + out -= 2; + copy2(out, digits2(static_cast(value))); +} + + +/* + * + * Integral types + * + */ + + +template +constexpr inline void format_integral(char* out, uint_t value, + fmt_data_t fmt_node) { + format_decimal(out, value, fmt_node.length); +} + +template +constexpr inline void format_integral(char* out, uint_t value, + fmt_data_t fmt_node) { + if (value < 0) value = -value; + format_decimal(out, value, fmt_node.length); +} + + +/* + * + * Floating point types + * + */ + + +template +constexpr inline void format_integral(char* out, float_t value, + fmt_data_t fmt_node) { + // TODO +} + + +} // namespace detail + + +#endif // LOGGER_FORMAT_IMPL_H diff --git a/src/main.cpp b/src/main.cpp index 84c5cb3..ade67f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,14 +1,14 @@ -#include +//#include #include -int main() { - constexpr auto formatted = "Test: {:012.5} {:6} {:8}"_fmt(142.4334, "abcdef", -1234); +int main(int argc, char* argv[]) { + auto formatted = "Test: {:12} {:012.5} {:8}"_fmt(argv[0], argc, -1234); for (const auto& c : formatted) std::cout << c; std::cout << std::endl; - return 0; + return formatted[6]; } \ No newline at end of file