/**
 *  @file   a_vector.h
 *  @brief  動的メモリ確保を行わず、メンバーにバッファを持つvector.
 *  @author tenk*
 *  @date   2003-2010
 *  @note
 *      - std::arrayの vector 版のようなもの.
 *      - コンストラクタ、デストラクタの都合、クラス内メモリは
 *        基本型の配列で確保.
 *      - このため、アライメント不具合を起こす可能性あり.
 *      - デバッガで不便なので、A_VECTOR_USE_DBG_PTR を定義すると
 *        buf_を指すT*型のポインタ dbgPtr_ をメンバーに加える.
 *        (a_vectorのサイズが変動しても問題ない場合用)
 *      - メンバーテンプレートがあるので、watcomとかはdmcはたぶん不可.
 *      - Public Domain Software
 */
#ifndef A_VECTOR_H
#define A_VECTOR_H

#include <cstddef>
#include <iterator>
#include <algorithm>
#include <functional>
#include <new>
#ifndef assert
#include <cassert>
#endif
#ifndef UNUSE_THROW
#include <stdexcept>
#endif

#if defined _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4100)
#endif


#if 0 //ndef NDEBUG // デバッガでの表示を楽にするためのポインタを付加する場合.
#define A_VECTOR_USE_DBG_PTR
#endif

#ifdef  A_VECTOR_USE_DBG_PTR    // デバッガでの表示用のポインタを追加する場合.
#define A_VECTOR_SET_DBG_PTR()      (dbgPtr_ = (T*)buf_)
#else
#define A_VECTOR_SET_DBG_PTR()
#endif


template< typename T, unsigned N >
class a_vector {
public:
    typedef T                   value_type;
    typedef std::size_t         size_type;
    typedef std::ptrdiff_t      difference_type;
    typedef T&                  reference;
    typedef const T&            const_reference;
    typedef T*                  pointer;
    typedef const T*            const_pointer;
    typedef pointer             iterator;
    typedef const_pointer       const_iterator;
    typedef std::reverse_iterator<iterator>         reverse_iterator;
    typedef std::reverse_iterator<const_iterator>   const_reverse_iterator;

    a_vector() : size_(0) { A_VECTOR_SET_DBG_PTR(); }
    ~a_vector() { clear(); }

    explicit a_vector(size_type sz);
    a_vector(size_type sz, const T& t);
    template<typename InpIte>   a_vector(InpIte bgn, InpIte end);
    template<unsigned N2>       a_vector(const a_vector<T,N2>& r);

    a_vector&       operator=(const a_vector& x);

    void            assign(size_type n, const T &t);
    template<typename InpIte>
    void            assign(InpIte bgn, InpIte end);

    size_type       size()          const { return size_;}
    size_type       max_size()      const { return N;}
    size_type       capacity()      const { return N;}
    bool            empty()         const { return size_ == 0;}

    iterator        begin()               { return ptr();}
    const_iterator  begin()         const { return ptr();}
    const_iterator  cbegin()        const { return ptr();}
    iterator        end()                 { return ptr() + size_;}
    const_iterator  end()           const { return ptr() + size_;}
    const_iterator  cend()          const { return ptr() + size_;}

    reverse_iterator       rbegin()       { return reverse_iterator( end() );}
    const_reverse_iterator rbegin() const { return const_reverse_iterator( end() );}
    const_reverse_iterator crbegin()const { return const_reverse_iterator( end() );}
    reverse_iterator       rend()         { return reverse_iterator( begin() ); }
    const_reverse_iterator rend()   const { return const_reverse_iterator( begin() );}
    const_reverse_iterator crend()  const { return const_reverse_iterator( begin() );}

    reference       front()               { return *ptr();}
    const_reference front()         const { return *ptr();}
    reference       back()                { assert(size_ > 0); return *(end() - 1);}
    const_reference back()          const { assert(size_ > 0); return *(end() - 1);}

    reference       operator[](size_type n)       { assert(n < size_); return *(ptr() + n); }
    const_reference operator[](size_type n) const { assert(n < size_); return *(ptr() + n); }
    reference       at(size_type n)       { if (n >= size_) outOfRng(); return *(ptr() + n); }
    const_reference at(size_type n) const { if (n >= size_) outOfRng(); return *(ptr() + n); }

