// -*- C++ -*-
/***************************************************************************
 *
 * valaray - Declarations for the Standard Library valarray
 *
 * $Id$
 *
 ***************************************************************************
 *
 * Copyright (c) 1994-2001 Rogue Wave Software, Inc.  All Rights Reserved.
 *
 * This computer software is owned by Rogue Wave Software, Inc. and is
 * protected by U.S. copyright laws and other laws and by international
 * treaties.  This computer software is furnished by Rogue Wave Software,
 * Inc. pursuant to a written license agreement and may be used, copied,
 * transmitted, and stored only in accordance with the terms of such
 * license and with the inclusion of the above copyright notice.  This
 * computer software or any other copies thereof may not be provided or
 * otherwise made available to any other person.
 *
 * U.S. Government Restricted Rights.  This computer software is provided
 * with Restricted Rights.  Use, duplication, or disclosure by the
 * Government is subject to restrictions as set forth in subparagraph (c)
 * (1) (ii) of The Rights in Technical Data and Computer Software clause
 * at DFARS 252.227-7013 or subparagraphs (c) (1) and (2) of the
 * Commercial Computer Software--Restricted Rights at 48 CFR 52.227-19,
 * as applicable.  Manufacturer is Rogue Wave Software, Inc., 5500
 * Flatiron Parkway, Boulder, Colorado 80301 USA.
 *
 **************************************************************************/

#ifndef _RWSTD_VALARRAY_INCLUDED
#define _RWSTD_VALARRAY_INCLUDED

#include <algorithm>
#include <functional>
#include <numeric>

#include <rw/_math.h>
#include <rw/_array.h>


_RWSTD_NAMESPACE_BEGIN (std)

// forward declarations
class _RWSTD_EXPORT slice;

template <class _TypeT> class slice_array;

class _RWSTD_EXPORT gslice;

template <class _TypeT> class gslice_array;

template <class _TypeT> class mask_array;

template <class _TypeT> class indirect_array;


// 26.3.2
template <class _TypeT>
class valarray
{
public:

    typedef _TypeT value_type;

    // 26.3.2.1, p1
    valarray () { }

    // 26.3.2.1, p2
    _EXPLICIT valarray (size_t __size)
        : _C_array (value_type (), __size) { }

    // 26.3.2.1, p3
    valarray (const value_type& __val, size_t __size)
        : _C_array (__val, __size) { }

    // 26.3.2.1, p4
    valarray (const value_type* __p, size_t __size)
        : _C_array (__p, __size) { }

    // 26.3.2.1, p5
    valarray (const valarray& __rhs)
        : _C_array (__rhs._C_array) { }

    // 26.3.2.1, p6
    valarray (const slice_array<value_type>&);
    valarray (const gslice_array<value_type>&);
    valarray (const mask_array<value_type>&);
    valarray (const indirect_array<value_type>&);

    // 26.3.2.2, p1 - assignment
    valarray& operator= (const valarray &__rhs) {
        if (this != &__rhs)
            _C_array = __rhs._C_array;
        return *this;
    }

    // 26.3.2.2, p2 - assignment
    valarray& operator= (const value_type &__val) {
        return _STD::fill (_C_array.begin (), _C_array.end (), __val), *this;
    }

    // 26.3.2.2, p3 - assignment
    valarray& operator= (const slice_array<value_type>&);
    valarray& operator= (const gslice_array<value_type>&);
    valarray& operator= (const mask_array<value_type>&);
    valarray& operator= (const indirect_array<value_type>&);

    // 26.3.2.3 - element access
    value_type operator[] (size_t __i) const {
        _RWSTD_ASSERT (__i < size ());
        return _C_array[__i];
    }

    value_type& operator[] (size_t __i) {
        _RWSTD_ASSERT (__i < size ());
        return _C_array[__i];
    }

    // 26.3.2.4 - subset operations
    valarray                   operator[] (slice) const;
    slice_array<value_type>    operator[] (slice);
    valarray                   operator[] (const gslice&) const;
    gslice_array<value_type>   operator[] (const gslice&);
    valarray                   operator[] (const valarray<bool>&) const;
    mask_array<value_type>     operator[] (const valarray<bool>&);
    valarray                   operator[] (const valarray<size_t>&) const;
    indirect_array<value_type> operator[] (const valarray<size_t>&);

    // 26.3.2.5 - unary operators
    valarray operator+ () const;
    valarray operator- () const;
    valarray operator~ () const;
    valarray<bool> operator! () const;

    // 26.3.2.6, p1 - computed assignment
    valarray& operator*= (const valarray&);
    valarray& operator/= (const valarray&);
    valarray& operator+= (const valarray&);
    valarray& operator-= (const valarray&);
    valarray& operator%= (const valarray&);
    valarray& operator^= (const valarray&);
    valarray& operator&= (const valarray&);
    valarray& operator|= (const valarray&);
    valarray& operator<<= (const valarray&);
    valarray& operator>>= (const valarray&);

    // 26.3.2.6, p5 - computed assignment
    valarray& operator*= (const value_type&);
    valarray& operator/= (const value_type&);
    valarray& operator%= (const value_type&);
    valarray& operator+= (const value_type&);
    valarray& operator-= (const value_type&);
    valarray& operator^= (const value_type&);
    valarray& operator&= (const value_type&);
    valarray& operator|= (const value_type&);
    valarray& operator<<= (const value_type&);
    valarray& operator>>= (const value_type&);

    // 26.3.2.7, p1
    size_t size () const {
        return _C_array.size ();
    }

    // 26.3.2.7, p2
    value_type sum () const {
        return accumulate (_C_array.begin (), _C_array.end (), value_type ());
    }

    // 26.3.2.7, p3
    value_type min () const {
        _RWSTD_ASSERT (0 != size ());
        return *min_element (_C_array.begin (), _C_array.end ());
    }

    // 26.3.2.7, p4
    value_type max () const {
        _RWSTD_ASSERT (0 != size ());
        return *max_element (_C_array.begin (), _C_array.end ());
    }

    // 26.3.2.7, p5 - ordinary shift
    valarray shift (int) const;

    // 26.3.2.7, p7 - circular shift
    valarray cshift (int) const;

