// array standard header -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _ARRAY_
#define _ARRAY_

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#include <algorithm>
#include <iterator>
#include <tuple>

namespace std {

// TEMPLATE CLASS array
template<class _Ty, size_t _Size>
class array
{       // fixed size array of values
public:
  typedef array<_Ty, _Size> _Myt;
  typedef _Ty value_type;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef _Ty *pointer;
  typedef const _Ty *const_pointer;
  typedef _Ty& reference;
  typedef const _Ty& const_reference;

  typedef _Array_iterator<_Ty, _Size> iterator;
  typedef _Array_const_iterator<_Ty, _Size> const_iterator;

  typedef std::reverse_iterator<iterator> reverse_iterator;
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

  void assign(const _Ty& _Value)
  {       // assign value to all elements
    _Fill_n(_Elems, _Size, _Value);
  }

  void fill(const _Ty& _Value)
  {       // assign value to all elements
    _Fill_n(_Elems, _Size, _Value);
  }

  void swap(_Myt& _Other)
    _NOEXCEPT_OP(_NOEXCEPT_OP(_Swap_adl(_Elems[0], _Elems[0])))
  {       // swap contents with _Other
    _Swap_ranges(std::addressof(_Elems[0]),
                 std::addressof(_Elems[0]) + _Size,
                 std::addressof(_Other._Elems[0]));
  }

  iterator begin() _NOEXCEPT
  {       // return iterator for beginning of mutable sequence
    return iterator(std::addressof(_Elems[0]), 0);
  }

  const_iterator begin() const _NOEXCEPT
  {       // return iterator for beginning of nonmutable sequence
    return const_iterator(std::addressof(_Elems[0]), 0);
  }

  iterator end() _NOEXCEPT
  {       // return iterator for end of mutable sequence
    return iterator(std::addressof(_Elems[0]), _Size);
  }

  const_iterator end() const _NOEXCEPT
  {       // return iterator for beginning of nonmutable sequence
    return const_iterator(std::addressof(_Elems[0]), _Size);
  }

  reverse_iterator rbegin() _NOEXCEPT
  {       // return iterator for beginning of reversed mutable sequence
    return reverse_iterator(end());
  }

  const_reverse_iterator rbegin() const _NOEXCEPT
  {       // return iterator for beginning of reversed nonmutable sequence
    return const_reverse_iterator(end());
  }

  reverse_iterator rend() _NOEXCEPT
  {       // return iterator for end of reversed mutable sequence
    return reverse_iterator(begin());
  }

  const_reverse_iterator rend() const _NOEXCEPT
  {       // return iterator for end of reversed nonmutable sequence
    return const_reverse_iterator(begin());
  }

  const_iterator cbegin() const _NOEXCEPT
  {       // return iterator for beginning of nonmutable sequence
    return begin();
  }

  const_iterator cend() const _NOEXCEPT
  {       // return iterator for end of nonmutable sequence
    return end();
  }

  const_reverse_iterator crbegin() const _NOEXCEPT
  {       // return iterator for beginning of reversed nonmutable sequence
    return rbegin();
  }

  const_reverse_iterator crend() const _NOEXCEPT
  {       // return iterator for end of reversed nonmutable sequence
    return rend();
  }

  constexpr size_type size() const _NOEXCEPT
  {       // return length of sequence
    return _Size;
  }

  constexpr size_type max_size() const _NOEXCEPT
  {       // return maximum possible length of sequence
    return _Size;
  }

  constexpr bool empty() const _NOEXCEPT
  {       // test if sequence is empty
    return false;
  }

  reference at(size_type _Pos)
  {       // subscript mutable sequence with checking
    if (_Size <= _Pos)
      __iar_Raise_ran();
    return _Elems[_Pos];
  }

  constexpr const_reference at(size_type _Pos) const
  {       // subscript nonmutable sequence with checking
    if (_Size <= _Pos)
      __iar_Raise_ran();
    return _Elems[_Pos];
  }

  reference operator[](size_type _Pos)
  {       // subscript mutable sequence
    #if _ITERATOR_DEBUG_LEVEL == 2
      if (_Size <= _Pos)
        _DEBUG_ERROR("array subscript out of range");
    #elif _ITERATOR_DEBUG_LEVEL == 1
      _SCL_SECURE_VALIDATE_RANGE(_Pos < _Size);
    #endif /* _ITERATOR_DEBUG_LEVEL */

    return _Elems[_Pos];
  }

