My Project
fmt_options.hpp
Go to the documentation of this file.
1 
28 #ifndef BSL_FMT_OPTIONS_HPP
29 #define BSL_FMT_OPTIONS_HPP
30 
31 #include "char_type.hpp"
32 #include "cstr_type.hpp"
33 #include "cstdint.hpp"
34 #include "cstring.hpp"
35 #include "npos.hpp"
36 
37 // TODO
38 // - Once Clang/LLVM supports C++20's consteval, we should determine if
39 // consteval can be used with this class's constructors, which would
40 // ensure that all format strings are parsed at compile-time. We
41 // should also add error logic to the parsers as errors can then be
42 // detected at compile-time, preventing the possibility of format string
43 // errors.
44 //
45 
46 namespace bsl
47 {
48  namespace details
49  {
62  enum class fmt_fsm : bsl::uint32
63  {
64  fmt_fsm_align = 0U,
65  fmt_fsm_sign = 1U,
66  fmt_fsm_alternate_form = 2U,
67  fmt_fsm_sign_aware = 3U,
68  fmt_fsm_width = 4U,
69  fmt_fsm_type = 5U,
70  };
71  }
72 
80  enum class fmt_align : bsl::uint32
81  {
82  fmt_align_default = 0U,
83  fmt_align_left = 1U,
84  fmt_align_right = 2U,
85  fmt_align_center = 3U
86  };
87 
94  enum class fmt_sign : bsl::uint32
95  {
96  fmt_sign_neg_only = 0U,
97  fmt_sign_pos_neg = 1U,
98  fmt_sign_space_for_pos = 3U,
99  };
100 
109  enum class fmt_type : bsl::uint32
110  {
111  fmt_type_default = 0U,
112  fmt_type_b = 1U,
113  fmt_type_c = 2U,
114  fmt_type_d = 3U,
115  fmt_type_s = 4U,
116  fmt_type_x = 5U,
117  };
118 
141  class fmt_options final
142  {
144  char_type m_fill{' '};
146  fmt_align m_align{};
148  fmt_sign m_sign{};
150  bool m_alternate_form{};
152  bool m_sign_aware{};
154  bsl::uintmax m_width{};
156  fmt_type m_type{};
157 
158  public:
170  constexpr fmt_options(cstr_type const f) noexcept // NOLINT
171  {
172  details::fmt_fsm fsm{};
173 
174  bsl::uintmax idx{};
175  bsl::uintmax const len{bsl::builtin_strlen(f)};
176 
177  while (idx < len) {
178  switch (fsm) {
179  case details::fmt_fsm::fmt_fsm_align: {
180  this->fmt_options_impl_align(f, idx, len);
181  fsm = details::fmt_fsm::fmt_fsm_sign;
182  break;
183  }
184 
185  case details::fmt_fsm::fmt_fsm_sign: {
186  this->fmt_options_impl_sign(f, idx);
187  fsm = details::fmt_fsm::fmt_fsm_alternate_form;
188  break;
189  }
190 
191  case details::fmt_fsm::fmt_fsm_alternate_form: {
192  this->fmt_options_impl_alternate_form(f, idx);
193  fsm = details::fmt_fsm::fmt_fsm_sign_aware;
194  break;
195  }
196 
197  case details::fmt_fsm::fmt_fsm_sign_aware: {
198  this->fmt_options_impl_sign_aware(f, idx);
199  fsm = details::fmt_fsm::fmt_fsm_width;
200  break;
201  }
202 
203  case details::fmt_fsm::fmt_fsm_width: {
204  this->fmt_options_impl_width(f, idx, len);
205  fsm = details::fmt_fsm::fmt_fsm_type;
206  break;
207  }
208 
209  case details::fmt_fsm::fmt_fsm_type: {
210  this->fmt_options_impl_type(f, idx);
211  break;
212  }
213  }
214  }
215  }
216 
225  [[nodiscard]] constexpr char_type
226  fill() const noexcept
227  {
228  return m_fill;
229  }
230 
238  constexpr void
239  set_fill(char_type const val) noexcept
240  {
241  m_fill = val;
242  }
243 
252  [[nodiscard]] constexpr fmt_align
253  align() const noexcept
254  {
255  return m_align;
256  }
257 
265  constexpr void
266  set_align(fmt_align const val) noexcept
267  {
268  m_align = val;
269  }
270 
279  [[nodiscard]] constexpr fmt_sign
280  sign() const noexcept
281  {
282  return m_sign;
283  }
284 
292  constexpr void
293  set_sign(fmt_sign const val) noexcept
294  {
295  m_sign = val;
296  }
297 
306  [[nodiscard]] constexpr bool
307  alternate_form() const noexcept
308  {
309  return m_alternate_form;
310  }
311 
319  constexpr void
320  set_alternate_form(bool const val) noexcept
321  {
322  m_alternate_form = val;
323  }
324 
333  [[nodiscard]] constexpr bool
334  sign_aware() const noexcept
335  {
336  return m_sign_aware;
337  }
338 
346  constexpr void
347  set_sign_aware(bool const val) noexcept
348  {
349  m_sign_aware = val;
350  }
351 
360  [[nodiscard]] constexpr bsl::uintmax
361  width() const noexcept
362  {
363  return m_width;
364  }
365 
373  constexpr void
374  set_width(bsl::uintmax const val) noexcept
375  {
376  m_width = val;
377  }
378 
387  [[nodiscard]] constexpr fmt_type
388  type() const noexcept
389  {
390  return m_type;
391  }
392 
400  constexpr void
401  set_type(fmt_type const val) noexcept
402  {
403  m_type = val;
404  }
405 
406  private:
424  constexpr void
425  fmt_options_impl_align(
426  cstr_type const f, bsl::uintmax &idx, bsl::uintmax const len) noexcept
427  {
428  char_type f_fill{' '};
429  char_type f_align{};
430  bsl::uintmax idx_inc{1U};
431 
432  if ((idx + 1U) < len) {
433  f_fill = f[idx];
434  f_align = f[idx + 1U];
435  idx_inc = 2U;
436  }
437  else {
438  f_align = f[idx];
439  }
440 
441  switch (f_align) {
442  case '<': {
443  m_fill = f_fill;
444  m_align = fmt_align::fmt_align_left;
445  idx += idx_inc;
446  break;
447  }
448 
449  case '>': {
450  m_fill = f_fill;
451  m_align = fmt_align::fmt_align_right;
452  idx += idx_inc;
453  break;
454  }
455 
456  case '^': {
457  m_fill = f_fill;
458  m_align = fmt_align::fmt_align_center;
459  idx += idx_inc;
460  break;
461  }
462 
463  default: {
464  break;
465  }
466  }
467 
468  if (fmt_align::fmt_align_default == m_align) {
469  switch (f_fill) {
470  case '<': {
471  m_align = fmt_align::fmt_align_left;
472  ++idx;
473  break;
474  }
475 
476  case '>': {
477  m_align = fmt_align::fmt_align_right;
478  ++idx;
479  break;
480  }
481 
482  case '^': {
483  m_align = fmt_align::fmt_align_center;
484  ++idx;
485  break;
486  }
487 
488  default: {
489  break;
490  }
491  }
492  }
493  }
494 
504  constexpr void
505  fmt_options_impl_sign(cstr_type const f, bsl::uintmax &idx) noexcept
506  {
507  switch (f[idx]) {
508  case '+': {
509  m_sign = fmt_sign::fmt_sign_pos_neg;
510  ++idx;
511  break;
512  }
513 
514  case '-': {
515  m_sign = fmt_sign::fmt_sign_neg_only;
516  ++idx;
517  break;
518  }
519 
520  case ' ': {
521  m_sign = fmt_sign::fmt_sign_space_for_pos;
522  ++idx;
523  break;
524  }
525 
526  default: {
527  break;
528  }
529  }
530  }
531 
541  constexpr void
542  fmt_options_impl_alternate_form(cstr_type const f, bsl::uintmax &idx) noexcept
543  {
544  if ('#' == f[idx]) {
545  m_alternate_form = true;
546  ++idx;
547  }
548  }
549 
559  constexpr void
560  fmt_options_impl_sign_aware(cstr_type const f, bsl::uintmax &idx) noexcept
561  {
562  if ('0' == f[idx]) {
563  m_sign_aware = true;
564  ++idx;
565  }
566  }
567 
577  constexpr void
578  fmt_options_impl_width(
579  cstr_type const f, bsl::uintmax &idx, bsl::uintmax const len) noexcept
580  {
581  constexpr bsl::uintmax max_num_digits{3U};
582 
583  for (bsl::uintmax i{}; (i < max_num_digits) && (idx < len); ++i) {
584  char_type const digit{f[idx]};
585 
586  if ((digit >= '0') && (digit <= '9')) {
587  m_width *= 10U;
588  m_width += static_cast<bsl::uintmax>(digit);
589  m_width -= static_cast<bsl::uintmax>('0');
590  ++idx;
591  }
592  }
593  }
594 
607  constexpr void
608  fmt_options_impl_type(cstr_type const f, bsl::uintmax &idx) noexcept
609  {
610  switch (f[idx]) {
611  case 'b':
612  case 'B': {
613  m_type = fmt_type::fmt_type_b;
614  break;
615  }
616 
617  case 'c': {
618  m_type = fmt_type::fmt_type_c;
619  break;
620  }
621 
622  case 'd': {
623  m_type = fmt_type::fmt_type_d;
624  break;
625  }
626 
627  case 's': {
628  m_type = fmt_type::fmt_type_s;
629  break;
630  }
631 
632  case 'x':
633  case 'X': {
634  m_type = fmt_type::fmt_type_x;
635  break;
636  }
637 
638  default: {
639  break;
640  }
641  }
642 
643  idx = bsl::npos;
644  }
645  };
646 
648  constexpr fmt_options nullops{""};
650  constexpr fmt_options ptrops{
651  (sizeof(bsl::uintptr) == sizeof(bsl::uint32)) ? "#010x" : "#018x"}; // NOLINT
652 }
653 
654 #endif
constexpr fmt_sign sign() const noexcept
Returns the "sign" field in the {fmt} syntax based on the previously provided format string.
Definition: fmt_options.hpp:280
constexpr bsl::uintmax npos
defines npos
Definition: npos.hpp:37
constexpr void set_align(fmt_align const val) noexcept
Sets the "align" field in the {fmt} syntax, overriding what the previously provided format string pro...
Definition: fmt_options.hpp:266
constexpr void set_fill(char_type const val) noexcept
Sets the "fill" field in the {fmt} syntax, overriding what the previously provided format string prov...
Definition: fmt_options.hpp:239
constexpr bool sign_aware() const noexcept
Returns the "sign aware" field in the {fmt} syntax based on the previously provided format string.
Definition: fmt_options.hpp:334
constexpr void set_sign(fmt_sign const val) noexcept
Sets the "sign" field in the {fmt} syntax, overriding what the previously provided format string prov...
Definition: fmt_options.hpp:293
Used by fmt to determine how to format the output of an fmt command. See the documentation fo bsl::fm...
Definition: fmt_options.hpp:141
::uint32_t uint32
defines an 32bit unsigned integer
Definition: cstdint.hpp:49
constexpr bsl::uintmax width() const noexcept
Returns the "width" field in the {fmt} syntax based on the previously provided format string.
Definition: fmt_options.hpp:361
char const * cstr_type
C-style string type.
Definition: cstr_type.hpp:39
constexpr fmt_options ptrops
defines how to format a ptr like type.
Definition: fmt_options.hpp:650
constexpr fmt_align align() const noexcept
Returns the "align" field in the {fmt} syntax based on the previously provided format string.
Definition: fmt_options.hpp:253
fmt_align
Used to determine what the alignment of the output should be. If the width is not defined,...
Definition: fmt_options.hpp:80
constexpr bool alternate_form() const noexcept
Returns the "alt form" field in the {fmt} syntax based on the previously provided format string.
Definition: fmt_options.hpp:307
fmt_sign
Used to determine how an integral's sign field is handled. This only has an effect on signed types.
Definition: fmt_options.hpp:94
constexpr fmt_options nullops
defines no formatting.
Definition: fmt_options.hpp:648
char char_type
Standard Char Type.
Definition: char_type.hpp:41
constexpr fmt_type type() const noexcept
Returns the "type" field in the {fmt} syntax based on the previously provided format string.
Definition: fmt_options.hpp:388
constexpr fmt_options(cstr_type const f) noexcept
Creates a bsl::fmt_options given a user provided format string. The goal of this class is to pre-proc...
Definition: fmt_options.hpp:170
fmt_type
Used to determine how to output an unsigned integer type (either as hex or dec). All ofther {fmt} typ...
Definition: fmt_options.hpp:109
constexpr char_type fill() const noexcept
Returns the "fill" field in the {fmt} syntax based on the previously provided format string.
Definition: fmt_options.hpp:226
constexpr bsl::uintmax builtin_strlen(cstr_type const str) noexcept
Same as std::strlen with parameter checks. If str is a nullptr, this returns 0.
Definition: cstring.hpp:154
::uintptr_t uintptr
defines a unsigned integer the size of a void *
Definition: cstdint.hpp:92
constexpr void set_alternate_form(bool const val) noexcept
Sets the "alt form" field in the {fmt} syntax, overriding what the previously provided format string ...
Definition: fmt_options.hpp:320
constexpr void set_width(bsl::uintmax const val) noexcept
Sets the "width" field in the {fmt} syntax, overriding what the previously provided format string pro...
Definition: fmt_options.hpp:374
::uintmax_t uintmax
defines a unsigned integer with the maximum possible size
Definition: cstdint.hpp:97
constexpr void set_type(fmt_type const val) noexcept
Sets the "type" field in the {fmt} syntax, overriding what the previously provided format string prov...
Definition: fmt_options.hpp:401
fmt_fsm
Used to define a finite state machine that is used to parse the {fmt} style syntax for formatting....
Definition: fmt_options.hpp:62
constexpr void set_sign_aware(bool const val) noexcept
Sets the "sign aware" field in the {fmt} syntax, overriding what the previously provided format strin...
Definition: fmt_options.hpp:347