/*
 *
 * Copyright (c) 2002, 2003 Kresimir Fresl, Toon Knapen and Karl Meerbergen
 *
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * KF acknowledges the support of the Faculty of Civil Engineering,
 * University of Zagreb, Croatia.
 *
 */

#ifndef BOOST_NUMERIC_BINDINGS_TRAITS_VECTOR_TRAITS_HPP
#define BOOST_NUMERIC_BINDINGS_TRAITS_VECTOR_TRAITS_HPP

#include <boost/numeric/bindings/traits/config.hpp>

#ifndef BOOST_NUMERIC_BINDINGS_POOR_MANS_TRAITS

#include <boost/numeric/bindings/traits/detail/generate_const.hpp>
#include <boost/type_traits/remove_const.hpp>
#ifndef BOOST_NUMERIC_BINDINGS_NO_SANITY_CHECK
#  include <boost/type_traits/is_same.hpp>
#  include <boost/static_assert.hpp>
#endif

namespace boost { namespace numeric { namespace bindings { namespace traits {

  /// default_vector_traits is just a base-class that can be
  /// used as the default vector_traits and the different
  /// specialisation to automatically define most of the
  /// functions.
  template <typename V, typename T = typename V::value_type >
  struct default_vector_traits {
    typedef T                                                    value_type;
    typedef typename detail::generate_const<V,value_type>::type* pointer;      // if V is const, pointer will be a const value_type*

    static pointer storage (V& v) { return &v[0]; }
    static std::ptrdiff_t size (V& v) { return static_cast<std::ptrdiff_t>(v.size()); }
    static std::ptrdiff_t stride (V&) { return 1; }
  };

  // vector_detail_traits is used to implement specializations of vector_traits.
  // VIdentifier is the vector_type without const, while VType can have a const.
  // VIdentifier is used to write template specializations for VType and const VType.
  // e.g.  vector_detail_traits< std::vector<int>, std::vector<int> const >
  // e.g.  vector_detail_traits< std::vector<int>, std::vector<int> >
  // Note that  boost::remove_const<VType>::type == VIdentifier.
  template <typename VIdentifier, typename VType>
  struct vector_detail_traits : default_vector_traits<VType, typename VType::value_type >
  {
    typedef VIdentifier identifier_type;
    typedef VType       vector_type;
  };

  // vector_traits<> generic version:
  template <typename V>
  struct vector_traits : vector_detail_traits< typename boost::remove_const<V>::type, V > {};


  ///////////////////////////
  //
  // free accessor functions:
  //
  ///////////////////////////

  template <typename V>
  inline
  typename vector_traits<V>::pointer vector_storage (V& v) {
    return vector_traits<V>::storage (v);
  }

  template <typename V>
  inline
  std::ptrdiff_t vector_size (V& v) {
    return vector_traits<V>::size (v);
  }

  template <typename V>
  inline
  std::ptrdiff_t vector_stride (V& v) {
    return vector_traits<V>::stride (v);
  }

}}}}

#else // BOOST_NUMERIC_BINDINGS_POOR_MANS_TRAITS

#include <boost/numeric/bindings/traits/vector_raw.hpp>

#endif // BOOST_NUMERIC_BINDINGS_POOR_MANS_TRAITS

#endif // BOOST_NUMERIC_BINDINGS_TRAITS_VECTOR_TRAITS_HPP
