diff options
-rw-r--r-- | libadhocutil/compileTimeFormatter.h | 36 | ||||
-rw-r--r-- | libadhocutil/unittests/testCompileTimeFormatter.cpp | 26 |
2 files changed, 37 insertions, 25 deletions
diff --git a/libadhocutil/compileTimeFormatter.h b/libadhocutil/compileTimeFormatter.h index 09fdb6a..0a86946 100644 --- a/libadhocutil/compileTimeFormatter.h +++ b/libadhocutil/compileTimeFormatter.h @@ -3,6 +3,7 @@ #include <sstream> #include <cstring> +#include <optional> #include <array> #include <boost/preprocessor/variadic/size.hpp> #include "unique.h" @@ -26,24 +27,32 @@ namespace AdHoc { template<CtfString S> static constexpr auto strlen() { - auto off = 0; + auto off = 0U; while (S[off]) { ++off; } return off; } - template<CtfString S, auto n, auto start = 0, auto L = strlen<S>()> - static constexpr auto strchr() + template<typename char_type> + static constexpr auto strlen(const char_type * S) + { + auto off = 0U; + while (S[off]) { ++off; } + return off; + } + + template<CtfString S, auto n, auto start = 0U, auto L = strlen<S>()> + static constexpr std::optional<decltype(start)> strchr() { static_assert(start <= L); decltype(start) off = start; while (off < L && S[off] != n) { ++off; } if (off == L) { - return -1; + return {}; } return off; } - template<CtfString S, auto n, auto start = 0, auto L = strlen<S>()> + template<CtfString S, auto n, auto start = 0U, auto L = strlen<S>()> static constexpr decltype(L) strchrnul() { decltype(start) off = start; @@ -51,7 +60,7 @@ namespace AdHoc { return off; } - template<CtfString S, decltype(strlen<S>())> class Formatter; + template<CtfString 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 ...> @@ -71,7 +80,7 @@ namespace AdHoc { template<typename ... Pn> static inline void next(stream & s, const Pn & ... pn) { - Formatter<S, L>::template Parser<stream, pos + 1, Pn...>::run(s, pn...); + FormatterDetail<S, L>::template Parser<stream, pos + 1, Pn...>::run(s, pn...); } }; @@ -121,8 +130,8 @@ namespace AdHoc { * Compile time string formatter. * @param S the format string. */ - template <CtfString S, decltype(strlen<S>()) L = strlen<S>()> - class Formatter { + template <CtfString S, const auto L> + class FormatterDetail { private: using strlen_t = decltype(strlen<S>()); template<CtfString, auto, auto, typename> friend struct StreamWriterBase; @@ -161,7 +170,7 @@ namespace AdHoc { template<typename stream, typename ... Pn> static inline stream & write(stream & s, const Pn & ... pn) { - return Parser<stream, 0, Pn...>::run(s, pn...); + return Parser<stream, 0U, Pn...>::run(s, pn...); } /** * Write the result of formatting to the given stream. @@ -193,7 +202,7 @@ namespace AdHoc { } return s; } - template<strlen_t ph, strlen_t off = 0, auto ... Pck> + template<strlen_t ph, strlen_t off = 0U, auto ... Pck> static inline void packAndWrite(stream & s, const Pn & ... pn) { if constexpr (ph + off == L || sizeof...(Pck) == 32) { @@ -220,12 +229,15 @@ namespace AdHoc { }; template<typename T, T ... t> inline auto operator""_fmt() noexcept { - return AdHoc::Formatter<FMT<T, t...>::__FMT, sizeof...(t)>(); + return AdHoc::FormatterDetail<FMT<T, t...>::__FMT, sizeof...(t)>(); } #ifdef __clang__ #pragma clang diagnostic pop #endif } + + template <const auto & S, decltype(strlen<S>()) L = strlen<S>()> + class Formatter : public FormatterDetail<S, L> { }; } #define AdHocFormatterTypedef(name, str, id) \ diff --git a/libadhocutil/unittests/testCompileTimeFormatter.cpp b/libadhocutil/unittests/testCompileTimeFormatter.cpp index a19e588..ba8a46f 100644 --- a/libadhocutil/unittests/testCompileTimeFormatter.cpp +++ b/libadhocutil/unittests/testCompileTimeFormatter.cpp @@ -84,16 +84,16 @@ static_assert(strlen<formatEdgeCaseFormatLonely>() == 2); static_assert(strlen<formatStringLiteral>() == 7); static_assert(strlen<formatStringLong>() == 246); -static_assert(strchr<formatEdgeCaseEmpty, 't'>() == -1); -static_assert(strchr<formatEdgeCaseSingle, 't'>() == -1); -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'>() == -1); -static_assert(strchr<formatStringLiteral, 'e', 3>() == 3); -static_assert(strchr<formatStringLiteral, 'e', 4>() == -1); -static_assert(strchr<formatStringLiteral, 'f', 3>() == -1); +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); @@ -102,9 +102,9 @@ 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', 3>() == 3); -static_assert(strchrnul<formatStringLiteral, 'e', 4>() == 7); -static_assert(strchrnul<formatStringLiteral, 'f', 3>() == 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); |