/**
 *  @file   ya_array.h
 *  @brief  単純な唯の配列をstl風にしたもの. std::arrary/boost::arrayの変種.
 *  @author tenk* (Masashi Kitamura)
 *  @date   2003-07-19 , 2010
 *  @note
 *  -   UNUSE_THROW が定義されていれば, 例外でなくassertチェックになる.
 */
#ifndef YA_ARRAY_H
#define YA_ARRAY_H

#include <cstddef>
#include <cassert>
#include <iterator>
#include <algorithm>
#ifndef UNUSE_THROW
#include <stdexcept>
#endif
#if defined __WATCOMC__ || defined __DMC__
#define YA_ARRAY_NO_MEMBER_TEMPLATES            // メンバーテンプレートが使えない場合に定義.
#endif

/// 唯の配列を、stl風にしたもの。
template<class T, unsigned N>
class ya_array {
    T       ary_[N];

public:
    typedef unsigned                              size_type;
    typedef std::ptrdiff_t                        difference_type;
    typedef T&                                    reference;
    typedef const T&                              const_reference;
    typedef T                                     value_type;
    typedef T*                                    iterator;
    typedef const T*                              const_iterator;
    typedef std::reverse_iterator<iterator>       reverse_iterator;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

    //ya_array() { std::fill_n(begin(),size(),T()); }
    //ya_array(const ya_array& r) { std::copy(r.begin(), r.end(), begin()); }
    size_type       size()          const   { return N; }
    size_type       max_size()      const   { return N; }
    size_type       capacity()      const   { return N; }
    bool            empty()         const   { return 0; }

    iterator        begin()                 { return ary_;}
    const_iterator  begin()         const   { return ary_;}
    const_iterator  cbegin()        const   { return ary_;}
    iterator        end()                   { return ary_ + N;}
    const_iterator  end()           const   { return ary_ + N;}
    const_iterator  cend()          const   { return ary_ + N;}
    reverse_iterator       rbegin()         { return reverse_iterator(ary_ + N);}
    const_reverse_iterator rbegin() const   { return const_reverse_iterator(ary_ + N);}
    const_reverse_iterator crbegin() const  { return const_reverse_iterator(ary_ + N);}
    reverse_iterator       rend()           { return reverse_iterator(ary_); }
    const_reverse_iterator rend()   const   { return const_reverse_iterator(ary_);}
    const_reverse_iterator crend()  const   { return const_reverse_iterator(ary_);}

    reference       front()                 { return *ary_;}
    const_reference front()         const   { return *ary_;}
    reference       back()                  { return *(ary_ + N - 1); }
    const_reference back()          const   { return *(ary_ + N - 1); }
    reference       at(size_type n)         { chkOutOfRng(n); return *(ary_ + n);}
    const_reference at(size_type n) const   { chkOutOfRng(n); return *(ary_ + n);}
    reference       operator[](size_type n)       { assert(n < N ); return *(ary_ + n);}
    const_reference operator[](size_type n) const { assert(n < N ); return *(ary_ + n);}

    void swap(ya_array& x)                      { for (size_type i = 0; i < N; i++) std::swap(ary_[i], x[i]); }
    void assign(size_type sz, const T& t=T())   { assert(sz <= N); std::fill_n(begin(), sz, t); }

    // 比較演算子定義のための内部的な関数
    bool operator==(const ya_array& r) const { return std::equal(begin(), end(), r.begin());}
    bool operator!=(const ya_array& r) const { return !(*this == r); }
    bool operator< (const ya_array& r) const { return std::lexicographical_compare(begin(),end(),r.begin(),r.end());}
    bool operator>=(const ya_array& r) const { return  !(*this < r); }
    bool operator> (const ya_array& r) const { return    r < *this ; }
    bool operator<=(const ya_array& r) const { return ! (r < *this); }

  #ifndef YA_ARRAY_NO_MEMBER_TEMPLATES
    template <typename T2> ya_array<T,N>&
    operator= (const ya_array<T2,N>& r) { std::copy(r.begin(),r.end(), begin()); return *this; }
    template<typename Ite>
    void assign(Ite b, Ite e) { size_type l = std::distance(b,e); assert(l <= N); std::copy(b,e,begin()); }
  #else
    ya_array& operator=(const ya_array& r) { std::copy(r.begin(),r.end(), begin()); return *this; }
    void assign(const_iterator b, const_iterator e) { size_type l = e-b; assert(l <= N); std::copy(b,e,begin()); }
  #endif

private:
  #ifdef UNUSE_THROW    // 例外投げずassertチェック
    void chkOutOfRng(size_type n) const { assert(n < N && "invalid array<T,N> subscript\n"); }
  #else
    void chkOutOfRng(size_type n) const { if (n >= N) throw std::out_of_range("invalid array<T,N> subscript"); }
  #endif
};
#endif