Comments (1)
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/utility/string_ref.hpp>
template<std::size_t N>
constexpr bool checkValidFormats(const char (&fmt)[N], size_t n, char c)
{
return n >= N ?
false
: fmt[n] == c ?
true
: checkValidFormats(fmt, n + 1, c);
}
template<class>
struct FormatSupportedType;
#define SUPPORTED_TYPE(T, Fmts) \
template<> \
struct FormatSupportedType<T> \
{ \
constexpr static bool supports(char c) \
{ return checkValidFormats(Fmts, 0, c) \
? true : throw std::logic_error("invalid fmt for type"); } \
}
SUPPORTED_TYPE(char, "c");
SUPPORTED_TYPE(int, "d*");
SUPPORTED_TYPE(unsigned, "u*");
SUPPORTED_TYPE(char*, "s");
SUPPORTED_TYPE(const char*, "s");
SUPPORTED_TYPE(std::string, "s");
SUPPORTED_TYPE(boost::string_ref, "s");
SUPPORTED_TYPE(double, "f");
SUPPORTED_TYPE(float, "f");
/////////////////
constexpr bool isDigit(char c)
{
return c >= '0' && c <= '9';
}
constexpr bool isModifier(char c)
{
return c == 'l' ||
c == 'h' ||
c == 'j' ||
c == 'z' ||
c == 't' ||
c == 'L' ||
c == '#' ||
c == '+' ||
c == '-' ||
c == ' ' ||
c == '\'' ||
c == 'I' ||
c == '.' ||
c == '=' ||
isDigit(c);
}
template<std::size_t N>
constexpr size_t nextNonModifier(const char (&fmt)[N], std::size_t n)
{
return
n >= N ?
throw std::logic_error("invalid format string")
: isModifier(fmt[n]) ?
nextNonModifier(fmt, n + 1)
: n;
}
////////////////////
template<std::size_t N>
constexpr bool checkFormatHelper(const char (&fmt)[N], std::size_t n);
template<std::size_t N, class T, class... Ts>
constexpr bool checkFormatHelper(const char (&fmt)[N], std::size_t n, const T& arg, const Ts&... args);
////////////////////
template<std::size_t N, typename T1, typename T2, typename T3, typename... Ts>
constexpr auto checkWidthAndPrecision(const char (&fmt)[N], std::size_t n, const T1& /*width*/, const T2& /*precision*/, const T3& /* arg */, const Ts&... args)
-> typename std::enable_if<
std::is_integral<T1>::value &&
std::is_integral<T2>::value,
bool>::type
{
return FormatSupportedType< typename std::decay<T3>::type>::supports(fmt[n]) &&
checkFormatHelper(fmt, n + 1, args...);
}
template<std::size_t N, typename... Ts>
constexpr bool checkWidthAndPrecision(const char (&)[N], std::size_t, const Ts&...)
{
return false;
}
////////////////////
template<std::size_t N, typename T1, typename T2, typename... Ts>
constexpr auto checkWidthOrPrecision(const char (&fmt)[N], std::size_t n, const T1& /*precision*/, const T2& /* arg */, const Ts&... args)
-> typename std::enable_if<
std::is_integral<T1>::value,
bool>::type
{
return FormatSupportedType< typename std::decay<T2>::type>::supports(fmt[n]) &&
checkFormatHelper(fmt, n + 1, args...);
}
template<std::size_t N, typename... Ts>
constexpr bool checkWidthOrPrecision(const char (&)[N], std::size_t, const Ts&...)
{
return false;
}
////////////////////
template<std::size_t N>
constexpr bool checkFormatHelper(const char (&fmt)[N], std::size_t n)
{
return
n>= N ?
true
: fmt[n] != '%' ?
checkFormatHelper(fmt, n + 1)
: fmt[n + 1] == '%' ?
checkFormatHelper(fmt, n + 2)
: false;
}
template<std::size_t N, class T, class... Ts>
constexpr bool checkFormatHelper(const char (&fmt)[N], std::size_t n, const T& arg, const Ts&... args)
{
return
n >= N ?
throw std::logic_error("too many arguments for provided format string")
: fmt[n] != '%' ?
checkFormatHelper(fmt, n + 1, arg, args...)
// literal percent character
: (fmt[n + 1] == '%') ?
checkFormatHelper(fmt, n + 2, arg, args...)
// long-long modifier
: (fmt[n + 1] == 'l' && fmt[n + 2] == 'l') ?
FormatSupportedType< typename std::decay<T>::type >::supports(fmt[n + 3]) &&
checkFormatHelper(fmt, n + 4, args...)
// width & precision modifier
: (fmt[n + 1] == '*' && fmt[n + 2] == '.' && fmt[n + 3] == '*') ?
checkWidthAndPrecision(fmt, n + 4, arg, args...)
// width or precision modifier
: ((fmt[n + 1] == '.' && fmt[n + 2] == '*') || (fmt[n + 1] == '*')) ?
checkWidthOrPrecision(fmt, (fmt[n + 1] == '.' ? n + 3 : n + 2), arg, args...)
// other modifier
: (isModifier(fmt[n + 1])) ?
FormatSupportedType< typename std::decay<T>::type>::supports(fmt[nextNonModifier(fmt, n + 2)]) &&
checkFormatHelper(fmt, nextNonModifier(fmt, n + 2) + 1, args...)
// no modifier
: FormatSupportedType< typename std::decay<T>::type>::supports(fmt[n + 1]) &&
checkFormatHelper(fmt, n + 2, args...);
}
template<std::size_t N, class... Ts>
constexpr bool checkFormat(const char (&fmt)[N], const Ts&... args)
{
return checkFormatHelper(fmt, 0, args...);
}
// printing...
void add(boost::format&)
{ }
template<typename T, typename... Ts>
void add(boost::format& f, const T& arg, const Ts&... ts)
{
f % arg;
add(f, ts...);
}
#define LOG(fmt, ...) \
{ \
static_assert(checkFormat(fmt, ##__VA_ARGS__), "Format is incorrect"); \
boost::format f(fmt); \
add(f, ##__VA_ARGS__); \
std::cout << f.str() << std::endl; \
}
int main()
{
// char
LOG("%c", 'x');
// integral
LOG("%d", -123);
LOG("%ld", -123);
LOG("%u", 123u);
LOG("%lu", 123u);
// strings
LOG("%s", "hello world");
{ const char* s = "hello world"; LOG("%s", s); }
{ std::string s = "hello world"; LOG("%s", s); }
{ std::string s = "hello world"; boost::string_ref r(s); LOG("%s", r); }
// floating point
LOG("%f", 1.23);
LOG("%f", 1.23f);
// width / precision
LOG("%02d", 1);
LOG("%.2d", 123);
LOG("% 3s", "hello");
LOG("% 3s", "yo");
LOG("%.3s", "hello");
LOG("%.3s", "yo");
// incorrect format string
// LOG("%f", 1);
// LOG("%d", 1.23);
// not supported by boost::format
// LOG("%*s", 3, "yo");
// LOG("%*d", 3, 12);
// LOG("%.*s", 3, "hello");
// LOG("%.*d", 3, 12345);
// LOG("%*.*s", 3, 3, "hello");
// LOG("%*.*d", 3, 3, 12345);
}
from emcpp.
Related Issues (2)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from emcpp.