// bdlat_arrayfunctions.h                                             -*-C++-*-
#ifndef INCLUDED_BDLAT_ARRAYFUNCTIONS
#define INCLUDED_BDLAT_ARRAYFUNCTIONS

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a namespace defining "array" functions.
//
//@CLASSES:
//  bdlat_ArrayFunctions: namespace for calling "array" functions
//
//@DESCRIPTION: The `bdlat_ArrayFunctions` `namespace` provided in this
// component defines parameterized functions that expose "array" behavior for
// "array" types.  See the `bdlat` package-level documentation for a brief
// description of "array" types.
//
// The functions in this namespace allow users to:
// * obtain the number of elements in an array (`size`).
// * set the number of elements in an array (`resize`).
// * manipulate an element in an array using a parameterized manipulator
//   (`manipulateElement`).
// * access an element in an array using a parameterized accessor
//   (`accessElement`).
//
// Also, if supported by the array type, reserve capacity for a number of
// elements in an array (`reserve`) and whether reserve capacity is supported
// (`supportsReserve`).  If not supported, the default implementations return
// non-zero (failure) for `reserve` and `false` for `supportsReserve`.
//
// A type becomes part of the `bdlat` "array" framework by creating, in the
// namespace where the type is defined, overloads of the following two (free)
// functions and two (free) function templates.  Note that the placeholder
// `YOUR_TYPE` is not a template argument and should be replaced with the name
// of the type being plugged into the framework.
// ```
// // MANIPULATORS
//
// /// Invoke the specified `manipulator` on the address of the element at
// /// the specified `index` of the specified `array`.  The supplied
// /// `manipulator` must be a callable type that can be called as if it had
// /// the following signature:
// /// ```
// /// int manipulator(ELEMENT_TYPE *element);
// /// ```
// /// Return the value from the invocation of `manipulator`.  The behavior is
// /// undefined unless `0 <= index` and `index < bdlat_arraySize(*array)`.
// template <class MANIPULATOR>
// int bdlat_arrayManipulateElement(YOUR_TYPE    *array,
//                                  MANIPULATOR&  manipulator,
//                                  int           index);
//
// /// Set the size of the specified modifiable `array` to the specified
// /// `newSize`.  If `newSize > bdlat_arraySize(*array)`, then
// /// `newSize - bdlat_arraySize(*array)` elements with default values
// /// (i.e., `ElementType()`) are appended to `array`.  If
// /// `newSize < bdlat_arraySize(*array)`, then the
// /// `bdlat_arraySize(*array) - newSize` elements at the end of `array`
// /// are destroyed.  The behavior is undefined unless `0 <= newSize`.
// void bdlat_arrayResize(YOUR_TYPE *array, int newSize);
//
// // ACCESSORS
//
// /// Invoke the specified `accessor` on a `const`-reference to the element at
// /// the specified `index` of the specified `array`.  The supplied `accessor`
// /// must be a callable type that can be called as if it had the following
// /// signature:
// /// ```
// /// int accessor(const ELEMENT_TYPE& element);
// /// ```
// /// Return the value from the invocation of `accessor`.  The behavior is
// /// undefined unless `0 <= index` and `index < bdlat_arraySize(array)`.
// template <class ACCESSOR>
// int bdlat_arrayAccessElement(const YOUR_TYPE& array,
//                              ACCESSOR&        accessor,
//                              int              index);
//
// /// Return the number of elements in the specified `array`.
// bsl::size_t bdlat_arraySize(const YOUR_TYPE& array);
// ```
//
// The "array" type must also define two meta-functions in the
// `bdlat_ArrayFunctions` namespace:
//
// * the meta-function `IsArray` contains a compile-time constant `value` that
//   is non-zero if the parameterized `TYPE` exposes "array" behavior.
// * the `ElementType` meta-function contains a `typedef` `Type` that
//   specifies the type of the element stored in the parameterized "array"
//   type.
//
// The two optional methods for reserving capacity:
// ```
// /// If successful, make the capacity of the specified modifiable `array` at
// /// least the specified `numElements` and return zero.  If unsuccessful or
// /// unsupported, return a non-zero value.  This method has no effect, and
// /// returns zero, if the current capacity meets or exceeds the required
// /// capacity.  The behavior is undefined unless `0 <= numElements`.
// int bdlat_arrayReserve(YOUR_TYPE *array, int numElements);
//
// /// Return `true` if `bdlat_arrayReserve` will attempt to reserve capacity
// /// in the specified `array`, and `false` otherwise.
// bool bdlat_arraySupportsReserve(const YOUR_TYPE& array);
// ```
//
// Note that `bsl::vector<TYPE>` is already part of the `bdlat`
// infrastructure for "array" types because this component also provides
// overloads of the required functions and meta-function specializations.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Defining an "Array" Type
///- - - - - - - - - - - - - - - - - -
// Suppose you had a type, `mine::MyIntArray`, that provides the essential
// features of an "array" type.
// ```
// namespace BloombergLP {
// namespace mine {
//
// class MyIntArray {
//
//     int         *d_data_p;
//     bsl::size_t  d_size;
//
//   public:
//     // CREATORS
//     MyIntArray()
//     : d_data_p(0)
//     , d_size(0)
//     {
//     }
//
//     ~MyIntArray()
//     {
//         bsl::free(d_data_p);
//     }
//
//     // MANIPULATORS
//     void resize(bsl::size_t newSize);
//
//     int& value(bsl::size_t index)
//     {
//         assert(index < d_size);
//
//         return d_data_p[index];
//     }
//
//     // ACCESSORS
//     const int& value(bsl::size_t index) const
//     {
//         assert(index < d_size);
//
//         return d_data_p[index];
//     }
//
//     bsl::size_t size() const
//     {
//         return d_size;
//     }
// };
//
// void MyIntArray::resize(bsl::size_t newSize)
// {
//     // Always match buffer to size exactly.
//
//     if (d_size == newSize) {
//         return;                                                   // RETURN
//     }
//
//     int *newData = static_cast<int *>(bsl::malloc(sizeof(int)
//                                                 * newSize));
//     if (d_size < newSize) {
//         if (d_data_p) {
//             bsl::memcpy(newData, d_data_p, d_size * sizeof(int));
//         }
//         std::memset(newData + d_size,
//                     0,
//                     (newSize - d_size) * sizeof(int));
//
//     } else {
//         bsl::memcpy(newData, d_data_p, newSize);
//     }
//
//     bsl::free(d_data_p);
//     d_data_p = newData;
//     d_size   = newSize;
// }
//
// }  // close namespace mine
// }  // close enterprise namespace
// ```
//
// We can now make `mine::MyIntArray` expose "array" behavior by implementing
// the necessary `bdlat_ArrayFunctions` for `MyIntArray` inside the `mine`
// namespace and defining the required meta-functions withing the
// `bdlat_ArrayFunctions` namespace.
//
// First, we should forward declare all the functions that we will implement
// inside the `mine` namespace:
// ```
// namespace BloombergLP {
// namespace mine {
//
// // MANIPULATORS
//
// /// Invoke the specified `manipulator` on the address of the element at
// /// the specified `index` of the specified `array`.  Return the value
// /// from the invocation of `manipulator`.  The behavior is undefined
// /// unless `0 <= index` and `index < bdlat_arraySize(*array)`.
// template <class MANIPULATOR>
// int bdlat_arrayManipulateElement(MyIntArray   *array,
//                                  MANIPULATOR&  manipulator,
//                                  int           index);
//
// /// Set the size of the specified modifiable `array` to the specified
// /// `newSize`.  If `newSize > bdlat_arraySize(*array)`, then
// /// `newSize - bdlat_arraySize(*array)` elements with default values
// /// (i.e., `ElementType()`) are appended to `array`.  If
// /// `newSize < bdlat_arraySize(*array)`, then the
// /// `bdlat_arraySize(*array) - newSize` elements at the end of `array`
// /// are destroyed.  The behavior is undefined unless `0 <= newSize`.
// void bdlat_arrayResize(MyIntArray *array, int newSize);
//
// // ACCESSORS
//
// /// Invoke the specified `accessor` on a `const`-reference to the
// /// element at the specified `index` of the specified `array`.  Return
// /// the value from the invocation of `accessor`.  The behavior is
// /// undefined unless `0 <= index` and `index < bdlat_arraySize(array)`.
// template <class ACCESSOR>
// int bdlat_arrayAccessElement(const MyIntArray& array,
//                              ACCESSOR&         accessor,
//                              int               index);
//
// /// Return the number of elements in the specified `array`.
// bsl::size_t bdlat_arraySize(const MyIntArray& array);
//
// }  // close namespace mine
// }  // close enterprise namespace
// ```
//
// Then, we will implement these functions.  Recall that the two (non-template)
// functions should be defined in some `.cpp` file, unless you choose to make
// them `inline` functions.
// ```
// namespace BloombergLP {
// namespace mine {
//
// // MANIPULATORS
// template <class MANIPULATOR>
// int bdlat_arrayManipulateElement(MyIntArray   *array,
//                                  MANIPULATOR&  manipulator,
//                                  int           index)
// {
//     assert(array);
//     assert(0 <= index);
//     assert(static_cast<bsl::size_t>(index) < array->size());
//
//     return manipulator(&array->value(index));
// }
//
// void bdlat_arrayResize(MyIntArray *array, int newSize)
// {
//     assert(array);
//     assert(0 <= newSize);
//
//     array->resize(newSize);
// }
//
// // ACCESSORS
// template <class ACCESSOR>
// int bdlat_arrayAccessElement(const MyIntArray& array,
//                              ACCESSOR&         accessor,
//                              int               index)
// {
//     assert(0 <= index);
//     assert(static_cast<bsl::size_t>(index) < array.size());
//
//     return accessor(array.value(index));
// }
//
// bsl::size_t bdlat_arraySize(const MyIntArray& array)
// {
//     return array.size();
// }
//
// }  // close namespace mine
// }  // close enterprise namespace
// ```
// Finally, we specialize the `IsArray` and `ElementType` meta-functions
// in the `bdlat_ArrayFunctions` namespace for the
// `mine::MyIntArray` type:
// ```
// namespace BloombergLP {
// namespace bdlat_ArrayFunctions {
//
// // TRAITS
// template <>
// struct IsArray<mine::MyIntArray> : bsl::true_type {
// };
//
// template <>
// struct ElementType<mine::MyIntArray> {
//     typedef int Type;
// };
//
// }  // close namespace bdlat_ArrayFunctions
// }  // close enterprise namespace
// ```
//
// This completes the `bdlat` infrastructure for `mine::MyIntArray` and
// allows the generic software to recognize the type as an array abstraction.
//
///Example 2: Using the Infrastructure Via General Methods
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The `bdlat` "array" framework provides a set of fundamental operations
// common to any "array" type.  We can build upon these operations to make our
// own utilities, or use them on our own types that are plugged into the
// framework, like `mine::MyIntArray`, which we created in {Example 1}.  For
// example, we can use the (fundamental) operations in the
// `bdlat_ArrayFunctions` namespace to operate on `mine::MyIntArray`, even
// though they have no knowledge of that type in particular:
// ```
// void usageMakeArray()
// {
//     BSLMF_ASSERT(bdlat_ArrayFunctions::IsArray<mine::MyIntArray>::value);
//
//     mine::MyIntArray array;
//     assert(0 == bdlat_ArrayFunctions::size(array));
//
//     bdlat_ArrayFunctions::resize(&array, 8);
//     assert(8 == bdlat_ArrayFunctions::size(array));
//
//     bdlat_ArrayFunctions::resize(&array, 4);
//     assert(4 == bdlat_ArrayFunctions::size(array));
// }
// ```
// To perform operations on the elements of an array requires use of the
// functions that employ accessor and manipulator functors.  For example:
// ```
// template <class ELEMENT_TYPE>
// class GetElementAccessor {
//
//     // DATA
//     ELEMENT_TYPE *d_element_p;
//
//   public:
//     // CREATORS
//     explicit GetElementAccessor(ELEMENT_TYPE *value)
//     : d_element_p(value)
//     {
//     }
//
//     // MANIPULATORS
//     int operator()(const ELEMENT_TYPE& elementValue)
//     {
//         *d_element_p = elementValue;
//         return 0;
//     }
// };
//
// template<class ELEMENT_TYPE>
// class SetElementManipulator {
//
//     // DATA
//     ELEMENT_TYPE d_value;
//
//   public:
//     // CREATORS
//     SetElementManipulator(const ELEMENT_TYPE& value)
//     : d_value(value)
//     {
//     }
//
//     // ACCESSOR
//     int operator()(ELEMENT_TYPE *element) const
//     {
//         *element = d_value;
//         return 0;
//     }
// };
// ```
// Notice that these functors make few assumptions of `ELEMENT_TYPE`, merely
// that it is copy constructable and copy assignable.
//
// With these definitions we can now use the generic functions to set and
// get values from an `mine::MyIntArray` object:
// ```
// void usageArrayElements()
// {
//     mine::MyIntArray array;
//     bdlat_ArrayFunctions::resize(&array, 4);
//
//     // Confirm initial array elements from resize.
//
//     int                     value;
//     GetElementAccessor<int> accessor(&value);
//
//     for (int index = 0; index < 4; ++index) {
//         int rc = bdlat_ArrayFunctions::accessElement(array,
//                                                      accessor,
//                                                      index);
//         assert(0 == rc);
//         assert(0 == value)
//     }
//
//     // Set element `index * 10` as its value.
//
//     for (int index = 0; index < 4; ++index) {
//         SetElementManipulator<int> manipulator(index * 10);
//
//         int rc = bdlat_ArrayFunctions::manipulateElement(&array,
//                                                          manipulator,
//                                                          index);
//         assert(0 == rc);
//     }
//
//     // Confirm new value of each element.
//
//     for (int index = 0; index < 4; ++index) {
//         int rc = bdlat_ArrayFunctions::accessElement(array,
//                                                      accessor,
//                                                      index);
//         assert(0          == rc);
//         assert(index * 10 == value);
//     }
// }
// ```
//
///Example 3: Defining Utility Functions
///- - - - - - - - - - - - - - - - - - -
// Creating functor objects for each operation can be tedious and error prone;
// consequently, those types are often executed via utility functions.
//
// Suppose we want to create utilities for getting and setting the elements of
// an arbitrary "array" type.  We might define a utility `struct`, `ArrayUtil`,
// a namespace for those functions:
// ```
// struct ArrayUtil {
//
//     // CLASS METHODS
//
//     /// Load to the specified `value` the element at the specified
//     /// `index` of the specified `object` array.  Return 0 if the
//     /// element is successfully loaded to `value`, and a non-zero value
//     /// otherwise.  This function template requires that the specified
//     /// `ARRAY_TYPE` is a `bdlat` "array" type.  The behavior is
//     /// undefined unless `0 <= index` and
//     /// `index < bdlat_ArrayFunctions::size(object)`.
//     template <class ARRAY_TYPE>
//     static int getElement(typename bdlat_ArrayFunctions
//                                    ::ElementType<ARRAY_TYPE>::Type *value,
//                         const ARRAY_TYPE&                           object,
//                         int                                         index)
//     {
//         BSLMF_ASSERT(bdlat_ArrayFunctions::IsArray<ARRAY_TYPE>::value);
//
//         typedef typename bdlat_ArrayFunctions
//                                ::ElementType<ARRAY_TYPE>::Type ElementType;
//
//         GetElementAccessor<ElementType> elementAccessor(value);
//
//         return bdlat_ArrayFunctions::accessElement(object,
//                                                    elementAccessor,
//                                                    index);
//     }
//
//     /// Assign the specified `value` to the element of the specified
//     /// `object` array at the specified `index`.  Return 0 if the
//     /// element is successfully assigned to `value`, and a non-zero
//     /// value otherwise.  This function template requires that the
//     /// specified `ARRAY_TYPE` is a `bdlat` "array" type.  The behavior
//     /// is undefined unless `0 <= index` and
//     /// `index < bdlat_ArrayFunctions::size(*object)`.
//     template <class ARRAY_TYPE>
//     static int setElement(
//      ARRAY_TYPE                                                    *object,
//      int                                                            index,
//      const typename bdlat_ArrayFunctions::ElementType<ARRAY_TYPE>
//                                                            ::Type&  value)
//     {
//         BSLMF_ASSERT(bdlat_ArrayFunctions::IsArray<ARRAY_TYPE>::value);
//
//         typedef typename bdlat_ArrayFunctions::ElementType<ARRAY_TYPE>
//                                                         ::Type ElementType;
//
//         SetElementManipulator<ElementType> manipulator(value);
//
//         return bdlat_ArrayFunctions::manipulateElement(object,
//                                                        manipulator,
//                                                        index);
//     }
// };
// ```
// Now, we can use these functors to write generic utility functions for
// getting and setting the value types of arbitrary "array" classes.
// ```
// void myUsageScenario()
// {
//     mine::MyIntArray array;
//     bdlat_ArrayFunctions::resize(&array, 4);
//
//     // Confirm initial values.
//
//     for (int index = 0; index < 4; ++index) {
//         int value;
//         int rc = ArrayUtil::getElement(&value, array, index);
//         assert(0 == rc);
//         assert(0 == value);
//     }
//
//     // Set element `index * 10` as its value.
//
//     for (int index = 0; index < 4; ++index) {
//         int value = index * 10;
//         int rc     = ArrayUtil::setElement(&array, index, value);
//         assert(0 == rc);
//     }
//
//     // Confirm value of each element.
//
//     for (int index = 0; index < 4; ++index) {
//         int value;
//         int rc = ArrayUtil::getElement(&value, array, index);
//         assert(0           == rc);
//         assert(index * 10 == value);
//     }
// }
// ```
//
///Example 4: Achieving Type Independence
/// - - - - - - - - - - - - - - - - - - -
// Suppose we have another type such as `your::YourFloatArray`, shown below:
// ```
// namespace BloombergLP {
// namespace your {
//
// class YourFloatArray {
//
//     float       *d_data_p;
//     bsl::size_t  d_size;
//     bsl::size_t  d_capacity;
//
//   public:
//     // CREATORS
//     YourFloatArray()
//     : d_data_p(0)
//     , d_size(0)
//     {
//     }
//
//     ~YourFloatArray()
//     {
//         delete[] d_data_p;
//     }
//
//     // MANIPULATORS
//     void setSize(bsl::size_t newSize); // Too large for inline.
//
//     float& element(bsl::size_t index)
//     {
//         assert(index < d_size);
//
//         return d_data_p[index];
//     }
//
//     // ACCESSORS
//     const float& element(bsl::size_t index) const
//     {
//         assert(index < d_size);
//
//         return d_data_p[index];
//     }
//
//     bsl::size_t numElements() const
//     {
//         return d_size;
//     }
//
//     bsl::size_t capacity() const
//     {
//         return d_capacity;
//     }
// };
//
// }  // close namespace your
// }  // close enterprise namespace
// ```
// Notice that while there are many similarities to `mine::MyIntArray`, there
// are also significant differences:
// * The element type is `float`, not `int`.
// * Many of the accessors are named differently (e.g., `numElements` instead
//   of `size`, `setSize` instead of `resize`).
// * There is an additional attribute, `capacity`, because this class has a
//   `setSize` method (not shown) that reduces calls to the heap by over
//   allocating when the size is increased beyond the current capacity.
//
// Nevertheless, since `your::YourFloatArray` also provides the functions
// and types expected by the `bdlat` infrastructure (not shown) we can
// successfully use `your::FloatArray` value instead of `mine::MyIntArray`
// in the previous usage scenario, with no other changes:
// ```
// void yourUsageScenario()
// {
//     your::YourFloatArray array;
//     bdlat_ArrayFunctions::resize(&array, 4);
//
//     // Confirm initial values.
//
//     for (int index = 0; index < 4; ++index) {
//         float value;
//         int   rc = ArrayUtil::getElement(&value, array, index);
//         assert(0   == rc);
//         assert(0.0 == value);
//     }
//
//     // Set element `index * 10` as its value.
//
//     for (int index = 0; index < 4; ++index) {
//         float value = static_cast<float>(index * 10);
//         int   rc    = ArrayUtil::setElement(&array, index, value);
//         assert(0 == rc);
//     }
//
//     // Confirm value of each element.
//
//     for (int index = 0; index < 4; ++index) {
//         float value;
//         int   rc = ArrayUtil::getElement(&value, array, index);
//         assert(0                              == rc);
//         assert(static_cast<float>(index * 10) == value);
//     }
// }
// ```
//
// Notice that syntax and order of `bdlat_ArrayFunctions` function
// calls have not been changed.  The only difference is that the element
// type has changed from `int` to `float`.
//
// Finally, instead of defining a new "array" type, we could substitute the
// existing type template `bsl::vector`.  Note that this component
// provides specializations of the `bdlat_ArrayFunctions` for that
// type.  Since the accessor and manipulator functions we created earlier are
// type neutral, we can simply drop `bsl::vector<bsl::string>` into our
// familiar scenario:
// ```
// void anotherUsageScenario()
// {
//     bsl::vector<bsl::string> array;  // STANDARD ARRAY TYPE
//     bdlat_ArrayFunctions::resize(&array, 4);
//
//     // Confirm initial values.
//
//     for (int index = 0; index < 4; ++index) {
//         bsl::string value;
//         int         rc = ArrayUtil::getElement(&value, array, index);
//         assert(0  == rc);
//         assert("" == value);
//     }
//
//     // Set element `index * 10` as its value.
//
//     for (int index = 0; index < 4; ++index) {
//         bsl::ostringstream oss; oss << (index * 10);
//         int rc = ArrayUtil::setElement(&array, index, oss.str());
//         assert(0 == rc);
//     }
//
//     // Confirm value of each element.
//
//     for (int index = 0; index < 4; ++index) {
//         bsl::string value;
//         int         rc = ArrayUtil::getElement(&value, array, index);
//
//         bsl::ostringstream oss; oss << (index * 10);
//
//         assert(0         == rc);
//         assert(oss.str() == value);
//     }
// }
// ```

