xref: /freebsd-src/contrib/llvm-project/libcxx/include/__format/formatter_bool.h (revision e67e85659c0de33e617e5fbf1028c6e8b49eee53)
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef _LIBCPP___FORMAT_FORMATTER_BOOL_H
11 #define _LIBCPP___FORMAT_FORMATTER_BOOL_H
12 
13 #include <__availability>
14 #include <__config>
15 #include <__format/format_error.h>
16 #include <__format/format_fwd.h>
17 #include <__format/formatter.h>
18 #include <__format/formatter_integral.h>
19 #include <__format/parser_std_format_spec.h>
20 #include <string_view>
21 
22 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
23 #include <locale>
24 #endif
25 
26 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
27 #pragma GCC system_header
28 #endif
29 
30 _LIBCPP_BEGIN_NAMESPACE_STD
31 
32 #if _LIBCPP_STD_VER > 17
33 
34 // TODO FMT Remove this once we require compilers with proper C++20 support.
35 // If the compiler has no concepts support, the format header will be disabled.
36 // Without concepts support enable_if needs to be used and that too much effort
37 // to support compilers with partial C++20 support.
38 #if !defined(_LIBCPP_HAS_NO_CONCEPTS)
39 
40 namespace __format_spec {
41 
42 template <class _CharT>
43 class _LIBCPP_TEMPLATE_VIS __parser_bool : public __parser_integral<_CharT> {
44 public:
45   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(auto& __parse_ctx)
46       -> decltype(__parse_ctx.begin()) {
47     auto __it = __parser_integral<_CharT>::__parse(__parse_ctx);
48 
49     switch (this->__type) {
50     case _Flags::_Type::__default:
51       this->__type = _Flags::_Type::__string;
52       [[fallthrough]];
53     case _Flags::_Type::__string:
54       this->__handle_bool();
55       break;
56 
57     case _Flags::_Type::__char:
58       this->__handle_char();
59       break;
60 
61     case _Flags::_Type::__binary_lower_case:
62     case _Flags::_Type::__binary_upper_case:
63     case _Flags::_Type::__octal:
64     case _Flags::_Type::__decimal:
65     case _Flags::_Type::__hexadecimal_lower_case:
66     case _Flags::_Type::__hexadecimal_upper_case:
67       this->__handle_integer();
68       break;
69 
70     default:
71       __throw_format_error(
72           "The format-spec type has a type not supported for a bool argument");
73     }
74 
75     return __it;
76   }
77 };
78 
79 template <class _CharT>
80 struct _LIBCPP_TEMPLATE_VIS __bool_strings;
81 
82 template <>
83 struct _LIBCPP_TEMPLATE_VIS __bool_strings<char> {
84   static constexpr string_view __true{"true"};
85   static constexpr string_view __false{"false"};
86 };
87 
88 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
89 template <>
90 struct _LIBCPP_TEMPLATE_VIS __bool_strings<wchar_t> {
91   static constexpr wstring_view __true{L"true"};
92   static constexpr wstring_view __false{L"false"};
93 };
94 #endif
95 
96 template <class _CharT>
97 using __formatter_bool = __formatter_integral<__parser_bool<_CharT>>;
98 
99 } //namespace __format_spec
100 
101 // [format.formatter.spec]/2.3
102 // For each charT, for each cv-unqualified arithmetic type ArithmeticT other
103 // than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
104 
105 template <__formatter::__char_type _CharT>
106 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<bool, _CharT>
107     : public __format_spec::__formatter_bool<_CharT> {
108   using _Base = __format_spec::__formatter_bool<_CharT>;
109 
110   _LIBCPP_HIDE_FROM_ABI auto format(bool __value, auto& __ctx)
111       -> decltype(__ctx.out()) {
112     if (this->__type != __format_spec::_Flags::_Type::__string)
113       return _Base::format(static_cast<unsigned char>(__value), __ctx);
114 
115     if (this->__width_needs_substitution())
116       this->__substitute_width_arg_id(__ctx.arg(this->__width));
117 
118 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
119     if (this->__locale_specific_form) {
120       const auto& __np = use_facet<numpunct<_CharT>>(__ctx.locale());
121       basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename();
122       return __formatter::__write_unicode(
123           __ctx.out(), basic_string_view<_CharT>{__str}, this->__width, -1,
124           this->__fill, this->__alignment);
125     }
126 #endif
127     basic_string_view<_CharT> __str =
128         __value ? __format_spec::__bool_strings<_CharT>::__true
129                 : __format_spec::__bool_strings<_CharT>::__false;
130 
131     // The output only uses ASCII so every character is one column.
132     unsigned __size = __str.size();
133     if (__size >= this->__width)
134       return _VSTD::copy(__str.begin(), __str.end(), __ctx.out());
135 
136     return __formatter::__write(__ctx.out(), __str.begin(), __str.end(), __size,
137                                 this->__width, this->__fill, this->__alignment);
138   }
139 };
140 
141 #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
142 
143 #endif //_LIBCPP_STD_VER > 17
144 
145 _LIBCPP_END_NAMESPACE_STD
146 
147 #endif // _LIBCPP___FORMAT_FORMATTER_BOOL_H
148