Code Monkey home page Code Monkey logo

Comments (1)

larytet avatar larytet commented on July 18, 2024
#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 photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.