#include <bdlscm_version.h>

#include <bdlat_bdeatoverrides.h>

#include <bslmf_integralconstant.h>

#include <bsl_cstddef.h>
#include <bsl_cstdlib.h>
#include <bsl_vector.h>

namespace BloombergLP {

                       // ==============================
                       // namespace bdlat_ArrayFunctions
                       // ==============================

/// This `namespace` provides functions that expose "array" behavior for
/// "array" types.  Specializations are provided for `bsl::vector<TYPE>`.
/// See the component-level documentation for more information.
namespace bdlat_ArrayFunctions {

    // META-FUNCTIONS

    /// This meta-function should contain a typedef `Type` that specifies
    /// the type of element stored in an array of the parameterized `TYPE`.
    template <class TYPE>
    struct ElementType;

    /// This `struct` should be specialized for third-party types that are
    /// need to expose "array" behavior.  See the component-level
    /// documentation for further information.
    template <class TYPE>
    struct IsArray : bsl::false_type {
    };

    // MANIPULATORS

    /// Invoke the specified `manipulator` on the address of the element at the
    /// specified `index` of the specified `array`.  The supplied `manipulator`
    /// must be a callable type that can be called as if it had the following
    /// signature:
    /// ```
    //  int manipulator(ELEMENT_TYPE *element);
    /// ```
    /// Return the value from the invocation of `manipulator`.  The behavior is
    /// undefined unless `0 <= index` and `index < size(*array)`.
    template <class TYPE, class MANIPULATOR>
    int manipulateElement(TYPE         *array,
                          MANIPULATOR&  manipulator,
                          int           index);