    // 26.3.2.7, p8
    valarray apply (value_type func (value_type)) const;
    valarray apply (value_type func (const value_type&)) const;

    // 26.3.2.7, p9
    void resize (size_t __size, value_type __val = value_type ()) {
        _C_array.resize (__size, __val);
    }

    // implementation
    valarray (_RW::__rw_array<value_type> &__rhs) {
        _C_array.swap (__rhs);
    }

    _RW::__rw_array<value_type> _C_array;
};


_RWSTD_NAMESPACE_END   // std


_RWSTD_NAMESPACE_BEGIN (__rw)


template<class _TypeT, class _UnaryFunction>
inline _STD::valarray<_TypeT>
__rw_unary_function (const _STD::valarray<_TypeT> &__val, _UnaryFunction __fun)
{
    // allocate but do not initialize
    __rw_array<_TypeT> __tmp (__val.size ());

    typedef _STD::raw_storage_iterator<_TypeT*, _TypeT> _Iter;

    // apply `fun' to each element of `a' and initialize `tmp'
    _STD::transform (__val._C_array.begin (), __val._C_array.end (),
                     _Iter (__tmp.begin ()), __fun);
    
    return _STD::valarray<_TypeT>(__tmp);
}


// implements symmetric non-member valarray binary operators
template<class _TypeT, class _BinaryFunction>
inline _STD::valarray<_TYPENAME _BinaryFunction::result_type>
__rw_binary_function (const _STD::valarray<_TypeT> &__lhs, 
                      const _STD::valarray<_TypeT> &__rhs, 
                      _BinaryFunction               __fun)
{
    typedef _TYPENAME _BinaryFunction::result_type                result_type;
    typedef _STD::raw_storage_iterator<result_type*, result_type> _Iter;

    // allocate but do not initialize
    __rw_array<result_type> __tmp =
        __rw_array<result_type>(_STD::min (__lhs.size (), __rhs.size ()));

    // apply `fun' to each pair of elements of `lhs' and `rhs'
    _STD::transform (__lhs._C_array.begin (),
                     __lhs._C_array.begin () + __tmp.size (), 
                     __rhs._C_array.begin (), _Iter (__tmp.begin ()), __fun);
    
    return _STD::valarray<result_type>(__tmp);
}


// implements asymmetric non-member valarray binary operators
template<class _TypeT, class _BinaryFunction>
inline _STD::valarray<_TYPENAME _BinaryFunction::result_type>
__rw_binary_function (const _STD::valarray<_TypeT> &__val, 
                      _BinaryFunction               __fun)
{
    typedef _TYPENAME _BinaryFunction::result_type                result_type;
    typedef _STD::raw_storage_iterator<result_type*, result_type> _Iter;

    // allocate but do not initialize
    __rw_array<result_type> __tmp = __rw_array<result_type>(__val.size ());

    // apply `fun' to each element of `a' and initialize `tmp'
    _STD::transform (__val._C_array.begin (), __val._C_array.end (),
                     _Iter (__tmp.begin ()), __fun);
    
    return _STD::valarray<result_type>(__tmp);
}


template <class _TypeT, class _UnaryFunction>
inline void
__rw_unary_function (const _STD::slice_array<_TypeT>&,
                     const _STD::valarray<_TypeT>&,
                     _UnaryFunction);


template <class _TypeT, class _BinaryFunction>
inline void 
__rw_binary_function (const _STD::slice_array<_TypeT>&,
                      const _STD::valarray<_TypeT>&,
                      _BinaryFunction);


template <class _TypeT, class _UnaryFunction>
inline void
__rw_unary_function (const _STD::mask_array<_TypeT>&,
                     const _STD::valarray<_TypeT>&,
                     _UnaryFunction);


template <class _TypeT, class _BinaryFunction>
inline void
__rw_binary_function (const _STD::mask_array<_TypeT>&,
                      const _STD::valarray<_TypeT>&,
                      _BinaryFunction);


template <class _TypeT, class _UnaryFunction>
inline void
__rw_unary_function (const _STD::indirect_array<_TypeT>&,
                     const _STD::valarray<_TypeT>&,
                     _UnaryFunction);


template <class _TypeT, class _BinaryFunction>
inline void
__rw_binary_function (const _STD::indirect_array<_TypeT>&,
                      const _STD::valarray<_TypeT>&,
                      _BinaryFunction);


_RWSTD_NAMESPACE_END   // __rw


_RWSTD_NAMESPACE_BEGIN (std)


template<class _TypeT>
inline valarray<_TypeT>
valarray<_TypeT>::operator+ () const
{
    return _RW::__rw_unary_function (*this, _RW::unary_plus<_TypeT>());
}


template <class _TypeT>
inline valarray<_TypeT>
valarray<_TypeT>::operator- () const
{
    return _RW::__rw_unary_function (*this, negate<_TypeT>());
}


template <class _TypeT>
inline valarray<_TypeT>
valarray<_TypeT>::operator~ () const
{
    return _RW::__rw_unary_function (*this, _RW::bitwise_complement<_TypeT>());
}


