RBControl
Library for the RB3201-RBControl board with the ESP32 by RoboticsBrno.
format.hpp
Go to the documentation of this file.
1 #pragma once
2 #include "formatters.hpp"
3 #include <algorithm>
4 #include <functional>
5 #include <string>
6 
8 template <
9  typename String,
10  typename SizeType,
11  template <typename Val> class Fmt>
12 class FormatObject {
13 private:
14  String _data;
15  SizeType _idx;
16  std::function<void(const String&)> _del;
17 
18 public:
19  template <typename F>
20  FormatObject(const String& fmt, F f)
21  : _data(fmt)
22  , _idx(0)
23  , _del(f) {}
24  FormatObject(const String& fmt)
25  : _data(fmt)
26  , _idx(0) {}
27  ~FormatObject() {
28  if (_del)
29  _del(*this);
30  }
31 
32  FormatObject(const FormatObject& other) = delete;
33  FormatObject& operator=(const FormatObject&) = delete;
34 
35  FormatObject(FormatObject&& other)
36  : _data(std::move(other._data))
37  , _idx(other._idx)
38  , _del(std::move(other._del)) {}
39  FormatObject& operator=(FormatObject&& other) {
40  swap(other);
41  return *this;
42  }
43 
44  operator String() const {
45  return unescape(_data);
46  }
47 
48  template <typename T>
49  typename std::enable_if<std::is_fundamental<T>::value, FormatObject&>::type
50  operator<<(const T& t) {
51  Fmt<T> fmt(t);
52  return place([&fmt](auto iterator) {
53  fmt.format(iterator);
54  });
55  }
56 
57  FormatObject& operator<<(const std::string& s) {
58  return place([&s](auto iterator) {
59  for (char c : s)
60  placeEscapedChar(c, iterator);
61  });
62  }
63 
64  FormatObject& operator<<(const char* c) {
65  return place([&c](auto iterator) {
66  while (*c)
67  placeEscapedChar(*(c++), iterator);
68  });
69  }
70 
71  template <typename T>
72  typename std::enable_if<std::is_base_of<Formatable, T>::value, FormatObject&>::type
73  operator<<(const T& t) {
74  return place([&t](auto iterator) {
75  t.format(iterator);
76  });
77  }
78 
79  FormatObject& fillWith() {
80  return *this;
81  }
82 
83  template <typename T, typename... Args>
84  FormatObject& fillWith(T t, Args... args) {
85  return (*this << t).fillWith(args...);
86  }
87 
88 private:
89  static const SizeType npos = -1;
90 
91  struct Marker {
92  SizeType begin, end, id;
93  };
94 
95  SizeType nextChar(SizeType pos, char c) {
96  if (pos == npos)
97  return npos;
98  bool skip = false;
99  for (; pos < static_cast<SizeType>(_data.size()); pos++) {
100  if (skip || _data[pos] == '\\') {
101  skip = !skip;
102  continue;
103  }
104  if (_data[pos] == c)
105  return pos;
106  skip = false;
107  }
108  return npos;
109  }
110 
111  Marker nextMarker(SizeType pos) {
112  SizeType b = nextChar(pos, '{');
113  SizeType e = nextChar(b, '}') + 1;
114  if (e == npos)
115  return { npos, npos, npos };
116  if (b + 2 == e)
117  return { b, e, -1 };
118  // Ignore invalid characters, pretend it is zero
119  SizeType idx = strtol(&(_data[b + 1]), nullptr, 0);
120  return { b, e, idx };
121  }
122 
123  template <typename F>
124  FormatObject& place(F replaceCallback) {
125  String result;
126  SizeType copyFrom = 0;
127  bool hit = false;
128  Marker m = nextMarker(0);
129  while (m.begin != npos) {
130  if (m.id == -1 || m.id == _idx) {
131  std::copy(_data.begin() + copyFrom, _data.begin() + m.begin,
132  std::back_inserter(result));
133  copyFrom = m.end;
134  replaceCallback(std::back_inserter(result));
135  hit = true;
136  }
137  if (m.id == -1)
138  break;
139  m = nextMarker(m.end);
140  }
141  std::copy(_data.begin() + copyFrom, _data.end(), std::back_inserter(result));
142  if (!hit)
143  replaceCallback(std::back_inserter(result));
144  _data = result;
145  _idx++;
146  return *this;
147  }
148 
149  template <typename OutIt>
150  static void placeEscapedChar(char c, OutIt& iterator) {
151  if (c == '{' || c == '}' || c == '\\')
152  *(iterator++) = '\\';
153  *(iterator++) = c;
154  }
155 
156  static String unescape(const String& s) {
157  String result;
158  bool ignore = true;
159  for (char c : s) {
160  if (c == '\\' && ignore) {
161  ignore = false;
162  continue;
163  }
164  ignore = true;
165  result.push_back(c);
166  }
167  return result;
168  }
169 
170  void swap(FormatObject& other) {
171  using std::swap;
172  swap(_data, other._data);
173  swap(_idx, other._idx);
174  swap(_del, other._del);
175  }
176 };
177 
178 template <
179  typename String,
180  typename SizeType,
181  template <typename Val> class Fmt>
182 std::ostream& operator<<(std::ostream& stream,
183  const FormatObject<String, SizeType, Fmt>& fmt) {
184  return stream << static_cast<std::string>(fmt);
185 }
186 
187 using FormatString = FormatObject<std::string, int, DefaultSprintfFormatter>;
188 
189 template <typename T>
190 using NumberFortmatter = NumberSprintfFormatter<T>;
191 
192 template <typename... Args>
193 inline FormatString format(const char* fmt, Args... args) {
194  return std::move(FormatString(fmt).fillWith(args...));
195 }
196 
197 inline FormatString format(const char* fmt) {
198  return FormatString(fmt);
199 }
200 
201 template <typename T>
202 NumberFortmatter<T> number(T t) {
203  return NumberSprintfFormatter<T>(t);
204 }
205 
206 using string = StringFormatter<std::string>;