STX  1.0.0
report.h
Go to the documentation of this file.
1 
30 #pragma once
31 
32 #include <cinttypes>
33 #include <cstdio>
34 #include <string>
35 #include <string_view>
36 
37 #include "stx/common.h"
38 
40 
41 #ifndef STX_REPORT_RESERVE_SIZE
42 constexpr size_t kReportReserveSize = 128;
43 #else
44 constexpr size_t kReportReserveSize = STX_REPORT_RESERVE_SIZE;
45 #endif
46 
47 constexpr char const kReportTruncationMessage[] =
48  "... (error report truncated)";
49 
50 // this also ensures we don't perform an out-of-bounds access on the reserve
51 static_assert(kReportReserveSize > (sizeof(kReportTruncationMessage) - 1),
52  "STX_REPORT_RESERVE_SIZE must contain truncation message");
53 
55 struct ReportQuery {};
56 
58 constexpr ReportQuery const report_query{};
59 
60 // rather than having one report type and paying at runtime by having a `bool`
61 // to tell if the report string is allocated on the stack or is a forwarding
62 // reference we pay for it at compile-time by tag dispatch
63 
121 // rather than having a `bool` to tell if this is allocated on the stack or is a
122 // forwarding reference we pay for it at compile time by tag dispatch
123 class [[nodiscard]] FixedReport {
124  public:
126 
127  constexpr FixedReport() noexcept : reserve_{}, report_size_{0} {}
128 
130  constexpr FixedReport(const char* str, size_t size) noexcept
131  : reserve_{}, report_size_{size} {
132  *this = FixedReport(std::string_view(str, size));
133  }
134 
135  explicit constexpr FixedReport(std::string_view const& info) noexcept
136  : reserve_{}, report_size_{0} {
137  // account for truncation
138  // check bounds
139  size_t const str_size = info.size();
140  bool const should_truncate = str_size > kReportReserveSize;
141  size_t const str_clip_size =
142  should_truncate
143  ? (kReportReserveSize - (sizeof(kReportTruncationMessage) - 1))
144  : str_size;
145 
146  size_t pos = 0;
147  for (; pos < str_clip_size; pos++) {
148  reserve_[pos] = info[pos];
149  }
150 
151  if (should_truncate) {
152  for (; pos < kReportReserveSize; pos++) {
153  reserve_[pos] = kReportTruncationMessage[pos - str_clip_size];
154  }
155  }
156 
157  report_size_ = pos;
158  }
159 
160  constexpr FixedReport(FixedReport const&) noexcept = default;
161  constexpr FixedReport(FixedReport &&) noexcept = default;
162  constexpr FixedReport& operator=(FixedReport const&) noexcept = default;
163  constexpr FixedReport& operator=(FixedReport&&) noexcept = default;
164  ~FixedReport() noexcept = default;
165 
166  [[nodiscard]] constexpr std::string_view what() const noexcept {
167  return std::string_view(reserve_, report_size_);
168  };
169 
170  private:
171  storage_type reserve_;
172  size_t report_size_;
173 };
174 
265 class [[nodiscard]] SpanReport {
266  public:
267  // maintains a reference to a string, instead of using a stack
268  // allocated reservation buffer
269  // it does not own the contents, so make sure the referenced buffer lives
270  // longer than this object
271 
272  constexpr SpanReport() noexcept : custom_payload_{nullptr}, report_size_{0} {}
273 
275  constexpr SpanReport(const char* str, size_t size) noexcept
276  : custom_payload_{str}, report_size_{size} {}
277 
278  explicit constexpr SpanReport(std::string_view const& str) noexcept
279  : custom_payload_{str.data()}, report_size_{str.size()} {}
280 
281  [[nodiscard]] constexpr std::string_view what() const noexcept {
282  return std::string_view(custom_payload_, report_size_);
283  };
284 
285  constexpr SpanReport(SpanReport const&) noexcept = default;
286  constexpr SpanReport(SpanReport &&) noexcept = default;
287  constexpr SpanReport& operator=(SpanReport const&) noexcept = default;
288  constexpr SpanReport& operator=(SpanReport&&) noexcept = default;
289  ~SpanReport() noexcept = default;
290 
291  private:
292  const char* custom_payload_;
293  size_t report_size_;
294 };
295 
304 class [[nodiscard]] ReportPayload {
305  public:
306  explicit constexpr ReportPayload(FixedReport const& report) noexcept
307  : content_{report.what()} {}
308 
309  explicit constexpr ReportPayload(SpanReport const& report) noexcept
310  : content_{report.what()} {}
311 
312  constexpr ReportPayload(ReportPayload const&) noexcept = default;
313  constexpr ReportPayload(ReportPayload &&) noexcept = default;
314  constexpr ReportPayload& operator=(ReportPayload const&) noexcept = default;
315  constexpr ReportPayload& operator=(ReportPayload&&) noexcept = default;
316  ~ReportPayload() noexcept = default;
317 
318  [[nodiscard]] constexpr std::string_view const& data() const noexcept {
319  return content_;
320  }
321 
322  private:
323  std::string_view content_;
324 };
325 
326 // this allows tolerance for platforms without snprintf.
327 constexpr char const kFormatError[] = "<format error>";
328 constexpr size_t const kFormatErrorSize = sizeof(kFormatError) - 1;
329 
330 template <typename T>
331 [[nodiscard]] inline SpanReport operator>>(ReportQuery, T const&) noexcept {
332  return SpanReport();
333 }
334 
335 #define STX_INTERNAL_MAKE_REPORT_(STX_ARG_SIZE, STX_ARG_FORMAT, STX_ARG_VALUE) \
336  /* string size + terminating null character */ \
337  char fmt_buffer[STX_ARG_SIZE + 1]; \
338  int fmt_buffer_size = std::snprintf(fmt_buffer, STX_ARG_SIZE + 1, \
339  STX_ARG_FORMAT, STX_ARG_VALUE); \
340  if (fmt_buffer_size < 0 || fmt_buffer_size >= STX_ARG_SIZE + 1) { \
341  return FixedReport(kFormatError, kFormatErrorSize); \
342  } else { \
343  return FixedReport(fmt_buffer, fmt_buffer_size); \
344  }
345 
346 template <typename T>
347 [[nodiscard]] inline FixedReport operator>>(ReportQuery,
348  T const* const& ptr) noexcept {
350  reinterpret_cast<uintptr_t const>(ptr));
351 }
352 
353 template <typename T>
354 [[nodiscard]] inline FixedReport operator>>(ReportQuery,
355  T* const& ptr) noexcept {
357  reinterpret_cast<uintptr_t>(ptr));
358 }
359 
360 [[nodiscard]] inline FixedReport operator>>(ReportQuery,
361  int8_t const& v) noexcept {
363 }
364 
365 [[nodiscard]] inline FixedReport operator>>(ReportQuery,
366  uint8_t const& v) noexcept {
368 }
369 
370 [[nodiscard]] inline FixedReport operator>>(ReportQuery,
371  int16_t const& v) noexcept {
373 }
374 
375 [[nodiscard]] inline FixedReport operator>>(ReportQuery,
376  uint16_t const& v) noexcept {
378 }
379 
380 [[nodiscard]] inline FixedReport operator>>(ReportQuery,
381  int32_t const& v) noexcept {
383 }
384 
385 [[nodiscard]] inline FixedReport operator>>(ReportQuery,
386  uint32_t const& v) noexcept {
388 }
389 
390 #undef STX_INTERNAL_MAKE_REPORT_
391 
392 [[nodiscard]] inline SpanReport operator>>(ReportQuery,
393  std::string_view const& v) noexcept {
394  return SpanReport(v);
395 }
396 
397 [[nodiscard]] inline SpanReport operator>>(ReportQuery,
398  std::string const& v) noexcept {
399  return SpanReport(v);
400 }
401 
constexpr int kU16FmtSize
5 digits
Definition: common.h:124
constexpr int kU32FmtSize
10 digits
Definition: common.h:120
constexpr size_t const kFormatErrorSize
Definition: report.h:328
char[kReportReserveSize] storage_type
Definition: report.h:125
#define STX_INTERNAL_MAKE_REPORT_(STX_ARG_SIZE, STX_ARG_FORMAT, STX_ARG_VALUE)
Definition: report.h:335
constexpr std::string_view what() const noexcept
Definition: report.h:281
constexpr FixedReport(const char *str, size_t size) noexcept
size: string size excluding null-terminator
Definition: report.h:130
constexpr FixedReport(std::string_view const &info) noexcept
Definition: report.h:135
constexpr char const kFormatError[]
Definition: report.h:327
constexpr char const kReportTruncationMessage[]
Definition: report.h:47
constexpr SpanReport(const char *str, size_t size) noexcept
size: string size excluding null-terminator
Definition: report.h:275
Definition: report.h:304
constexpr ReportPayload(SpanReport const &report) noexcept
Definition: report.h:309
constexpr int kI16FmtSize
5 digits + 1 sign
Definition: common.h:122
constexpr std::string_view const & data() const noexcept
Definition: report.h:318
constexpr SpanReport() noexcept
Definition: report.h:272
constexpr ReportPayload(FixedReport const &report) noexcept
Definition: report.h:306
constexpr int kI8FmtSize
3 digits + 1 sign
Definition: common.h:126
Definition: report.h:265
#define STX_END_NAMESPACE
Definition: config.h:329
constexpr int kI32FmtSize
10 digits + 1 sign
Definition: common.h:118
constexpr ReportQuery const report_query
Tag value for dispatching reports.
Definition: report.h:58
Definition: report.h:123
constexpr FixedReport() noexcept
Definition: report.h:127
constexpr int kxPtrFmtSize
Definition: common.h:110
constexpr int kU8FmtSize
3 digits
Definition: common.h:128
#define STX_BEGIN_NAMESPACE
Definition: config.h:325
SpanReport operator>>(ReportQuery, std::string const &v) noexcept
Definition: report.h:397
Tag type for dispatching reports.
Definition: report.h:55
constexpr size_t kReportReserveSize
Definition: report.h:42
constexpr std::string_view what() const noexcept
Definition: report.h:166
constexpr SpanReport(std::string_view const &str) noexcept
Definition: report.h:278