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 <__algorithm/copy.h>
14 #include <__availability>
15 #include <__config>
16 #include <__format/format_error.h>
17 #include <__format/format_fwd.h>
18 #include <__format/formatter.h>
19 #include <__format/formatter_integral.h>
20 #include <__format/parser_std_format_spec.h>
21 #include <string_view>
22 
23 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
24 #include <locale>
25 #endif
26 
27 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28 #  pragma GCC system_header
29 #endif
30 
31 _LIBCPP_BEGIN_NAMESPACE_STD
32 
33 #if _LIBCPP_STD_VER > 17
34 
35 namespace __format_spec {
36 
37 template <class _CharT>
38 class _LIBCPP_TEMPLATE_VIS __parser_bool : public __parser_integral<_CharT> {
39 public:
40   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(auto& __parse_ctx)
41       -> decltype(__parse_ctx.begin()) {
42     auto __it = __parser_integral<_CharT>::__parse(__parse_ctx);
43 
44     switch (this->__type) {
45     case _Flags::_Type::__default:
46       this->__type = _Flags::_Type::__string;
47       [[fallthrough]];
48     case _Flags::_Type::__string:
49       this->__handle_bool();
50       break;
51 
52     case _Flags::_Type::__binary_lower_case:
53     case _Flags::_Type::__binary_upper_case:
54     case _Flags::_Type::__octal:
55     case _Flags::_Type::__decimal:
56     case _Flags::_Type::__hexadecimal_lower_case:
57     case _Flags::_Type::__hexadecimal_upper_case:
58       this->__handle_integer();
59       break;
60 
61     default:
62       __throw_format_error(
63           "The format-spec type has a type not supported for a bool argument");
64     }
65 
66     return __it;
67   }
68 };
69 
70 template <class _CharT>
71 struct _LIBCPP_TEMPLATE_VIS __bool_strings;
72 
73 template <>
74 struct _LIBCPP_TEMPLATE_VIS __bool_strings<char> {
75   static constexpr string_view __true{"true"};
76   static constexpr string_view __false{"false"};
77 };
78 
79 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
80 template <>
81 struct _LIBCPP_TEMPLATE_VIS __bool_strings<wchar_t> {
82   static constexpr wstring_view __true{L"true"};
83   static constexpr wstring_view __false{L"false"};
84 };
85 #endif
86 
87 template <class _CharT>
88 using __formatter_bool = __formatter_integral<__parser_bool<_CharT>>;
89 
90 } //namespace __format_spec
91 
92 // [format.formatter.spec]/2.3
93 // For each charT, for each cv-unqualified arithmetic type ArithmeticT other
94 // than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
95 
96 template <__formatter::__char_type _CharT>
97 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<bool, _CharT>
98     : public __format_spec::__formatter_bool<_CharT> {
99   using _Base = __format_spec::__formatter_bool<_CharT>;
100 
101   _LIBCPP_HIDE_FROM_ABI auto format(bool __value, auto& __ctx)
102       -> decltype(__ctx.out()) {
103     if (this->__type != __format_spec::_Flags::_Type::__string)
104       return _Base::format(static_cast<unsigned char>(__value), __ctx);
105 
106     if (this->__width_needs_substitution())
107       this->__substitute_width_arg_id(__ctx.arg(this->__width));
108 
109 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
110     if (this->__locale_specific_form) {
111       const auto& __np = use_facet<numpunct<_CharT>>(__ctx.locale());
112       basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename();
113       return __formatter::__write_unicode(
114           __ctx.out(), basic_string_view<_CharT>{__str}, this->__width, -1,
115           this->__fill, this->__alignment);
116     }
117 #endif
118     basic_string_view<_CharT> __str =
119         __value ? __format_spec::__bool_strings<_CharT>::__true
120                 : __format_spec::__bool_strings<_CharT>::__false;
121 
122     // The output only uses ASCII so every character is one column.
123     unsigned __size = __str.size();
124     if (__size >= this->__width)
125       return _VSTD::copy(__str.begin(), __str.end(), __ctx.out());
126 
127     return __formatter::__write(__ctx.out(), __str.begin(), __str.end(), __size,
128                                 this->__width, this->__fill, this->__alignment);
129   }
130 };
131 
132 #endif //_LIBCPP_STD_VER > 17
133 
134 _LIBCPP_END_NAMESPACE_STD
135 
136 #endif // _LIBCPP___FORMAT_FORMATTER_BOOL_H
137