// --------
// Array2.h
// --------

#ifndef Array2_h
#define Array2_h

#include <algorithm> // copy, equal, lexicographical_compare
#include <cstddef>   // ptrdiff_t, size_t
#include <memory>    // allocator
#include <stdexcept> // out_of_range
#include <utility>   // !=, <=, >, >=

#include "Memory.h" // my_destroy, my_uninitialized_copy, my_uninitialized_fill

using namespace std::rel_ops;

template <typename T, std::size_t N, typename A = std::allocator<T> >
class Array2 {
    public:
        typedef A                                        allocator_type;
        typedef typename allocator_type::value_type      value_type;

        typedef typename allocator_type::size_type       size_type;
        typedef typename allocator_type::difference_type difference_type;

        typedef typename allocator_type::pointer         pointer;
        typedef typename allocator_type::const_pointer   const_pointer;

        typedef typename allocator_type::reference       reference;
        typedef typename allocator_type::const_reference const_reference;

        typedef typename allocator_type::pointer         iterator;
        typedef typename allocator_type::const_pointer   const_iterator;

    public:
        friend bool operator == (const Array2& lhs, const Array2& rhs) {
            return std::equal(lhs.begin(), lhs.end(), rhs.begin());}
        
        friend bool operator < (const Array2& lhs, const Array2& rhs) {
            return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());}

    private:
        pointer        _a;
        char           _x[N * sizeof(value_type)];
        allocator_type _z;

    public:
        explicit Array2 (const_reference v = value_type(), const allocator_type& z = allocator_type()) :
                _a (reinterpret_cast<pointer>(_x)),
                _z (z) {
            my_uninitialized_fill(_z, begin(), end(), v);}

        Array2 (const Array2& that) :
                _a (reinterpret_cast<pointer>(_x)),
                _z (that._z) {
            my_uninitialized_copy(_z, that.begin(), that.end(), begin());}

        template <typename II>
        Array2 (II b, II e, const allocator_type& z = allocator_type()) :
                _a (reinterpret_cast<pointer>(_x)),
                _z (z) {
            my_uninitialized_copy(_z, b, e, begin());}

        ~Array2 () {
            my_destroy(_z, begin(), end());}

        Array2& operator = (const Array2& that) {
            if (this != &that)
                std::copy(that.begin(), that.end(), begin());
            return *this;}

        reference operator [] (size_type i) {
            return _a[i];}

        const_reference operator [] (size_type i) const {
            return (*const_cast<Array2*>(this))[i];}

        reference at (size_type i) {
            if (i >= size())
                throw std::out_of_range("Array::at index out of range");
            return (*this)[i];}

        const_reference at (size_type i) const {
            return const_cast<Array2*>(this)->at(i);}

        iterator begin () {
            return _a;}

        const_iterator begin () const {
            return _a;}

        iterator end () {
            return _a + N;}

        const_iterator end () const {
            return _a + N;}

        size_type size () const {
            return N;}};

#endif // Array2_h


syntax highlighted by Code2HTML, v. 0.9.1