template <class _TypeT>
inline valarray<bool> valarray<_TypeT>::operator! () const
{
    _RW::__rw_array<bool> __tmp = _RW::__rw_array<bool>(size ());

    transform (_C_array.begin (), _C_array.end (), __tmp.begin (), 
               logical_not<_TypeT>());
    
    return valarray<bool>(__tmp);
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator*= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               multiplies<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator/= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               divides<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator+= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               plus<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator-= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               minus<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator%= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               modulus<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator^= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               _RW::exclusive_or<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator&= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               _RW::bitwise_and<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator|= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               _RW::bitwise_or<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator<<= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               _RW::shift_left<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator>>= (const valarray<_TypeT>& __rhs)
{
    transform (_C_array.begin (), 
               _C_array.begin () + _STD::min (size (), __rhs.size ()), 
               __rhs._C_array.begin (), _C_array.begin (), 
               _RW::shift_right<_TypeT>());

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator*= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (multiplies<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>& valarray<_TypeT>::operator/= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (divides<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>& valarray<_TypeT>::operator+= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (plus<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>& valarray<_TypeT>::operator-= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (minus<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>& valarray<_TypeT>::operator%= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (modulus<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>& valarray<_TypeT>::operator^= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (_RW::exclusive_or<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>& valarray<_TypeT>::operator&= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (_RW::bitwise_and<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>& valarray<_TypeT>::operator|= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (_RW::bitwise_or<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>& valarray<_TypeT>::operator<<= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (_RW::shift_left<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>& valarray<_TypeT>::operator>>= (const _TypeT& __rhs)
{
    transform (_C_array.begin (), _C_array.end (), _C_array.begin (), 
               bind2nd (_RW::shift_right<_TypeT>(), __rhs));

    return *this;
}


template <class _TypeT>
inline valarray<_TypeT>
valarray<_TypeT>::apply (value_type __fun (value_type)) const
{
    return _RW::__rw_unary_function (*this, __fun);
}


template <class _TypeT>
inline valarray<_TypeT>
valarray<_TypeT>::apply (value_type __fun (const value_type&)) const
{
    return _RW::__rw_unary_function (*this, __fun);
} 


// 26.3.3 - valarray non-members


// 26.3.3.1 - valarray binary operators
template<class _TypeT>
inline valarray<_TypeT>
operator* (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) *= __rhs;
}
 
template<class _TypeT>
inline valarray<_TypeT>
operator/ (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) /= __rhs;
}
 

template<class _TypeT>
inline valarray<_TypeT>
operator% (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) %= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator+ (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) += __rhs;
}
 
template<class _TypeT>
inline valarray<_TypeT>
operator- (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) -= __rhs;
}
  
template<class _TypeT>
inline valarray<_TypeT>
operator^ (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) ^= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator& (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) &= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator| (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) |= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator<< (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) <<= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator>>(const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return valarray<_TypeT>(__lhs) >>= __rhs;
}

template<class _TypeT>
inline valarray<bool>
operator&& (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__lhs, __rhs, logical_and<_TypeT>());
}

template<class _TypeT>
inline valarray<bool>
operator|| (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__lhs, __rhs, logical_or<_TypeT>());
}

template<class _TypeT>
inline valarray<_TypeT>
operator* (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) *= __rhs;
}
 
template<class _TypeT>
inline valarray<_TypeT>
operator/ (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) /= __rhs;
}
 
template<class _TypeT>
inline valarray<_TypeT>
operator% (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) %= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator+ (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) += __rhs;
}
 
template<class _TypeT>
inline valarray<_TypeT>
operator- (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) -= __rhs;
}
  
template<class _TypeT>
inline valarray<_TypeT>
operator^ (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) ^= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator& (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) &= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator| (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) |= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator<< (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) <<= __rhs;
}

template<class _TypeT>
inline valarray<_TypeT>
operator>>(const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return valarray<_TypeT>(__lhs) >>= __rhs;
}


// 26.3.3.2 - valarray logical operators
template<class _TypeT>
inline valarray<bool>
operator&& (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return _RW::__rw_binary_function (__lhs,
                                      bind2nd (equal_to<_TypeT>(), __rhs));
}

template<class _TypeT>
inline valarray<bool>
operator|| (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return _RW::__rw_binary_function (__lhs,
                                      bind2nd (logical_or<_TypeT>(), __rhs));
}


template<class _TypeT>
inline valarray<_TypeT>
operator* (const _TypeT& __lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs,
                                      bind1st (multiplies<_TypeT>(), __lhs));
}
 
template<class _TypeT>
inline valarray<_TypeT>
operator/ (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs,
                                      bind1st (divides<_TypeT>(), __lhs));
}
 
template<class _TypeT>
inline valarray<_TypeT>
operator% (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs,
                                      bind1st (modulus<_TypeT>(), __lhs));
}

template<class _TypeT>
inline valarray<_TypeT>
operator+ (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, bind1st (plus<_TypeT>(), __lhs));
}
 
template<class _TypeT>
inline valarray<_TypeT>
operator- (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, bind1st (minus<_TypeT>(), __lhs));
}
 
template<class _TypeT>
inline valarray<_TypeT>
operator^ (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, 
                                 bind1st (_RW::exclusive_or<_TypeT>(), __lhs));
}

template<class _TypeT>
inline valarray<_TypeT>
operator& (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, 
                                 bind1st (_RW::bitwise_and<_TypeT>(), __lhs));
}

template<class _TypeT>
inline valarray<_TypeT>
operator| (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, 
                                 bind1st (_RW::bitwise_or<_TypeT>(), __lhs));
}


template<class _TypeT>
inline valarray<_TypeT>
operator<< (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, 
                                 bind1st (_RW::shift_left<_TypeT>(), __lhs));
}

template<class _TypeT>
inline valarray<_TypeT>
operator>>(const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, 
                                 bind1st (_RW::shift_right<_TypeT>(), __lhs));
}

template<class _TypeT>
inline valarray<bool>
operator&& (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, 
                                 bind1st (logical_and<_TypeT>(), __lhs));
}

template<class _TypeT>
inline valarray<bool>
operator|| (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, 
                                 bind1st (logical_or<_TypeT>(), __lhs));
}

template<class _TypeT>
inline valarray<bool>
operator== (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__lhs, __rhs, equal_to<_TypeT>());
}
    
template<class _TypeT>
inline valarray<bool>
operator!= (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__lhs, __rhs, not_equal_to<_TypeT>());
}
   
template<class _TypeT>
inline valarray<bool>
operator< (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__lhs, __rhs, less<_TypeT>());
}
 
template<class _TypeT>
inline valarray<bool>
operator>(const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__lhs, __rhs, greater<_TypeT>());
}
   
template<class _TypeT>
inline valarray<bool>
operator<= (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__lhs, __rhs, less_equal<_TypeT>());
}

template<class _TypeT>
valarray<bool>
operator>= (const valarray<_TypeT> &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__lhs, __rhs, greater_equal<_TypeT>());
}
 
template<class _TypeT>
inline valarray<bool>
operator== (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return _RW::__rw_binary_function (__lhs,
                                      bind2nd (equal_to<_TypeT>(), __rhs));
}
 