    /// If successful, make the capacity of the specified modifiable `array` at
    /// least the specified `numElements` and return zero.  If unsuccessful or
    /// unsupported, return a non-zero value.  This method has no effect, and
    /// returns zero, if the current capacity meets or exceeds the required
    /// capacity.  The behavior is undefined unless `0 <= numElements`.
    template <class TYPE>
    int reserve(TYPE *array, int numElements);

    /// Set the size of the specified modifiable `array` to the specified
    /// `newSize`.  If `newSize > size(array)`, then `newSize - size(array)`
    /// elements with default values are appended to `array`.  If
    /// `newSize < size(array)`, then the `size(array) - newSize` elements
    /// at the end of `array` are destroyed.  The behavior is undefined
    /// unless `0 <= newSize`.
    template <class TYPE>
    void resize(TYPE *array, int newSize);

    // ACCESSORS

    /// Invoke the specified `accessor` on the non-modifiable element at the
    /// specified `index` of the specified `array`.  The supplied `accessor`
    /// must be a callable type that can be called as if it had the following
    /// signature:
    /// ```
    /// int accessor(const ELEMENT_TYPE& element);
    /// ```
    /// Return the value from the invocation of `accessor`.  The behavior is
    /// undefined unless `0 <= index` and `index < size(array)`.
    template <class TYPE, class ACCESSOR>
    int accessElement(const TYPE& array,
                      ACCESSOR&   accessor,
                      int         index);

