ape  0.5.0
Audio Programming Environment
print.h
Go to the documentation of this file.
1 #ifndef CPPAPE_PRINT_H
2 #define CPPAPE_PRINT_H
3 
4 #include "baselib.h"
5 
6 #include <cstddef>
7 #include <charconv>
8 #include <complex>
9 
15 int printf(const char * fmt, ...);
21 extern "C" int sprintf(char* buffer, const char* fmt, ...);
22 
23 namespace std
24 {
27 }
28 
29 #define CPPAPE_CONCAT_IMPL( x, y ) x##y
30 #define CPPAPE_MACRO_CONCAT( x, y ) CPPAPE_CONCAT_IMPL( x, y )
31 
32 namespace ape
33 {
34  /*
35  */
36 
37  namespace detail
38  {
39  template<typename T>
40  inline char* format(const T& val, char* b, char* e)
41  {
42 #define __CPPAPE_FORMAT_ERROR "<format error>"
43 
44  using namespace std;
45  auto result = to_chars(b, e, val);
46 
47  if (result.ec != std::errc())
48  {
49  memcpy(b, __CPPAPE_FORMAT_ERROR, sizeof(__CPPAPE_FORMAT_ERROR) - 1);
50  return b + sizeof(__CPPAPE_FORMAT_ERROR) - 1;
51  }
52 
53 #undef __CPPAPE_FORMAT_ERROR
54 
55  return result.ptr;
56  }
57 
58  template<typename T>
59  inline char* format(const std::complex<T>& val, char* b, char* e)
60  {
61  return b + std::sprintf(b, "(%f, %fi)", val.real(), val.imag());
62  }
63 
64  inline char* format(const long double& val, char* b, char* e)
65  {
66  return b + std::sprintf(b, "%f", (double)val);
67  }
68 
69  inline char* format(const double& val, char* b, char* e)
70  {
71  return b + std::sprintf(b, "%f", val);
72  }
73 
74  inline char* format(const float& val, char* b, char* e)
75  {
76  return b + std::sprintf(b, "%f", val);
77  }
78 
79  inline char* format(const void* val, char* b, char* e)
80  {
81  return b + std::sprintf(b, "0x%p", val);
82  }
83 
84  inline char* format(std::string_view val, char* b, char* e)
85  {
86  assert(e > (b + val.size()));
87  std::memcpy(b, val.data(), val.size());
88  return b + val.size();
89  }
90 
91  inline char* format(const char* val, char* b, char* e)
92  {
93  return format(std::string_view(val), b, e);
94  }
95 
96  inline char* format(const std::string& val, char* b, char* e)
97  {
98  return format(std::string_view(val), b, e);
99  }
100 
101  struct print_buffer
102  {
103  static constexpr std::size_t size = 4096;
104 
105  void putc(char c)
106  {
107  if (begin() == end())
108  return;
109 
110  *begin() = c;
111  current++;
112  }
113 
114  void seal()
115  {
116  *begin() = '\0';
117  }
118 
119  char* begin() { return current; }
120  char* end() { return buffer + size; }
121 
122  char buffer[size];
123  char* current = buffer;
124  };
125 
126  template<typename T>
127  inline print_buffer& operator << (print_buffer& left, const T& value)
128  {
129  left.current = format(value, left.begin(), left.end());
130  return left;
131  }
132 
133  inline void safe_printf(print_buffer& buffer, std::string_view view)
134  {
135  for (auto it = view.begin(); it != view.end(); ++it)
136  {
137  if (*it == '%')
138  {
139  auto next = it;
140  next++;
141  if (next != view.end() && *next == '%')
142  {
143  it = next;
144  }
145  else
146  {
147  abort("too few arguments for print()");
148  }
149  }
150 
151  buffer.putc(*it);
152  }
153  }
154 
155  template<typename T, typename... Args>
156  inline void safe_printf(print_buffer& buffer, std::string_view view, const T& value, Args&&... args)
157  {
158  for (auto it = view.begin(); it != view.end(); ++it)
159  {
160  if (*it == '%')
161  {
162  auto next = it;
163  next++;
164  if (next != view.end() && *next == '%')
165  {
166  it = next;
167  }
168  else
169  {
170  buffer << value;
171  safe_printf(buffer, view.substr(std::distance(view.begin(), next)), std::forward<Args>(args)...); // call even when *s == 0 to detect extra arguments
172  return;
173  }
174  }
175 
176  buffer.putc(*it);
177  }
178 
179  abort("too many arguments provided to print()");
180  }
181  }
182 
199  template<typename Derived>
201  {
202  friend std::to_chars_result to_chars(char* begin, char* end, const Derived& type)
203  {
204  if (!type.format(begin, end, &begin))
205  return { end, std::errc::value_too_large };
206 
207  return { begin, std::errc() };
208  }
209  };
210 
211 }
212 
237 template<typename... Args>
238 inline void print(std::string_view fmt, Args&&... args)
239 {
240  ape::detail::print_buffer stackBuffer;
241  ape::detail::safe_printf(stackBuffer, fmt, std::forward<Args>(args)...);
242 
243  stackBuffer.seal();
244 
245  printf("%s", stackBuffer.buffer);
246 }
247 
255 template<typename... Args>
256 inline std::string sprint(std::string_view fmt, Args&&... args)
257 {
258  ape::detail::print_buffer stackBuffer;
259  ape::detail::safe_printf(stackBuffer, fmt, std::forward<Args>(args)...);
260 
261  stackBuffer.seal();
262 
263  return { stackBuffer.begin(), stackBuffer.end() };
264 }
265 
266 
267 #define __CPPAPE_PRINTF_ONCE(cname, ...) \
268  static bool cname = false; \
269  if (!cname) \
270  { \
271  cname = true; \
272  printf(__VA_ARGS__); \
273  }
274 
278 #define printf_once(...) __CPPAPE_PRINTF_ONCE(CPPAPE_MACRO_CONCAT(__once_flag, __COUNTER__), __VA_ARGS__)
279 
280 #define __CPPAPE_PRINT_ONCE(cname, ...) \
281  static bool cname = false; \
282  if (!cname) \
283  { \
284  cname = true; \
285  print(__VA_ARGS__); \
286  }
287 
291 #define print_once(...) __CPPAPE_PRINT_ONCE(CPPAPE_MACRO_CONCAT(__once_flag, __COUNTER__), __VA_ARGS__)
292 
293 #endif
ape::PrintFormatter
Helper type to automatically support formatted printing for user defined types through print()
Definition: print.h:200
ape::PrintFormatter::to_chars
friend std::to_chars_result to_chars(char *begin, char *end, const Derived &type)
Definition: print.h:202
sprintf
int sprintf(char *buffer, const char *fmt,...)
Print to a string buffer. This function is inherently unsafe, but may prove useful for particular for...
abort
void abort(const char *reason)
Terminate the script (not the host application!) safely, with a reason. All resources will automatica...
print
void print(std::string_view fmt, Args &&... args)
Safely print a string replacing the nth "%" character with the nth variadic argument....
Definition: print.h:238
ape
Definition: audiofile.h:7
baselib.h
ape::detail::safe_printf
void safe_printf(print_buffer &buffer, std::string_view view)
Definition: print.h:133
ape::detail::operator<<
print_buffer & operator<<(print_buffer &left, const T &value)
Definition: print.h:127
sprint
std::string sprint(std::string_view fmt, Args &&... args)
Safely format the arguments. print()
Definition: print.h:256
ape::detail::format
char * format(const T &val, char *b, char *e)
Definition: print.h:40
printf
int printf(const char *fmt,...)
Print to the console attached to this plugin. This function is inherently unsafe, but may prove usefu...