template<class _TypeT>
inline valarray<bool>
operator!= (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return _RW::__rw_binary_function (__lhs, 
                                      bind2nd (not_equal_to<_TypeT>(), __rhs));
}
 
template<class _TypeT>
inline valarray<bool>
operator< (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return _RW::__rw_binary_function (__lhs, bind2nd (less<_TypeT>(), __rhs));
}

template<class _TypeT>
inline valarray<bool>
operator>(const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return _RW::__rw_binary_function (__lhs,
                                      bind2nd (greater<_TypeT>(), __rhs));
}
 
template<class _TypeT>
inline valarray<bool>
operator<= (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return _RW::__rw_binary_function (__lhs,
                                      bind2nd (less_equal<_TypeT>(), __rhs));
}
  
template<class _TypeT>
inline valarray<bool>
operator>= (const valarray<_TypeT> &__lhs, const _TypeT &__rhs)
{
    return _RW::__rw_binary_function (__lhs, 
                                      bind2nd (greater_equal<_TypeT>(), __rhs));
}
 
template<class _TypeT>
inline valarray<bool>
operator== (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs,
                                      bind1st (equal_to<_TypeT>(), __lhs));
}
 
template<class _TypeT>
inline valarray<bool>
operator!= (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, 
                                      bind1st (not_equal_to<_TypeT>(), __lhs));
}
 
template<class _TypeT>
inline valarray<bool>
operator< (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, bind1st (less<_TypeT>(), __lhs));
}
 
template<class _TypeT>
inline valarray<bool>
operator>(const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs,
                                      bind1st (greater<_TypeT>(), __lhs));
}
 
template<class _TypeT>
inline valarray<bool>
operator<= (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs,
                                      bind1st (less_equal<_TypeT>(), __lhs));
}
  
template<class _TypeT>
valarray<bool> operator>= (const _TypeT &__lhs, const valarray<_TypeT> &__rhs)
{
    return _RW::__rw_binary_function (__rhs, 
                                      bind1st (greater_equal<_TypeT>(), __lhs));
}
 

// 26.3.3.3 - valarray transcendentals