    void            clear();
    void            resize( size_type size);
    void            reserve(size_type size) { size; assert(size <= N); }
    void            push_back(const T& t);
    void            pop_back();

    iterator        erase(iterator pos);
    iterator        erase(iterator first, iterator last);
    iterator        insert(iterator pos, const T& t) { return insert(pos, 1U, t); }
    iterator        insert(iterator pos, size_type n, const T& t);
    template <typename InpIte>
    iterator        insert(iterator pos, InpIte a, InpIte b);

    void            swap(a_vector& x) { std::swap(x, *this); }      // 効率悪いので注意!

    bool operator==(const a_vector& r) const { return (size_ == r.size_) && std::equal(begin(), end(), r.begin()); }
    bool operator!=(const a_vector& r) const { return !(*this == r); }
    bool operator< (const a_vector& r) const { return std::lexicographical_compare(begin(), end(), r.begin(), r.end()); }
    bool operator>=(const a_vector& r) const { return !(*this <  r); }
    bool operator> (const a_vector& r) const { return   r <  *this ; }
    bool operator<=(const a_vector& r) const { return !(r <  *this); }

private:
    static void construct(T* a, const T& t) { new(reinterpret_cast<void*>(a)) T(t); }
    static void set_construct(T* a, const T& t, size_type sz);
    template<typename InpIte>
    static void copy_construct(T* ary, InpIte bgn, InpIte end);

    static void destroy(T* a) { a->~T(); }
    static void destruct(T* ary, size_type n);

    T*       ptr()       { return reinterpret_cast<T*>(buf_); }
    const T* ptr() const { return reinterpret_cast<const T*>(buf_); }

  #ifdef UNUSE_THROW
    void outOfRng() { assert(n < size_ && "invalid a_vector subscript"); }
  #else
    void outOfRng() { throw std::out_of_range("invalid a_vector subscript"); }
  #endif

private:
    typedef double  aln_t;      //typedef void* aln_t;
    aln_t           buf_[ (N * sizeof(T) + sizeof(aln_t)-1) / sizeof(aln_t) ];
    size_type       size_;
 #ifdef A_VECTOR_USE_DBG_PTR
    T*              dbgPtr_;
 #endif
};




template< typename T, unsigned N > inline
void a_vector<T,N>::set_construct(T* a, const T& t, typename a_vector<T,N>::size_type sz) {
    if (sz) {
        assert(a != 0);
        do {
            construct(a, t);
            ++a;
        } while (--sz);
    }
}


template< typename T, unsigned N >
template<typename InpIte> inline
void a_vector<T,N>::copy_construct(T* d, InpIte s, InpIte e) {
    assert(d != 0);
    while (s != e) {
        construct(d++, *s);
        ++s;
    }
}


template< typename T, unsigned N > inline
void a_vector<T,N>::destruct(T* a, typename a_vector<T,N>::size_type sz) {
    assert(sz > 0);
    if (sz) {
        assert(a != 0);
        do {
            destroy(a);
            ++a;
        } while (--sz);
    }
}




template< typename T, unsigned N >
a_vector<T,N>::a_vector(typename a_vector<T,N>::size_type sz) {
    A_VECTOR_SET_DBG_PTR();
    assert(sz <= N);
    if (sz > N)
        sz = N;
    size_ = sz;
    set_construct(ptr(), T(), sz);
}


template< typename T, unsigned N >
a_vector<T,N>::a_vector(typename a_vector<T,N>::size_type sz, const T& t) {
    A_VECTOR_SET_DBG_PTR();
    assert(sz <= N);
    if (sz > N)
        sz = N;
    size_ = sz;
    set_construct(ptr(), t, sz);
}


template< typename T, unsigned N >
template<typename InpIte>
a_vector<T,N>::a_vector(InpIte bgn, InpIte end) {
    A_VECTOR_SET_DBG_PTR();
    size_type   sz = std::distance(bgn, end);
    size_          = sz;
    assert(sz <= N);
    copy_construct(ptr(), bgn, end);
}


template< typename T, unsigned N >
template<unsigned N2>
a_vector<T,N>::a_vector(const a_vector<T,N2>& r) {
    A_VECTOR_SET_DBG_PTR();
    size_type   sz = r.size();
    size_          = sz;
    assert(sz <= N);
    if (sz > N)
        sz = N;
    copy_construct(ptr(), r.begin(), r.begin() + sz);
}




