RBControl
Library for the RB3201-RBControl board with the ESP32 by RoboticsBrno.
formatters.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <algorithm>
4 #include <cctype>
5 #include <cinttypes>
6 #include <cstdio>
7 #include <cstring>
8 
10 struct Formatable {};
11 
12 #define FMT_CONST(FMT) \
13  static constexpr auto fmt = FMT; \
14  static constexpr auto fmt_full = "%" FMT;
15 
16 template <class T, class U = void>
17 struct FmtStr {};
18 
19 template <>
20 struct FmtStr<int8_t> { FMT_CONST("c"); };
21 
22 template <>
23 struct FmtStr<int16_t> { FMT_CONST(PRId16); };
24 
25 template <>
26 struct FmtStr<int32_t> { FMT_CONST(PRId32); };
27 
28 template <>
29 struct FmtStr<int64_t> { FMT_CONST(PRId64); };
30 
31 template <>
32 struct FmtStr<uint8_t> { FMT_CONST("c"); };
33 
34 template <>
35 struct FmtStr<uint16_t> { FMT_CONST(PRIu16); };
36 
37 template <>
38 struct FmtStr<uint32_t> { FMT_CONST(PRIu32); };
39 
40 template <>
41 struct FmtStr<uint64_t> { FMT_CONST(PRIu64); };
42 
43 template <>
44 struct FmtStr<float> { FMT_CONST("f"); };
45 
46 template <>
47 struct FmtStr<double> { FMT_CONST("f"); };
48 
49 template <>
50 struct FmtStr<long double> { FMT_CONST("Lf"); };
51 
52 template <class T>
53 struct FmtStr<T, typename std::enable_if<std::is_pointer<T>::value>::type> {
54  FMT_CONST("p");
55 };
56 
57 template <class T>
58 class DefaultSprintfFormatter : public Formatable {
59  T _val;
60 
61 public:
62  DefaultSprintfFormatter(T val)
63  : _val(val) {};
64 
65  template <class It>
66  void format(It it) {
67  constexpr const int SIZE = 64;
68  char buffer[SIZE];
69  snprintf(buffer, SIZE, FmtStr<T>::fmt_full, _val);
70  for (char* c = buffer; *c != '\0'; c++)
71  *(it++) = *c;
72  }
73 };
74 
75 template <class T>
76 struct SprintfFormatter : public Formatable {
77  SprintfFormatter(T val)
78  : _alignLeft(false)
79  , _forceSign(false)
80  , _reserveSpaceForSign(false)
81  , _showPrefix(false)
82  , _leadingZeroes(false)
83  , _upperCase(false)
84  , _width(-1)
85  , _precision(-1)
86  , _replacement('\0')
87  , _val(val) {}
88 
89  template <class It>
90  void format(It it) const {
91  char fmt[64];
92  char* pos = fmt;
93  *(pos++) = '%';
94  if (_alignLeft)
95  *(pos++) = '-';
96  if (_forceSign)
97  *(pos++) = '+';
98  if (_reserveSpaceForSign)
99  *(pos++) = ' ';
100  if (_showPrefix)
101  *(pos++) = '#';
102  if (_leadingZeroes)
103  *(pos++) = '0';
104  if (_width >= 0)
105  pos += sprintf(pos, "%d", _width);
106  if (_precision >= 0)
107  pos += sprintf(pos, ".%d", _precision);
108  strcpy(pos, FmtStr<T>::fmt);
109  pos += strlen(FmtStr<T>::fmt);
110  if (_replacement != '\0')
111  *(pos - 1) = _replacement;
112  if (_upperCase)
113  *(pos - 1) = toupper(*(pos - 1));
114 
115  *pos = '\0';
116  constexpr const int SIZE = 64;
117  char buffer[SIZE];
118  snprintf(buffer, SIZE, fmt, _val);
119  for (char* c = buffer; *c != '\0'; c++)
120  *(it++) = *c;
121  }
122 
123 protected:
124  bool _alignLeft;
125  bool _forceSign;
126  bool _reserveSpaceForSign;
127  bool _showPrefix;
128  bool _leadingZeroes;
129  bool _upperCase;
130  int _width;
131  int _precision;
132  char _replacement;
133 
134 private:
135  T _val;
136 };
137 
138 template <typename T, typename Enable = void>
139 struct NumberSprintfFormatter;
140 
141 template <typename T>
142 struct NumberSprintfFormatter<T,
143  typename std::enable_if<std::is_integral<T>::value>::type>
144  : public SprintfFormatter<T> {
145  NumberSprintfFormatter(T t)
146  : SprintfFormatter<T>(t) {}
147 
148  NumberSprintfFormatter& alignLeft() {
149  SprintfFormatter<T>::_alignLeft = true;
150  return *this;
151  }
152 
153  NumberSprintfFormatter& alignRight() {
154  SprintfFormatter<T>::_alignLeft = false;
155  return *this;
156  }
157 
158  NumberSprintfFormatter& forceSign() {
159  SprintfFormatter<T>::_forceSign = true;
160  return *this;
161  }
162 
163  NumberSprintfFormatter& spaceForSign() {
164  SprintfFormatter<T>::_reserveSpaceForSign = true;
165  return *this;
166  }
167 
168  NumberSprintfFormatter& basePrefix() {
169  SprintfFormatter<T>::_showPrefix = true;
170  return *this;
171  }
172 
173  NumberSprintfFormatter& leadingZeroes() {
174  SprintfFormatter<T>::_leadingZeroes = true;
175  return *this;
176  }
177 
178  NumberSprintfFormatter& upperCase() {
179  SprintfFormatter<T>::_upperCase = true;
180  return *this;
181  }
182 
183  NumberSprintfFormatter& precision(unsigned prec) {
184  SprintfFormatter<T>::_precision = static_cast<int>(prec);
185  return *this;
186  }
187 
188  NumberSprintfFormatter& width(unsigned width) {
189  SprintfFormatter<T>::_width = static_cast<int>(width);
190  return *this;
191  }
192 
193  NumberSprintfFormatter& hex() {
194  SprintfFormatter<T>::_replacement = 'x';
195  return *this;
196  }
197 
198  NumberSprintfFormatter& octal() {
199  SprintfFormatter<T>::_replacement = 'o';
200  return *this;
201  }
202 };
203 
204 template <typename T>
205 struct NumberSprintfFormatter<T,
206  typename std::enable_if<std::is_floating_point<T>::value>::type>
207  : public SprintfFormatter<T> {
208  NumberSprintfFormatter(T t)
209  : SprintfFormatter<T>(t) {}
210 
211  NumberSprintfFormatter& alignLeft() {
212  SprintfFormatter<T>::_alignLeft = true;
213  return *this;
214  }
215 
216  NumberSprintfFormatter& alignRight() {
217  SprintfFormatter<T>::_alignLeft = false;
218  return *this;
219  }
220 
221  NumberSprintfFormatter& forceSign() {
222  SprintfFormatter<T>::_forceSign = true;
223  return *this;
224  }
225 
226  NumberSprintfFormatter& spaceForSign() {
227  SprintfFormatter<T>::_reserveSpaceForSign = true;
228  return *this;
229  }
230 
231  NumberSprintfFormatter& basePrefix() {
232  SprintfFormatter<T>::_showPrefix = true;
233  return *this;
234  }
235 
236  NumberSprintfFormatter& leadingZeroes() {
237  SprintfFormatter<T>::_leadingZeroes = true;
238  return *this;
239  }
240 
241  NumberSprintfFormatter& upperCase() {
242  SprintfFormatter<T>::_upperCase = true;
243  return *this;
244  }
245 
246  NumberSprintfFormatter& precision(unsigned prec) {
247  SprintfFormatter<T>::_precision = static_cast<int>(prec);
248  return *this;
249  }
250 
251  NumberSprintfFormatter& width(unsigned width) {
252  SprintfFormatter<T>::_width = static_cast<int>(width);
253  return *this;
254  }
255 
256  NumberSprintfFormatter& hex() {
257  SprintfFormatter<T>::_replacement = 'a';
258  return *this;
259  }
260 
261  NumberSprintfFormatter& decimal() {
262  SprintfFormatter<T>::_replacement = 'f';
263  return *this;
264  }
265 
266  NumberSprintfFormatter& scientific() {
267  SprintfFormatter<T>::_replacement = 'e';
268  return *this;
269  }
270 
271  NumberSprintfFormatter& shortest() {
272  SprintfFormatter<T>::_replacement = 'g';
273  return *this;
274  }
275 };
276 
277 template <typename String>
278 struct StringFormatter : public Formatable {
279  StringFormatter(const char* msg)
280  : _msg(msg)
281  , _center(false)
282  , _alignLeft(false)
283  , _clip(false)
284  , _width(-1) {}
285  StringFormatter(const String& s)
286  : _msg(nullptr)
287  , _str(s)
288  , _center(false)
289  , _alignLeft(false)
290  , _clip(false)
291  , _width(-1) {}
292 
293  template <typename It>
294  void format(It it) const {
295  if (_msg)
296  format(_msg, strlen(_msg), it);
297  else
298  format(_str.begin(), _str.size(), it);
299  }
300 
301  StringFormatter& width(unsigned width) {
302  _width = static_cast<int>(width);
303  return *this;
304  }
305 
306  StringFormatter& alignLeft() {
307  _alignLeft = true;
308  return *this;
309  }
310 
311  StringFormatter& alignRight() {
312  _alignLeft = false;
313  return *this;
314  }
315 
316  StringFormatter& center() {
317  _center = true;
318  return *this;
319  }
320 
321  StringFormatter& clip() {
322  _clip = true;
323  return *this;
324  }
325 
326 private:
327  template <typename Elem, typename It>
328  void format(Elem msg, int len, It it) const {
329  if (_width < 0) {
330  std::copy_n(msg, len, it);
331  } else {
332  int spaces = _width - len;
333  if (spaces < 0) {
334  std::copy_n(msg, _clip ? _width : len, it);
335  } else if (_center) {
336  int oddity = spaces % 2;
337  std::fill_n(it, spaces / 2 + (_alignLeft ? 0 : oddity), ' ');
338  std::copy_n(msg, len, it);
339  std::fill_n(it, spaces / 2 + (_alignLeft ? oddity : 0), ' ');
340  } else if (_alignLeft) {
341  std::copy_n(msg, len, it);
342  std::fill_n(it, spaces, ' ');
343  } else {
344  std::fill_n(it, spaces, ' ');
345  std::copy_n(msg, len, it);
346  }
347  }
348  }
349 
350  const char* _msg;
351  String _str;
352  bool _center;
353  bool _alignLeft;
354  bool _clip;
355  int _width;
356 };
#define FMT_CONST(FMT)
Definition: formatters.hpp:12