diff options
-rw-r--r-- | libadhocutil/compileTimeFormatter.h | 79 | ||||
-rw-r--r-- | libadhocutil/ctf-impl/printf-compat.h | 4 | ||||
-rw-r--r-- | libadhocutil/unittests/testCompileTimeFormatter.cpp | 43 |
3 files changed, 21 insertions, 105 deletions
diff --git a/libadhocutil/compileTimeFormatter.h b/libadhocutil/compileTimeFormatter.h index 33fe677..be57fee 100644 --- a/libadhocutil/compileTimeFormatter.h +++ b/libadhocutil/compileTimeFormatter.h @@ -1,25 +1,17 @@ #ifndef ADHOCUTIL_COMPILE_TIME_FORMATTER_H #define ADHOCUTIL_COMPILE_TIME_FORMATTER_H +#include <array> #include <boost/preprocessor/control/iif.hpp> // IWYU pragma: keep #include <boost/preprocessor/variadic/size.hpp> // IWYU pragma: keep +#include <cstddef> +#include <iostream> #include <optional> #include <sstream> // IWYU pragma: export #include <type_traits> // Mapped for for BOOST_PP_VARIADIC_SIZE, BOOST_PP... in tests // IWYU pragma: no_include <boost/test/unit_test.hpp> -#ifdef __cpp_nontype_template_parameter_class -# define USE_FIXED_STRING -#endif - -#ifdef USE_FIXED_STRING -# define CtfString const auto -# include <array> -# include <iostream> -#else -# define CtfString const auto & -#endif namespace AdHoc { // Template char utils template<typename char_type> @@ -37,7 +29,7 @@ namespace AdHoc { } // Template string utils - template<CtfString S> + template<const auto S> static constexpr auto strlen() { @@ -59,7 +51,7 @@ namespace AdHoc { return off; } - template<CtfString S, auto n, auto start = 0U, auto L = strlen<S>()> + template<const auto S, auto n, auto start = 0U, auto L = strlen<S>()> static constexpr std::optional<decltype(start)> strchr() { @@ -74,7 +66,7 @@ namespace AdHoc { return off; } - template<CtfString S, auto n, auto start = 0U, auto L = strlen<S>()> + template<const auto S, auto n, auto start = 0U, auto L = strlen<S>()> static constexpr decltype(L) strchrnul() { @@ -85,10 +77,10 @@ namespace AdHoc { return off; } - template<CtfString S, const auto L> class FormatterDetail; + template<const auto S, const auto L> class FormatterDetail; /// Template used to apply parameters to a stream. - template<CtfString S, auto L, auto pos, typename stream, typename, auto...> struct StreamWriter { + template<const auto S, auto L, auto pos, typename stream, typename, auto...> struct StreamWriter { /// Write parameters to stream. template<typename... Pn> static void @@ -99,7 +91,7 @@ namespace AdHoc { }; /// Helper to simplify implementations of StreamWriter. - template<CtfString S, auto L, auto pos, typename stream> struct StreamWriterBase { + template<const auto S, auto L, auto pos, typename stream> struct StreamWriterBase { /// Continue processing parameters. template<typename... Pn> static inline void @@ -110,12 +102,12 @@ namespace AdHoc { }; #define StreamWriterT(...) \ - template<CtfString S, auto L, auto pos, typename stream, auto... sn> \ + template<const auto S, auto L, auto pos, typename stream, auto... sn> \ struct StreamWriter<S, L, pos, stream, void, '%', __VA_ARGS__, sn...> : \ public StreamWriterBase<S, L, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__) + pos, stream> #define StreamWriterTP(P, ...) \ - template<CtfString S, auto L, auto pos, typename stream, auto P, auto... sn> \ + template<const auto S, auto L, auto pos, typename stream, auto P, auto... sn> \ struct StreamWriter<S, L, pos, stream, void, '%', __VA_ARGS__, sn...> : \ public StreamWriterBase<S, L, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__) + pos, stream> @@ -159,10 +151,10 @@ namespace AdHoc { * Compile time string formatter. * @param S the format string. */ - template<CtfString S, const auto L> class FormatterDetail { + template<const auto S, const auto L> class FormatterDetail { private: using strlen_t = decltype(strlen<S>()); - template<CtfString, auto, auto, typename> friend struct StreamWriterBase; + template<const auto, auto, auto, typename> friend struct StreamWriterBase; public: /// The derived charater type of the format string. @@ -246,18 +238,18 @@ namespace AdHoc { }; }; -#ifdef USE_FIXED_STRING - // New C++20 implementation namespace support { template<typename CharT, std::size_t N> class basic_fixed_string : public std::array<CharT, N> { public: // cppcheck-suppress noExplicitConstructor + // NOLINTNEXTLINE(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,hicpp-explicit-conversions) constexpr basic_fixed_string(const CharT (&str)[N + 1]) { for (decltype(N) x = 0; x < N; x++) { this->at(x) = str[x]; } } + // NOLINTNEXTLINE(hicpp-avoid-c-arrays,modernize-avoid-c-arrays) constexpr basic_fixed_string(const CharT * str, decltype(N) len) { for (decltype(N) x = 0; x < len; x++) { @@ -267,7 +259,8 @@ namespace AdHoc { }; template<typename CharT, std::size_t N> - basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string<CharT, N - 1>; + // NOLINTNEXTLINE(hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + basic_fixed_string(const CharT (&str)[N])->basic_fixed_string<CharT, N - 1>; } template<const support::basic_fixed_string Str> class LiteralFormatter : public FormatterDetail<Str, Str.size()> { @@ -278,7 +271,7 @@ namespace AdHoc { public FormatterDetail<support::basic_fixed_string<typename std::decay<decltype(S[0])>::type, L>(S, L), L> { }; -# define AdHocFormatter(name, str) using name = ::AdHoc::LiteralFormatter<str> +#define AdHocFormatter(name, str) using name = ::AdHoc::LiteralFormatter<str> template<const support::basic_fixed_string Str, typename... Pn> inline auto @@ -301,47 +294,11 @@ namespace AdHoc { return scprintf<Str>(std::cout, pn...); } -#else - // Classic pre-C++20 implementation -# include "unique.h" - template<const auto & S, decltype(strlen<S>()) L = strlen<S>()> class Formatter : public FormatterDetail<S, L> { - }; - -# define AdHocFormatterTypedef(name, str, id) \ - inline constexpr auto id = str; \ - using name = ::AdHoc::Formatter<id> -# define AdHocFormatter(name, str) AdHocFormatterTypedef(name, str, MAKE_UNIQUE(name)) - -#endif - namespace literals { -#ifdef USE_FIXED_STRING template<const support::basic_fixed_string Str> constexpr inline auto operator""_fmt() noexcept { return AdHoc::FormatterDetail<Str, Str.size()>(); } -#else -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wpedantic" -# ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template" -# endif - /// CTF format string holder - template<typename T, T... t> struct FMT { - /// CTF format string - // NOLINTNEXTLINE(hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - static constexpr char fmtstr[] = {t...}; - }; - template<typename T, T... t> inline auto operator""_fmt() noexcept - { - return AdHoc::FormatterDetail<FMT<T, t...>::fmtstr, sizeof...(t)>(); - } -# ifdef __clang__ -# pragma clang diagnostic pop -# endif -# pragma GCC diagnostic pop -#endif } } diff --git a/libadhocutil/ctf-impl/printf-compat.h b/libadhocutil/ctf-impl/printf-compat.h index 1ca30c3..40508f7 100644 --- a/libadhocutil/ctf-impl/printf-compat.h +++ b/libadhocutil/ctf-impl/printf-compat.h @@ -131,7 +131,7 @@ namespace AdHoc { BOOST_PP_CAT(data, n) #define ISDIGIT(z, n, data) &&isdigit(BOOST_PP_CAT(data, BOOST_PP_ADD(n, 1))) #define FMTWIDTH(unused, d, data) \ - template<CtfString S, auto L, auto pos, typename stream, BOOST_PP_REPEAT(BOOST_PP_ADD(d, 1), AUTON, n), auto nn, \ + template<const auto S, auto L, auto pos, typename stream, BOOST_PP_REPEAT(BOOST_PP_ADD(d, 1), AUTON, n), auto nn, \ auto... sn> \ struct StreamWriter<S, L, pos, stream, \ typename std::enable_if<ispositivedigit(n0) BOOST_PP_REPEAT(d, ISDIGIT, n) && !isdigit(nn)>::type, '%', \ @@ -147,7 +147,7 @@ namespace AdHoc { }; BOOST_PP_REPEAT(6, FMTWIDTH, void) #define FMTPRECISION(unused, d, data) \ - template<CtfString S, auto L, auto pos, typename stream, BOOST_PP_REPEAT(BOOST_PP_ADD(d, 1), AUTON, n), auto nn, \ + template<const auto S, auto L, auto pos, typename stream, BOOST_PP_REPEAT(BOOST_PP_ADD(d, 1), AUTON, n), auto nn, \ auto... sn> \ struct StreamWriter<S, L, pos, stream, \ typename std::enable_if<isdigit(n0) BOOST_PP_REPEAT(d, ISDIGIT, n) && !isdigit(nn)>::type, '%', '.', \ diff --git a/libadhocutil/unittests/testCompileTimeFormatter.cpp b/libadhocutil/unittests/testCompileTimeFormatter.cpp index fc45dba..a79e369 100644 --- a/libadhocutil/unittests/testCompileTimeFormatter.cpp +++ b/libadhocutil/unittests/testCompileTimeFormatter.cpp @@ -10,9 +10,9 @@ #include <cxxabi.h> #include <definedDirs.h> #include <fileUtils.h> +#include <iostream> #include <locale> #include <memory> -#include <optional> #include <string> #include <string_view> #include <type_traits> @@ -93,45 +93,6 @@ namespace AdHoc { }; } -#ifndef __cpp_nontype_template_parameter_class -// Compile string util assertions -static_assert(strlen<formatEdgeCaseEmpty>() == 0); -static_assert(strlen<formatEdgeCaseSingle>() == 1); -static_assert(strlen<formatEdgeCaseFormatLonely>() == 2); -static_assert(strlen<formatStringLiteral>() == 7); -static_assert(strlen<formatStringLong>() == 246); - -static_assert(!strchr<formatEdgeCaseEmpty, 't'>()); -static_assert(!strchr<formatEdgeCaseSingle, 't'>()); -static_assert(*strchr<formatEdgeCaseSingle, '1'>() == 0); -static_assert(*strchr<formatEdgeCaseFormatLonely, '%'>() == 0); -static_assert(*strchr<formatEdgeCaseFormatLonely, '?'>() == 1); -static_assert(*strchr<formatStringLiteral, 'e'>() == 3); -static_assert(!strchr<formatStringLiteral, 'f'>()); -static_assert(*strchr<formatStringLiteral, 'e', 3U>() == 3); -static_assert(!strchr<formatStringLiteral, 'e', 4U>()); -static_assert(!strchr<formatStringLiteral, 'f', 3U>()); - -static_assert(strchrnul<formatEdgeCaseEmpty, 't'>() == 0); -static_assert(strchrnul<formatEdgeCaseSingle, 't'>() == 1); -static_assert(strchrnul<formatEdgeCaseSingle, '1'>() == 0); -static_assert(strchrnul<formatEdgeCaseFormatLonely, '%'>() == 0); -static_assert(strchrnul<formatEdgeCaseFormatLonely, '?'>() == 1); -static_assert(strchrnul<formatStringLiteral, 'e'>() == 3); -static_assert(strchrnul<formatStringLiteral, 'f'>() == 7); -static_assert(strchrnul<formatStringLiteral, 'e', 3U>() == 3); -static_assert(strchrnul<formatStringLiteral, 'e', 4U>() == 7); -static_assert(strchrnul<formatStringLiteral, 'f', 3U>() == 7); - -static_assert(strchrnul<formatEdgeCaseEmpty, 't'>() == 0); -static_assert(strchrnul<formatEdgeCaseSingle, 't'>() == 1); -static_assert(strchrnul<formatEdgeCaseSingle, '1'>() == 0); -static_assert(strchrnul<formatEdgeCaseFormatLonely, '%'>() == 0); -static_assert(strchrnul<formatEdgeCaseFormatLonely, '?'>() == 1); -static_assert(strchrnul<formatStringLiteral, 'e'>() == 3); -static_assert(strchrnul<formatStringLiteral, 'f'>() == 7); -#endif - BOOST_FIXTURE_TEST_SUITE(TestStreamWrite, std::stringstream) BOOST_AUTO_TEST_CASE(empty) @@ -464,7 +425,6 @@ BOOST_AUTO_TEST_CASE(smartptr) smartptr_fmt::get(shrd); } -#ifdef __cpp_nontype_template_parameter_class BOOST_AUTO_TEST_CASE(literal_format_string) { std::stringstream str; @@ -511,7 +471,6 @@ BOOST_AUTO_TEST_CASE(scprintf_get_no_args) auto stng = scprintf<"Some literal format string.">(); BOOST_CHECK_EQUAL(stng, "Some literal format string."); } -#endif using namespace AdHoc::literals; |