]> WPIA git - cassiopeia.git/blob - src/log/format.hpp
5cfd36936b73800a324296b54607824fb33d8c5e
[cassiopeia.git] / src / log / format.hpp
1 #pragma once
2
3 #include <string>
4 #include <sstream>
5 #include <iomanip>
6 #include <initializer_list>
7 #include <tuple>
8
9 namespace logger {
10
11     namespace format {
12
13         template <typename Integer>
14         struct formated_integer;
15         struct formated_string;
16
17         struct width_t {
18             explicit width_t( unsigned v ): value{v} {}
19             unsigned value = 0u;
20         };
21         struct base_t {
22             explicit base_t( unsigned v ): value{v} {}
23             unsigned value = 10u;
24         };
25         struct fill_t {
26             explicit fill_t( char v ): value{v} {}
27             char value = ' ';
28         };
29         enum class align_t {
30             left, right
31         };
32
33         inline namespace literals {
34             inline width_t operator"" _w( unsigned long long value ) {
35                 return width_t{static_cast<unsigned>( value )};
36             }
37             inline base_t operator"" _b( unsigned long long value ) {
38                 return base_t{static_cast<unsigned>( value )};
39             }
40             inline fill_t operator"" _f( char c ) {
41                 return fill_t{c};
42             }
43         }
44
45         struct format_data {
46             unsigned width = 0;
47             std::uint8_t base = 10;
48             char fill = ' ';
49             bool align_right = false;
50
51             void set( width_t w ) {
52                 width = w.value;
53             }
54             void set( base_t b ) {
55                 base = b.value;
56             }
57             void set( fill_t f ) {
58                 fill = f.value;
59             }
60             void set( align_t a ) {
61                 align_right = ( a == align_t::right );
62             }
63
64             formated_string operator()( const std::string& str ) const;
65
66             template <typename Integer,
67                       typename = typename std::enable_if<std::is_integral<Integer>::value>::type>
68             formated_integer<Integer> operator()( Integer i ) const;
69         };
70
71         template <typename Integer>
72         struct formated_integer : public format_data {
73             formated_integer( Integer i, format_data f ) : format_data( f ), value {i} {}
74             Integer value;
75         };
76
77         struct formated_string : public format_data {
78             formated_string( const std::string& s, format_data f ) :
79                 format_data( f ), value( std::move( s ) ) {}
80
81             const std::string& value;
82         };
83
84         inline formated_string format_data::operator()( const std::string& str ) const {
85             return {str, *this};
86         }
87
88         template <typename Integer, typename>
89         inline formated_integer<Integer> format_data::operator()( Integer i ) const {
90             return {i, *this};
91         }
92
93         template <typename... Args>
94         formated_string fmt( const std::string& str, const Args& ... args ) {
95             auto format = format_data{};
96             std::ignore = std::initializer_list<int> {( format.set( args ), 0 )...};
97             return format( str );
98         }
99
100         template <typename Integer, typename... Args>
101         formated_integer<Integer> fmt( const Integer i, const Args& ... args ) {
102             auto format = format_data{};
103             std::ignore = std::initializer_list<int> {( format.set( args ), 0 )...};
104             return format( i );
105         }
106
107         inline namespace literals {
108             format_data operator"" _fmt( const char *, std::size_t );
109         }
110
111     } // namespace format
112
113     namespace conv {
114
115         template <typename Integer>
116         inline std::string to_string( const format::formated_integer<Integer>& arg ) {
117             std::ostringstream stream;
118             stream <<
119                    std::setbase( arg.base ) <<
120                    std::setw( arg.width ) <<
121                    std::setfill( arg.fill ) <<
122                    arg.value;
123             return stream.str();
124         }
125
126         std::string to_string( const format::formated_string& arg );
127
128     } // namespace conf
129
130 } // namespace logger