template< typename T, unsigned N >
a_vector<T,N>& a_vector<T,N>::operator=(const a_vector<T,N>& x) {
    assert(N >= x.size());
    clear();
    size_ = x.size();
    if (size_ > 0) {
        copy_construct(ptr(), x.begin(), x.end());
    }
    return *this;
}


template< typename T, unsigned N >
void a_vector<T,N>::assign(typename a_vector<T,N>::size_type n, const T& t) {
    assert(N >= n);
    clear();
    if (n > N)
        n = N;
    size_ = n;
    set_construct(ptr(),t,n);
}


template< typename T, unsigned N >
template<typename InpIte>
void a_vector<T,N>::assign(InpIte bgn, InpIte end) {
    size_type   n = std::distance(bgn, end);
    assert(N >= n);
    clear();
    if (n > N)
        n = N;
    size_ = n;
    copy_construct(ptr(),bgn,end);
}



template< typename T, unsigned N >
void a_vector<T,N>::clear() {
    if (size_ > 0) {
        destruct(ptr(), size_);
        size_ = 0;
    }
}



template< typename T, unsigned N >
void a_vector<T,N>::resize( typename a_vector<T,N>::size_type sz ) {
    if (sz > N) {
        assert(sz <= N);
        sz = N;
    }
    size_type   size = size_;
    if (sz < size) {
        destruct(ptr()+sz, size - sz);
    } else if (sz > size) {
        set_construct(ptr()+size, T(), sz - size);
    }
    size_ = sz;
}



template< typename T, unsigned N >
void a_vector<T,N>::push_back( const T& t ) {
    if (size_ < N) {
        construct(ptr()+size_, t);
        ++size_;
    } else {
        assert(size_ < N);
    }
}


template< typename T, unsigned N >
void a_vector<T,N>::pop_back() {
    if (size_ > 0) {
        --size_;
        destroy(ptr()+size_);
    } else {
        assert(size_ > 0);
    }
}




template< typename T, unsigned N >
T*  a_vector<T,N>::erase(typename a_vector<T,N>::iterator pos) {
    T*  b = ptr();
    T*  e = b+size_;
    assert(b <= pos && pos < e);
    if (pos <  b || pos >= e)
        return e;
    --e;
    for (T* p = pos; p != e; ++p)
        *p = *(p+1);
    destroy(e);
    --size_;
    return pos;
}


template< typename T, unsigned N >
T*  a_vector<T,N>::erase(
        typename a_vector<T,N>::iterator first,
        typename a_vector<T,N>::iterator last)
{
    T*  b = ptr();
    T*  e = b+size_;
    assert(first < last && b <= first && last <= e);
    if (first >= last || first < b || last > e)
        return e;
    size_type l = last - first;
    e -= l;
    for (T* p = first; p != e; ++p)
        *p = *(p+l);
    destruct(e, l);
    size_ -= l;
    return first;
}




template< typename T, unsigned N >
T*  a_vector<T,N>::insert(
        typename a_vector<T,N>::iterator    pos,
        typename a_vector<T,N>::size_type   n,
        const T&                            t)
{
    if (n == 0)
        return pos;
    T*  b = ptr();
    T*  e = b + size_;
    if (pos < b || pos > e || size_+n > N) {
        outOfRng();
        return e;
    }
    size_ += n;
    for (T* p = e; --p >= pos;) {
        construct(p+n, *p);
        destroy(p);
    }
    e = pos + n;
    while (pos < e)
        construct(pos++, t);
    return pos;
}


template< typename T, unsigned N >
template <typename InpIte>
T* a_vector<T,N>::insert(typename a_vector<T,N>::iterator pos, InpIte first, InpIte last) {
    size_type n = std::distance(first, last);
    if (n == 0)
        return pos;
    T*  b = ptr();
    T*  e = b + size_;
    if (pos < b || pos > e || size_+n > N) {
        outOfRng();
        return e;
    }
    size_ += n;
    for (T* p = e; --p >= pos;) {
        construct(p+n, *p);
        destroy(p);
    }
    e = pos + n;
    while (pos < e) {
        construct(pos++, *first);
        ++first;
    }
    return pos;
}


#if defined _MSC_VER
#pragma warning(pop)
#endif

#endif  // AVECTOR_H