    /// Return the number of elements in the specified `array`.
    template <class TYPE>
    bsl::size_t size(const TYPE& array);

    /// Return `true` if `reserve` will attempt to reserve capacity in the
    /// specified `array`, and `false` otherwise.
    template <class TYPE>
    bool supportsReserve(const TYPE& array);

}  // close namespace bdlat_ArrayFunctions

                   // =====================================
                   // default reserve capacity declarations
                   // =====================================

/// This namespace declaration adds the default implementations for reserve
/// capacity methods.
namespace bdlat_ArrayFunctions {

    // MANIPULATORS
    template <class TYPE>
    int bdlat_arrayReserve(TYPE *array, int numElements);

    // ACCESSORS
    template <class TYPE>
    bool bdlat_arraySupportsReserve(const TYPE& array);

}  // close namespace bdlat_ArrayFunctions

                          // ========================
                          // bsl::vector declarations
                          // ========================

/// This namespace declaration adds the implementation of the "array" traits
/// for `bsl::vector` to `bdlat_ArrayFunctions`.  Note that `bsl::vector` is
/// the canonical "array" type.
namespace bdlat_ArrayFunctions {

    // META-FUNCTIONS
    template <class TYPE, class ALLOC>
    struct IsArray<bsl::vector<TYPE, ALLOC> > : bsl::true_type {
    };

