// bslstl_array.h                                                     -*-C++-*-
#ifndef INCLUDED_BSLSTL_ARRAY
#define INCLUDED_BSLSTL_ARRAY

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

//@PURPOSE: Provide an STL compliant array.
//
//@CLASSES:
//   bsl::array: an STL compliant array
//
//@CANONICAL_HEADER: bsl_array.h
//
//@SEE_ALSO: bslstl_vector
//
//@DESCRIPTION: This component defines a single class template, 'bsl::array',
// implementing the standard container 'std::array', holding a non-resizable
// array of values of a template parameter type where the size is specified as
// the second template parameter.
//
// An instantiation of 'array' is a value-semantic type whose salient
// attributes are its size and the sequence of values the array contains.  If
// 'array' is instantiated with a value type that is not value-semantic, then
// the array will not retain all of its value-semantic qualities.  In
// particular, if a value type cannot be tested for equality, then an 'array'
// containing objects of that type will fail to compile the equality comparison
// operator.  Similarly, if an 'array' is instantiated with a type that does
// not have a copy-constructor, then the 'array' will not be copyable.
//
// An array meets most the requirements of a container with random access
// iterators in the C++ standard [array].  The 'array' implemented here follows
// the C++11 standard when compiled with a C++11 compiler and follows the C++03
// standard otherwise.

// An array lacks certain requirements of a sequential container.  Array lacks
// 'insert', 'erase', 'emplace', and 'clear', as these functions would require
// modifying the size of the array.

// An array also meets the requirements of an aggregate.  This means that an
// array has: no user-declared constructors, no private or protected non-static
// data members, no base classes, and no virtual functions.  An array can be
// constructed using aggregate initialization.  Refer to the section
// [del.init.aggr] in the C++ standard for more detailed information.
//
///Operations
///----------
// This section describes the run-time complexity of operations on instances of
// 'array':
//..
//  Legend
//  ------
//  'V'                 - (template parameter) 'VALUE_TYPE' of the array
//  'S'                 - (template parameter) 'SIZE' of the array
//  'a', 'b'            - two distinct objects of type 'array<V, S>'
//  'k'                 - non-negative integer
//  'vt1', 'vt2', 'vt3' - objects of type 'VALUE_TYPE'
//
//  |-----------------------------------------+-------------------------------|
//  | Operation                               | Complexity                    |
//  |=========================================+===============================|
//  | array<V> a    (default construction)    | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | array<V> a(b) (copy construction)       | O[S]                          |
//  |-----------------------------------------+-------------------------------|
//  | array<V> a = {{vt1, vt2, vt3}}          | O[S]                          |
//  | array<V> a = {vt1, vt2, vt3}            |                               |
//  |               (aggregate initialization)|                               |
//  |-----------------------------------------+-------------------------------|
//  | a.~array<V>() (destruction)             | O[S]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.begin(), a.end(),                     | O[1]                          |
//  | a.cbegin(), a.cend(),                   |                               |
//  | a.rbegin(), a.rend(),                   |                               |
//  | a.crbegin(), a.crend()                  |                               |
//  |-----------------------------------------+-------------------------------|
//  | a.size()                                | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.max_size()                            | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.empty()                               | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a[k]                                    | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.at(k)                                 | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.front()                               | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.back()                                | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.swap(b), swap(a,b)                    | O[S]                          |
//  |-----------------------------------------+-------------------------------|
//  | a = b;           (copy assignment)      | O[S]                          |
//  |-----------------------------------------+-------------------------------|
//  | a == b, a != b                          | O[S]                          |
//  |-----------------------------------------+-------------------------------|
//  | a < b, a <= b, a > b, a >= b            | O[S]                          |
//  |-----------------------------------------+-------------------------------|
//..
//
///Comparing an array of floating point values
///-------------------------------------------
// The comparison operator performs a bit-wise comparison for floating point
// types ('float' and 'double'), which produces results for NaN, +0, and -0
// values that do not meet the guarantees provided by the standard.
// The 'bslmf::IsBitwiseEqualityComparable' trait for 'double' and 'float'
// types returns 'true' which is incorrect because a comparison with a NaN
// value is always 'false', and -0 and +0 are equal.
//..
//    bsl::array<double, 1> a{bsl::numeric_limits<double>::quiet_NaN()};
//    ASSERT(a == a);   // This assertion will *NOT* fail!
//..
// Addressing this issue, i.e., updating 'bslmf::IsBitwiseEqualityComparable'
// to return 'false' for floating point types, could potentially destabilize
// production software so the change (for the moment) has not been made.
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Returning an array from a function
///- - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want to define a function that will return an array of 'float's.
// If a raw array were used, the size would need to be tracked separately
// because raw arrays decay to pointers when passed as function arguments, or
// returned by-value.  'bsl::array' does not decay, and so provides a simple
// solution to this problem.
//..
//  typedef bsl::array<float, 3> Point;
//
//  Point createPoint(float f1, float f2, float f3)
//  {
//      bsl::array<float, 3> ret = {f1, f2, f3};
//      return ret;
//  }
//..
// Create a bsl::array object containing three values set to the specified
// 'f1', 'f2', 'f3'.
//..
//  void usageExample()
//  {
//      Point p1 = createPoint(1.0, 1.0, 1.0);
//      Point p2 = createPoint(2.0, 2.0, 2.0);
//      Point p3 = createPoint(3.0, 3.0, 3.0);
//
//      bsl::array<Point, 3> points = {p1, p2, p3};
//
//      for(size_t i = 0; i < points.size(); ++i) {
//          for(size_t j = 0; j < points[i].size(); ++j) {
//              points[i][j] *= 2.0f;
//          }
//      }
//  }
//..
// Use the createPoint function to generate three arrays of floats.  The arrays
// are returned by copy and the 'size()' member function is used to access the
// size of the arrays that could not be done with a raw array.

