Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlb_arrayutil
[Package bdlb]

Provide utilities to determine properties of fixed-sized arrays. More...

Namespaces

namespace  bdlb

Detailed Description

Outline
Purpose:
Provide utilities to determine properties of fixed-sized arrays.
Classes:
bdlb::ArrayUtil namespace for array access function templates
Macros:
BDLB_ARRAYUTIL_SIZE get a constant expression with an array's length.
BDLB_ARRAYUTIL_LENGTH get a constant expression with an array's length.
Description:
This component provides a utility struct, bdlb::ArrayUtil, that serves as a namespace for a collection of function templates providing access to the length and iterators of statically sized built-in arrays.
The basic idea is that the compiler knows the length of statically sized arrays and the corresponding information can be exposed using simple function templates. The use of these function templates is easier and safer than the alternatives like use of sizeof (turning the array into a pointer doesn't cause the use of sizeof to fail at compile-time but it yields a wrong result) or manually specifying the length of an array.
Usage:
This section illustrates intended use of this component.
Example 1: Basic Syntax:
When creating a sequence of values it is often easy to write the sequence as an initialized array and use this array to initialize a container. Since the array's length may be changed as the program is maintained, the code using the array should automatically determine the array's length or automatically determine iterators to the beginning and the end of the array.
For example, to initialize a bsl::vector<int> with the first few prime numbers stored in an array the following code uses the begin and end methods of bdlb::ArrayUtil:
  void usePrimes(bool verbose)
  {
      if (verbose) cout << "\n" << "'usePrimes'" << "\n"
                                << "===========" << "\n";

      const int        primes[] = { 2, 3, 5, 7, 11, 13, 17 };
      bsl::vector<int> values(bdlb::ArrayUtil::begin(primes),
                              bdlb::ArrayUtil::end(primes));

      assert(values.size() == bdlb::ArrayUtil::size(primes));
Notice that, after constructing values with the content of the array primes the assertion verifies that the correct number of values is stored in values.
When the length is needed as a constant expression, e.g., to use it for the length of another array, the macro BDLB_ARRAYUTIL_LENGTH(array) can be used:
      int reversePrimes[BDLB_ARRAYUTIL_SIZE(primes)];

      bsl::copy(values.rbegin(),
                values.rend(),
                bdlb::ArrayUtil::begin(reversePrimes));

      assert(bsl::mismatch(bdlb::ArrayUtil::rbegin(primes),
                           bdlb::ArrayUtil::rend(primes),
                           bdlb::ArrayUtil::begin(reversePrimes)).second
             == bdlb::ArrayUtil::end(reversePrimes));
  }
After defining the array reversePrimes with the same length as primes the elements of values are copied in reverse order into this array. The assertion verifies that reversePrimes contains the values from primes but in reverse order: bsl::mismatch is used with a reverse sequence of primes by using the rbegin and rend methods for primes and normal sequence using the begin and end methods for reversePrimes.
Example 2: Use with Database Interfaces:
The functions begin, end, and size provided by this component are similar to functions provided by containers. The main difference is that they reside in a utility component rather than being member functions.
A typical use case for the size function is a function expecting a pointer to a sequence of keys (e.g., columns in a database) and the number of the keys in the sequence:
  void query(bsl::string       *result,
             const bsl::string *columns,
             int                numberOfColumns)
  {

      // Query the database....

  }

  void loadData(bsl::vector<bsl::string> *data)
  {
      const bsl::string columns[] = { "column1", "column2", "column3" };
      bsl::string       result[BDLB_ARRAYUTIL_SIZE(columns)];

      query(result, columns, bdlb::ArrayUtil::size(columns));
      data->assign(bdlb::ArrayUtil::begin(result),
                   bdlb::ArrayUtil::end(result));
  }
The loadData function shows how to use the different function templates. The array columns doesn't have a length specified. It is determined from the number of elements it is initialized with. In this case it is easy to see that there are three elements but in real situations the number of elements can be non-trivial to get right. Also, changing the number of elements would make it necessary to apply the corresponding change in multiple places. Thus, the length is determined using bdlb::ArrayUtil:
  • The length of result should match the length of columns. When specifying the length of an array a constant expression is necessary. In C++ 2011 the function bdlb::ArrayUtil::size could return a constant expression but compilers not, yet, implementing the standard a trick must be used (using sizeof with a reference to suitably sized array of char). This trick is packaged into the macro BDLB_ARRAYUTIL_SIZE().
  • When the length is needed in a context where a const expression is not required, e.g., when calling query, the `bdlbArrayUtil::size' function can be used with the array.
  • The bdlb::ArrayUtil::begin and bdlb::ArrayUtil::end functions are used to obtain begin and end iterators used with the vector's assign function to put the result obtained from the call to query into the vector pointed to by data.
Similar needs for an array of a sequence of values frequently arise when using one of the database interfaces.
Another common use case are test cases where the content of a computed sequence must be compared with an expected result:
  void checkData(const bsl::vector<bsl::string>& data)
  {
      const bsl::string expect[] = {
                                       // ...
                                   };
      assert(data.size() == bdlb::ArrayUtil::size(expect));
      assert(bdlb::ArrayUtil::end(expect)
          == bsl::mismatch(bdlb::ArrayUtil::begin(expect),
                           bdlb::ArrayUtil::end(expect),
                           data.begin()).first);
  }
In the code below the actual result in data is compared to the values in the array expect:
  1. We make sure that the lengths of data and expect are identical using bdlb::ArrayUtil::size.
  2. The sequences are compared using the mismatch algorithm: To get the begin and of the expect array bdlb::ArrayUtil::begin and bdlb::ArrayUtil::end, respectively, are used.
  void getAndCheckData(bool verbose)
  {
      if (verbose) cout << "\n" << "'getAndCheckData'" << "\n"
                                << "=================" << "\n";
      bsl::vector<bsl::string> data;
      loadData(&data);
      checkData(data);
  }