aboutsummaryrefslogtreecommitdiffstats
path: root/include/jau
diff options
context:
space:
mode:
authorSven Göthel <[email protected]>2024-09-14 06:10:35 +0200
committerSven Göthel <[email protected]>2024-09-14 06:10:35 +0200
commitbc3df78443ad99c8fa76a6b58d07c4336255e323 (patch)
tree6c8461d49e1c2fbd996c6835ed7e92abf1e237ff /include/jau
parentb8f7f12979bc35d7cab0905ae83040847721c86a (diff)
jau::cfmt: cleanup and add robusteness, adding alternative recursive version
Diffstat (limited to 'include/jau')
-rw-r--r--include/jau/string_cfmt.hpp55
-rw-r--r--include/jau/string_util.hpp5
2 files changed, 31 insertions, 29 deletions
diff --git a/include/jau/string_cfmt.hpp b/include/jau/string_cfmt.hpp
index 9574c6a..c097b70 100644
--- a/include/jau/string_cfmt.hpp
+++ b/include/jau/string_cfmt.hpp
@@ -274,7 +274,7 @@ namespace jau::cfmt {
* @return true if no error _and_ not complete, i.e. further calls with subsequent parameter required. Otherwise parsing is done due to error or completeness.
*/
template <typename T>
- constexpr bool parseOne(PResult &pc) const {
+ constexpr bool parseOne(PResult &pc) const noexcept {
if( !pc.hasNext() ) {
return false; // done or error
}
@@ -306,7 +306,7 @@ namespace jau::cfmt {
pc.state = pstate_t::precision;
if( c == '.' ) {
if( !parsePrecision<T>(pc, c) ) {
- return !pc.error(); // error or continue with next argument for same conversion -> field_width
+ return !pc.error(); // error or continue with next argument for same conversion -> precision
}
}
}
@@ -398,6 +398,7 @@ namespace jau::cfmt {
return true; // continue with current argument
}
+ /* parse length modifier, returns true if parsing can continue or false on error. */
constexpr bool parseLengthMods(PResult &pc, char &c) const noexcept {
if( 'h' == c ) {
if( !pc.nextSymbol(c) ) { return false; }
@@ -441,28 +442,16 @@ namespace jau::cfmt {
case '%':
case 'c':
case 's':
- if( !parseStringFmtSpec<T>(pc, fmt_literal) ) {
- return false;
- }
- break;
+ return parseStringFmtSpec<T>(pc, fmt_literal);
case 'p':
- if( !parseAPointerFmtSpec<T>(pc) ) {
- return false;
- }
- break;
+ return parseAPointerFmtSpec<T>(pc);
case 'd':
- if( !parseSignedFmtSpec<T>(pc) ) {
- return false;
- }
- break;
+ return parseSignedFmtSpec<T>(pc);
case 'o':
case 'x':
case 'X':
case 'u':
- if( !parseUnsignedFmtSpec<T>(pc, fmt_literal) ) {
- return false;
- }
- break;
+ return parseUnsignedFmtSpec<T>(pc, fmt_literal);
case 'f':
case 'e':
case 'E':
@@ -470,15 +459,11 @@ namespace jau::cfmt {
case 'A':
case 'g':
case 'G':
- if( !parseFloatFmtSpec<T>(pc, fmt_literal) ) {
- return false;
- }
- break;
+ return parseFloatFmtSpec<T>(pc, fmt_literal);
default:
pc.setError(__LINE__);
return false;
} // switch( fmt_literal )
- return true;
}
constexpr char unaliasFmtSpec(const char fmt_literal) const noexcept {
@@ -491,7 +476,6 @@ namespace jau::cfmt {
template <typename T>
constexpr bool parseStringFmtSpec(PResult &pc, const char fmt_literal) const noexcept {
- pc.length_mod = plength_t::none;
if constexpr( std::is_same_v<no_type_t, T> ) {
pc.setError(__LINE__);
return false;
@@ -546,7 +530,9 @@ namespace jau::cfmt {
return false;
}
break;
- default: break;
+ default:
+ pc.setError(__LINE__);
+ return false;
}
return true;
}
@@ -754,7 +740,7 @@ namespace jau::cfmt {
* @see @ref jau_cfmt_header
*/
template <typename... Targs>
- constexpr bool check(std::string_view fmt, const Targs &...) {
+ constexpr bool check(const std::string_view fmt, const Targs &...) noexcept {
PResult ctx(fmt);
constexpr const impl::Parser p;
if constexpr( 0 < sizeof...(Targs) ) {
@@ -774,7 +760,18 @@ namespace jau::cfmt {
* @see @ref jau_cfmt_header
*/
template <typename... Targs>
- constexpr bool check2(std::string_view fmt) {
+ constexpr bool check2(const std::string_view fmt) noexcept {
+ PResult ctx(fmt);
+ constexpr const impl::Parser p;
+ if constexpr( 0 < sizeof...(Targs) ) {
+ ((p.template parseOne<Targs>(ctx)), ...);
+ }
+ p.template parseOne<impl::no_type_t>(ctx);
+ return !ctx.error();
+ }
+
+ template <typename StrView, typename... Targs>
+ constexpr bool check3(StrView fmt) noexcept {
PResult ctx(fmt);
constexpr const impl::Parser p;
if constexpr( 0 < sizeof...(Targs) ) {
@@ -796,7 +793,7 @@ namespace jau::cfmt {
* @see @ref jau_cfmt_header
*/
template <typename... Targs>
- constexpr PResult checkR(std::string_view fmt, const Targs &...) {
+ constexpr PResult checkR(const std::string_view fmt, const Targs &...) noexcept {
PResult ctx(fmt);
constexpr const impl::Parser p;
if constexpr( 0 < sizeof...(Targs) ) {
@@ -817,7 +814,7 @@ namespace jau::cfmt {
* @see @ref jau_cfmt_header
*/
template <typename... Targs>
- constexpr PResult checkR2(std::string_view fmt) {
+ constexpr PResult checkR2(const std::string_view fmt) noexcept {
PResult ctx(fmt);
constexpr const impl::Parser p;
if constexpr( 0 < sizeof...(Targs) ) {
diff --git a/include/jau/string_util.hpp b/include/jau/string_util.hpp
index a9844cd..7520166 100644
--- a/include/jau/string_util.hpp
+++ b/include/jau/string_util.hpp
@@ -29,6 +29,7 @@
#include <cstring>
#include <string>
#include <cstdarg>
+#include <string_view>
#include <type_traits>
#include <vector>
@@ -433,6 +434,10 @@ namespace jau {
} // namespace jau
+#define jau_format_string_static(...) \
+ jau::format_string(__VA_ARGS__); \
+ static_assert( 0 <= jau::cfmt::checkR(__VA_ARGS__).argCount() ); // compile time validation!
+
/** \example test_intdecstring01.cpp
* This C++ unit test validates the jau::to_decstring implementation
*/