summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libadhocutil/compileTimeFormatter.h2
-rw-r--r--libadhocutil/ctf-impl/printf-compat.h (renamed from libadhocutil/detail/compileTimeFormatters.h)79
-rw-r--r--libadhocutil/unittests/testCompileTimeFormatter.cpp26
3 files changed, 74 insertions, 33 deletions
diff --git a/libadhocutil/compileTimeFormatter.h b/libadhocutil/compileTimeFormatter.h
index bb80edf..77fa753 100644
--- a/libadhocutil/compileTimeFormatter.h
+++ b/libadhocutil/compileTimeFormatter.h
@@ -176,8 +176,6 @@ namespace AdHoc {
};
}
-#include "detail/compileTimeFormatters.h"
-
#define AdHocFormatterTypedef(name, str, id) \
inline constexpr auto id = str; \
typedef ::AdHoc::Formatter<id> name
diff --git a/libadhocutil/detail/compileTimeFormatters.h b/libadhocutil/ctf-impl/printf-compat.h
index 00ee852..3367b4a 100644
--- a/libadhocutil/detail/compileTimeFormatters.h
+++ b/libadhocutil/ctf-impl/printf-compat.h
@@ -3,6 +3,11 @@
#include "../compileTimeFormatter.h"
#include <boost/assert.hpp>
+#include <boost/preprocessor/repetition/repeat.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/preprocessor/if.hpp>
+#include <boost/preprocessor/comma_if.hpp>
+#include <boost/preprocessor/arithmetic/add.hpp>
#include <iomanip>
#include <type_traits>
@@ -67,6 +72,7 @@ namespace AdHoc {
static inline void write(stream & s, Obj * const ptr, const Pn & ... pn)
{
s << std::showbase << std::hex << (long unsigned int)ptr;
+ s.copyfmt(std::ios(NULL));
StreamWriter::next(s, pn...);
}
template<typename Ptr, typename ... Pn>
@@ -81,6 +87,7 @@ namespace AdHoc {
static inline void write(stream & s, const Pn & ... pn)
{
s << strerror(errno);
+ s.copyfmt(std::ios(NULL));
StreamWriter::next(s, pn...);
}
};
@@ -90,50 +97,58 @@ namespace AdHoc {
{
BOOST_ASSERT_MSG(n, "%n conversion requires non-null parameter");
*n = streamLength(s);
+ s.copyfmt(std::ios(NULL));
StreamWriter::next(s, pn...);
}
};
////
// Width/precision embedded in format string
- // Limitted to 3 digits at the moment
- template<const auto & S, auto L, auto pos, typename stream, auto n0, auto nn, auto ... sn>
- struct StreamWriter<S, L, pos, stream, typename std::enable_if<ispositivedigit(n0) && !isdigit(nn)>::type, '%', n0, nn, sn...> {
- template<typename ... Pn>
- static inline void write(stream & s, const Pn & ... pn)
- {
- constexpr auto p = (n0 - '0');
- s << std::setw(p) << std::setprecision(p);
- StreamWriter<S, L, pos + 1, stream, void, '%', nn, sn...>::write(s, pn...);
- }
- };
- template<const auto & S, auto L, auto pos, typename stream, auto n0, auto n1, auto nn, auto ... sn>
- struct StreamWriter<S, L, pos, stream, typename std::enable_if<ispositivedigit(n0) && isdigit(n1) && !isdigit(nn)>::type, '%', n0, n1, nn, sn...> {
- template<typename ... Pn>
- static inline void write(stream & s, const Pn & ... pn)
- {
- constexpr auto p = ((n0 - '0') * 10) + (n1 - '0');
- s << std::setw(p) << std::setprecision(p);
- StreamWriter<S, L, pos + 2, stream, void, '%', nn, sn...>::write(s, pn...);
- }
+ template<auto ... chs>
+ constexpr auto decdigits()
+ {
+ static_assert((isdigit(chs) && ... && true));
+ int n = 0;
+ ([&n](auto ch) {
+ n = (n * 10) + (ch - '0');
+ }(chs), ...);
+ return n;
+ }
+#define AUTON(z, n, data) BOOST_PP_COMMA_IF(n) auto BOOST_PP_CAT(data, n)
+#define NS(z, n, data) BOOST_PP_COMMA_IF(n) 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<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, '%', BOOST_PP_REPEAT(BOOST_PP_ADD(d, 1), NS, n), nn, sn...> { \
+ template<typename ... Pn> \
+ static inline void write(stream & s, const Pn & ... pn) { \
+ constexpr auto p = decdigits<BOOST_PP_REPEAT(BOOST_PP_ADD(d, 1), NS, n)>(); \
+ s << std::setw(p); \
+ StreamWriter<S, L, pos + BOOST_PP_ADD(d, 1), stream, void, '%', nn, sn...>::write(s, pn...); \
+ } \
};
- template<const auto & S, auto L, auto pos, typename stream, auto n0, auto n1, auto n2, auto nn, auto ... sn>
- struct StreamWriter<S, L, pos, stream, typename std::enable_if<ispositivedigit(n0) && isdigit(n1) && isdigit(n2) && !isdigit(nn)>::type, '%', n0, n1, n2, nn, sn...> {
- template<typename ... Pn>
- static inline void write(stream & s, const Pn & ... pn)
- {
- constexpr auto p = ((n0 - '0') * 100) + ((n1 - '0') * 10) + (n2 - '0');
- s << std::setw(p) << std::setprecision(p);
- StreamWriter<S, L, pos + 3, stream, void, '%', nn, sn...>::write(s, pn...);
- }
+ BOOST_PP_REPEAT(6, FMTWIDTH, void);
+#define FMTPRECISION(unused, d, data) \
+ 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, '%', '.', BOOST_PP_REPEAT(BOOST_PP_ADD(d, 1), NS, n), nn, sn...> { \
+ template<typename ... Pn> \
+ static inline void write(stream & s, const Pn & ... pn) { \
+ constexpr auto p = decdigits<BOOST_PP_REPEAT(BOOST_PP_ADD(d, 1), NS, n)>(); \
+ s << std::setprecision(p); \
+ StreamWriter<S, L, pos + BOOST_PP_ADD(d, 2), stream, void, '%', nn, sn...>::write(s, pn...); \
+ } \
};
- ////
+ BOOST_PP_REPEAT(6, FMTPRECISION, void);
+#undef AUTON
+#undef NS
+#undef ISDIGIT
+#undef FMTWIDTH
StreamWriterT('.', '*') {
template<typename ... Pn>
static inline void write(stream & s, int l, const Pn & ... pn)
{
- s << std::setw(l) << std::setprecision(l);
+ s << std::setw(l);
StreamWriter<S, L, pos + 2, stream, void, '%', sn...>::write(s, pn...);
}
};
@@ -142,6 +157,7 @@ namespace AdHoc {
static inline void write(stream & s, int l, const std::string_view & p, const Pn & ... pn)
{
s << p.substr(0, l);
+ s.copyfmt(std::ios(NULL));
StreamWriter::next(s, pn...);
}
};
@@ -157,6 +173,7 @@ namespace AdHoc {
FLAGCONV(s << std::showbase, '#');
FLAGCONV(s << std::setfill('0'), '0');
FLAGCONV(s << std::left, '-');
+ FLAGCONV(s << std::showpos, '+');
FLAGCONV(s << std::setfill(' '), ' ');
#undef FLAGCONV
}
diff --git a/libadhocutil/unittests/testCompileTimeFormatter.cpp b/libadhocutil/unittests/testCompileTimeFormatter.cpp
index 138d5dc..b966078 100644
--- a/libadhocutil/unittests/testCompileTimeFormatter.cpp
+++ b/libadhocutil/unittests/testCompileTimeFormatter.cpp
@@ -308,6 +308,25 @@ BOOST_AUTO_TEST_CASE( filestar )
free(buf);
}
+#include "ctf-impl/printf-compat.h"
+
+static_assert(isdigit('0'));
+static_assert(isdigit('9'));
+static_assert(!isdigit('.'));
+static_assert(!isdigit('a'));
+
+static_assert(!ispositivedigit('0'));
+static_assert(ispositivedigit('1'));
+static_assert(ispositivedigit('9'));
+static_assert(!ispositivedigit('.'));
+static_assert(!ispositivedigit('a'));
+
+static_assert(0 == decdigits<'0'>());
+static_assert(1 == decdigits<'1'>());
+static_assert(19 == decdigits<'1', '9'>());
+static_assert(419 == decdigits<'4', '1', '9'>());
+static_assert(419 == decdigits<'0', '4', '1', '9'>());
+
// The following tests represent CTF's [partial] emulation of many
// POSIX formatting features
#define GLIBC_FMT_TEST(NAME, FMT, ...) \
@@ -332,6 +351,10 @@ GLIBC_FMT_TEST(s5, "in %.*s.", 7, "other");
GLIBC_FMT_TEST(s35, "in %3s.", "other");
GLIBC_FMT_TEST(s55, "in %5s.", "other");
GLIBC_FMT_TEST(s115, "in %11s.", "other");
+//std::setw does not truncate strings
+//GLIBC_FMT_TEST(sd35, "in %.3s.", "other");
+GLIBC_FMT_TEST(sd55, "in %.5s.", "other");
+GLIBC_FMT_TEST(sd115, "in %.11s.", "other");
GLIBC_FMT_TEST(c1, "in %c.", 'b');
GLIBC_FMT_TEST(c2, "in %c.", 'B');
@@ -398,6 +421,9 @@ GLIBC_FMT_TEST(g6, "in %G.", -123.456789);
GLIBC_FMT_TEST(g7, "in %g.", 123456789.123);
GLIBC_FMT_TEST(g8, "in %g.", -123456789.123);
+GLIBC_FMT_TEST(fmtlibt_fmt, "%0.10f:%04d:%+g:%s:%p:%c:%%\n",
+ 1.234, 42, 3.13, "str", (void*)1000, (int)'X');
+
AdHocFormatter(chars_written_fmt, "%n %s %n %d %n");
BOOST_AUTO_TEST_CASE(chars_written)
{