#include <bslscm_version.h>

#include <bslstl_iterator.h>
#include <bslstl_stdexceptutil.h>

#include <bslalg_rangecompare.h>
#include <bslalg_hasstliterators.h>

#include <bslh_hash.h>

#include <bslmf_assert.h>
#include <bslmf_enableif.h>
#include <bslmf_isnothrowswappable.h>
#include <bslmf_issame.h>
#include <bslmf_movableref.h>

#include <bsls_assert.h>
#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_libraryfeatures.h>
#include <bsls_platform.h>

#include <stddef.h>

#if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_TUPLE)
# include <tuple>  // 'std::tuple_size' etc.
#endif

#if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY)
#include <utility>     // std::swap (C++11)
#else
#include <algorithm>   // std::swap (C++03)
#endif

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bsls_nativestd.h>
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

#ifndef BDE_DISABLE_CPP17_ABI
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY

#include <array>  // 'std::array'
#include <tuple>  // 'std::get'

namespace bsl {
using std::array;
using std::get;
}  // close namespace bsl

#define BSLSTL_ARRAY_IS_ALIASED
#endif  // BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY
#endif  // BDE_DISABLE_CPP17_ABI


#ifndef BSLSTL_ARRAY_IS_ALIASED

// DEFECT DETECTION MACROS

#if defined(BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP14)                    \
 && defined(BSLS_PLATFORM_CMP_GNU) && BSLS_PLATFORM_CMP_VERSION < 60000
// gcc 5.4 (and earlier) does not allow non-'constexpr' code in a relaxed
// 'constexpr' function, such as a 'BSLS_ASSERT' macro.  As use of such code in
// this component is limited to function templates, the effect is to silently
// disable the 'constexpr'-ness of those functions, which parse correctly and
// evaluate as expected at run-time, but fail to compile in a constant
// evaluation context.  In order to support C++14 standard conformance, we
// choose to disable our BDE contract checks on platforms affected by this
// compiler bug.
# define BSLSTL_ARRAY_DISABLE_CONSTEXPR_CONTRACTS       1
#endif

namespace bsl {
                                // ===========
                                // class array
                                // ===========

template <class VALUE_TYPE, size_t SIZE>
struct array {
    // This class template provides a standard conforming implementation of
    // 'std::array'.  'array' is an aggregate wrapper around a raw array,
    // supporting aggregate initialization and an iterator interface as
    // required for a standard container.

// BDE_VERIFY pragma: push
// BDE_VERIFY pragma: -KS02  // Tag implicitly requires private declaration

    // DATA
    VALUE_TYPE d_data[(0 == SIZE) ? 1 : SIZE];

// BDE_VERIFY pragma: pop