// can't use function objects in definitions below due to different linkage
// of the math functions' overloads (e.g., extern "C" double cos (double)
// and extern "C++" float cos (float), etc...)
template<class _TypeT>
inline valarray<_TypeT> abs (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = abs (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> acos (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = acos (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> asin (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = asin (__val [__i]);

    return valarray<_TypeT>(__tmp);
}


template<class _TypeT>
valarray<_TypeT> atan (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = atan (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> cos (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = cos (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> cosh (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = cosh (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> exp (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = exp (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> log (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = log (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> log10 (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = log10 (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> sinh (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = sinh (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> sin (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = sin (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> sqrt (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = sqrt (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> tan (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = tan (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> tanh (const valarray<_TypeT> &__val)
{
    _RW::__rw_array<_TypeT> __tmp (__val.size ());

    for (size_t __i = 0; __i != __val.size (); ++__i)
        __tmp [__i] = tanh (__val [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT>
atan2 (const valarray<_TypeT> &__x, const valarray<_TypeT> &__y)
{
    _RWSTD_ASSERT (__x.size () == __y.size ());

    _RW::__rw_array<_TypeT> __tmp (__x.size ());

    for (size_t __i = 0; __i != __tmp.size (); ++__i)
        __tmp [__i] = atan2 (__x [__i], __y [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> atan2 (const valarray<_TypeT> &__x, const _TypeT &__y)
{
    _RW::__rw_array<_TypeT> __tmp (__x.size ());

    for (size_t __i = 0; __i != __tmp.size (); ++__i)
        __tmp [__i] = atan2 (__x [__i], __y);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> atan2 (const _TypeT &__x, const valarray<_TypeT> &__y)
{
    _RW::__rw_array<_TypeT> __tmp (__y.size ());

    for (size_t __i = 0; __i != __tmp.size (); ++__i)
        __tmp [__i] = atan2 (__x, __y [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT>
pow (const valarray<_TypeT> &__x, const valarray<_TypeT> &__y)
{
    _RWSTD_ASSERT (__x.size () == __y.size ());

    _RW::__rw_array<_TypeT> __tmp (__x.size ());

    for (size_t __i = 0; __i != __tmp.size (); ++__i)
        __tmp [__i] = pow (__x [__i], __y [__i]);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> pow (const valarray<_TypeT> &__x, const _TypeT &__y)
{
    _RW::__rw_array<_TypeT> __tmp (__x.size ());

    for (size_t __i = 0; __i != __tmp.size (); ++__i)
        __tmp [__i] = pow (__x [__i], __y);

    return valarray<_TypeT>(__tmp);
}

template<class _TypeT>
inline valarray<_TypeT> pow (const _TypeT &__x, const valarray<_TypeT> &__y)
{
    _RW::__rw_array<_TypeT> __tmp (__y.size ());

    for (size_t __i = 0; __i != __tmp.size (); ++__i)
        __tmp [__i] = pow (__x, __y [__i]);

    return valarray<_TypeT>(__tmp);
}


// 26.3.4
class _RWSTD_EXPORT slice
{
public:

    slice (): _C_start (0), _C_length (0), _C_stride (0) { }

    slice (size_t __start, size_t __length, size_t __stride)
      : _C_start (__start)
      , _C_length (__length)
      , _C_stride (__stride)
    { }

    // 26.3.4.2 - slice access functions
    size_t start () const {
        return _C_start;
    }

    size_t size () const {
        return _C_length;
    }

    size_t stride () const {
        return _C_stride;
    }

private:

    size_t _C_start;   // starting offset
    size_t _C_length;  // length of this slice
    size_t _C_stride;  // offset between elements
};


// 26.3.5 - helper class not to be directly used
template <class _TypeT>
class slice_array
{
    friend class valarray<_TypeT>;

public:

    typedef _TypeT value_type;

    slice_array (const slice_array &__rhs)
        : _C_array(__rhs.get_ref_mem_array()),
          _C_slice(__rhs.get_slice())
        { }
          
    // implementation
    slice_array (_RW::__rw_array<value_type>* __a, const slice &__s) 
        : _C_array (__a),
          _C_slice (__s)
        { }

    _RW::__rw_array<value_type>* get_ref_mem_array () const {
        return _C_array;
    }

    slice get_slice () const {
        return _C_slice;
    }

    // 26.3.5.4 - fill function
    void operator= (const value_type&) const;

    // 26.3.5.2 - assignment
    void operator= (const valarray<value_type> &__rhs) const {
        _RW::__rw_unary_function (*this, __rhs, _RW::identity<value_type>());
    }

    // 26.3.5.3 - slice_array computed assignment
    void operator*= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, multiplies<value_type>());
    }

    void operator/= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, divides<value_type>());
    }

    void operator+= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, plus<value_type>());
    }

    void operator-= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, minus<value_type>());
    }

    void operator%= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, modulus<value_type>());
    }

    void operator^= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::exclusive_or<value_type>());
    }

    void operator&= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::bitwise_and<value_type>());
    }

    void operator|= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, _RW::bitwise_or<value_type>());
    }

    void operator<<= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, _RW::shift_left<value_type>());
    }

    void operator>>= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::shift_right<value_type>());
    }

private:
    slice_array (); 
    slice_array& operator= (const slice_array&);

    _RW::__rw_array<value_type> *_C_array;   // the referenced valarray
    slice                        _C_slice;   // slice of referenced valarray
};


template <class _TypeT>
inline void slice_array<_TypeT>::operator= (const value_type &__rhs) const
{
    // assign the value `__rhs' to the given slice of valarray
    for (size_t __i = _C_slice.start(), __j = 0;
         __i < _C_array->size () && __j != _C_slice.size ();
         __i += _C_slice.stride (), ++__j)
        (*_C_array)[__i] = __rhs;
}



// 26.3.6 - generalized slice of a valarray
class _RWSTD_EXPORT gslice
{
public:

    // 26.3.6.1
    gslice ()
        : _C_start (0),
          _C_reset (true)
        { }
         

    gslice (size_t                  __start,
            const valarray<size_t>& __length,
            const valarray<size_t>& __stride)
        : _C_start (__start),
          _C_length (__length),
          _C_stride (__stride),
          _C_reset (true),
          _C_r_length (size_t (), __length.size ()) {
        _RWSTD_ASSERT (_C_length.size () == _C_stride.size ());
        }

    gslice (const gslice &__rhs) 
        : _C_start (__rhs._C_start),
          _C_length (__rhs._C_length),
          _C_stride (__rhs._C_stride),
          _C_reset (true),
          _C_r_length (size_t (), __rhs._C_length.size ()) {
        _RWSTD_ASSERT (_C_length.size () == _C_stride.size ());
    }

    // 26.3.6.2
    size_t start () const {
        return _C_start;
    }

    valarray<size_t> size () const {
        return _C_length;
    }

    valarray<size_t> stride () const {
        return _C_stride;
    }

    // convenience functions
    size_t next_ind ();

    bool is_reseted () const {
        return _C_reset;
    }

    size_t ind_numb () const;

private:

    size_t           _C_start;    // starting offset
    valarray<size_t> _C_length;   // set of lengths (sizes equal)
    valarray<size_t> _C_stride;   // set of strides (sizes equal)

    bool              _C_reset;
    valarray<size_t>  _C_r_length;
};


template <class _TypeT>
class gslice_array
{
    friend class valarray<_TypeT>;

public:

    typedef _TypeT value_type;

    gslice_array (const gslice_array<value_type>& __rhs)
        : _C_array (__rhs.get_ref_mem_array ()),
          _C_slice (__rhs.get_slice ())
        { }

    gslice_array (_RW::__rw_array<value_type>* __a, const gslice & __s)
        : _C_array (__a),
          _C_slice (__s)
        { }



    _RW::__rw_array<value_type>* get_ref_mem_array () const {
        return _C_array;
    }

    gslice get_slice () const {
        return _C_slice;
    }

    void operator= (const valarray<value_type> &__rhs) const;
    void operator= (const value_type &__rhs) const;

    void operator*= (const valarray<value_type> &__rhs) const;
    void operator/= (const valarray<value_type> &__rhs) const;
    void operator+= (const valarray<value_type> &__rhs) const;
    void operator-= (const valarray<value_type> &__rhs) const;
    void operator%= (const valarray<value_type> &__rhs) const;
    void operator^= (const valarray<value_type> &__rhs) const;
    void operator&= (const valarray<value_type> &__rhs) const;         
    void operator|= (const valarray<value_type> &__rhs) const;         
    void operator<<= (const valarray<value_type> &__rhs) const;        
    void operator>>= (const valarray<value_type> &__rhs) const;

private:
    gslice_array ();
    gslice_array<value_type>& operator= (const gslice_array<value_type>&);

    _RW::__rw_array<value_type>* _C_array;
    gslice                       _C_slice;
};
 

template <class _TypeT>
class mask_array
{
    friend class valarray<_TypeT>;

public:

    typedef _TypeT value_type;


    mask_array (const mask_array<value_type> &__rhs)
        : _C_array (__rhs.get_ref_mem_array ()),
          _C_valarray (__rhs.get_array ())
        { }

    mask_array (_RW::__rw_array<value_type> *__a, const valarray<bool>& __val)
      : _C_array (__a),
        _C_valarray (__val)
        { }

    _RW::__rw_array<value_type>* get_ref_mem_array () const {
        return _C_array;
    }

    valarray<bool> get_array () const {
        return _C_valarray;
    }

    const valarray<bool>* get_array_pt () const {
        return &_C_valarray;
    }

    void operator= (const value_type&) const;

    void operator= (const valarray<value_type> &__rhs) const {
        _RW::__rw_unary_function (*this, __rhs, _RW::identity<value_type>());
    }

    void operator*= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, multiplies<value_type>());
    }

    void operator/= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, divides<value_type>());
    }

    void operator+= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, plus<value_type>());
    }

    void operator-= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, minus<value_type>());
    }

    void operator%= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, modulus<value_type>());
    }

    void operator^= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::exclusive_or<value_type>());
    }

    void operator&= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::bitwise_and<value_type>());
    }

    void operator|= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, _RW::bitwise_or<value_type>());
    }

    void operator<<= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs, _RW::shift_left<value_type>());
    }

    void operator>>= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::shift_right<value_type>());
    }

