BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsls_nameof.h
Go to the documentation of this file.
1/// @file bsls_nameof.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_nameof.h -*-C++-*-
8#ifndef INCLUDED_BSLS_NAMEOF
9#define INCLUDED_BSLS_NAMEOF
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_nameof bsls_nameof
15/// @brief Provide a `NameOf` type for displaying template type at run-time.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_nameof
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_nameof-purpose"> Purpose</a>
25/// * <a href="#bsls_nameof-classes"> Classes </a>
26/// * <a href="#bsls_nameof-description"> Description </a>
27/// * <a href="#bsls_nameof-usage"> Usage </a>
28/// * <a href="#bsls_nameof-example-1"> Example 1: </a>
29///
30/// # Purpose {#bsls_nameof-purpose}
31/// Provide a `NameOf` type for displaying template type at run-time.
32///
33/// # Classes {#bsls_nameof-classes}
34///
35/// - bsls::NameOf: template class to return name of template parameter
36///
37///@FREE FUNCTIONS:
38/// bsls::nameOfType(const TYPE&): template function to return name of `TYPE`
39///
40/// # Description {#bsls_nameof-description}
41/// This component provides a template class,
42/// `bsls::NameOf<TYPE>`, which can implicitly cast to a `const char *` which
43/// will point to a description of `TYPE`.
44///
45/// ## Usage {#bsls_nameof-usage}
46///
47///
48/// This section illustrates intended usage of this component.
49///
50/// ### Example 1: {#bsls_nameof-example-1}
51///
52///
53/// First, your test driver must have the following `using` statements so that
54/// the template class `NameOf` and the template function `nameOfType` can be
55/// referred to concisely, without having to qualify them with namespaces on
56/// each call. Note that if you've already said `using namespace BloombergLP`
57/// you don't have to give the `BloombergLP::` qualifiers here:
58/// @code
59/// using BloombergLP::bsls::NameOf;
60/// using BloombergLP::bsls::nameOfType;
61/// @endcode
62/// Next, we define some types in the unnamed namespace:
63/// @code
64/// namespace {
65///
66/// struct MyType {
67/// int d_i;
68/// char d_c;
69/// };
70///
71/// union MyUnion {
72/// int d_i;
73/// char d_buffer[100];
74/// };
75///
76/// } // close unnamed namespace
77/// @endcode
78/// Next, we see that the `NameOf` template class, when created with a type, can
79/// be implicitly cast to a `const char *` which points to a description of the
80/// type.
81/// @code
82/// assert(!std::strcmp("double", NameOf<double>()));
83/// assert(!std::strcmp("int", NameOf<int>()));
84/// @endcode
85/// Then, we see that when `NameOf` is passed a `typedef` or template parameter,
86/// it resolves it to the original type:
87/// @code
88/// typedef int Woof;
89///
90/// assert(!std::strcmp("int", NameOf<Woof>()));
91/// @endcode
92/// Next, we introduce the `nameOfType` template function, which takes as any
93/// variable as an argument, and returns a `const char *` pointing to a
94/// description of the type of the variable.
95/// @code
96/// int ii = 2;
97///
98/// assert(!std::strcmp("int", nameOfType(ii)));
99/// @endcode
100/// Then, we see that `NameOf` and `nameOfType` will strip `BloombergLP::`
101/// namespace qualifiers, as well as anonymous namespace qualifiers.
102/// @code
103/// typedef BloombergLP::bsls::Stopwatch SW;
104///
105/// const SW sw;
106/// const MyType mt = { 2, 'a' };
107/// MyUnion mu;
108/// mu.d_i = 7;
109///
110/// assert(!std::strcmp("bsls::Stopwatch", NameOf<SW>()));
111/// assert(!std::strcmp("bsls::Stopwatch",
112/// NameOf<BloombergLP::bsls::Stopwatch>()));
113/// assert(!std::strcmp("bsls::Stopwatch", nameOfType(sw)));
114///
115/// assert(!std::strcmp("MyType", NameOf<MyType>()));
116/// assert(!std::strcmp("MyType", nameOfType(mt)));
117///
118/// assert(!std::strcmp("MyUnion", NameOf<MyUnion>()));
119/// assert(!std::strcmp("MyUnion", nameOfType(mu)));
120/// @endcode
121/// There is a problem with template code not knowing how to implicitly cast the
122/// `NameOf` type to `const char *` for initializing or comparing with
123/// `std::string`s. To facilitate, `NameOf` provides a `const char *` `name`
124/// accessor, to avoid the user having to do a more verbose `static cast`.
125/// @code
126/// const std::string swName = "bsls::Stopwatch";
127/// assert(swName == static_cast<const char *>(NameOf<SW>()));
128/// assert(swName == NameOf<SW>().name());
129///
130/// const std::string swNameB = NameOf<SW>().name();
131/// assert(swNameB == swName);
132///
133/// printf("NameOf<SW>() = \"%s\"\n", NameOf<SW>().name());
134/// printf("NameOfType(4 + 3) = \"%s\"\n", nameOfType(4 + 3));
135/// @endcode
136/// Note that `nameOfType` naturally returns a `const char *` and needs no help
137/// casting. Note also that `bsls::debugprint` is able to figure out how to
138/// cast `NameOf` directly to `const char *` with no problems, as can iostreams,
139/// so there is no problem with putting a `NameOf` in a `LOOP_ASSERT` or
140/// `ASSERTV`. It is anticipated that displaying by the BDE `ASSERTV`,
141/// `LOOP_ASSERT, and `P' macros will be the primary use of this component.
142/// @code
143/// printf("NameOf<double>() = ");
144/// BloombergLP::bsls::debugprint(NameOf<double>());
145/// printf("\n");
146///
147/// typedef double DTYPE;
148/// DTYPE x = 7.3;
149///
150/// LOOP_ASSERT(NameOf<DTYPE>(), x > 7);
151///
152/// std::string myStr; // Assign, not init, of string doesn't need
153/// myStr = NameOf<DTYPE>(); // '.name()'.
154/// assert("double" == myStr);
155/// @endcode
156/// Which produces:
157/// @code
158/// NameOf<SW>() = "bsls::Stopwatch"
159/// @endcode
160/// Finally, we see that `NameOf` and `nameOfType` will simplify
161/// `std::basic_string<...>` declarations to `std::string`.
162/// @code
163/// const std::string s = "std::string";
164///
165/// assert(s == NameOf<std::basic_string<char> >().name());
166/// assert(s == NameOf<std::string>().name());
167/// assert(s == nameOfType(s));
168///
169/// typedef NameOf<std::string> Nos;
170///
171/// const std::string s2 = "bsls::NameOf<std::string>";
172///
173/// assert(s2 == NameOf<NameOf<std::basic_string<char> > >().name());
174/// assert(s2 == NameOf<NameOf<std::string> >().name());
175/// assert(s2 == NameOf<Nos>().name());
176/// assert(s2 == nameOfType(Nos()));
177/// @endcode
178/// @}
179/** @} */
180/** @} */
181
182/** @addtogroup bsl
183 * @{
184 */
185/** @addtogroup bsls
186 * @{
187 */
188/** @addtogroup bsls_nameof
189 * @{
190 */
191
192#include <bsls_assert.h>
193#include <bsls_atomic.h>
194#include <bsls_bslonce.h>
195#include <bsls_platform.h>
196
197
198namespace bsls {
199
200 // =======================
201 // class bsls::NameOf_Base
202 // =======================
203
204/// This `class` provide non-template implementation code for the `NameOf`
205/// template class.
206///
207/// See @ref bsls_nameof
209
210 protected:
211 // PROTECTED TYPES
212#if defined(BSLS_PLATFORM_CMP_SUN)
213 enum { k_BUF_SIZE_SOLARIS_CC = 256 };
214#endif
215
216 // On all platforms, the 'functionName' passed to 'initBuffer' will start
217 // with the contents of local buffer 'uselessPreamble', which will not make
218 // it into the final buffer, so we know that the final buffer can be
219 // trimmed of this length.
220
221#if defined(BSLS_PLATFORM_CMP_MSVC)
222# if defined(BSLS_PLATFORM_CPU_64_BIT)
223 enum { k_USELESS_PREAMBLE_LEN = 34 };
224# else
225 enum { k_USELESS_PREAMBLE_LEN = 37 };
226# endif
227#else
229#endif
230
231 // PROTECTED CLASS METHOD
232
233 /// Initialize the specified `buffer` with the type name contained in
234 /// the specified `functionName`, where `functionName` is the function
235 /// name of the `NameOf` constructor. Return either a pointer to
236 /// `buffer`, or if `buffer` couldn't be properly initialized,
237 /// `functionName`.
238 static const char *initBuffer(char *buffer,
239 const char *functionName);
240};
241
242 // ==================
243 // class bsls::NameOf
244 // ==================
245
246/// This `class` provides a means to display the type name of its template
247/// parameter `TYPE`. An instance of this `class` can be implicitly (or
248/// explicitly via the `name` accessor) cast to a `const char *` which will
249/// point to a buffer containing the description of the type. Note that all
250/// instances of a given type will refer to the same character buffer
251/// containing the name.
252///
253/// See @ref bsls_nameof
254template <class TYPE>
255class NameOf : public NameOf_Base {
256
257 // CLASS DATA
258 static bsls::AtomicPointer<const char> s_buffer_p;
259
260 public:
261 // CREATOR
262
263 /// Initialize the base class of this object to the name of `TYPE`.
264 NameOf();
265
266 // ACCESSOR
267
268 /// Return a pointer to the a string containing the name of `TYPE`.
269 operator const char *() const;
270
271 /// Return a pointer to the a string containing the name of `TYPE`, this
272 /// serves as a convenient way to explicitly cast the return value to a
273 /// `const char *`.
274 const char *name() const;
275};
276
277// ============================================================================
278// TEMPLATE FUNCTION DEFINITIONS
279// ----------------------------------------------------------------------------
280
281 // ------------------
282 // class bsls::NameOf
283 // ------------------
284
285// CLASS DATA
286template <class TYPE>
288
289// CREATOR
290
291/// Initialize the base class of this object to name of `TYPE`.
292template <class TYPE>
294{
295 // It is important to ensure that no two threads are initializing the same
296 // buffer at the same time.
297
298 static BslOnce once = BSLS_BSLONCE_INITIALIZER;
299 BslOnceGuard onceGuard;
300
301 if (!s_buffer_p && onceGuard.enter(&once)) {
302#if defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG)
303 static char buffer[sizeof(__PRETTY_FUNCTION__) -
304 k_USELESS_PREAMBLE_LEN];
305 s_buffer_p = initBuffer(buffer, __PRETTY_FUNCTION__);
306#elif defined(BSLS_PLATFORM_CMP_SUN)
307# if BSLS_PLATFORM_CMP_VERSION >= 0x5120
308 // The Solaris CC compiler doesn't understand
309 // 'sizeof(__PRETTY_FUNCTION__)'.
310
311 static char buffer[k_BUF_SIZE_SOLARIS_CC];
312 s_buffer_p = initBuffer(buffer, __PRETTY_FUNCTION__);
313# else
314 // '__PRETTY_FUNCTION__' not supported, only '__FUNCTION__', which
315 // doesn't mention 'TYPE', so we can't deduce the name of 'TYPE'
316
317 s_buffer_p = "unknown_type";
318# endif
319#elif defined(BSLS_PLATFORM_CMP_IBM)
320 static char buffer[sizeof(__FUNCTION__) - k_USELESS_PREAMBLE_LEN];
321 s_buffer_p = initBuffer(buffer, __FUNCTION__);
322#elif defined(BSLS_PLATFORM_CMP_MSVC)
323 static char buffer[sizeof(__FUNCSIG__) - k_USELESS_PREAMBLE_LEN];
324 s_buffer_p = initBuffer(buffer, __FUNCSIG__);
325#else
326# error No function signature macro defined.
327#endif
328
329 BSLS_ASSERT_SAFE(s_buffer_p);
330 }
331}
332
333// ACCESSOR
334template <class TYPE>
335inline
336NameOf<TYPE>::operator const char *() const
337{
338 return s_buffer_p;
339}
340
341template <class TYPE>
342inline
343const char *NameOf<TYPE>::name() const
344{
345 return s_buffer_p;
346}
347
348// FREE FUNCTIONS
349
350/// Return the name of the type of the object passed to this function.
351template <class TYPE>
352const char *nameOfType(const TYPE&)
353{
354 return NameOf<TYPE>();
355}
356
357} // close package namespace
358
359
360#endif
361
362// ----------------------------------------------------------------------------
363// Copyright 2016 Bloomberg Finance L.P.
364//
365// Licensed under the Apache License, Version 2.0 (the "License");
366// you may not use this file except in compliance with the License.
367// You may obtain a copy of the License at
368//
369// http://www.apache.org/licenses/LICENSE-2.0
370//
371// Unless required by applicable law or agreed to in writing, software
372// distributed under the License is distributed on an "AS IS" BASIS,
373// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
374// See the License for the specific language governing permissions and
375// limitations under the License.
376// ----------------------------- END-OF-FILE ----------------------------------
377
378/** @} */
379/** @} */
380/** @} */
#define BSLS_BSLONCE_INITIALIZER
Definition bsls_bslonce.h:143
Definition bsls_atomic.h:1349
Definition bsls_bslonce.h:219
bool enter(BslOnce *once)
Definition bsls_bslonce.h:314
Definition bsls_nameof.h:208
@ k_USELESS_PREAMBLE_LEN
Definition bsls_nameof.h:228
static const char * initBuffer(char *buffer, const char *functionName)
Definition bsls_nameof.h:255
const char * name() const
Definition bsls_nameof.h:343
NameOf()
Initialize the base class of this object to the name of TYPE.
Definition bsls_nameof.h:293
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlt_iso8601util.h:691
const char * nameOfType(const TYPE &)
Return the name of the type of the object passed to this function.
Definition bsls_nameof.h:352
Definition bsls_bslonce.h:150