    // PUBLIC TYPES
    typedef VALUE_TYPE                             value_type;
    typedef VALUE_TYPE                            *pointer;
    typedef const VALUE_TYPE                      *const_pointer;
    typedef VALUE_TYPE&                            reference;
    typedef const VALUE_TYPE&                      const_reference;
    typedef size_t                                 size_type;
    typedef ptrdiff_t                              difference_type;
    typedef pointer                                iterator;
    typedef const_pointer                          const_iterator;
    typedef bsl::reverse_iterator<iterator>        reverse_iterator;
    typedef bsl::reverse_iterator<const_iterator>  const_reverse_iterator;

    // CREATORS
    //! array() = default;
        // Create an 'array' object.  Every element is default constructed if
        // 'VALUE_TYPE' is default constructible; otherwise, 'array' is not
        // default constructible.
    //! array(const array& original) = default;
        // Create an 'array' object having the same value as the specified
        // 'original' object.  Every element is copy constructed from the
        // corresponding element in the specified 'original' if 'VALUE_TYPE' is
        // copy constructible; otherwise, 'array' is not copy constructible.
        // Only in C++11 and later.
    //! array(array&& original) = default;
        // Create an 'array' object having the same value as the specified
        // 'original' object.  Every element is move constructed from the
        // corresponding element in the specified 'original' if 'VALUE_TYPE' is
        // move constructible; otherwise, 'array' is not move constructible.
    //! ~array() = default;
        // Destroy this object.  Evert element is destroyed if 'VALUE_TYPE' is
        // destructible; otherwise, array is not destructible.

    // MANIPULATORS
    void fill(const VALUE_TYPE& value);
        // Set every element in this array to the specified 'value' using the
        // 'operator=' of 'value_type'.

    void swap(array& rhs) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                 bsl::is_nothrow_swappable<VALUE_TYPE>::value);
        // Exchange each corresponding element between this array and the
        // specified 'rhs' array by calling 'swap(a,b)' where 'swap' is found
        // by overload resolution including at least the namespaces 'std' and
        // the associated namespaces of 'VALUE_TYPE'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    iterator begin() BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator providing modifiable access to the first element
        // in this array; return a past-the-end iterator if this array has size
        // 0.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    iterator end() BSLS_KEYWORD_NOEXCEPT;
        // Return a past-the-end iterator providing modifiable access to this
        // array.

    BSLS_KEYWORD_CONSTEXPR_CPP17
    reverse_iterator rbegin() BSLS_KEYWORD_NOEXCEPT;
        // Return a reverse iterator providing modifiable access to the last
        // element in this array; return a past-the-end iterator if this array
        // has size 0.

    BSLS_KEYWORD_CONSTEXPR_CPP17
    reverse_iterator rend() BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end reverse iterator providing modifiable access
        // to this array.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reference operator[](size_type position);
        // Return a reference providing modifiable access to the element at the
        // specified 'position' in this array.  The behavior is undefined
        // unless 'position < size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reference at(size_type position);
        // Return a reference to the element at the specified 'position' in
        // this array.  Throw an 'out_of_range' exception if
        // 'position >= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reference front();
        // Return a reference to the first element in this array.  The behavior
        // is undefined unless 'SIZE > 0'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reference back();
        // Return a reference to the last element in this array.  The behavior
        // is undefined unless 'SIZE > 0'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    pointer data() BSLS_KEYWORD_NOEXCEPT;
        // Return the address of the first element of the underlying raw array.
        // Return a valid 'T*' which cannot be dereferenced if the 'SIZE' is 0.

    //! array& operator=(const array& other);
        // Sets every element in this array to the corresponding element in the
        // specified 'other' if 'VALUE_TYPE' is copy assignable; otherwise,
        // 'array' is not copy assignable.
    //! array& operator=(array&& other);
        // Moves every element in the specified 'other' into the corresponding
        // element in this array in the if 'VALUE_TYPE' is moves assignable;
        // otherwise, 'array' is not move assignable.

    // BDE_VERIFY pragma: -FABC01  // Function not in alphanumeric order
    // ACCESSORS
    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_iterator begin() const BSLS_KEYWORD_NOEXCEPT;
    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_iterator cbegin() const BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator providing non-modifiable access to the first
        // element in this array; return a past-the-end iterator if this array
        // has size 0.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_iterator end() const BSLS_KEYWORD_NOEXCEPT;
    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_iterator cend() const BSLS_KEYWORD_NOEXCEPT;
        // Return a past-the-end iterator providing non-modifiable access to
        // this array.

