Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdld_datumarraybuilder
[Package bdld]

Provide a utility to build a Datum object holding an array. More...

Namespaces

namespace  bdld

Detailed Description

Outline
Purpose:
Provide a utility to build a Datum object holding an array.
Classes:
bdld::DatumArrayBuilder utility to build a Datum object holding an array
See also:
Component bdld_datum
Description:
This component defines a mechanism, bdld::DatumArrayBuilder, used to populate a Datum array value in an exception-safe manner. In addition to providing exception safety, a DatumArrayBuilder is particularly useful when the length of the array to be constructed is not known in advance. The user can append elements to the datum array as needed, and when there are no more elements to append the user calls commit and ownership of the populated Datum object is transferred to the caller. After the call to commit, no additional elements can be appended to the Datum array value.
Usage:
This section illustrates intended use of this component.
Example 1: Using a DatumArrayBuilder to Create a Datum array.:
Suppose we receive a string that is constructed by streaming a bunch of values together in the format shown below:
  "2.34,4,hi there,true"
Notice that the values are separated by a ,. Also note that a , is not allowed to be part of a string value to simplify the implementation of the utility that parses this string. The following code snippets illustrate how to create a Datum object that holds an array of Datum objects constructed using the streamed values.
First we define a function nextValue that we will use to tokenize the input string:
  bsl::size_t nextValue(bsl::string *value, const bsl::string& input)
      // Extract the next value from a list of comma separated values in the
      // specified 'input' string and load it in the specified 'value'.
      // Return the index of the next value within 'input'.
  {
      if (input.empty()) {
          return bsl::string::npos;
      }
      int start = 0;
      bsl::size_t nextIndex = input.find(',', start);
      if (bsl::string::npos != nextIndex) {
          *value = input.substr(start, nextIndex - start);
      }
      else {
          *value = input.substr(start);
      }
      return nextIndex;
  }
Next, we define a function convertToDatum that will convert a string token into a Datum scalar value:
  bdld::Datum convertToDatum(const bsl::string&  token,
                             bslma::Allocator   *basicAllocator)
      // Convert the specified 'token' into the appropriate type of scalar
      // value and then create and return a 'Datum' object using that value.
      // Use the specified 'basicAllocator' to supply memory.
  {
      bool isInteger = true;
      bool isDouble = false;
      bool isBoolean = false;
      for (bsl::size_t i = 0; i < token.size(); ++i) {
          if (!isdigit(token[i])) {
              if ('.' == token[i] && !isDouble) {
                  isDouble = true;
                  isInteger = false;
                  continue;
              }
              isInteger = false;
              isDouble = false;
              break;
          }
      }

      if (!isInteger && !isDouble) {
          if ("true" == token || "false" == token) {
              isBoolean = true;
          }
      }

      if (isInteger) { // integer token
          return bdld::Datum::createInteger(atoi(token.c_str()));
      }
      else if (isDouble) { // double token
          return bdld::Datum::createDouble(atof(token.c_str()));
      }
      else if (isBoolean) { // boolean token
          return bdld::Datum::createBoolean("true" == token ? true : false);
      }
      else { // string value
          return bdld::Datum::copyString(token, basicAllocator);
      }
  }
Now, in our example main, we tokenize an input string "2.34,4,hi there,true" to populate a Datum array containing the values '[2.34, 4, "hi there", true]':
  void exampleMain() {
      bslma::TestAllocator allocator;
      const bsl::string    input("2.34,4,hi there,true", &allocator);
Here, we create a DatumArrayBuilder, and iterate over the parsed tokens from input, using pushBack on the array builder to add the tokens to a Datum array value:
      bdld::DatumArrayBuilder builder(0, &allocator);

      bsl::string str(input, &allocator);

      bsl::string value;
      bsl::size_t nextIndex;
      do {
          nextIndex = nextValue(&value, str);
          builder.pushBack(convertToDatum(value, &allocator));
          if (bsl::string::npos == nextIndex) {
              break;
          }
          str = str.substr(nextIndex + 1);
      } while (bsl::string::npos != nextIndex);

      bdld::Datum result = builder.commit();
Notice that calling commit on the DatumArrayBuilder adopts ownership for the returned Datum object, and that the behavior is undefined if pushBack is called after commit.
Finally, we verify that result has the expected array value, and destroy the created Datum value:
      assert(true       == result.isArray());
      assert(4          == result.theArray().length());
      assert(true       == result.theArray()[0].isDouble());
      assert(2.34       == result.theArray()[0].theDouble());
      assert(true       == result.theArray()[1].isInteger());
      assert(4          == result.theArray()[1].theInteger());
      assert(true       == result.theArray()[2].isString());
      assert("hi there" == result.theArray()[2].theString());
      assert(true       == result.theArray()[3].isBoolean());
      assert(true       == result.theArray()[3].theBoolean());

      // Destroy the 'Datum' object.
      bdld::Datum::destroy(result, &allocator);
  }