BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslfmt_formattable.h
Go to the documentation of this file.
1/// @file bslfmt_formattable.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslfmt_formattable.h -*-C++-*-
8
9#ifndef INCLUDED_BSLFMT_FORMATTABLE
10#define INCLUDED_BSLFMT_FORMATTABLE
11
12#include <bsls_ident.h>
13BSLS_IDENT("$Id: $")
14
15/// @defgroup bslfmt_formattable bslfmt_formattable
16/// @brief Provide a concept to check for the presence of a `bsl::formatter`.
17/// @addtogroup bsl
18/// @{
19/// @addtogroup bslfmt
20/// @{
21/// @addtogroup bslfmt_formattable
22/// @{
23///
24/// <h1> Outline </h1>
25/// * <a href="#bslfmt_formattable-purpose"> Purpose</a>
26/// * <a href="#bslfmt_formattable-classes"> Classes </a>
27/// * <a href="#bslfmt_formattable-macros"> Macros </a>
28/// * <a href="#bslfmt_formattable-description"> Description </a>
29/// * <a href="#bslfmt_formattable-when-is-a-type-formattable"> When is a Type Formattable? </a>
30/// * <a href="#bslfmt_formattable-usage"> Usage </a>
31/// * <a href="#bslfmt_formattable-example-verify-the-presence-of-a-bsl-formatter"> Example: Verify the Presence of a bsl::formatter </a>
32///
33/// # Purpose {#bslfmt_formattable-purpose}
34/// Provide a concept to check for the presence of a `bsl::formatter`.
35///
36/// # Classes {#bslfmt_formattable-classes}
37///
38/// - bsl::formattable<t_TYPE, t_CHAR>: `bsl::formatter` presence concept
39///
40/// # Macros {#bslfmt_formattable-macros}
41///
42/// - BSL_FORMATTABLE_DEFINED: `bsl::formatter` is available
43///
44/// # Description {#bslfmt_formattable-description}
45/// This component conditionally provides `bsl::formattable`, a
46/// concept that determines if a type has a formatter enabled for a given
47/// character type (i.e. `char` or `wchar_t`). The concept is defined only if
48/// concepts are available on the current platform. The macro
49/// `BSL_FORMATTABLE_DEFINED` may be used to determine if the concept is present
50/// or not.
51///
52/// Because this component requires concepts support it is not available
53/// portably on all platforms, therefore any portable use of this concept should
54/// make use of the appropriate preprocessor guards.
55///
56/// ## When is a Type Formattable? {#bslfmt_formattable-when-is-a-type-formattable}
57///
58///
59/// A type is formattable if it can be used as a formatted argument of the
60/// `bsl::format` family of functions:
61/// @code
62/// bsl::string fmtd = bsl::format("{}", MyType(42));
63/// @endcode
64/// That in turn works if there is a matching `bsl::formatter` specialization
65/// for that type, such as:
66/// @code
67/// namespace bsl {
68/// template <class t_CHAR>
69/// class formatter<MyType, t_CHAR> ...
70/// }
71/// @endcode
72///
73/// ## Usage {#bslfmt_formattable-usage}
74///
75///
76/// In this section we show the intended use of this component.
77///
78/// ### Example: Verify the Presence of a bsl::formatter {#bslfmt_formattable-example-verify-the-presence-of-a-bsl-formatter}
79///
80///
81/// Suppose we want to write different code depending on if a type has a
82/// formatter enabled, and fall back to using standard streaming if it does not.
83///
84/// First we create a type that supports streaming but not formatting with
85/// `bsl::format`:
86/// @code
87/// struct Streamable {};
88/// std::ostream& operator<<(std::ostream& os, const Streamable&) {
89/// return os << "Streamable";
90/// }
91/// @endcode
92/// Then we demonstrate that this type is not formattable, but an `int` is.
93/// Since the concept may not exists (older compilers/standards) we need to
94/// protect the code with the preprocessor:
95/// @code
96/// #ifdef BSL_FORMATTABLE_DEFINED
97/// assert(false == (bsl::formattable<Streamable, char>));
98/// assert(true == (bsl::formattable<int, char>));
99/// #endif
100/// @endcode
101/// Next we create a generic function to convert a value to string,
102/// center-aligned, and we provide two implementations, the first one for types
103/// that are formattable in case the concept exists, and just the stream-based
104/// variation if it does not.
105/// @code
106/// template <class t_TYPE>
107/// bsl::string
108/// centeredIn(const t_TYPE& obj, size_t width)
109/// #ifdef BSL_FORMATTABLE_DEFINED
110/// requires (!bsl::formattable<t_TYPE, char>)
111/// #endif
112/// {
113/// bsl::ostringstream os;
114/// os << obj;
115/// bsl::string s = os.str();
116///
117/// width = bsl::max(width, s.length());
118///
119/// const size_t allPadding = width - s.length();
120/// s.insert(s.begin(), allPadding / 2, ' ');
121/// s.append(allPadding - allPadding / 2, ' ');
122///
123/// return s;
124/// }
125/// @endcode
126/// Then, if the concept is present, we define the format-based overload:
127/// @code
128/// #ifdef BSL_FORMATTABLE_DEFINED
129/// template <class t_TYPE>
130/// bsl::string
131/// centeredIn(const t_TYPE& obj, size_t width)
132/// requires (bsl::formattable<t_TYPE, char>)
133/// {
134/// return bsl::format("{:^{}}", obj, width);
135/// }
136/// #endif
137/// @endcode
138/// Finally, we can call the `centeredIn` function and let concepts select the
139/// right variation (if concepts are available):
140/// @code
141/// bsl::string s = centeredIn(Streamable(), 14);
142/// assert(s == " Streamable ");
143///
144/// s = centeredIn(42, 8);
145/// assert(s == " 42 ");
146/// @endcode
147/// @}
148/** @} */
149/** @} */
150
151/** @addtogroup bsl
152 * @{
153 */
154/** @addtogroup bslfmt
155 * @{
156 */
157/** @addtogroup bslfmt_formattable
158 * @{
159 */
160
161#include <bslscm_version.h>
162
163#include <bslfmt_format.h>
164
166#include <bsls_libraryfeatures.h>
167
168#ifdef BSLS_COMPILERFEATURES_SUPPORT_CONCEPTS
169# define BSL_FORMATTABLE_DEFINED 1
170
171
172# ifdef BSLS_LIBRARYFEATURES_HAS_CPP23_RANGE_FORMAT
173// In C++23 we just use the `std`-defined concept directly
174namespace bsl {
175 using std::formattable;
176}
177# else
178
179# include <concepts>
180# include <type_traits>
181
182# include <stddef.h>
183
184
185namespace bslfmt {
186
187 // =====================================
188 // class Formattable_DummyOutputIterator
189 // =====================================
190
191/// A dummy iterator class that provides the signatures of an output iterator,
192/// but whose implementation does nothing. This type serves as a stand in for
193/// the unknown output iterator (used by the standard) when defining the `formattable` trait.
194///
195/// \note Note that the output iterator used by the
196/// `bsl::format` implementation is a component private type, so we do not use
197/// it here.
198///
199/// See @ref bslfmt_formattable
200template <class t_CHAR>
201class Formattable_DummyOutputIterator {
202 public:
203 using difference_type = ptrdiff_t;
204
205 // MANIPULATORS
206 Formattable_DummyOutputIterator& operator++();
207 Formattable_DummyOutputIterator operator++(int);
208
209 // ACCESSORS
210 t_CHAR& operator*() const;
211};
212
213
214// The following @ref static_assert s verify the dummy output iterator conforms to
215// some of the requirements of an output iterator.
216static_assert(
217 std::output_iterator<Formattable_DummyOutputIterator<char>, char>);
218static_assert(
219 std::output_iterator<Formattable_DummyOutputIterator<wchar_t>, wchar_t>);
220
221 // ========================
222 // concept Formattable_With
223 // ========================
224
225/// This concept, `bslfmt::Formattable_With`, is an implementation detail of
226/// the `bsl::formattable` concept and it is not to be used directly.
227///
228/// This concept answers the question if the specified `t_TYPE` is formattable
229/// with the given `t_CONTEXT`. The `t_FORMATTER` type parameter is just a
230/// "local variable" that retrieves the actual formatter type from the context,
231/// it must not be specified when the concept is invoked.
232template <class t_TYPE,
233 class t_CONTEXT,
234 class t_FORMATTER =
235 typename t_CONTEXT::template
236 formatter_type<std::remove_const_t<t_TYPE>> >
237concept Formattable_With =
238 std::semiregular<t_FORMATTER> &&
239 requires (t_FORMATTER& f, const t_FORMATTER& cf, t_TYPE&& t, t_CONTEXT fc,
240 bsl::basic_format_parse_context<
241 typename t_CONTEXT::char_type
242 > pc) {
243 { f.parse(pc) } -> std::same_as<typename decltype(pc)::iterator>;
244 { cf.format(t, fc) } -> std::same_as<typename t_CONTEXT::iterator>;
245};
246
247} // close package namespace
248
249
250 // ===================
251 // concept Formattable
252 // ===================
253
254/// The `bsl::formattable` concept answers the question if the specified
255/// `t_TYPE` has a formatter specialization enabled for the specified `t_CHAR`
256/// character type (in other words if `t_TYPE` can be used as a `bsl::format`
257/// formatted argument with a format string of `t_CHAR`). The `t_CHAR`
258/// character type must be one of `char` or `wchar_t`.
259namespace bsl {
260template <class t_TYPE, class t_CHAR>
261concept formattable = BloombergLP::bslfmt::Formattable_With<
262 std::remove_reference_t<t_TYPE>,
263 bsl::basic_format_context<
264 BloombergLP::bslfmt::Formattable_DummyOutputIterator<t_CHAR>,
265 t_CHAR> >;
266} // close namespace bsl
267
268# endif // else of - BSLS_LIBRARYFEATURES_HAS_CPP23_RANGE_FORMAT
269#endif // BSLS_COMPILERFEATURES_SUPPORT_CONCEPTS
270
271#endif // INCLUDED_BSLFMT_FORMATTABLE
272
273// ----------------------------------------------------------------------------
274// Copyright 2025 Bloomberg Finance L.P.
275//
276// Licensed under the Apache License, Version 2.0 (the "License");
277// you may not use this file except in compliance with the License.
278// You may obtain a copy of the License at
279//
280// http://www.apache.org/licenses/LICENSE-2.0
281//
282// Unless required by applicable law or agreed to in writing, software
283// distributed under the License is distributed on an "AS IS" BASIS,
284// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
285// See the License for the specific language governing permissions and
286// limitations under the License.
287// ----------------------------- END-OF-FILE ----------------------------------
288
289/** @} */
290/** @} */
291/** @} */
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
FunctionOutputIterator< FUNCTION > & operator++(FunctionOutputIterator< FUNCTION > &iterator)
Do nothing and return specified iterator.
Definition bdlb_functionoutputiterator.h:408
Decimal32 operator*(Decimal32 lhs, Decimal32 rhs)
Definition bdlat_valuetypefunctions.h:939
Definition bslfmt_enablestreamedformatter.h:130