text: /**
   * \file dcs/iterator/detail/any_iterator_metafunctions.hpp
   *
   * \brief Meta-functions for generic (type-erased) iterator.
   *
   * (C) Copyright Thomas Becker 2005. Permission to copy, use, modify, sell and
   * distribute this software is granted provided this copyright notice appears
   * in all copies. This software is provided "as is" without express or implied
   * warranty, and with no claim as to its suitability for any purpose.
   *
   * \author Thomas Becker (thomas@styleadvisor.com)
   */
  
  //  (C) Copyright Thomas Becker 2005. Permission to copy, use, modify, sell and
  //  distribute this software is granted provided this copyright notice appears
  //  in all copies. This software is provided "as is" without express or implied
  //  warranty, and with no claim as to its suitability for any purpose.
  
  // File Name
  // =========
  //
  // metafunctions.h
  
  // Description
  // ===========
  //
  // Metafunctions for any_iterator
  
  #ifndef ANY_ITERATOR_METAFUNCTIONS_01102007TMB_HPP
  #define ANY_ITERATOR_METAFUNCTIONS_01102007TMB_HPP
  
  // Revision History
  // ================
  //
  // 27 Dec 2006 (Thomas Becker) Created
  
  // Includes
  // ========
  #include <boost/iterator/iterator_categories.hpp>
  #include <boost/iterator/iterator_traits.hpp>
  #include <boost/type_traits/remove_const.hpp>
  #include <boost/type_traits/remove_reference.hpp>
  #include <boost/type_traits/is_same.hpp>
  #include <boost/type_traits/is_base_of.hpp>
  #include <boost/type_traits/is_convertible.hpp>
  #include <boost/type_traits/is_reference.hpp>
  #include <boost/type_traits/is_pointer.hpp>
  #include <boost/mpl/bool.hpp>
  #include <boost/mpl/and.hpp>
  #include <boost/mpl/or.hpp>
  #include <boost/mpl/not.hpp>
  
  namespace dcs { namespace iterator {
  
    template<
      class Value,
      class Traversal,
      class Reference,
      class Difference
      >
    class any_iterator;
  
    namespace detail
    {
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<typename T>
      struct remove_reference_and_const
      {
        typedef typename boost::remove_const<
          typename boost::remove_reference<
            typename boost::remove_const<
              T
            >::type
          >::type
        >::type type;
      };
      
      ///////////////////////////////////////////////////////////////////////
      // 
      template<typename IteratorReference>
      struct make_iterator_reference_const
      {
        typedef typename boost::mpl::if_< 
          typename boost::is_reference<IteratorReference>::type,
          typename boost::remove_const<
            typename boost::remove_reference<
              typename boost::remove_const<
                IteratorReference
                >::type
              >::type
            >::type const &,
          typename boost::remove_const<
            typename boost::remove_reference<
              typename boost::remove_const<
                IteratorReference
                >::type
              >::type
            >::type const
          >::type type;
      };
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<
        class WrappedIterator,
        class AnyIterator
      >
      struct value_types_erasure_compatible
      {
        // Really, we just want WrappedIterator's value_type to convert to
        // AnyIterator's value_type. But many real world output iterators
        // define their value_type as void. Therefore, we simply ignore
        // the value type for output iterators. That's fine because for
        // output iterators, the relevant type erasure information is all
        // in the reference type.
  
        typedef typename boost::mpl::or_<
          boost::is_same<
            typename boost::iterator_category<WrappedIterator>::type,
            std::output_iterator_tag
          >,
  
          // Really, we just want WrappedIterator's value_type to convert to
          // AnyIterator's value_type. But we need to work around a flaw in
          // boost::is_convertible. boost::is_convertible<X, Y>::value is
          // false whenever X and Y are abstract base classes (even when X
          // and Y are the same). This will be fixed in C++ concepts.
          boost::mpl::or_<
            boost::is_same<
              typename boost::iterator_value<WrappedIterator>::type,
              typename boost::iterator_value<AnyIterator>::type
            >,
            boost::is_base_of<
              typename boost::iterator_value<AnyIterator>::type,
              typename boost::iterator_value<WrappedIterator>::type
            >,
            boost::is_convertible<
              typename boost::iterator_value<WrappedIterator>::type,
              typename boost::iterator_value<AnyIterator>::type
            >
          >
        > type;
      };
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<
        class WrappedIterator,
        class AnyIterator
      >
      struct reference_types_erasure_compatible_1
      {
        typedef typename boost::is_convertible<
          typename boost::iterator_reference<WrappedIterator>::type,
          typename boost::iterator_reference<AnyIterator>::type
        >::type type;
      };
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<
        class WrappedIterator,
        class AnyIterator
      >
      struct reference_types_erasure_compatible_2
      {
        typedef typename boost::mpl::if_<
          boost::is_reference<
            typename boost::iterator_reference<AnyIterator>::type
          >,
          boost::is_reference<
            typename boost::iterator_reference<WrappedIterator>::type
          >,
          boost::mpl::bool_<true>
        >::type type;
      };
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<
        class WrappedIterator,
        class AnyIterator
      >
      struct reference_types_erasure_compatible_3
      {
        
        typedef typename boost::mpl::if_<
          boost::mpl::and_<
            boost::is_reference<
              typename boost::iterator_reference<AnyIterator>::type
            >,
            boost::is_reference<
              typename boost::iterator_reference<WrappedIterator>::type
            >
          >,
          boost::mpl::or_<
            boost::is_same<
              typename remove_reference_and_const<
                typename boost::iterator_reference<AnyIterator>::type
              >::type,
              typename remove_reference_and_const<
                typename boost::iterator_reference<WrappedIterator>::type
              >::type
            >,
            boost::is_base_of<
              typename remove_reference_and_const<
                typename boost::iterator_reference<AnyIterator>::type
              >::type,
              typename remove_reference_and_const<
                typename boost::iterator_reference<WrappedIterator>::type
              >::type
            >
          >,
          boost::mpl::bool_<true>
        >::type type;
      };
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<
        class WrappedIterator,
        class AnyIterator
      >
      struct reference_types_erasure_compatible
      {
        // Output iterators are weird. Many real world output iterators
        // define their reference type as void. In the world of boost
        // iterators, that's terribly wrong, because in that world, an
        // iterator's reference type is always the result type of
        // operator* (and that makes very good sense, too). Therefore,
        // when WrappedIterator is an output iterator, we use
        // WrappedIterator& for WrappedIterator's reference type,
        // because that's the real, true reference type. Moreover,
        // we just require that WrappedIterator& convert to AnyIterator's
        // reference type. The other subtleties are not relevant.
  
        typedef typename boost::mpl::if_<
          boost::is_same<
            typename boost::iterator_category<WrappedIterator>::type,
            std::output_iterator_tag
          >,
          boost::is_convertible<
            WrappedIterator&,
            typename boost::iterator_reference<AnyIterator>::type
          >,
          boost::mpl::and_<
  
            // WrappedIterator's reference type must convert to AnyIterator's reference type.
            typename reference_types_erasure_compatible_1<WrappedIterator, AnyIterator>::type,
  
            // If AnyIterator's reference type is a reference, then the
            // same must be true for WrappedIterator's reference type.
            typename reference_types_erasure_compatible_2<WrappedIterator, AnyIterator>::type,
  
            // If AnyIterator's reference type and WrappedIterator's
            // reference type are both references, then one of the
            // following must hold:
            //
            // 1) AnyIterator's reference type and WrappedIterator's
            //    reference type are the same.
            //
            // 2) AnyIterator's reference type is a base class of WrappedIterator's
            //    reference type.
            //
            typename reference_types_erasure_compatible_3<WrappedIterator, AnyIterator>::type
          >
        >::type type;
      };
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<
        class WrappedIterator,
        class AnyIterator
      >
      struct difference_types_erasure_compatible
      {
  
        // Difference type matters only for random access iterators.
        
        typedef typename boost::mpl::or_<
          boost::mpl::not_<
            boost::is_same<
              // Do not use boost::iterator_traversal<AnyIterator>::type here,
              // as it does not equal the traversal tag.
              typename AnyIterator::traversal_type,
              boost::random_access_traversal_tag
            >
          >,
          boost::mpl::and_<
            boost::is_convertible<
              typename boost::iterator_difference<WrappedIterator>::type,
              typename boost::iterator_difference<AnyIterator>::type
            >,
            boost::is_convertible<
              typename boost::iterator_difference<AnyIterator>::type,
              typename boost::iterator_difference<WrappedIterator>::type
            >
          >
        > type;
      };
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<
        class WrappedIterator,
        class AnyIterator
      >
      struct traversal_types_erasure_compatible
      {
        typedef typename boost::mpl::or_<
          boost::is_same<
            // Do not use boost::iterator_traversal<AnyIterator>::type here,
            // as it does not equal the traversal tag.
            typename AnyIterator::traversal_type,
            typename boost::iterator_traversal<WrappedIterator>::type
          >,
          boost::is_base_of<
            // Do not use boost::iterator_traversal<AnyIterator>::type here,
            // as it does not equal the traversal tag.
            typename AnyIterator::traversal_type,
            typename boost::iterator_traversal<WrappedIterator>::type
          >
        > type;
      };
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<
        class WrappedIterator,
        class AnyIterator
      >
      struct is_iterator_type_erasure_compatible :
        public boost::mpl::bool_<
          boost::mpl::and_<
            value_types_erasure_compatible<WrappedIterator, AnyIterator>,
            reference_types_erasure_compatible<WrappedIterator, AnyIterator>,
            difference_types_erasure_compatible<WrappedIterator, AnyIterator>,
            traversal_types_erasure_compatible<WrappedIterator, AnyIterator>
          >::value
        >
      {
      };
  
      ///////////////////////////////////////////////////////////////////////
      // 
      template<class SomeIterator>
      struct is_any_iterator : public boost::mpl::bool_<false>
      {
      };
      //
      template<
        class Value,
        class Traversal,
        class Reference,
        class Difference
        >
      struct is_any_iterator<
        any_iterator<
          Value,
          Traversal,
          Reference,
          Difference
        >
      > : public boost::mpl::bool_<true>
      {
      };
      
    } // Namespace detail
  
  }} // Namespace dcs::iterator
  
  #endif // ANY_ITERATOR_METAFUNCTIONS_01102007TMB_HPP
  