    template <class TYPE, class ALLOC>
    struct ElementType<bsl::vector<TYPE, ALLOC> > {
        typedef TYPE Type;
    };

    // MANIPULATORS
    template <class TYPE, class ALLOC, class MANIPULATOR>
    int bdlat_arrayManipulateElement(bsl::vector<TYPE, ALLOC> *array,
                                     MANIPULATOR&              manipulator,
                                     int                       index);

    template <class TYPE, class ALLOC>
    int bdlat_arrayReserve(bsl::vector<TYPE, ALLOC> *array, int numElements);

    template <class TYPE, class ALLOC>
    void bdlat_arrayResize(bsl::vector<TYPE, ALLOC> *array, int newSize);

    // ACCESSORS
    template <class TYPE, class ALLOC, class ACCESSOR>
    int bdlat_arrayAccessElement(const bsl::vector<TYPE, ALLOC>& array,
                                 ACCESSOR&                       accessor,
                                 int                             index);

    template <class TYPE, class ALLOC>
    bsl::size_t bdlat_arraySize(const bsl::vector<TYPE, ALLOC>& array);

    template <class TYPE, class ALLOC>
    bool bdlat_arraySupportsReserve(const bsl::vector<TYPE, ALLOC>& array);

}  // close namespace bdlat_ArrayFunctions

// ============================================================================
//                            INLINE DEFINITIONS
// ============================================================================

