BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bsls_objectbuffer.h
Go to the documentation of this file.
1/// @file bsls_objectbuffer.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_objectbuffer.h -*-C++-*-
8#ifndef INCLUDED_BSLS_OBJECTBUFFER
9#define INCLUDED_BSLS_OBJECTBUFFER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_objectbuffer bsls_objectbuffer
15/// @brief Provide raw buffer with size and alignment of user-specified type.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_objectbuffer
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_objectbuffer-purpose"> Purpose</a>
25/// * <a href="#bsls_objectbuffer-classes"> Classes </a>
26/// * <a href="#bsls_objectbuffer-description"> Description </a>
27/// * <a href="#bsls_objectbuffer-usage"> Usage </a>
28/// * <a href="#bsls_objectbuffer-example-1-creating-a-dynamic-array-of-objects"> Example 1: Creating a Dynamic Array of Objects </a>
29/// * <a href="#bsls_objectbuffer-example-2-containing-different-object-types"> Example 2: Containing Different Object Types </a>
30///
31/// # Purpose {#bsls_objectbuffer-purpose}
32/// Provide raw buffer with size and alignment of user-specified type.
33///
34/// # Classes {#bsls_objectbuffer-classes}
35///
36/// - bsls::ObjectBuffer: parameterized buffer aligned to hold specified type
37///
38/// @see bsls_alignmentfromtype
39///
40/// # Description {#bsls_objectbuffer-description}
41/// This component provides a templated buffer type,
42/// `bsls::ObjectBuffer`, that is compile-time sized and aligned to hold a
43/// specified object type. Defining a `bsls::ObjectBuffer<TYPE>` object does
44/// not cause the constructor for `TYPE` to be called. Similarly, destroying
45/// the object buffer does not call the destructor for `TYPE`. Instead, the
46/// user instantiates `bsls::ObjectBuffer` with a specific type, then constructs
47/// an object of that type within that buffer. When the object is no longer
48/// needed, the user must explicitly call its destructor. A
49/// `bsls::ObjectBuffer` can reside on the stack or within another object,
50/// including within a `union`.
51///
52/// Typically, a `bsls::ObjectBuffer` is used in situations where efficient
53/// (e.g., stack-based) storage is required but where straightforward
54/// initialization or destruction of an object is not possible. For example,
55/// `bsls::ObjectBuffer` can be used to construct an array where the number of
56/// used elements varies at run-time or where the element type does not have a
57/// default constructor. It can also be used to create a `union` containing
58/// non-POD element types.
59///
60/// ## Usage {#bsls_objectbuffer-usage}
61///
62///
63/// The examples below use a value-semantic string class, `my_String`, that can
64/// be constructed from a null-terminated string and contains a member, `c_str`,
65/// that returns a null-terminated string. `my_String` does not have a default
66/// constructor and thus cannot be used in C-style arrays or unions.
67///
68/// ### Example 1: Creating a Dynamic Array of Objects {#bsls_objectbuffer-example-1-creating-a-dynamic-array-of-objects}
69///
70///
71/// Here we use `bsls::ObjectBuffer` to create a variable-length array of
72/// `my_String` objects. For efficiency, the array is created on the stack as
73/// a fixed-sized array of `bsls::ObjectBuffer<my_String>` objects and the
74/// length is kept in a separate variable. Only `len` calls are made to the
75/// `my_String` constructor, with the unused array elements left as raw
76/// memory. An array directly containing `my_String` objects would not have
77/// been possible because `my_String` does not have a default constructor.
78///
79/// WARNING: the `manipulateStrings` function below is not exception-safe.
80/// If an exception is thrown anywhere within the function (e.g., from a
81/// constructor call), the destructor will not be called on the constructed
82/// string objects. This logic would typically be augmented with guard objects
83/// that call destructors in case of an exception.
84/// @code
85/// void manipulateStrings(const my_String *stringArray, int len)
86/// {
87/// assert(len <= 10);
88///
89/// bsls::ObjectBuffer<my_String> tempArray[10];
90/// for (int i = 0; i < len; ++i) {
91/// new (tempArray[i].buffer()) my_String(stringArray[i]);
92/// assert(stringArray[i] == tempArray[i].object())
93/// }
94///
95/// for (int i = 0; i < len; ++i)
96/// {
97/// my_String& s = tempArray[i].object();
98/// // ... String manipulations go here. 's' might be analyzed,
99/// // appended-to, passed to other functions, etc.
100/// }
101///
102/// while (len) {
103/// // Destroy strings. Although not critical to this example, we
104/// // follow the general rule of destroying the objects in reverse
105/// // order of their construction, thus mimicking the
106/// // compiler-generated destruction order for normal array objects.
107/// tempArray[--len].object().~my_String();
108/// }
109/// }
110///
111/// int main()
112/// {
113/// const my_String INARRAY[3] = {
114/// my_String("hello"),
115/// my_String("goodbye"),
116/// my_String("Bloomberg")
117/// };
118///
119/// manipulateStrings(INARRAY, 3);
120///
121/// return 0;
122/// }
123/// @endcode
124///
125/// ### Example 2: Containing Different Object Types {#bsls_objectbuffer-example-2-containing-different-object-types}
126///
127///
128/// Here we use `bsls::ObjectBuffer` to compose a variable-type object capable
129/// of holding a string or an integer:
130/// @code
131/// class my_Union {
132/// public:
133/// enum TypeTag { INT, STRING };
134///
135/// private:
136/// TypeTag d_type;
137/// union {
138/// int d_int;
139/// bsls::ObjectBuffer<my_String> d_string;
140/// };
141///
142/// public:
143/// my_Union(int i = 0) : d_type(INT) { d_int = i; } // IMPLICIT
144/// my_Union(const my_String& s) : d_type(STRING) { // IMPLICIT
145/// new (d_string.buffer()) my_String(s); }
146/// my_Union(const char *s) : d_type(STRING) { // IMPLICIT
147/// new (d_string.buffer()) my_String(s); }
148/// my_Union(const my_Union& rhs) : d_type(rhs.d_type) {
149/// if (INT == d_type) {
150/// d_int = rhs.d_int;
151/// }
152/// else {
153/// new (d_string.buffer()) my_String(rhs.d_string.object());
154/// }
155/// }
156/// ~my_Union() {
157/// if (STRING == d_type) d_string.object().~my_String(); }
158///
159/// my_Union& operator=(const my_Union& rhs) {
160/// if (INT == d_type) {
161/// if (INT == rhs.d_type) {
162/// d_int = rhs.d_int;
163/// }
164/// else { // if STRING == rhs.d_type
165/// new (d_string.buffer()) my_String(rhs.d_string.object());
166/// }
167/// }
168/// else { // if (STRING == d_type)
169/// if (INT == rhs.d_type) {
170/// d_string.object().~my_String();
171/// d_int = rhs.d_int;
172/// }
173/// else { // if STRING == rhs.d_type
174/// d_string.object() = rhs.d_string.object();
175/// }
176/// }
177/// d_type = rhs.d_type;
178/// return *this;
179/// }
180///
181/// TypeTag typeTag() const { return d_type; }
182///
183/// int asInt() const {
184/// return INT == d_type ?
185/// d_int : static_cast<int>(
186/// strtol(d_string.object().c_str(), 0, 0));
187/// }
188///
189/// my_String asString() const {
190/// if (INT == d_type) {
191/// char temp[15];
192/// snprintf(temp, sizeof temp, "%d", d_int);
193/// return my_String(temp);
194/// }
195/// else {
196/// return d_string.object();
197/// }
198/// }
199/// };
200///
201/// int main()
202/// {
203/// assert(sizeof(bsls::ObjectBuffer<my_String>) == sizeof(my_String));
204///
205/// // Create a 'my_Union' object containing a string.
206/// const my_Union U1("hello");
207/// assert(my_Union::STRING == U1.typeTag());
208/// assert(0 == U1.asInt());
209/// assert("hello" == U1.asString());
210///
211/// // Create a 'my_Union' object containing an integer.
212/// const my_Union U2(123);
213/// assert(my_Union::INT == U2.typeTag());
214/// assert(123 == U2.asInt());
215/// assert("123" == U2.asString());
216///
217/// // Create a 'my_Union' object containing a string that can be
218/// // interpreted as an integer.
219/// const my_Union U3("0x456");
220/// assert(my_Union::STRING == U3.typeTag());
221/// assert(0x456 == U3.asInt());
222/// assert("0x456" == U3.asString());
223///
224/// // Copy-construct a 'my_Union' object containing a string.
225/// my_Union u4(U3);
226/// assert(my_Union::STRING == u4.typeTag());
227/// assert(0x456 == u4.asInt());
228/// assert("0x456" == u4.asString());
229///
230/// // Use assignment to change 'u4' from string to integer.
231/// u4 = U2;
232/// assert(my_Union::INT == u4.typeTag());
233/// assert(123 == u4.asInt());
234/// assert("123" == u4.asString());
235///
236/// return 0;
237/// }
238/// @endcode
239/// @}
240/** @} */
241/** @} */
242
243/** @addtogroup bsl
244 * @{
245 */
246/** @addtogroup bsls
247 * @{
248 */
249/** @addtogroup bsls_objectbuffer
250 * @{
251 */
252
253#include <bsls_alignmentfromtype.h>
254
255
256
257namespace bsls {
258
259 // ==================
260 // union ObjectBuffer
261 // ==================
262
263/// An instance of this union is a raw block of memory suitable for storing
264/// an object of type `TYPE`. Specifically, the size and alignment of this
265/// union exactly matches that of `TYPE`. A `TYPE` object can be
266/// constructed into an `ObjectBuffer` using the placement `new` operator
267/// and can be destroyed by explicitly calling its destructor, `~TYPE()`.
268/// It is the user's responsibility to perform this construction and
269/// destruction; an `ObjectBuffer` object does not manage the construction
270/// or destruction of any other objects.
271///
272///
273/// \note Note that a collaboration is implied between `ObjectBuffer` and the
274/// user. An `ObjectBuffer` provides aligned memory and the user handles
275/// construction and destruction of the object contained within that memory.
276template <class TYPE>
278
279 private:
280 // DATA
281 // Buffer correctly sized and aligned for object of type 'TYPE'.
282 char d_buffer[sizeof(TYPE)];
283 typename AlignmentFromType<TYPE>::Type d_align;
284
285 public:
286 // CREATORS
287 // Note that we deliberately omit defining constructors and destructors in
288 // order to keep this union "POD-like". In particular, an 'ObjectBuffer'
289 // may be used as a member in another 'union'. Copying an 'ObjectBuffer'
290 // by assignment or copy construction will result in a bit-wise copy and
291 // will not invoke 'TYPE's assignment operator or copy constructor.
292
293 // MANIPULATORS
294
295 /// Return the address of the first byte of this object, cast to a
296 /// `TYPE *` pointer.
297 TYPE *address();
298
299 /// Return the address of the first byte of this object, cast to a
300 /// `char *` pointer.
301 char *buffer();
302
303 /// Return a modifiable reference to the `TYPE` object occupying this
304 /// buffer. The referenced object has undefined state unless a valid
305 /// `TYPE` object has been constructed in this buffer.
306 TYPE& object();
307
308 // ACCESSORS
309
310 /// Return the address of the first byte of this object, cast to a
311 /// `const TYPE *` pointer.
312 const TYPE *address() const;
313
314 /// Return the address of the first byte of this object, cast to a
315 /// `const char *` pointer.
316 const char *buffer() const;
317
318 /// Return a `const` reference to the `TYPE` object occupying this
319 /// buffer. The referenced object has undefined state unless a valid
320 /// `TYPE` object has been constructed in this buffer.
321 const TYPE& object() const;
322};
323
324// ============================================================================
325// INLINE FUNCTION DEFINITIONS
326// ============================================================================
327
328 // ------------------
329 // union ObjectBuffer
330 // ------------------
331
332// MANIPULATORS
333template <class TYPE>
334inline
336{
337 // A redundant cast to 'void *' persuades gcc/Solaris that there are no
338 // alignment issues to warn about.
339
340 return reinterpret_cast<TYPE *>(static_cast<void *>(d_buffer));
341}
342
343template <class TYPE>
344inline
346{
347 return d_buffer;
348}
349
350template <class TYPE>
351inline
353{
354 return *reinterpret_cast<TYPE *>(this);
355}
356
357// ACCESSORS
358template <class TYPE>
359inline
361{
362 // A redundant cast to 'const void *' persuades gcc/Solaris that there are
363 // no alignment issues to warn about.
364
365 return reinterpret_cast<const TYPE *>(static_cast<const void *>(d_buffer));
366}
367
368template <class TYPE>
369inline
370const char *ObjectBuffer<TYPE>::buffer() const
371{
372 return d_buffer;
373}
374
375template <class TYPE>
376inline
377const TYPE& ObjectBuffer<TYPE>::object() const
378{
379 return *reinterpret_cast<const TYPE *>(this);
380}
381
382} // close package namespace
383
384// ============================================================================
385// BACKWARD COMPATIBILITY
386// ============================================================================
387
388#ifndef BDE_OMIT_INTERNAL_DEPRECATED
389
390#ifdef bdes_ObjectBuffer
391#undef bdes_ObjectBuffer
392#endif
393/// This alias is defined for backward compatibility.
394#define bdes_ObjectBuffer bsls::ObjectBuffer
395
396#endif // BDE_OMIT_INTERNAL_DEPRECATED
397
398#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
399
400#ifdef bsls_ObjectBuffer
401#undef bsls_ObjectBuffer
402#endif
403/// This alias is defined for backward compatibility.
404#define bsls_ObjectBuffer bsls::ObjectBuffer
405
406#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
407
408
409
410#endif
411
412// ----------------------------------------------------------------------------
413// Copyright 2013 Bloomberg Finance L.P.
414//
415// Licensed under the Apache License, Version 2.0 (the "License");
416// you may not use this file except in compliance with the License.
417// You may obtain a copy of the License at
418//
419// http://www.apache.org/licenses/LICENSE-2.0
420//
421// Unless required by applicable law or agreed to in writing, software
422// distributed under the License is distributed on an "AS IS" BASIS,
423// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
424// See the License for the specific language governing permissions and
425// limitations under the License.
426// ----------------------------- END-OF-FILE ----------------------------------
427
428/** @} */
429/** @} */
430/** @} */
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlt_iso8601util.h:707
AlignmentToType< VALUE >::Type Type
Definition bsls_alignmentfromtype.h:388
Definition bsls_objectbuffer.h:277
const TYPE & object() const
Definition bsls_objectbuffer.h:377
char * buffer()
Definition bsls_objectbuffer.h:345
const char * buffer() const
Definition bsls_objectbuffer.h:370
const TYPE * address() const
Definition bsls_objectbuffer.h:360
TYPE * address()
Definition bsls_objectbuffer.h:335
TYPE & object()
Definition bsls_objectbuffer.h:352