private:
    mask_array ();
    mask_array<value_type>& operator= (const mask_array<value_type>&); 

    _RW::__rw_array<value_type>* _C_array;
    valarray<bool>               _C_valarray;
};


template <class _TypeT>
void mask_array<_TypeT>::operator= (const value_type &__rhs) const
{
    _RWSTD_ASSERT (0 != get_ref_mem_array ());

    _RW::__rw_array<_TypeT> &__a = *get_ref_mem_array ();

    for (size_t __i = 0; __i != _C_valarray.size (); ++__i) {
        if (_C_valarray [__i])
            __a [__i] = __rhs;
    }
}
 
/****************************************************************
 *                       INDIRECT_ARRAY                         *
 ****************************************************************/


template <class _TypeT>
class indirect_array
{
    friend class valarray<_TypeT>;

public:

    typedef _TypeT value_type;

    indirect_array (const indirect_array<value_type>& __sl)
      :_C_array (__sl.get_ref_mem_array ()),
       _C_valarray (__sl.get_array ())
        { }

    indirect_array (_RW::__rw_array<value_type> *__a,
                    const valarray<size_t>      &__v) 
        :_C_array (__a),
         _C_valarray (__v)
        { }

    _RW::__rw_array<value_type>* get_ref_mem_array () const {
        return _C_array;
    }

    valarray<size_t> get_array () const {
        return _C_valarray;
    }

    const valarray<size_t>* get_array_pt () const {
        return &_C_valarray;
    }

    void operator= (const value_type&) const;

    void operator= (const valarray<value_type> &__rhs) const {
        _RW::__rw_unary_function (*this, __rhs,
                                  _RW::identity<value_type>());
    }

    void operator*= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   multiplies<value_type>());
    }

    void operator/= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   divides<value_type>());
    }

    void operator+= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   plus<value_type>());
    }

    void operator-= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   minus<value_type>());
    }

    void operator%= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   modulus<value_type>());
    }

    void operator^= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::exclusive_or<value_type>());
    }

    void operator&= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::bitwise_and<value_type>());
    }

    void operator|= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::bitwise_or<value_type>());
    }

    void operator<<= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::shift_left<value_type>());
    }

    void operator>>= (const valarray<value_type> &__rhs) const {
        _RW::__rw_binary_function (*this, __rhs,
                                   _RW::shift_right<value_type>());
    }

private:
    indirect_array ();
    indirect_array& operator= (const indirect_array&); 


    _RW::__rw_array<value_type>* _C_array;
    valarray<size_t>             _C_valarray;
};


template <class _TypeT>
inline void indirect_array<_TypeT>::operator= (const _TypeT &__rhs) const
{
    for (size_t __i = 0; __i != _C_valarray.size (); ++__i)
        (*_C_array)[_C_valarray [__i]] = __rhs;
}


_RWSTD_NAMESPACE_END   // std


_RWSTD_NAMESPACE_BEGIN (__rw)


_USING (_RWSTD_C::size_t);


template <class _TypeT, class _UnaryFunction>
inline void
__rw_unary_function (const _STD::slice_array<_TypeT> &__lhs,
                     const _STD::valarray<_TypeT>    &__rhs,
                           _UnaryFunction             __fun)
{
    _RWSTD_ASSERT (0 != __lhs.get_ref_mem_array ());

    _STD::slice __slice           = __lhs.get_slice ();
    _RW::__rw_array<_TypeT> &__ar = *__lhs.get_ref_mem_array ();

    for (size_t __i = __slice.start(), __j = 0; __j != __slice.size(); ++__j) {
        if (__j < __rhs.size () && __i < __ar.size ())
            __ar [__i] = __fun (__rhs [__j]);
        __i += __slice.stride ();
    }
}


template <class _TypeT, class _BinaryFunction>
inline void
__rw_binary_function (const _STD::slice_array<_TypeT> &__lhs,
                      const _STD::valarray<_TypeT>    &__rhs,
                            _BinaryFunction            __fun)
{
    _RWSTD_ASSERT (0 != __lhs.get_ref_mem_array ());

    _STD::slice __slice           = __lhs.get_slice ();
    _RW::__rw_array<_TypeT> &__ar = *__lhs.get_ref_mem_array ();

    for (size_t __i = __slice.start(), __j = 0; __j != __slice.size(); ++__j) {
        if (__j < __rhs.size () && __i < __ar.size ())
            __ar [__i] = __fun (__ar [__i], __rhs [__j]);
        __i += __slice.stride ();
    }
}


template <class _TypeT, class _UnaryFunction>
inline void
__rw_unary_function (const _STD::mask_array<_TypeT> &__lhs,
                     const _STD::valarray<_TypeT>   &__rhs,
                           _UnaryFunction            __fun)
{
    _RWSTD_ASSERT (0 != __lhs.get_ref_mem_array ());

    _RW::__rw_array<_TypeT>    &__ar    = *__lhs.get_ref_mem_array ();
    const _STD::valarray<bool> &__vlray = *__lhs.get_array_pt ();

    for (size_t __i = 0, __j = 0; __i != __vlray.size (); ++__i)
        if (__vlray [__i])
            __ar [__i] = __fun (__rhs [__j++]);
}


template <class _TypeT, class _BinaryFunction>
inline void
__rw_binary_function (const _STD::mask_array<_TypeT> &__lhs,
                      const _STD::valarray<_TypeT>   &__rhs,
                            _BinaryFunction           __fun)
{
    _RWSTD_ASSERT (0 != __lhs.get_ref_mem_array ());

    _RW::__rw_array<_TypeT>    &__ar    = *__lhs.get_ref_mem_array ();
    const _STD::valarray<bool> &__vlray = *__lhs.get_array_pt ();

    for (size_t __i = 0, __j = 0; __i != __vlray.size (); ++__i)
        if (__vlray [__i])
            __ar [__i] = __fun (__ar [__i], __rhs [__j++]);
}