    BSLS_KEYWORD_CONSTEXPR_CPP17
    const_reverse_iterator rbegin() const BSLS_KEYWORD_NOEXCEPT;
    BSLS_KEYWORD_CONSTEXPR_CPP17
    const_reverse_iterator crbegin() const BSLS_KEYWORD_NOEXCEPT;
        // Return a reverse iterator providing non-modifiable access to the
        // last element in this array, and the past-the-end reverse iterator if
        // this array has size 0.

    BSLS_KEYWORD_CONSTEXPR_CPP17
    const_reverse_iterator rend() const BSLS_KEYWORD_NOEXCEPT;
    BSLS_KEYWORD_CONSTEXPR_CPP17
    const_reverse_iterator crend() const BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end reverse iterator providing non-modifiable
        // access to this 'array'.

    BSLS_KEYWORD_CONSTEXPR bool empty() const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if the array has size 0, and 'false' otherwise.

    BSLS_KEYWORD_CONSTEXPR size_type size() const BSLS_KEYWORD_NOEXCEPT;
    BSLS_KEYWORD_CONSTEXPR size_type max_size() const BSLS_KEYWORD_NOEXCEPT;
        // Return the number of elements in this array.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_reference operator[](size_type position) const;
        // Return a reference providing non-modifiable access to the element at
        // the specified 'position' in this array.  The behavior is undefined
        // unless 'position < size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_reference at(size_type position) const;
        // Return a reference providing non-modifiable access to the element at
        // the specified 'position' in this array.  Throw an 'out_of_range'
        // exception if 'position >= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14 const_reference front() const;
        // Return a reference providing non-modifiable access to the first
        // element in this array.  The behavior is undefined unless 'SIZE > 0'.

