Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdld_manageddatum
[Package bdld]

Provide a smart-pointer-like manager for a Datum object. More...

Namespaces

namespace  bdld

Detailed Description

Outline
Purpose:
Provide a smart-pointer-like manager for a Datum object.
Classes:
bdld::ManagedDatum a smart-pointer-like manager for a Datum object
See also:
Component bdld_datum
Description:
This component implements a type, bdld::ManagedDatum, that provides two important services for Datum objects:
  1. ManagedDatum provides value-semantic-like operations for Datum.
  2. ManagedDatum is a resource manager, similar to a smart pointer, for Datum.
These services allow clients to use a ManagedDatum object in most contexts where an object of a value-semantic type can be used (passed by value, stored in containers, and so on), even though ManagedDatum is not strictly value-semantic. These services are explored in subsequent sections.
The Datum type maintained by a ManagedDatum provides a space-efficient discriminated union (i.e., a variant) holding the value of a scalar type (e.g., int, double, string) or an aggregate of other Datum objects. See bdld_datum for more details.
Value Semantics:
ManagedDatum, while not strictly a value-semantic type, provides the full set of value-semantic-like operations for Datum (see bsldoc_glossary|Value-Semantic Operations):
  • Equality and Non-Equality Comparisons
  • Copy Construction
  • Copy Assignment
  • Default Construction
  • ostream Printing
In other words, the syntax of ManagedDatum is regular, but not all of its copy behavior is value-semantic. Specifically, for User Defined Types (i.e., those that bdld::Datum::clone does not deep-copy) ManagedDatum performs a shallow copy (copying the reference rather than the value), which is inconsistent with value-semantics. For all other types ManagedDatum copy operations (copy construction, copy assignment, and non-member swap when the allocators differ) will deep-copy the value using 'Datumclone, which creates a completely independent copy, with independent lifetime, by duplicating all data, even referenced data (except for UDTs).
Note that a default constructed ManagedDatum, or a ManagedDatum on which release has been called, will have the null Datum value.
Resource Management:
A Datum object's relationship to memory can be seen as analogous to a raw pointer, requiring calls to static functions Datum::create* and Datum::destroy to initialize and release resources (see the bdld_datum component documentation). A ManagedDatum, by extension, provides a resource manager for a Datum that is analogous to a smart pointer.
The adopt method of a ManagedDatum is used to take ownership of a supplied Datum object, after which point the ManagedDatum object's destructor will free the resources of the managed Datum (unless release is subsequently called). Similar to a smart pointer, a ManagedDatum provides dereference operators to access the Datum object under management.
Usage:
This section illustrates intended use of this component.
Example 1: Basic Use of bdld::ManagedDatum:
This example demonstrates the basic construction and manipulation of a ManagedDatum object.
First, we create a ManagedDatum object that manages a Datum holding a double and verify that the managed object has the expected type and value:
  bslma::TestAllocator ta("test", veryVeryVerbose);

  const ManagedDatum realObj(Datum::createDouble(-3.4375), &ta);

  assert(realObj->isDouble());
  assert(-3.4375 == realObj->theDouble());
Next, we create a ManagedDatum object that holds a string and again verify that it has the expected type and value:
  const char         *str = "This is a string";
  const ManagedDatum  strObj(Datum::copyString(str, &ta), &ta);

  assert(strObj->isString());
  assert(str == strObj->theString());
Then, we assign this ManagedDatum object to another object and verify both objects have the same value:
  ManagedDatum strObj1(&ta);
  strObj1 = strObj;
  assert(strObj == strObj1);
Next, copy-construct this ManagedDatum object and verify that the copy has the same value as the original:
  const ManagedDatum strObj2(strObj, &ta);
  assert(strObj == strObj2);
Then, we create a ManagedDatum object that holds an opaque pointer to a bdlt::Date object and verify that the managed Date has the expected value:
  bdlt::Date   udt;
  ManagedDatum udtObj(Datum::createUdt(&udt, UDT_TYPE), &ta);

  assert(udtObj->isUdt());
  assert(&udt == udtObj->theUdt().data());
  assert(UDT_TYPE == udtObj->theUdt().type());
Next, we assign a boolean value to this ManagedDatum object and verify that it has the new type and value:
  udtObj.adopt(Datum::createBoolean(true));
  assert(udtObj->isBoolean());
  assert(true == udtObj->theBoolean());
Then, we create a ManagedDatum object having an array and verify that it has the same array value. Note that in practice we would use bdld_datumarraybuilder, but do not do so here for dependency reasons:
  const Datum datumArray[2] = {
      Datum::createInteger(12),
      Datum::copyString("A long string", &ta)
  };

  DatumMutableArrayRef arr;
  Datum::createUninitializedArray(&arr, 2, &ta);
  for (int i = 0; i < 2; ++i) {
      arr.data()[i] = datumArray[i];
  }
  *(arr.length()) = 2;
  const ManagedDatum arrayObj(Datum::adoptArray(arr), &ta);

  assert(arrayObj->isArray());
  assert(DatumArrayRef(datumArray, 2) == arrayObj->theArray());
Next, we create a ManagedDatum object having a map and verify that it has the same map value. Note that in practice we would use bdld_datummapbuilder, but do not do so here to for dependency reasons.
  const DatumMapEntry datumMap[2] = {
      DatumMapEntry(StringRef("first", static_cast<int>(strlen("first"))),
                    Datum::createInteger(12)),
      DatumMapEntry(StringRef("second", static_cast<int>(strlen("second"))),
                    Datum::copyString("A very long string", &ta))
  };

  DatumMutableMapRef mp;
  Datum::createUninitializedMap(&mp, 2, &ta);
  for (int i = 0; i < 2; ++i) {
      mp.data()[i] = datumMap[i];
  }
  *(mp.size()) = 2;
  const ManagedDatum mapObj(Datum::adoptMap(mp), &ta);

  assert(mapObj->isMap());
  assert(DatumMapRef(datumMap, 2, false, false) == mapObj->theMap());
Then, we create a Datum object and assign its ownership to a ManagedDatum object and verify that the ownership was transferred:
  const Datum  rcObj = Datum::copyString("This is a string", &ta);
  ManagedDatum obj(Datum::createInteger(1), &ta);
  obj.adopt(rcObj);
  assert(obj.datum() == rcObj);
Next, we release the Datum object managed by obj and verify that it was released:
  const Datum internalObj = obj.release();
  assert(obj->isNull());
  assert(internalObj == rcObj);
Finally, we destroy the released Datum object:
  Datum::destroy(internalObj, obj.get_allocator().mechanism());