williamr@2: // Copyright 2002 The Trustees of Indiana University.
williamr@2: 
williamr@2: // Use, modification and distribution is subject to the Boost Software 
williamr@2: // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
williamr@2: // http://www.boost.org/LICENSE_1_0.txt)
williamr@2: 
williamr@2: //  Boost.MultiArray Library
williamr@2: //  Authors: Ronald Garcia
williamr@2: //           Jeremy Siek
williamr@2: //           Andrew Lumsdaine
williamr@2: //  See http://www.boost.org/libs/multi_array for documentation.
williamr@2: 
williamr@2: #ifndef BOOST_STORAGE_ORDER_RG071801_HPP
williamr@2: #define BOOST_STORAGE_ORDER_RG071801_HPP
williamr@2: 
williamr@2: #include "boost/multi_array/types.hpp"
williamr@2: #include "boost/array.hpp"
williamr@2: #include "boost/multi_array/algorithm.hpp"
williamr@2: #include <algorithm>
williamr@2: #include <cstddef>
williamr@2: #include <functional>
williamr@2: #include <numeric>
williamr@2: #include <vector>
williamr@2: 
williamr@2: namespace boost {
williamr@2: 
williamr@2:   // RG - This is to make things work with VC++. So sad, so sad.
williamr@2:   class c_storage_order; 
williamr@2:   class fortran_storage_order;
williamr@2: 
williamr@2:   template <std::size_t NumDims>
williamr@2:   class general_storage_order
williamr@2:   {
williamr@2:   public:
williamr@2:     typedef detail::multi_array::size_type size_type;
williamr@2:     template <typename OrderingIter, typename AscendingIter>
williamr@2:     general_storage_order(OrderingIter ordering,
williamr@2:                           AscendingIter ascending) {
williamr@2:       boost::detail::multi_array::copy_n(ordering,NumDims,ordering_.begin());
williamr@2:       boost::detail::multi_array::copy_n(ascending,NumDims,ascending_.begin());
williamr@2:     }
williamr@2: 
williamr@2:     // RG - ideally these would not be necessary, but some compilers
williamr@2:     // don't like template conversion operators.  I suspect that not
williamr@2:     // too many folk will feel the need to use customized
williamr@2:     // storage_order objects, I sacrifice that feature for compiler support.
williamr@2:     general_storage_order(const c_storage_order&) {
williamr@2:       for (size_type i=0; i != NumDims; ++i) {
williamr@2:         ordering_[i] = NumDims - 1 - i;
williamr@2:       }
williamr@2:       ascending_.assign(true);
williamr@2:     }
williamr@2: 
williamr@2:     general_storage_order(const fortran_storage_order&) {
williamr@2:       for (size_type i=0; i != NumDims; ++i) {
williamr@2:         ordering_[i] = i;
williamr@2:       }
williamr@2:       ascending_.assign(true);
williamr@2:     }
williamr@2: 
williamr@2:     size_type ordering(size_type dim) const { return ordering_[dim]; }
williamr@2:     bool ascending(size_type dim) const { return ascending_[dim]; }
williamr@2: 
williamr@2:     bool all_dims_ascending() const {
williamr@2:       return std::accumulate(ascending_.begin(),ascending_.end(),true,
williamr@2:                       std::logical_and<bool>());
williamr@2:     }
williamr@2: 
williamr@2:     bool operator==(general_storage_order const& rhs) const {
williamr@2:       return (ordering_ == rhs.ordering_) &&
williamr@2:         (ascending_ == rhs.ascending_);
williamr@2:     }
williamr@2: 
williamr@2:   protected:
williamr@2:     boost::array<size_type,NumDims> ordering_;
williamr@2:     boost::array<bool,NumDims> ascending_;
williamr@2:   };
williamr@2: 
williamr@2:   class c_storage_order 
williamr@2:   {
williamr@2:     typedef detail::multi_array::size_type size_type;
williamr@2:   public:
williamr@2:     // This is the idiom for creating your own custom storage orders.
williamr@2:     // Not supported by all compilers though!
williamr@2: #ifndef __MWERKS__ // Metrowerks screams "ambiguity!"
williamr@2:     template <std::size_t NumDims>
williamr@2:     operator general_storage_order<NumDims>() const {
williamr@2:       boost::array<size_type,NumDims> ordering;
williamr@2:       boost::array<bool,NumDims> ascending;
williamr@2: 
williamr@2:       for (size_type i=0; i != NumDims; ++i) {
williamr@2:         ordering[i] = NumDims - 1 - i;
williamr@2:         ascending[i] = true;
williamr@2:       }
williamr@2:       return general_storage_order<NumDims>(ordering.begin(),
williamr@2:                                             ascending.begin());
williamr@2:     }
williamr@2: #endif
williamr@2:   };
williamr@2: 
williamr@2:   class fortran_storage_order
williamr@2:   {
williamr@2:     typedef detail::multi_array::size_type size_type;
williamr@2:   public:
williamr@2:     // This is the idiom for creating your own custom storage orders.
williamr@2:     // Not supported by all compilers though! 
williamr@2: #ifndef __MWERKS__ // Metrowerks screams "ambiguity!"
williamr@2:     template <std::size_t NumDims>
williamr@2:     operator general_storage_order<NumDims>() const {
williamr@2:       boost::array<size_type,NumDims> ordering;
williamr@2:       boost::array<bool,NumDims> ascending;
williamr@2: 
williamr@2:       for (size_type i=0; i != NumDims; ++i) {
williamr@2:         ordering[i] = i;
williamr@2:         ascending[i] = true;
williamr@2:       }
williamr@2:       return general_storage_order<NumDims>(ordering.begin(),
williamr@2:                                             ascending.begin());
williamr@2:     }
williamr@2: #endif
williamr@2:   };
williamr@2: 
williamr@2: } // namespace boost
williamr@2: 
williamr@2: #endif // BOOST_ARRAY_STORAGE_RG071801_HPP