    BSLS_KEYWORD_CONSTEXPR_CPP14 const_reference back() const;
        // Return a reference providing non-modifiable access to the last
        // element in this array.  Behavior is undefined unless 'SIZE > 0'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_pointer data() const BSLS_KEYWORD_NOEXCEPT;
        // Return the address of the first element of the underlying raw array.
        // Return a valid 'T*' which cannot be dereferenced if the 'SIZE' is 0.
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
// CLASS TEMPLATE DEDUCTION GUIDES

template<class    VALUE_TYPE,
         class... OTHERS,
         class = bsl::enable_if_t<(bsl::is_same_v<VALUE_TYPE, OTHERS> && ...)>
         >
array(VALUE_TYPE, OTHERS...) -> array<VALUE_TYPE, 1 + sizeof...(OTHERS)>;
    // Deduce the specified types 'VALUE_TYPE' and 'SIZE' from the
    // corresponding elements in the sequence supplied to the constructor of
    // 'array'. The type of the first element in the sequence is the type of
    // the elements of the array, and the length of the sequence is the size of
    // the array.
#endif

// FREE OPERATORS
template <class VALUE_TYPE, size_t SIZE>
bool operator==(const array<VALUE_TYPE, SIZE>& lhs,
                const array<VALUE_TYPE, SIZE>& rhs);
    // Return 'true' if the specified 'lhs' has the same value as the specified
    // 'rhs'; return false otherwise.  Two arrays have the same value if each
    // element has the same value as the corresponding element in the other
    // array.

template <class VALUE_TYPE, size_t SIZE>
bool operator!=(const array<VALUE_TYPE, SIZE>& lhs,
                const array<VALUE_TYPE, SIZE>& rhs);
    // Return 'true' if the specified 'lhs' does not have the same value as the
    // specified 'rhs'; return false otherwise.  Two arrays do not have the
    // same value if some element in the ordered sequence of elements of 'lhs'
    // does not have the same value as the corresponding element in the ordered
    // sequence of elements of 'rhs'.

template <class VALUE_TYPE, size_t SIZE>
bool operator<(const array<VALUE_TYPE, SIZE>& lhs,
               const array<VALUE_TYPE, SIZE>& rhs);
    // Return 'true' if the specified 'lhs' is lexicographically less than the
    // specified 'rhs' by using the comparison operators of 'VALUE_TYPE' on
    // each element; return 'false' otherwise.

template <class VALUE_TYPE, size_t SIZE>
bool operator>(const array<VALUE_TYPE, SIZE>& lhs,
               const array<VALUE_TYPE, SIZE>& rhs);
    // Return 'true' if the specified 'lhs' is lexicographically greater than
    // the specified 'rhs' by using the comparison operators of 'VALUE_TYPE' on
    // each element; return 'false' otherwise.

template <class VALUE_TYPE, size_t SIZE>
bool operator<=(const array<VALUE_TYPE, SIZE>& lhs,
                const array<VALUE_TYPE, SIZE>& rhs);
    // Return 'true' if the specified 'lhs' is lexicographically less than the
    // specified 'rhs' by using the comparison operators of 'VALUE_TYPE' on
    // each element or if 'lhs' and 'rhs' are equal; return 'false' otherwise.

template <class VALUE_TYPE, size_t SIZE>
bool operator>=(const array<VALUE_TYPE, SIZE>& lhs,
                const array<VALUE_TYPE, SIZE>& rhs);
    // Return 'true' if the specified 'lhs' is lexicographically greater than
    // the specified 'rhs' by using the comparison operators of 'VALUE_TYPE' on
    // each element or if 'lhs' and 'rhs' are equal; return 'false' otherwise.

// FREE FUNCTIONS
template <class VALUE_TYPE, size_t SIZE>
void swap(array<VALUE_TYPE, SIZE>& lhs, array<VALUE_TYPE, SIZE>& rhs);
    // Call 'swap' using ADL on each element of the specified 'lhs' with the
    // corresponding element in the specified 'rhs'.

template<size_t INDEX, class TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
TYPE& get(array<TYPE, SIZE>& a) BSLS_KEYWORD_NOEXCEPT;
    // Return a reference providing modifiable access to the element of the
    // specified 'a', having the ordinal number specified by the (template
    // parameter) 'INDEX'.  This function will not compile unless 'INDEX < N'.

template<size_t INDEX, class TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR
const TYPE& get(const array<TYPE, SIZE>& a) BSLS_KEYWORD_NOEXCEPT;
    // Return a reference providing non-modifiable access to the element of the
    // specified 'a', having the ordinal number specified by the (template
    // parameter) 'INDEX'.  This function will not compile unless 'INDEX < N'.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES)
template<size_t INDEX, class TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
TYPE&& get(array<TYPE, SIZE>&& a) BSLS_KEYWORD_NOEXCEPT;
    // Return an rvalue reference providing modifiable access to the element of
    // the specified 'a', having the ordinal number specified by the (template
    // parameter) 'INDEX'.  This function will not compile unless 'INDEX < N'.

template<size_t INDEX, class TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR
const TYPE&& get(const array<TYPE, SIZE>&& a) BSLS_KEYWORD_NOEXCEPT;
    // Return an rvalue reference providing non-modifiable access to the
    // element of the specified 'a', having the ordinal number specified by the
    // (template parameter) 'INDEX'.  This function will not compile unless
    // 'INDEX < N'.
#endif  // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES

// HASH SPECIALIZATIONS
template <class HASH_ALGORITHM, class TYPE, size_t SIZE>
void hashAppend(HASH_ALGORITHM& hashAlgorithm, const array<TYPE, SIZE>& input);
    // Pass the specified 'input' to the specified 'hashAlgorithm'

}  // close namespace bsl

#if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_TUPLE)

namespace std {

#if defined(BSLS_PLATFORM_CMP_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmismatched-tags"
    // The native STL library headers for libstdc++ are internally inconsistent
    // so it is not possible for this header to resolve this warning by picking
    // either 'struct' or 'class' for the class introducer.  We do not see this
    // warning directly from the native libraries only because they are tagged
    // as system headers, which implicitly silences all warnings.
#endif

                            // ====================
                            // struct tuple_element
                            // ====================

template<size_t INDEX, class TYPE, size_t SIZE>
struct tuple_element<INDEX, bsl::array<TYPE, SIZE> >
{
    // This partial specialization of 'tuple_element' provides compile-time
    // access to the type of the array's elements.

    // STATIC CHECKS
    BSLMF_ASSERT(INDEX < SIZE);

    // TYPES
    typedef TYPE type;
};

                             // =================
                             // struct tuple_size
                             // =================

template<class TYPE, size_t SIZE>
struct tuple_size<bsl::array<TYPE, SIZE> > : integral_constant<size_t, SIZE>
{
    // This meta-function provides a compile-time way to obtain the number of
    // elements in an array.
};

#if defined(BSLS_PLATFORM_CMP_CLANG)
#pragma clang diagnostic pop
#endif

}  // close namespace std

#endif  // BSLS_LIBRARYFEATURES_HAS_CPP11_TUPLE
#endif  // !BSLSTL_ARRAY_IS_ALIASED