                       // -------------------------
                       // namespace-level functions
                       // -------------------------

// MANIPULATORS
template <class TYPE, class MANIPULATOR>
inline
int bdlat_ArrayFunctions::manipulateElement(TYPE         *array,
                                            MANIPULATOR&  manipulator,
                                            int           index)
{
    return bdlat_arrayManipulateElement(array, manipulator, index);
}

template <class TYPE>
inline
int bdlat_ArrayFunctions::reserve(TYPE *array, int numElements)
{
    return bdlat_arrayReserve(array, numElements);
}

template <class TYPE>
inline
void bdlat_ArrayFunctions::resize(TYPE *array, int newSize)
{
    bdlat_arrayResize(array, newSize);
}

// ACCESSORS
template <class TYPE, class ACCESSOR>
inline
int bdlat_ArrayFunctions::accessElement(const TYPE& array,
                                        ACCESSOR&   accessor,
                                        int         index)
{
    return bdlat_arrayAccessElement(array, accessor, index);
}

template <class TYPE>
inline
bsl::size_t bdlat_ArrayFunctions::size(const TYPE& array)
{
    return bdlat_arraySize(array);
}

template <class TYPE>
inline
bool bdlat_ArrayFunctions::supportsReserve(const TYPE& array)
{
    return bdlat_arraySupportsReserve(array);
}

