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);  | 