#ifdef BSLSTL_ARRAY_IS_ALIASED
namespace BloombergLP {
namespace bslh {

// HASH SPECIALIZATIONS
template <class HASH_ALGORITHM, class TYPE, size_t SIZE>
void hashAppend(HASH_ALGORITHM&               hashAlgorithm,
                const std::array<TYPE, SIZE>& input);
    // Pass the specified 'input' to the specified 'hashAlgorithm' hashing
    // algorithm of the (template parameter) type 'HASH_ALGORITHM'.  Note that
    // this function violates the BDE coding standard, adding a function for a
    // namespace for a different package, and none of the function parameters
    // are from this package either.  This is necessary in order to provide an
    // implementation of 'bslh::hashAppend' for the (native) standard library
    // 'array' type as we are not allowed to add overloads directly into
    // namespace 'std', and this component essentially provides the interface
    // between 'bsl' and 'std' array types.

}  // close namespace bslh
}  // close enterprise namespace

#endif  // BSLSTL_ARRAY_IS_ALIASED

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

#ifndef BSLSTL_ARRAY_IS_ALIASED

namespace bsl {
                                // -----------
                                // class array
                                // -----------

// MANIPULATORS

// suppress comparison of 'unsigned' expression is always false warnings
#ifdef BSLS_PLATFORM_HAS_PRAGMA_GCC_DIAGNOSTIC
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
#endif

template <class VALUE_TYPE, size_t SIZE>
void array<VALUE_TYPE, SIZE>::fill(const VALUE_TYPE& value)
{
    for (size_t i = 0; i < SIZE; ++i) {
        d_data[i] = value;
    }
}

template <class VALUE_TYPE, size_t SIZE>
void array<VALUE_TYPE, SIZE>::swap(array<VALUE_TYPE, SIZE>& rhs)
    BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
        bsl::is_nothrow_swappable<VALUE_TYPE>::value)
{
    for (size_t i = 0; i < SIZE; ++i) {
        using std::swap;
        swap(d_data[i], rhs.d_data[i]);
    }
}

// suppress comparison of 'unsigned' expression is always false warnings
#ifdef BSLS_PLATFORM_HAS_PRAGMA_GCC_DIAGNOSTIC
#pragma GCC diagnostic pop
#endif

