#ifndef BLOCK_H
#define BLOCK_H

// ----------------------------------------------------------------------
//
// Block.h - Array-like container class
//
// Purpose:
//   Declaration and definition of the struct template zmt::Block<T,N>.
//   This struct defines a type that can be used as a C-style array can,
//   but which also meets the requirements for use as an STL container.
//   Block<T,N> is a model of Random Access Container.  Further, since
//   Block<T,N> is also an aggregate type, it may be initialized as an
//   array is initialized:
//               Block<int,3> A = {1, -3, 17};
//
// History:
//   24-Feb-2000  WEB  Original version by Matthew H Austern, _Generic
//     Programming and the STL_, ISBN 0-201-30956-4; import from Marc
//     Paterno with his changes to "avoid problems with illegal
//     zero-length arrays"; edit for conformance with Zoom and ISOcxx;
//     inline the helper functions
//   06-Mar-2000  WEB  Fix typo
//   31-May-2000  WEB  Fix typos; add front() and back() members; add
//     non-member swap(); avoid internal inequality comparison; slightly
//     reword documentation
//   14-Jun-2000  WEB  Fix typo
//
// ----------------------------------------------------------------------


#ifndef NT_MSVCPP
#define REVERSE_ITERATOR( iter, valtype ) reverse_iterator<iter>
#else /* defective */
#define REVERSE_ITERATOR( iter, valtype ) reverse_iterator<iter,valtype>
#endif


#include "ZMutility/ZMenvironment.h"

#include <algorithm>  // for std::swap()


ZM_BEGIN_NAMESPACE( zmt )

  template< typename T, size_t N >
  struct Block  {

    // ----------------------------------------
    // Required typedefs:
    // ----------------------------------------

    typedef  T                         value_type;

    typedef  value_type *              pointer;
    typedef  value_type const  *       const_pointer;
    typedef  value_type &              reference;
    typedef  value_type const &        const_reference;

    typedef  ptrdiff_t                 difference_type;
    typedef  size_t                    size_type;

    typedef  pointer                   iterator;
    typedef  const_pointer             const_iterator;

    typedef  std::REVERSE_ITERATOR( iterator, value_type )
             reverse_iterator;
    typedef  std::REVERSE_ITERATOR( const_iterator, value_type )
             const_reverse_iterator;

    // ----------------------------------------
    // Useful additional typedef:
    // ----------------------------------------

    typedef  Block<T,N>  container_type;

    // ----------------------------------------
    // Iterators:
    // ----------------------------------------

    iterator  begin()  { return data;   }
    iterator  end()    { return data+N; }

    const_iterator  begin() const  { return data;   }
    const_iterator  end()   const  { return data+N; }

    reverse_iterator  rbegin()  { return reverse_iterator( end()   ); }
    reverse_iterator  rend()    { return reverse_iterator( begin() ); }

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

    // ----------------------------------------
    // Element access:
    // ----------------------------------------

    reference        operator[] ( size_type k )        { return data[k]; }
    const_reference  operator[] ( size_type k ) const  { return data[k]; }

    reference        front()        { return data[0]; }
    const_reference  front() const  { return data[0]; }

    reference        back()        { return data[N-1]; }
    const_reference  back() const  { return data[N-1]; }

    // ----------------------------------------
    // Testing:
    // ----------------------------------------

    size_type  size() const      { return N; }
    size_type  max_size() const  { return N; }
    bool       empty() const     { return false; }

    // ----------------------------------------
    // Manipulation:
    // ----------------------------------------

    void  swap( container_type & y )  {
      for ( size_type k( 0 );  k < N;  ++k )
        std::swap( data[k], y.data[k] );
    }

    // ----------------------------------------
    // Member data:
    // ----------------------------------------

    T  data[N];  // the data is public so that Block<> is an aggregate type

  };  // struct Block<>


  // --------------------------------------------------------------------
  //
  // Specialization for 0-length blocks;
  // needed because C++ forbids arrays of extent 0
  //
  // --------------------------------------------------------------------