template <class _TypeT, class _UnaryFunction>
inline void
__rw_unary_function (const _STD::indirect_array<_TypeT> &__lhs,
                     const _STD::valarray<_TypeT>       &__rhs,
                     _UnaryFunction                      __fun)
{
    _RWSTD_ASSERT (0 != __lhs.get_ref_mem_array ());

    _RW::__rw_array<_TypeT>      &__ar    = *__lhs.get_ref_mem_array ();
    const _STD::valarray<size_t> &__vlray = *__lhs.get_array_pt ();

    for (size_t __i = 0; __i != __vlray.size (); ++__i)
        __ar [__vlray [__i]] = __fun (__rhs [__i]);
}


template <class _TypeT, class _BinaryFunction>
inline void
__rw_binary_function (const _STD::indirect_array<_TypeT> &__lhs,
                      const _STD::valarray<_TypeT>       &__rhs,
                      _BinaryFunction                     __fun)

{
    _RWSTD_ASSERT (0 != __lhs.get_ref_mem_array ());

    _RW::__rw_array<_TypeT>      &__ar    = *__lhs.get_ref_mem_array ();
    const _STD::valarray<size_t> &__vlray = *__lhs.get_array_pt ();

    for (size_t __i = 0; __i != __vlray.size (); ++__i)
        __ar [__vlray [__i]] = __fun (__ar [__vlray [__i]], __rhs [__i]);
}


_RWSTD_NAMESPACE_END   // __rw


_RWSTD_NAMESPACE_BEGIN (std)


/*****************************************************************
 *                                                                *
 *                 GSLICE_ARRAY MEMBER FUNCTIONS                  *
 *                                                                *
 ******************************************************************/


// gslice_array inline member functions

template <class _TypeT>
inline void
gslice_array<_TypeT>::operator= (const valarray<_TypeT>& __rhs) const
{
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] = __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
}

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator= (const _TypeT& value) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();

    while( !gsl->is_reseted() )
    {
      (*_C_array)[__i] = value;
      __i= gsl->next_ind();
    }
  }


// computed assignment

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator*= (const valarray<_TypeT>& __rhs) const
  {
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] *= __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator/= (const valarray<_TypeT>& __rhs) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] /= __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator+= (const valarray<_TypeT>& __rhs) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] += __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator-= (const valarray<_TypeT>& __rhs) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] -= __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }


  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator%= (const valarray<_TypeT>& __rhs) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] %= __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator^= (const valarray<_TypeT>& __rhs) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] ^= __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator&= (const valarray<_TypeT>& __rhs) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] &= __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator|= (const valarray<_TypeT>& __rhs) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] |= __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator<<= (const valarray<_TypeT>& __rhs) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] <<= __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }

  template <class _TypeT>
  inline void gslice_array<_TypeT>::operator>>= (const valarray<_TypeT>& __rhs) const
  { 
    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &_C_slice);
    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( (!gsl->is_reseted()) && (__cpt < __rhs.size()) )
    {
      (*_C_array)[__i] >>= __rhs[__cpt];
      __i= gsl->next_ind();
      __cpt++;
    }
  }


inline size_t gslice::ind_numb() const
{
    size_t value = 1;
    for(size_t __i=0; __i< _C_length.size(); __i++ )
        value*= _C_length[__i];

    return value;
}


template <class _TypeT> 
inline valarray<_TypeT> valarray<_TypeT>::operator[] (slice __slice) const
{
    _RW::__rw_array <_TypeT> __tmp =
        _RW::__rw_array <_TypeT>(_TypeT (), size ());
      
    for (size_t __i = __slice.start (), __j = 0; __j != __slice.size();
        __i += __slice.stride (), ++__j)
        __tmp [__j] = _C_array [__i];

    return valarray<_TypeT>(__tmp);
}


template <class _TypeT>
inline valarray<_TypeT>::valarray (const slice_array<_TypeT>& sl_ar)
{
    _RW::__rw_array <_TypeT> __tmp =
        _RW::__rw_array <_TypeT>(_TypeT (), sl_ar.get_slice ().size());
      
    size_t __i = sl_ar.get_slice().start();
    size_t __cpt = 0; 

    while( __cpt < sl_ar.get_slice().size() )
    {
        __tmp[__cpt] = (*(sl_ar.get_ref_mem_array()))[__i];
        __i+= sl_ar.get_slice().stride();
        __cpt++;
    }

    _C_array.swap (__tmp);
}
   

template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator= (const slice_array<_TypeT>& sl_ar)
{ 
    _RW::__rw_array <_TypeT> __tmp =
        _RW::__rw_array <_TypeT>(_TypeT (), sl_ar.get_slice ().size());

    size_t __i = sl_ar.get_slice().start();
    size_t __cpt = 0; 

    while( __cpt < sl_ar.get_slice().size() )
    {
      __tmp[__cpt] = (*(sl_ar.get_ref_mem_array()))[__i];
      __i+= sl_ar.get_slice().stride();
      __cpt++;
    }

    if ( &_C_array == sl_ar.get_ref_mem_array() )
      _C_array.resize(0); 

    _C_array.swap (__tmp);

    return *this;
}


template <class _TypeT> 
inline valarray<_TypeT>
valarray<_TypeT>::operator[](const gslice& sl) const
{
    _RW::__rw_array <_TypeT> __tmp =
        _RW::__rw_array <_TypeT>(_TypeT (), sl.ind_numb());

    gslice *gsl = _RWSTD_CONST_CAST (gslice*, &sl);

    size_t __i = gsl->next_ind();
    size_t __cpt = 0;

    while( !sl.is_reseted() )
    {
      __tmp[__cpt] = _C_array[__i];
      __i= gsl->next_ind();
      __cpt++;
    }

    return valarray<_TypeT>(__tmp);
}


