// bdlb_arrayutil.h                                                   -*-C++-*-
#ifndef INCLUDED_BDLB_ARRAYUTIL
#define INCLUDED_BDLB_ARRAYUTIL
#  include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@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':
//
//: o 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()'.
//:
//: o When the length is needed in a context where a 'const' expression is not
//:   required, e.g., when calling 'query', the `bdlb::ArrayUtil::size'
//:   function can be used with the array.
//:
//: o 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);
//  }
//..

#include <bdlscm_version.h>

#include <bsl_iterator.h>
#include <bsl_cstddef.h>

#define BDLB_ARRAYUTIL_SIZE(a) sizeof(BloombergLP::bdlb::ArrayUtil::sizer(a))
    // Return the number of elements in the passed array 'a' as a constant
    // expression.

#define BDLB_ARRAYUTIL_LENGTH(a) sizeof(BloombergLP::bdlb::ArrayUtil::sizer(a))
    // Return the number of elements in the passed array 'a' as a constant
    // expression.

namespace BloombergLP {
namespace bdlb {
                            // ====================
                            // struct bdeuArrayUtil
                            // ====================

struct ArrayUtil {
    // This 'struct' provides a namespace for a collection of function
    // templates providing access to the length and iterators of statically
    // sized built-in arrays

    // CLASS METHODS

                      // ** iterators **

    template <class TYPE, bsl::size_t LENGTH>
    static TYPE *begin(TYPE (&array)[LENGTH]);
        // Return an iterator pointing to the first element of the specified
        // 'array' of template parameter 'LENGTH' elements of template
        // parameter 'TYPE'.

    template <class TYPE, bsl::size_t LENGTH>
    static TYPE *end(TYPE (&array)[LENGTH]);
        // Return the past-the-end iterator for the specified 'array' of
        // template parameter 'LENGTH' elements of template parameter 'TYPE'.

    template <class TYPE, bsl::size_t LENGTH>
    static bsl::reverse_iterator<TYPE *> rbegin(TYPE (&array)[LENGTH]);
        // Return a reverse iterator pointing to the last element of the
        // specified 'array' of template parameter 'LENGTH' elements of
        // template parameter 'TYPE'.

    template <class TYPE, bsl::size_t LENGTH>
    static bsl::reverse_iterator<TYPE *> rend(TYPE (&array)[LENGTH]);
        // Return the past-the-end reverse iterator for the specified 'array'
        // of template parameter 'LENGTH' elements of template parameter
        // 'TYPE'.

                      // ** size and length **

    template <class TYPE, bsl::size_t LENGTH>
    static bsl::size_t length(TYPE (&array)[LENGTH]);
        // Return the number of elements in the specified 'array' of template
        // parameter 'LENGTH' elements of template parameter 'TYPE'.  This
        // method is synonymous with the 'size' method.

    template <class TYPE, bsl::size_t LENGTH>
    static bsl::size_t size(TYPE (&array)[LENGTH]);
        // Return the number of elements in the specified 'array' of template
        // parameter 'LENGTH' elements of template parameter 'TYPE'.  This
        // method is synonymous with the 'length' method.

    template <class TYPE, bsl::size_t LENGTH>
    static char (&sizer(TYPE (&array)[LENGTH]))[LENGTH];
        // Return a reference to an array of 'char's with the same number of
        // elements as the specified 'array' of template parameter 'LENGTH'
        // elements of template parameter 'TYPE'.  This function is *not*
        // implemented and can only be used in a non-evaluated context.  The
        // function is used together with 'sizeof' to obtain a constant
        // expression with the 'LENGTH' of the 'array'.  See
        // 'BDLB_ARRAYUTIL_SIZE' and 'BDLB_ARRAYUTIL_LENGTH'.
};

// ============================================================================
//                 INLINE AND TEMPLATE FUNCTION DEFINITIONS
// ============================================================================

                            // --------------------
                            // struct bdeuArrayUtil
                            // --------------------

// CLASS METHODS

                      // ** iterators **

template <class TYPE, bsl::size_t LENGTH>
inline
TYPE *ArrayUtil::begin(TYPE (&array)[LENGTH])
{
    return array;
}

template <class TYPE, bsl::size_t LENGTH>
inline
TYPE *ArrayUtil::end(TYPE (&array)[LENGTH])
{
    return array + LENGTH;
}

template <class TYPE, bsl::size_t LENGTH>
inline
bsl::reverse_iterator<TYPE *> ArrayUtil::rbegin(TYPE (&array)[LENGTH])
{
    return bsl::reverse_iterator<TYPE *>(end(array));
}

template <class TYPE, bsl::size_t LENGTH>
inline
bsl::reverse_iterator<TYPE *> ArrayUtil::rend(TYPE (&array)[LENGTH])
{
    return bsl::reverse_iterator<TYPE *>(begin(array));
}

                      // ** size and length **

template <class TYPE, bsl::size_t LENGTH>
inline
bsl::size_t ArrayUtil::length(TYPE (&)[LENGTH])
{
    return LENGTH;
}

template <class TYPE, bsl::size_t LENGTH>
inline
bsl::size_t ArrayUtil::size(TYPE (&)[LENGTH])
{
    return LENGTH;
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------