  constexpr const_reference operator[](size_type _Pos) const
  { // subscript nonmutable sequence
    #if _ITERATOR_DEBUG_LEVEL == 0
      return _Elems[_Pos];
    #else /* _ITERATOR_DEBUG_LEVEL == 0 */
      if (_Size <= _Pos)
      {
        #if _ITERATOR_DEBUG_LEVEL == 2
          _DEBUG_ERROR("array subscript out of range");
        #elif _ITERATOR_DEBUG_LEVEL == 1
          _SCL_SECURE_VALIDATE_RANGE(false);
        #endif /* _ITERATOR_DEBUG_LEVEL */
      }
      return _Elems[_Pos];
    #endif /* _ITERATOR_DEBUG_LEVEL == 0 */
  }

  reference front()
  {       // return first element of mutable sequence
    return _Elems[0];
  }

  constexpr const_reference front() const
  {       // return first element of nonmutable sequence
    return _Elems[0];
  }

  reference back()
  {       // return last element of mutable sequence
    return _Elems[_Size - 1];
  }

  constexpr const_reference back() const
  {       // return last element of nonmutable sequence
    return _Elems[_Size - 1];
  }

  _Ty *data() _NOEXCEPT
  {       // return pointer to mutable data array
    return _Elems;
  }

  const _Ty *data() const _NOEXCEPT
  {       // return pointer to nonmutable data array
    return _Elems;
  }

  _Ty _Elems[_Size];
};

template<class _Ty>
class array<_Ty, 0>
{       // zero size array of values
public:
  typedef array<_Ty, 0> _Myt;
  typedef _Ty value_type;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef _Ty *pointer;
  typedef const _Ty *const_pointer;
  typedef _Ty& reference;
  typedef const _Ty& const_reference;

  typedef _Array_iterator<_Ty, 0> iterator;
  typedef _Array_const_iterator<_Ty, 0> const_iterator;
  typedef std::reverse_iterator<iterator> reverse_iterator;
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

  void assign(const _Ty&)
  {       // assign value to all elements
  }

  void fill(const _Ty&)
  {       // assign value to all elements
  }

  void swap(_Myt&) _NOEXCEPT
  {       // swap contents with _Other
  }

  iterator begin()
  {       // return iterator for beginning of mutable sequence
    return iterator(0, 0);
  }

  const_iterator begin() const
  {       // return iterator for beginning of nonmutable sequence
    return iterator(0, 0);
  }

  iterator end()
  {       // return iterator for end of mutable sequence
    return iterator(0, 0);
  }

  const_iterator end() const
  {       // return iterator for beginning of nonmutable sequence
    return iterator(0, 0);
  }

  reverse_iterator rbegin()
  {       // return iterator for beginning of reversed mutable sequence
    return reverse_iterator(end());
  }

  const_reverse_iterator rbegin() const
  {       // return iterator for beginning of reversed nonmutable sequence
    return const_reverse_iterator(end());
  }

  reverse_iterator rend()
  {       // return iterator for end of reversed mutable sequence
    return reverse_iterator(begin());
  }

  const_reverse_iterator rend() const
  {       // return iterator for end of reversed nonmutable sequence
    return const_reverse_iterator(begin());
  }

  const_iterator cbegin() const
  {       // return iterator for beginning of nonmutable sequence
    return iterator(0, 0);
  }

  const_iterator cend() const
  {       // return iterator for end of nonmutable sequence
    return iterator(0, 0);
  }

  const_reverse_iterator crbegin() const
  {       // return iterator for beginning of reversed nonmutable sequence
    return rbegin();
  }

  const_reverse_iterator crend() const
  {       // return iterator for end of reversed nonmutable sequence
    return rend();
  }

  constexpr size_type size() const
  {       // return length of sequence
    return 0;
  }

  constexpr size_type max_size() const
  {       // return maximum possible length of sequence
    return 0;
  }

  constexpr bool empty() const
  {       // test if sequence is empty
    return true;
  }

  reference at(size_type)
  {       // subscript mutable sequence with checking
    __iar_Raise_ran();
  }

  const_reference at(size_type) const
  {       // subscript nonmutable sequence with checking
    __iar_Raise_ran();
  }

  reference operator[](size_type)
  {       // subscript mutable sequence
    #if _ITERATOR_DEBUG_LEVEL == 2
      _DEBUG_ERROR("array subscript out of range");
    #elif _ITERATOR_DEBUG_LEVEL == 1
      _SCL_SECURE_VALIDATE_RANGE(false);
    #endif /* _ITERATOR_DEBUG_LEVEL */

    return _Elems[0];
  }

  const_reference operator[](size_type) const
  {       // subscript nonmutable sequence
    #if _ITERATOR_DEBUG_LEVEL == 2
      _DEBUG_ERROR("array subscript out of range");
    #elif _ITERATOR_DEBUG_LEVEL == 1
      _SCL_SECURE_VALIDATE_RANGE(false);
    #endif /* _ITERATOR_DEBUG_LEVEL */

    return _Elems[0];
  }