#ifndef DEFECT_NO_PARTIAL_SPECIALIZATION

  template< typename T >
  struct Block< T, 0 >  {

    // ----------------------------------------
    // Required typedefs:
    // ----------------------------------------

    typedef  T                         value_type;

    typedef  value_type *              pointer;
    typedef  value_type const  *       const_pointer;
    typedef  value_type &              reference;
    typedef  value_type const &        const_reference;

    typedef  ptrdiff_t                 difference_type;
    typedef  size_t                    size_type;

    typedef  pointer                   iterator;
    typedef  const_pointer             const_iterator;

    typedef  std::REVERSE_ITERATOR( iterator, value_type )
             reverse_iterator;
    typedef  std::REVERSE_ITERATOR( const_iterator, value_type )
             const_reverse_iterator;

    // ----------------------------------------
    // Useful additional typedef:
    // ----------------------------------------

    typedef  Block<T,0>  container_type;

    // ----------------------------------------
    // Iterators:
    // ----------------------------------------

    iterator  begin()  { return 0; }
    iterator  end()    { return 0; }

    const_iterator  begin() const  { return 0; }
    const_iterator  end()   const  { return 0; }

    reverse_iterator  rbegin()  { return 0; }
    reverse_iterator  rend()    { return 0; }

    const_reverse_iterator  rbegin() const  { return 0; }
    const_reverse_iterator  rend() const    { return 0; }

    // ----------------------------------------
    // Element access:
    // ----------------------------------------

    // Since a Block<T,0> has no elements, we do not declare
    //   reference        operator[] ( size_type n );
    //   const_reference  operator[] ( size_type n ) const;
    // so that an attempt to use operator[] on a 0-length array
    // will be correctly detected/rejected at compile time
    // Similarly, we do not declare front() or back()

    // ----------------------------------------
    // Testing:
    // ----------------------------------------

    size_type  size() const      { return 0; }
    size_type  max_size() const  { return 0; }
    bool       empty() const     { return true; }

    // ----------------------------------------
    // Manipulation:
    // ----------------------------------------

    // A Block<T,0> contains no data.
    void  swap( container_type & y )  { ; }

  };  // struct Block<T,0>

#endif // DEFECT_NO_PARTIAL_SPECIALIZATION

  // --------------------------------------------------------------------
  //
  // Associated function templates
  //
  // --------------------------------------------------------------------

  // ----------------------------------------
  // Equality testing:
  // T must model EqualityComparable;
  // Two Block<>s are equal if all their elements are equal
  // ----------------------------------------

  // General case:
  template< typename T, size_t N >
  inline
  bool  operator== ( Block<T,N> const & x, Block<T,N> const & y )  {
    for ( size_t k( 0 );  k < N;  ++k )
      if ( !(x.data[k] == y.data[k]) )
        return false;
    return true;
  }

#ifndef DEFECT_NO_PARTIAL_SPECIALIZATION

  // Specialization:
  template< typename T >
  inline
  bool  operator== ( Block<T,0> const & x, Block<T,0> const & y )  {
    return true;
  }

#endif // DEFECT_NO_PARTIAL_SPECIALIZATION

  // ----------------------------------------
  // Inequality testing:
  // T must model LessThanComparable;
  // Define a lexicographical ordering
  // ----------------------------------------

  // General case:
  template< typename T, size_t N >
  inline
  bool  operator< ( Block<T,N> const & x, Block<T,N> const & y )  {
    for ( size_t k( 0 );  k < N;  ++k )  {
      if ( x.data[k] < y.data[k] )  return true;
      if ( y.data[k] < x.data[k] )  return false;
    }
    return false;
  }

#ifndef DEFECT_NO_PARTIAL_SPECIALIZATION

  // Specialization:
  template< typename T >
  inline
  bool  operator< ( Block<T,0> const & x, Block<T,0> const & y )  {
    return false;
  }

#endif // DEFECT_NO_PARTIAL_SPECIALIZATION

  // ----------------------------------------
  // Manipulation:
  // ----------------------------------------

  // General case:
  template< typename T, size_t N >
  inline
  void  swap( Block<T,N> const & x, Block<T,N> const & y )  {
    x.swap( y );
  }

#ifndef DEFECT_NO_PARTIAL_SPECIALIZATION

  // Specialization:
  template< typename T >
  inline
  void  swap( Block<T,0> const & x, Block<T,0> const & y )  { ; }

#endif // DEFECT_NO_PARTIAL_SPECIALIZATION

ZM_END_NAMESPACE( zmt )

#endif  // BLOCK_H