                   // ------------------------------------
                   // default reserve capacity definitions
                   // ------------------------------------

// MANIPULATORS
template <class TYPE>
inline
int bdlat_ArrayFunctions::bdlat_arrayReserve(TYPE *, int)
{
    return -1;
}

// ACCESSORS
template <class TYPE>
inline
bool bdlat_ArrayFunctions::bdlat_arraySupportsReserve(const TYPE&)
{
    return false;
}

                          // -----------------------
                          // bsl::vector definitions
                          // -----------------------

// MANIPULATORS
template <class TYPE, class ALLOC, class MANIPULATOR>
inline
int bdlat_ArrayFunctions::bdlat_arrayManipulateElement(
                                         bsl::vector<TYPE, ALLOC> *array,
                                         MANIPULATOR&              manipulator,
                                         int                       index)
{
    TYPE& element = (*array)[index];
    return manipulator(&element);
}

template <class TYPE, class ALLOC>
inline
int bdlat_ArrayFunctions::bdlat_arrayReserve(
                                         bsl::vector<TYPE, ALLOC> *array,
                                         int                       numElements)
{
    array->reserve(numElements);
    return 0;
}

template <class TYPE, class ALLOC>
inline
void bdlat_ArrayFunctions::bdlat_arrayResize(bsl::vector<TYPE, ALLOC> *array,
                                             int                       newSize)
{
    array->resize(newSize);
}

// ACCESSORS
template <class TYPE, class ALLOC, class ACCESSOR>
inline
int bdlat_ArrayFunctions::bdlat_arrayAccessElement(
                                      const bsl::vector<TYPE, ALLOC>& array,
                                      ACCESSOR&                       accessor,
                                      int                             index)
{
    return accessor(array[index]);
}

template <class TYPE, class ALLOC>
inline
bsl::size_t bdlat_ArrayFunctions::bdlat_arraySize(
                                         const bsl::vector<TYPE, ALLOC>& array)
{
    return array.size();
}

template <class TYPE, class ALLOC>
inline
bool bdlat_ArrayFunctions::bdlat_arraySupportsReserve(
                                               const bsl::vector<TYPE, ALLOC>&)
{
    return true;
}

}  // 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 ----------------------------------
