BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdld_manageddatum.h
Go to the documentation of this file.
1/// @file bdld_manageddatum.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdld_manageddatum.h -*-C++-*-
8#ifndef INCLUDED_BDLD_MANAGEDDATUM
9#define INCLUDED_BDLD_MANAGEDDATUM
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id$ $CSID$")
13
14/// @defgroup bdld_manageddatum bdld_manageddatum
15/// @brief Provide a smart-pointer-like manager for a `Datum` object.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdld
19/// @{
20/// @addtogroup bdld_manageddatum
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdld_manageddatum-purpose"> Purpose</a>
25/// * <a href="#bdld_manageddatum-classes"> Classes </a>
26/// * <a href="#bdld_manageddatum-description"> Description </a>
27/// * <a href="#bdld_manageddatum-value-semantics"> Value Semantics </a>
28/// * <a href="#bdld_manageddatum-resource-management"> Resource Management </a>
29/// * <a href="#bdld_manageddatum-usage"> Usage </a>
30/// * <a href="#bdld_manageddatum-example-1-basic-use-of-bdld-manageddatum"> Example 1: Basic Use of bdld::ManagedDatum </a>
31///
32/// # Purpose {#bdld_manageddatum-purpose}
33/// Provide a smart-pointer-like manager for a `Datum` object.
34///
35/// # Classes {#bdld_manageddatum-classes}
36///
37/// - bdld::ManagedDatum: a smart-pointer-like manager for a `Datum` object
38///
39/// @see bdld_datum
40///
41/// # Description {#bdld_manageddatum-description}
42/// This component implements a type, `bdld::ManagedDatum`, that
43/// provides two important services for `Datum` objects:
44///
45/// 1. `ManagedDatum` provides value-semantic-like operations for `Datum`.
46/// 2. `ManagedDatum` is a resource manager, similar to a smart pointer, for
47/// `Datum`.
48///
49/// These services allow clients to use a `ManagedDatum` object in most contexts
50/// where an object of a value-semantic type can be used (passed by value,
51/// stored in containers, and so on), even though `ManagedDatum` is not strictly
52/// value-semantic. These services are explored in subsequent sections.
53///
54/// The `Datum` type maintained by a `ManagedDatum` provides a space-efficient
55/// discriminated union (i.e., a variant) holding the value of a scalar type
56/// (e.g., `int`, `double`, `string`) or an aggregate of other `Datum` objects.
57/// See @ref bdld_datum for more details.
58///
59/// ## Value Semantics {#bdld_manageddatum-value-semantics}
60///
61///
62/// `ManagedDatum`, while not strictly a value-semantic type, provides the full
63/// set of value-semantic-like operations for `Datum` (see
64/// @ref bsldoc_glossary-value-semantic-operations :
65///
66/// * Equality and Non-Equality Comparisons
67/// * Copy Construction
68/// * Copy Assignment
69/// * Default Construction
70/// * `ostream` Printing
71///
72/// In other words, the syntax of `ManagedDatum` is *regular*, but not all of
73/// its copy behavior is value-semantic. Specifically, for User Defined Types
74/// (i.e., those that `bdld::Datum::clone` does not deep-copy) `ManagedDatum`
75/// performs a shallow copy (copying the reference rather than the value), which
76/// is inconsistent with value-semantics. For *all* other types `ManagedDatum`
77/// copy operations (copy construction, copy assignment, and non-member `swap`
78/// when the allocators differ) will deep-copy the value using `Datum::clone`,
79/// which creates a completely independent copy, with independent lifetime, by
80/// duplicating all data, even referenced data (except for UDTs).
81///
82/// Note that a default constructed `ManagedDatum`, or a `ManagedDatum` on which
83/// `release` has been called, will have the null `Datum` value.
84///
85/// ## Resource Management {#bdld_manageddatum-resource-management}
86///
87///
88/// A `Datum` object's relationship to memory can be seen as analogous to a raw
89/// pointer, requiring calls to static functions `Datum::create*` and
90/// `Datum::destroy` to initialize and release resources (see the @ref bdld_datum
91/// component documentation). A `ManagedDatum`, by extension, provides a
92/// resource manager for a `Datum` that is analogous to a smart pointer.
93///
94/// The `adopt` method of a `ManagedDatum` is used to take ownership of a
95/// supplied `Datum` object, after which point the `ManagedDatum` object's
96/// destructor will free the resources of the managed `Datum` (unless `release`
97/// is subsequently called). Similar to a smart pointer, a `ManagedDatum`
98/// provides dereference operators to access the `Datum` object under
99/// management.
100///
101/// ## Usage {#bdld_manageddatum-usage}
102///
103///
104/// This section illustrates intended use of this component.
105///
106/// ### Example 1: Basic Use of bdld::ManagedDatum {#bdld_manageddatum-example-1-basic-use-of-bdld-manageddatum}
107///
108///
109/// This example demonstrates the basic construction and manipulation of a
110/// `ManagedDatum` object.
111///
112/// First, we create a `ManagedDatum` object that manages a `Datum` holding a
113/// `double` and verify that the managed object has the expected type and value:
114/// @code
115/// bslma::TestAllocator ta("test", veryVeryVerbose);
116///
117/// const ManagedDatum realObj(Datum::createDouble(-3.4375), &ta);
118///
119/// assert(realObj->isDouble());
120/// assert(-3.4375 == realObj->theDouble());
121/// @endcode
122/// Next, we create a `ManagedDatum` object that holds a string and again verify
123/// that it has the expected type and value:
124/// @code
125/// const char *str = "This is a string";
126/// const ManagedDatum strObj(Datum::copyString(str, &ta), &ta);
127///
128/// assert(strObj->isString());
129/// assert(str == strObj->theString());
130/// @endcode
131/// Then, we assign this `ManagedDatum` object to another object and verify both
132/// objects have the same value:
133/// @code
134/// ManagedDatum strObj1(&ta);
135/// strObj1 = strObj;
136/// assert(strObj == strObj1);
137/// @endcode
138/// Next, copy-construct this `ManagedDatum` object and verify that the copy has
139/// the same value as the original:
140/// @code
141/// const ManagedDatum strObj2(strObj, &ta);
142/// assert(strObj == strObj2);
143/// @endcode
144/// Then, we create a `ManagedDatum` object that holds an opaque pointer to a
145/// `bdlt::Date` object and verify that the managed `Date` has the expected
146/// value:
147/// @code
148/// bdlt::Date udt;
149/// ManagedDatum udtObj(Datum::createUdt(&udt, UDT_TYPE), &ta);
150///
151/// assert(udtObj->isUdt());
152/// assert(&udt == udtObj->theUdt().data());
153/// assert(UDT_TYPE == udtObj->theUdt().type());
154/// @endcode
155/// Next, we assign a boolean value to this `ManagedDatum` object and verify
156/// that it has the new type and value:
157/// @code
158/// udtObj.adopt(Datum::createBoolean(true));
159/// assert(udtObj->isBoolean());
160/// assert(true == udtObj->theBoolean());
161/// @endcode
162/// Then, we create a `ManagedDatum` object having an array and verify that it
163/// has the same array value. Note that in practice we would use
164/// @ref bdld_datumarraybuilder , but do not do so here for dependency reasons:
165/// @code
166/// const Datum datumArray[2] = {
167/// Datum::createInteger(12),
168/// Datum::copyString("A long string", &ta)
169/// };
170///
171/// DatumMutableArrayRef arr;
172/// Datum::createUninitializedArray(&arr, 2, &ta);
173/// for (int i = 0; i < 2; ++i) {
174/// arr.data()[i] = datumArray[i];
175/// }
176/// *(arr.length()) = 2;
177/// const ManagedDatum arrayObj(Datum::adoptArray(arr), &ta);
178///
179/// assert(arrayObj->isArray());
180/// assert(DatumArrayRef(datumArray, 2) == arrayObj->theArray());
181/// @endcode
182/// Next, we create a `ManagedDatum` object having a map and verify that it has
183/// the same map value. Note that in practice we would use
184/// @ref bdld_datummapbuilder , but do not do so here to for dependency reasons.
185/// @code
186/// const DatumMapEntry datumMap[2] = {
187/// DatumMapEntry(StringRef("first", static_cast<int>(strlen("first"))),
188/// Datum::createInteger(12)),
189/// DatumMapEntry(StringRef("second", static_cast<int>(strlen("second"))),
190/// Datum::copyString("A very long string", &ta))
191/// };
192///
193/// DatumMutableMapRef mp;
194/// Datum::createUninitializedMap(&mp, 2, &ta);
195/// for (int i = 0; i < 2; ++i) {
196/// mp.data()[i] = datumMap[i];
197/// }
198/// *(mp.size()) = 2;
199/// const ManagedDatum mapObj(Datum::adoptMap(mp), &ta);
200///
201/// assert(mapObj->isMap());
202/// assert(DatumMapRef(datumMap, 2, false, false) == mapObj->theMap());
203/// @endcode
204/// Then, we create a `Datum` object and assign its ownership to a
205/// `ManagedDatum` object and verify that the ownership was transferred:
206/// @code
207/// const Datum rcObj = Datum::copyString("This is a string", &ta);
208/// ManagedDatum obj(Datum::createInteger(1), &ta);
209/// obj.adopt(rcObj);
210/// assert(obj.datum() == rcObj);
211/// @endcode
212/// Next, we release the `Datum` object managed by `obj` and verify that it was
213/// released:
214/// @code
215/// const Datum internalObj = obj.release();
216/// assert(obj->isNull());
217/// assert(internalObj == rcObj);
218/// @endcode
219/// Finally, we destroy the released `Datum` object:
220/// @code
221/// Datum::destroy(internalObj, obj.get_allocator());
222/// @endcode
223/// @}
224/** @} */
225/** @} */
226
227/** @addtogroup bdl
228 * @{
229 */
230/** @addtogroup bdld
231 * @{
232 */
233/** @addtogroup bdld_manageddatum
234 * @{
235 */
236
237#include <bdlscm_version.h>
238
239#include <bdld_datum.h>
240
241#include <bslma_allocator.h>
242#include <bslma_allocatorutil.h>
243#include <bslma_bslallocator.h>
245
248
249#include <bsls_assert.h>
250#include <bsls_review.h>
251
252#include <bsl_algorithm.h>
253#include <bsl_iosfwd.h>
254
255
256namespace bdld {
257
258 // ==================
259 // class ManagedDatum
260 // ==================
261
262/// This class implements a smart-pointer-like resource manager for a
263/// `Datum` object.
264///
265/// See @ref bdld_manageddatum
267
268 public:
269 // TYPES
271
272 private:
273 // DATA
274 Datum d_data; // storage for data
275 allocator_type d_allocator; // allocator of dynamic memory
276
277 public:
278 // TRAITS
279
280 /// 'ManagedDatum' objects are allocator-aware and bitwise movable.
282
283 // CREATORS
284
285 ManagedDatum();
286 /// Create a `ManagedDatum` object having the default (null) value, and
287 /// the specified `allocator` (e.g., the address of a `bslma::Allocator`
288 /// object) to supply memory. Calling `isNull` on the resulting managed
289 /// `Datum` object returns `true`.
290 explicit ManagedDatum(const allocator_type& allocator);
291
292 /// Create a `ManagedDatum` object that assumes ownership of the
293 /// specified `datum`. Optionally specify an `allocator` (e.g., the
294 /// address of a `bslma::Allocator` object) to supply memory; otherwise,
295 /// the default allocator is used. The behavior is undefined unless
296 /// `datum` was allocated using the indicated allocator and is not
297 /// subsequently destroyed externally using `Datum::destroy`.
298 explicit ManagedDatum(const Datum& datum,
300
301 /// Create a `ManagedDatum` object having the same value as the
302 /// specified `original` object. Optionally specify an `allocator`
303 /// (e.g., the address of a `bslma::Allocator` object) used to supply
304 /// memory; otherwise, the default allocator is used. This operation
305 /// performs a `clone` of the underlying `Datum`, see {Value Semantics}
306 /// for more detail.
307 ManagedDatum(const ManagedDatum& original,
309
310 /// Destroy this object and release all dynamically allocated memory
311 /// managed by this object.
313
314 // MANIPULATORS
315
316 /// Assign to this object the value of the specified `rhs` object, and
317 /// return a non-`const` reference to this object. This operation
318 /// performs a `clone` of the underlying `Datum`, see {Value Semantics}
319 /// for more detail.
321
322 /// Take ownership of the specified `obj` and destroy the `Datum`
323 /// object previously managed by this object. The behavior is undefined
324 /// unless `obj` was allocated using the same allocator used by this
325 /// object and is not subsequently destroyed externally using
326 /// `Datum::destroy`.
327 void adopt(const Datum& obj);
328
329 /// Assign to this object the specified `value` by making a "deep copy"
330 /// of `value`, so that any dynamically allocated memory managed by
331 /// `value` is cloned and not shared with `value`.
332 void clone(const Datum& value);
333
334 /// Make the `Datum` object managed by this object null and release all
335 /// dynamically allocated memory managed by this object.
336 void makeNull();
337
338 /// Return, *by* *value*, the `Datum` object managed by this object and
339 /// set the managed object to null. Ownership of the previously managed
340 /// `Datum` object is transferred to the caller.
341 Datum release();
342
343 /// Efficiently exchange the value of this object with the value of the
344 /// specified `other` object. This method provides the no-throw
345 /// exception-safety guarantee. The behavior is undefined unless this
346 /// object was created with the same allocator as `other`.
347 void swap(ManagedDatum& other);
348
349 // ACCESSORS
350
351 /// Return an address providing non-modifiable access to the `Datum`
352 /// object managed by this object.
353 const Datum *operator->() const;
354
355 /// Return a `const` reference to the `Datum` object managed by this
356 /// object.
357 const Datum& operator*() const;
358
359 /// Return a `const` reference to the `Datum` object managed by this
360 /// object.
361 const Datum& datum() const;
362
363 // Aspects
364
365 /// @deprecated Use @ref get_allocator() instead.
366 ///
367 /// Return `get_allocator().mechanism()`.
369
370 /// Return the allocator used by this object to supply memory. Note
371 /// that if no allocator was supplied at construction the default
372 /// allocator in effect at construction is used.
374
375 /// Format this object to the specified output `stream` at the (absolute
376 /// value of) the optionally specified indentation `level` and return a
377 /// reference to the modifiable `stream`. If `level` is specified,
378 /// optionally specify `spacesPerLevel`, the number of spaces per
379 /// indentation level for this and all of its nested objects. If
380 /// `level` is negative, suppress indentation of the first line. If
381 /// `spacesPerLevel` is negative, format the entire output on one line,
382 /// suppressing all but the initial indentation (as governed by
383 /// `level`). If `stream` is not valid on entry, this operation has no
384 /// effect.
385 bsl::ostream& print(bsl::ostream& stream,
386 int level = 0,
387 int spacesPerLevel = 4) const;
388};
389
390// FREE OPERATORS
391
392/// Return `true` if the specified `lhs` and `rhs` `ManagedDatum` objects
393/// have the same value, and `false` otherwise. Two `ManagedDatum` objects
394/// have the same value if their corresponding managed `Datum` objects have
395/// the same value. See the function-level documentation of the `Datum`
396/// equality-comparison operators for details.
397bool operator==(const ManagedDatum& lhs, const ManagedDatum& rhs);
398
399/// Return `true` if the specified `lhs` and `rhs` `ManagedDatum` objects do
400/// not have the same value, and `false` otherwise. Two `ManagedDatum`
401/// objects do not have the same value if their corresponding managed
402/// `Datum` objects do not have the same value. See the function-level
403/// documentation of the `Datum` equality-comparison operators for details.
404bool operator!=(const ManagedDatum& lhs, const ManagedDatum& rhs);
405
406/// Write the specified `rhs` value to the specified output `stream` and
407/// return a reference to the modifiable `stream`. This function has no
408/// effect if `stream` is not valid on entry. Note that this method invokes
409/// `operator<<` defined for `Datum`. See the function-level documentation
410/// of the `operator<<` defined for `Datum` for details of the format of the
411/// output.
412bsl::ostream& operator<<(bsl::ostream& stream, const ManagedDatum& rhs);
413
414// FREE FUNCTIONS
415
416/// Exchange the values of the specified `a` and `b` objects. This function
417/// provides the no-throw exception-safety guarantee if the two objects were
418/// created with the same allocator and the basic guarantee otherwise. Note
419/// that in case the allocators are different this function places a *clone*
420/// of `a` into `b`, and vice versa. See {Value Semantics} on details of
421/// the cloning that may happen.
422void swap(ManagedDatum& a, ManagedDatum& b);
423
424// ============================================================================
425// INLINE DEFINITIONS
426// ============================================================================
427
428 // ------------------
429 // class ManagedDatum
430 // ------------------
431
432// CREATORS
433inline
435: d_data(Datum::createNull())
436, d_allocator()
437{
438}
439
440inline
442: d_data(Datum::createNull())
443, d_allocator(allocator)
444{
445}
446
447inline
448ManagedDatum::ManagedDatum(const Datum& datum, const allocator_type& allocator)
449: d_data(datum)
450, d_allocator(allocator)
451{
452}
453
454inline
456 const allocator_type& allocator)
457: d_allocator(allocator)
458{
459 d_data = original.d_data.clone(d_allocator);
460}
461
462inline
464{
465 Datum::destroy(d_data, d_allocator);
466}
467
468// MANIPULATORS
469inline
471{
472 ManagedDatum copy(rhs, d_allocator);
473 swap(copy);
474 return *this;
475}
476
477inline
479{
480 if (&obj != &d_data) {
481 ManagedDatum(obj, d_allocator).swap(*this);
482 }
483}
484
485inline
486void ManagedDatum::clone(const Datum& value)
487{
488 Datum data = value.clone(d_allocator);
489 ManagedDatum(data, d_allocator).swap(*this);
490}
491
492inline
494{
495 ManagedDatum(d_allocator).swap(*this);
496}
497
498inline
500{
501 Datum temp = d_data;
502 d_data = Datum::createNull();
503 return temp;
504}
505
506inline
508{
509 BSLS_ASSERT(d_allocator == other.get_allocator());
510
511 using bsl::swap;
512 swap(d_data, other.d_data);
513}
514
515// ACCESSORS
516inline
518{
519 return &d_data;
520}
521
522inline
524{
525 return d_data;
526}
527
528inline
530{
531 return d_data;
532}
533
534 // Aspects
535
536inline
541
542inline
544{
545 return d_allocator;
546}
547
548inline
549bsl::ostream& ManagedDatum::print(bsl::ostream& stream,
550 int level,
551 int spacesPerLevel) const
552{
553 return d_data.print(stream, level, spacesPerLevel);
554}
555
556} // close package namespace
557
558// FREE OPERATORS
559inline
560bool bdld::operator==(const ManagedDatum& lhs, const ManagedDatum& rhs)
561{
562 return (lhs.datum() == rhs.datum());
563}
564
565inline
566bool bdld::operator!=(const ManagedDatum& lhs, const ManagedDatum& rhs)
567{
568 return (lhs.datum() != rhs.datum());
569}
570
571inline
572bsl::ostream& bdld::operator<<(bsl::ostream& stream, const ManagedDatum& rhs)
573{
574 return (stream << rhs.datum());
575}
576
577// FREE FUNCTIONS
578inline
579void bdld::swap(ManagedDatum& a, ManagedDatum& b)
580{
581 if (a.get_allocator() == b.get_allocator()) {
582 a.swap(b);
583 }
584 else {
585 ManagedDatum tempA(a, b.get_allocator());
586 ManagedDatum tempB(b, a.get_allocator());
587
588 a.swap(tempB);
589 b.swap(tempA);
590 }
591}
592
593
594
595#endif
596
597// ----------------------------------------------------------------------------
598// Copyright 2020 Bloomberg Finance L.P.
599//
600// Licensed under the Apache License, Version 2.0 (the "License");
601// you may not use this file except in compliance with the License.
602// You may obtain a copy of the License at
603//
604// http://www.apache.org/licenses/LICENSE-2.0
605//
606// Unless required by applicable law or agreed to in writing, software
607// distributed under the License is distributed on an "AS IS" BASIS,
608// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
609// See the License for the specific language governing permissions and
610// limitations under the License.
611// ----------------------------- END-OF-FILE ----------------------------------
612
613/** @} */
614/** @} */
615/** @} */
Definition bdld_datum.h:787
static Datum createNull()
Return, by value, a datum having no value.
Definition bdld_datum.h:3887
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
static void destroy(const Datum &value, const AllocatorType &allocator)
Datum clone(const AllocatorType &allocator) const
Definition bdld_manageddatum.h:266
~ManagedDatum()
Definition bdld_manageddatum.h:463
void swap(ManagedDatum &other)
Definition bdld_manageddatum.h:507
ManagedDatum()
Definition bdld_manageddatum.h:434
void adopt(const Datum &obj)
Definition bdld_manageddatum.h:478
bslma::Allocator * allocator() const
Definition bdld_manageddatum.h:537
BSLMF_NESTED_TRAIT_DECLARATION(ManagedDatum, bslmf::IsBitwiseMoveable)
'ManagedDatum' objects are allocator-aware and bitwise movable.
const Datum * operator->() const
Definition bdld_manageddatum.h:517
const Datum & datum() const
Definition bdld_manageddatum.h:529
void makeNull()
Definition bdld_manageddatum.h:493
bsl::allocator allocator_type
Definition bdld_manageddatum.h:270
Datum release()
Definition bdld_manageddatum.h:499
void clone(const Datum &value)
Definition bdld_manageddatum.h:486
allocator_type get_allocator() const
Definition bdld_manageddatum.h:543
const Datum & operator*() const
Definition bdld_manageddatum.h:523
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
Definition bdld_manageddatum.h:549
ManagedDatum & operator=(const ManagedDatum &rhs)
Definition bdld_manageddatum.h:470
Definition bslma_bslallocator.h:580
BloombergLP::bslma::Allocator * mechanism() const
Definition bslma_bslallocator.h:1126
Definition bslma_allocator.h:457
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdld_datum.h:730
bsl::ostream & operator<<(bsl::ostream &stream, const Datum &rhs)
bool operator==(const Datum &lhs, const Datum &rhs)
void swap(ManagedDatum &a, ManagedDatum &b)
bool operator!=(const Datum &lhs, const Datum &rhs)
Definition bslmf_isbitwisemoveable.h:718