  reference front()
  {       // return first element of mutable sequence
    #if _ITERATOR_DEBUG_LEVEL == 2
      _DEBUG_ERROR("array<T, 0>::front() invalid");
    #elif _ITERATOR_DEBUG_LEVEL == 1
      _SCL_SECURE_VALIDATE_RANGE(false);
    #endif /* _ITERATOR_DEBUG_LEVEL */

    return _Elems[0];
  }

  const_reference front() const
  {       // return first element of nonmutable sequence
    #if _ITERATOR_DEBUG_LEVEL == 2
      _DEBUG_ERROR("array<T, 0>::front() invalid");
    #elif _ITERATOR_DEBUG_LEVEL == 1
      _SCL_SECURE_VALIDATE_RANGE(false);
    #endif /* _ITERATOR_DEBUG_LEVEL */

    return _Elems[0];
  }

  reference back()
  {       // return last element of mutable sequence
    #if _ITERATOR_DEBUG_LEVEL == 2
      _DEBUG_ERROR("array<T, 0>::back() invalid");
    #elif _ITERATOR_DEBUG_LEVEL == 1
      _SCL_SECURE_VALIDATE_RANGE(false);
    #endif /* _ITERATOR_DEBUG_LEVEL */

    return _Elems[0];
  }

  const_reference back() const
  {       // return last element of nonmutable sequence
    #if _ITERATOR_DEBUG_LEVEL == 2
      _DEBUG_ERROR("array<T, 0>::back() invalid");
    #elif _ITERATOR_DEBUG_LEVEL == 1
      _SCL_SECURE_VALIDATE_RANGE(false);
    #endif /* _ITERATOR_DEBUG_LEVEL */

    return _Elems[0];
  }

  _Ty *data()
  {       // return pointer to mutable data array
    return _Elems;
  }

  const _Ty *data() const
  {       // return pointer to nonmutable data array
    return _Elems;
  }

  _Ty _Elems[1];
};

template<class _Ty, size_t _Size>
void swap(array<_Ty,_Size>& _Left,
          array<_Ty,_Size>& _Right)
  _NOEXCEPT_OP(_NOEXCEPT_OP(_Left.swap(_Right)))
{       // swap arrays
  return _Left.swap(_Right);
}

template<class _Ty, size_t _Size>
bool operator==(const array<_Ty,_Size>& _Left,
                const array<_Ty,_Size>& _Right)
{       // test for array equality
  return std::equal(_Left.begin(), _Left.end(), _Right.begin());
}

template<class _Ty, size_t _Size>
bool operator!=(const array<_Ty,_Size>& _Left,
                const array<_Ty,_Size>& _Right)
{       // test for array inequality
  return !(_Left == _Right);
}

template<class _Ty, size_t _Size>
bool operator<(const array<_Ty,_Size>& _Left,
               const array<_Ty,_Size>& _Right)
{       // test if _Left < _Right for arrays
  return std::lexicographical_compare(_Left.begin(), _Left.end(),
                                      _Right.begin(), _Right.end());
}

template<class _Ty, size_t _Size>
bool operator>(const array<_Ty,_Size>& _Left,
               const array<_Ty,_Size>& _Right)
{       // test if _Left > _Right for arrays
  return _Right < _Left;
}

template<class _Ty, size_t _Size>
bool operator<=(const array<_Ty,_Size>& _Left,
                const array<_Ty,_Size>& _Right)
{       // test if _Left <= _Right for arrays
  return !(_Right < _Left);
}

template<class _Ty, size_t _Size>
bool operator>=(const array<_Ty,_Size>& _Left,
                const array<_Ty,_Size>& _Right)
{       // test if _Left >= _Right for arrays
  return !(_Left < _Right);
}

// TUPLE INTERFACE TO array
template<size_t _Idx, class _Ty, size_t _Size>
constexpr _Ty& get(array<_Ty, _Size>& _Arr) _NOEXCEPT
{       // return element at _Idx in array _Arr
  _STATIC_ASSERT2(_Idx < _Size, "array index out of bounds");
  return _Arr._Elems[_Idx];
}

template<size_t _Idx, class _Ty, size_t _Size>
constexpr const _Ty& get(const array<_Ty, _Size>& _Arr) _NOEXCEPT
{       // return element at _Idx in array _Arr
  _STATIC_ASSERT2(_Idx < _Size, "array index out of bounds");
  return _Arr._Elems[_Idx];
}

template<size_t _Idx, class _Ty, size_t _Size>
constexpr _Ty&& get(array<_Ty, _Size>&& _Arr) _NOEXCEPT
{       // return element at _Idx in array _Arr
  _STATIC_ASSERT2(_Idx < _Size, "array index out of bounds");
  return move(_Arr._Elems[_Idx]);
}

} /* namespace std */

#endif /* _ARRAY_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0576 */