template <class _TypeT>
inline valarray<_TypeT>::valarray(const gslice_array<_TypeT>& sl_ar)
{
    gslice sl(sl_ar.get_slice());

    _RW::__rw_array <_TypeT> __tmp =
        _RW::__rw_array <_TypeT>(_TypeT (), sl.ind_numb());

    size_t __i = sl.next_ind();
    size_t __cpt = 0;

    while( !sl.is_reseted() )
    {
      __tmp[__cpt] = (*(sl_ar.get_ref_mem_array()))[__i];
      __i= sl.next_ind();
      __cpt++;
    }

    _C_array.swap (__tmp);
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator= (const gslice_array<_TypeT>& sl_ar)
{ 
    gslice sl(sl_ar.get_slice());

    _RW::__rw_array <_TypeT> __tmp =
        _RW::__rw_array <_TypeT>(_TypeT (), sl.ind_numb());

    size_t __i = sl.next_ind();
    size_t __cpt = 0;

    while( !sl.is_reseted() )
    {
      __tmp[__cpt] = (*(sl_ar.get_ref_mem_array()))[__i];
      __i= sl.next_ind();
      __cpt++;
    }

    if ( &_C_array == sl_ar.get_ref_mem_array() )
      _C_array.resize(0); 

    _C_array.swap (__tmp);

    return *this;
}


template <class _TypeT> 
inline valarray<_TypeT>
valarray<_TypeT>::operator[](const valarray<bool>& __rhs) const
{
    size_t __i, __n = 0;

    for(__i=0; __i < __rhs.size(); __i++ )
      if ( __rhs[__i]) __n++;

    _RW::__rw_array <_TypeT> __tmp = _RW::__rw_array <_TypeT>(_TypeT (), __n);
      
    size_t __cpt = 0; 

    for( __i=0; __i < __rhs.size(); __i++ )
        if ( __rhs[__i]) __tmp[__cpt++] = _C_array[__i];

    return valarray<_TypeT>(__tmp);
}


template <class _TypeT>
inline valarray<_TypeT>::valarray(const mask_array<_TypeT>& __rhs)
{

    mask_array<_TypeT>  *msk = _RWSTD_CONST_CAST (mask_array<_TypeT>*, &__rhs);
    const valarray<bool>*sec = msk->get_array_pt();

    size_t __i, __n = 0;

    for(__i = 0; __i < sec->size(); __i++)
        if ( (*sec)[__i]) __n++;

    _RW::__rw_array <_TypeT> __tmp = _RW::__rw_array <_TypeT>(_TypeT (), __n);
      
    size_t __cpt = 0; 

    for( __i=0; __i < sec->size(); __i++ )
      if ( (*sec)[__i]) __tmp[__cpt++] = (*(__rhs.get_ref_mem_array()))[__i];

    _C_array.swap (__tmp);
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator= (const mask_array<_TypeT>& __rhs)
{ 
    mask_array<_TypeT>  *msk = _RWSTD_CONST_CAST (mask_array<_TypeT>*, &__rhs);
    const valarray<bool>*sec = msk->get_array_pt();

    size_t __i, __n = 0;

    for (__i = 0; __i < sec->size(); __i++)
        if ((*sec)[__i])
            __n++;

    _RW::__rw_array <_TypeT> __tmp = _RW::__rw_array <_TypeT>(_TypeT (), __n);
      
    size_t __cpt = 0; 

    for( __i=0; __i < sec->size(); __i++ )
      if ( (*sec)[__i]) __tmp[__cpt++] = (*(__rhs.get_ref_mem_array()))[__i];

    if ( &_C_array == __rhs.get_ref_mem_array() )
      _C_array.resize(0); 

    _C_array.swap (__tmp);

    return *this;
}


template <class _TypeT> 
inline valarray<_TypeT>
valarray<_TypeT>::operator[](const valarray<size_t>& __rhs) const
{
    _RW::__rw_array <_TypeT> __tmp = _RW::__rw_array <_TypeT>(__rhs.size ());

    for (size_t __i = 0; __i != __rhs.size (); ++__i)
        new (&__tmp [__i]) _TypeT ((*this)[__rhs [__i]]);

    return valarray<_TypeT>(__tmp);
}


template <class _TypeT>
inline valarray<_TypeT>::valarray (const indirect_array<_TypeT>& __rhs)
{
    indirect_array<_TypeT> *__ia =
        _RWSTD_CONST_CAST (indirect_array<_TypeT>*, &__rhs);

    const valarray<size_t> *__sec = __ia->get_array_pt();

    _RW::__rw_array <_TypeT> __tmp =
        _RW::__rw_array <_TypeT>(_TypeT (), __sec->size());
      
    size_t __cpt = 0; 

    for(size_t __i=0; __i < __sec->size(); __i++ )
      __tmp[__cpt++] = (*(__rhs.get_ref_mem_array()))[(*__sec)[__i]];

    _C_array.swap (__tmp);
}


template <class _TypeT>
inline valarray<_TypeT>&
valarray<_TypeT>::operator= (const indirect_array<_TypeT>& __rhs)
{ 
    indirect_array<_TypeT> *__ia =
        _RWSTD_CONST_CAST (indirect_array<_TypeT>*, &__rhs);

    const valarray<size_t> *__sec = __ia->get_array_pt();

    _RW::__rw_array <_TypeT> __tmp =
        _RW::__rw_array <_TypeT>(_TypeT (), __sec->size());
      
    size_t __cpt = 0; 

    for(size_t __i=0; __i < __sec->size(); __i++ )
      __tmp[__cpt++] = (*(__rhs.get_ref_mem_array()))[(*__sec)[__i]];

    if (&_C_array == __rhs.get_ref_mem_array() )
      _C_array.resize(0); 

    _C_array.swap (__tmp);

    return *this;
}


template <class _TypeT>
inline slice_array<_TypeT>
valarray<_TypeT>::operator[] (slice __x)
{
    return slice_array<value_type>(&_C_array, __x);
}


template <class _TypeT>
inline gslice_array<_TypeT>
valarray<_TypeT>::operator[] (const gslice &__x)
{
    return gslice_array<value_type>(&_C_array, __x);
}


template <class _TypeT>
inline mask_array<_TypeT>
valarray<_TypeT>::operator[] (const valarray<bool> &__x)
{
    return mask_array<value_type>(&_C_array, __x);
}


template <class _TypeT>
inline indirect_array<_TypeT>
valarray<_TypeT>::operator[] (const valarray<size_t> &__x)
{
    return indirect_array<value_type>(&_C_array, __x);
}


_RWSTD_NAMESPACE_END   // std


#ifdef _RWSTD_COMPILE_INSTANTIATE
#  include <valarray.cc>
#endif


#endif   // _RWSTD_VALARRAY_INCLUDED