// ACCESSORS
template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::iterator
array<VALUE_TYPE, SIZE>::begin() BSLS_KEYWORD_NOEXCEPT
{
    return d_data;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::const_iterator
array<VALUE_TYPE, SIZE>::begin() const BSLS_KEYWORD_NOEXCEPT
{
    return d_data;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::iterator
array<VALUE_TYPE, SIZE>::end() BSLS_KEYWORD_NOEXCEPT
{
    return d_data + SIZE;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::const_iterator
array<VALUE_TYPE, SIZE>::end() const BSLS_KEYWORD_NOEXCEPT
{
    return d_data + SIZE;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP17
typename array<VALUE_TYPE, SIZE>::reverse_iterator
array<VALUE_TYPE, SIZE>::rbegin() BSLS_KEYWORD_NOEXCEPT
{
    return array<VALUE_TYPE, SIZE>::reverse_iterator(d_data + SIZE);
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP17
typename array<VALUE_TYPE, SIZE>::const_reverse_iterator
array<VALUE_TYPE, SIZE>::rbegin() const BSLS_KEYWORD_NOEXCEPT
{
    return array<VALUE_TYPE, SIZE>::const_reverse_iterator(d_data + SIZE);
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP17
typename array<VALUE_TYPE, SIZE>::reverse_iterator
array<VALUE_TYPE, SIZE>::rend() BSLS_KEYWORD_NOEXCEPT
{
    return array<VALUE_TYPE, SIZE>::reverse_iterator(d_data);
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP17
typename array<VALUE_TYPE, SIZE>::const_reverse_iterator
array<VALUE_TYPE, SIZE>::rend() const BSLS_KEYWORD_NOEXCEPT
{
    return array<VALUE_TYPE, SIZE>::const_reverse_iterator(d_data);
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::const_iterator
array<VALUE_TYPE, SIZE>::cbegin() const BSLS_KEYWORD_NOEXCEPT
{
    return d_data;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::const_iterator
array<VALUE_TYPE, SIZE>::cend() const BSLS_KEYWORD_NOEXCEPT
{
    return d_data + SIZE;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP17
typename array<VALUE_TYPE, SIZE>::const_reverse_iterator
array<VALUE_TYPE, SIZE>::crbegin() const BSLS_KEYWORD_NOEXCEPT
{
    return array<VALUE_TYPE, SIZE>::const_reverse_iterator(d_data + SIZE);
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP17
typename array<VALUE_TYPE, SIZE>::const_reverse_iterator
array<VALUE_TYPE, SIZE>::crend() const BSLS_KEYWORD_NOEXCEPT
{
    return array<VALUE_TYPE, SIZE>::const_reverse_iterator(d_data);
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR
bool array<VALUE_TYPE, SIZE>::empty() const BSLS_KEYWORD_NOEXCEPT
{
    return SIZE == 0;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR
size_t array<VALUE_TYPE, SIZE>::size() const BSLS_KEYWORD_NOEXCEPT
{
    return SIZE;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR
size_t array<VALUE_TYPE, SIZE>::max_size() const BSLS_KEYWORD_NOEXCEPT
{
    return SIZE;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::reference
array<VALUE_TYPE, SIZE>::operator[](size_type position)
{
    BSLS_ASSERT(position < SIZE);
    return d_data[position];
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::const_reference
array<VALUE_TYPE, SIZE>::operator[](size_type position) const
{
#if !defined(BSLSTL_ARRAY_DISABLE_CONSTEXPR_CONTRACTS)
    BSLS_ASSERT(position < SIZE);
#endif

    return d_data[position];
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::reference array<VALUE_TYPE, SIZE>::at(
                                                            size_type position)
{
    if (position >= SIZE) {
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
            "array<...>::at(position): invalid position");
    }
    return d_data[position];
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::const_reference
array<VALUE_TYPE, SIZE>::at(size_type position) const
{
    if (position >= SIZE) {
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
            "array<...>::at(position): invalid position");
    }
    return d_data[position];
}

template <class VALUE_TYPE, size_t SIZE>
typename array<VALUE_TYPE, SIZE>::reference
BSLS_KEYWORD_CONSTEXPR_CPP14
array<VALUE_TYPE, SIZE>::front()
{
    BSLS_ASSERT(SIZE > 0);
    return d_data[0];
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::const_reference
array<VALUE_TYPE, SIZE>::front() const
{
#if !defined(BSLSTL_ARRAY_DISABLE_CONSTEXPR_CONTRACTS)
    BSLS_ASSERT(SIZE > 0);
#endif

    return d_data[0];
}

template <class VALUE_TYPE, size_t SIZE>
typename array<VALUE_TYPE, SIZE>::reference
BSLS_KEYWORD_CONSTEXPR_CPP14
array<VALUE_TYPE, SIZE>::back()
{
    BSLS_ASSERT(SIZE > 0);
    return d_data[SIZE - 1];
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::const_reference
array<VALUE_TYPE, SIZE>::back() const
{
#if !defined(BSLSTL_ARRAY_DISABLE_CONSTEXPR_CONTRACTS)
    BSLS_ASSERT(SIZE > 0);
#endif

    return d_data[SIZE - 1];
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::iterator
array<VALUE_TYPE, SIZE>::data() BSLS_KEYWORD_NOEXCEPT
{
    return d_data;
}

template <class VALUE_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
typename array<VALUE_TYPE, SIZE>::const_iterator
array<VALUE_TYPE, SIZE>::data() const BSLS_KEYWORD_NOEXCEPT
{
    return d_data;
}

// HASH SPECIALIZATIONS

// suppress comparison of 'unsigned' expression is always false warnings
#ifdef BSLS_PLATFORM_HAS_PRAGMA_GCC_DIAGNOSTIC
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
#endif

template <class HASH_ALGORITHM, class TYPE, size_t SIZE>
void hashAppend(HASH_ALGORITHM& hashAlgorithm, const array<TYPE, SIZE>& input)
{
    using ::BloombergLP::bslh::hashAppend;

    hashAppend(hashAlgorithm, SIZE);
    for (size_t i = 0; i < SIZE; ++i)
    {
        hashAppend(hashAlgorithm, input[i]);
    }
}

// suppress comparison of 'unsigned' expression is always false warnings
#ifdef BSLS_PLATFORM_HAS_PRAGMA_GCC_DIAGNOSTIC
#pragma GCC diagnostic pop
#endif
}  // close namespace bsl

// FREE OPERATORS
template <class VALUE_TYPE, size_t SIZE>
bool bsl::operator==(const array<VALUE_TYPE, SIZE>& lhs,
                     const array<VALUE_TYPE, SIZE>& rhs)
{
    return BloombergLP::bslalg::RangeCompare::equal(lhs.begin(),
                                                    lhs.end(),
                                                    lhs.size(),
                                                    rhs.begin(),
                                                    rhs.end(),
                                                    rhs.size());
}

template <class VALUE_TYPE, size_t SIZE>
bool bsl::operator!=(const array<VALUE_TYPE, SIZE>& lhs,
                     const array<VALUE_TYPE, SIZE>& rhs)
{
    return !(lhs == rhs);
}

template <class VALUE_TYPE, size_t SIZE>
bool bsl::operator<(const array<VALUE_TYPE, SIZE>& lhs,
                    const array<VALUE_TYPE, SIZE>& rhs)
{
    return 0 > BloombergLP::bslalg::RangeCompare::lexicographical(lhs.begin(),
                                                                  lhs.end(),
                                                                  lhs.size(),
                                                                  rhs.begin(),
                                                                  rhs.end(),
                                                                  rhs.size());
}

template <class VALUE_TYPE, size_t SIZE>
bool bsl::operator>(const array<VALUE_TYPE, SIZE>& lhs,
                    const array<VALUE_TYPE, SIZE>& rhs)
{
    return rhs < lhs;
}

template <class VALUE_TYPE, size_t SIZE>
bool bsl::operator<=(const array<VALUE_TYPE, SIZE>& lhs,
                     const array<VALUE_TYPE, SIZE>& rhs)
{
    return !(rhs < lhs);
}

template <class VALUE_TYPE, size_t SIZE>
bool bsl::operator>=(const array<VALUE_TYPE, SIZE>& lhs,
                     const array<VALUE_TYPE, SIZE>& rhs)
{
    return !(lhs < rhs);
}

// FREE FUNCTIONS
template <class VALUE_TYPE, size_t SIZE>
void bsl::swap(array<VALUE_TYPE, SIZE>& lhs, array<VALUE_TYPE, SIZE>& rhs)
{
    lhs.swap(rhs);
}

template<size_t INDEX, class TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
TYPE& bsl::get(array<TYPE, SIZE>& a) BSLS_KEYWORD_NOEXCEPT
{
    return a.d_data[INDEX];
}

template<size_t INDEX, class TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR
const TYPE& bsl::get(const array<TYPE, SIZE>& a) BSLS_KEYWORD_NOEXCEPT
{
    return a.d_data[INDEX];
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES)
template<size_t INDEX, class TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14
TYPE&& bsl::get(array<TYPE, SIZE>&& a) BSLS_KEYWORD_NOEXCEPT
{
    return BloombergLP::bslmf::MovableRefUtil::move(a.d_data[INDEX]);
}

template<size_t INDEX, class TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR
const TYPE&& bsl::get(const array<TYPE, SIZE>&& a) BSLS_KEYWORD_NOEXCEPT
{
    return BloombergLP::bslmf::MovableRefUtil::move(a.d_data[INDEX]);
}
#endif  // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
#endif  // !BSLSTL_ARRAY_IS_ALIASED

#ifdef BSLSTL_ARRAY_IS_ALIASED
namespace BloombergLP {
namespace bslh {

// HASH SPECIALIZATIONS
template <class HASH_ALGORITHM, class TYPE, size_t SIZE>
void hashAppend(HASH_ALGORITHM&               hashAlgorithm,
                const std::array<TYPE, SIZE>& input)
{
    using ::BloombergLP::bslh::hashAppend;

    hashAppend(hashAlgorithm, SIZE);
    if BSLS_KEYWORD_CONSTEXPR_CPP17 (SIZE > 0) {
        for (size_t i = 0; i < SIZE; ++i) {
            hashAppend(hashAlgorithm, input[i]);
        }
    }
}

}  // close namespace bslh
}  // close enterprise namespace

#endif  // BSLSTL_ARRAY_IS_ALIASED

// ============================================================================
//                                TYPE TRAITS
// ============================================================================

namespace BloombergLP {

namespace bslalg {

template <class TYPE, size_t SIZE>
struct HasStlIterators<bsl::array<TYPE, SIZE> >
    : bsl::true_type
{};

}  // close namespace bslalg

}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2019 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 ----------------------------------