// Fake typeof implementation.  Yes, we're using typeof, but the
// amount of manual registration needed is carefully limited.  We will
// use Alexander Nasonov's implementation, which doesn't require users
// to conjure up unique primes.
#include <boost/utility/enable_if.hpp>
#define typeof(x) typename typeof_<sizeof(typeof_lookup_(x))>::type

template <int n, class enable1 = void, class enable2 = void> struct typeof_;

template <int n, class T>
struct template_typeof_result
{
    static T t;
    enum { x = n*sizeof(typeof_lookup_(t)) };
    typedef char type[x];
};

// n must be a unique prime
#define TYPEOF_REGISTER_CLASS(ns,x,n)                       \
    }                                                       \
    template <class T>                                      \
    char(&                                                  \
         typeof_lookup_(T)                                  \
    )[n];                                                   \
                                                            \
    template <int m>                                        \
    struct typeof_<                                         \
        m                                                   \
      , typename boost::enable_if_c<(m == n)>::type         \
    >                                                       \
    {                                                       \
        typedef ns::x type;                                 \
    };                                                      \
    namespace ns {

// n must be a unique prime
#define TYPEOF_REGISTER_TEMPLATE(ns,x,n)                            \
    }                                                               \
    template <class T>                                              \
    typename template_typeof_result<n,T>::type                      \
    typeof_lookup_(ns::x<T>);                                       \
                                                                    \
    template <int m>                                                \
    struct typeof_<                                                 \
        m                                                           \
      , typename boost::disable_if_c<(m == n)>::type                \
      , typename boost::enable_if_c<(m%n == 0)>::type               \
    >                                                               \
    {                                                               \
        typedef ns::x<typename typeof_<m/n>::type> type;            \
    };                                                              \
    namespace ns {                                                  \


// -----------------

namespace algorithm
{
  template <class Range>
  struct traversal_category
  {
      typedef typename Range::traversal_category type;
  };

  struct copy_tag {}; // identify the copy algorithm
  TYPEOF_REGISTER_CLASS(algorithm,copy_tag,3)


  namespace detail
  {
    // Compute the result of invoking any given algorithm
    template <class AlgorithmID, class Range1, class Range2>
    struct dispatch
    {
        typedef typename traversal_category<Range1>::type cat1;
        typedef typename traversal_category<Range2>::type cat2;

        // lookup_implementation uses ADL on category tags to look up an
        // implementation for this algorithm object.
        typedef typeof(
            lookup_implementation(AlgorithmID(), cat1(), cat2())
        ) implementation;
      
        typedef typename
        implementation::template result_type<Range1,Range2>::type
        result;
    };
  }
  
  //
  // The copy algorithm dispatcher
  //  
  template <class Range1, class Range2>
  typename detail::dispatch<copy_tag,Range1,Range2>::result
  copy(Range1 const& src, Range2& dst)
  {
      return
          detail::dispatch<copy_tag,Range1,Range2>::implementation
      ::execute(src,dst);
  }

  // Other algorithm dispatchers here...
}

// -----------------

// Someone implements FAST algorithms for fixed-size ranges
namespace fast
{
  // ranges using FAST iterators will have this traversal_category
  struct traversal_tag {};

  // An algorithm implementation strategy
  template <class AlgorithmID>
  struct unrolled;
  TYPEOF_REGISTER_TEMPLATE(fast,unrolled,5)
  
  // Any algorithm operating on two FAST ranges will use the
  // unrolled algorithm implementation.
  template <class AlgorithmID>
  unrolled<AlgorithmID>
  lookup_implementation(AlgorithmID,fast::traversal_tag,fast::traversal_tag)
  {
      return unrolled<AlgorithmID>();
  }

  // Implement the unrolled copy algorithm
  template <>
  struct unrolled< algorithm::copy_tag >
  {
      // Result type computer
      template <class Range1, class Range2>
      struct result_type
      {
          typedef int* type; // would usually be more interesting
      };

      // Implementation
      template <class Range1, class Range2>
      static int* execute(Range1 const&, Range2&) { return 0; }
  };

  // Other unrolled algorithm implementations here...
}

// -----------------

#include <boost/mpl/or.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>

// Someone implements hierarchical algorithms for segmented iterator ranges
namespace segmented
{
  // ranges using segmented iterators will have this traversal_category
  struct traversal_tag {};

  // An algorithm implementation strategy
  template <class AlgorithmID>
  struct hierarchical;
  TYPEOF_REGISTER_TEMPLATE(segmented,hierarchical,7)

  // Unless other overloads match better, any algorithm operating on
  // any segmented iterator range will use the hierarchical algorithm
  // implementation.
  template <class AlgorithmID, class Traversal1, class Traversal2>
  typename boost::enable_if<
      boost::mpl::or_<
          boost::is_convertible<Traversal1,segmented::traversal_tag>
        , boost::is_convertible<Traversal2,segmented::traversal_tag>
      >
    , hierarchical<AlgorithmID>
  >::type
  lookup_implementation(AlgorithmID,Traversal1,Traversal2)
  {
      return hierarchical<AlgorithmID>();
  }

  // Implement the hierarchical copy algorithm
  template <>
  struct hierarchical< algorithm::copy_tag >
  {
      // Result type computer
      template <class Range1, class Range2>
      struct result_type
      {
          typedef Range2 type;
      };

      // Implementation
      template <class Range1, class Range2>
      static Range2 execute(Range1 const&, Range2& x) { return x; }
  };

  // Other hierarchical algorithm implementations here...
}

// -----------------

// I implement a fixed-size range
namespace my
{
  struct range{/*...*/};
}

// and indicate its traversal_category
namespace algorithm
{
  template <>
  struct traversal_category<my::range>
  {
      typedef fast::traversal_tag type;
  };
}

// -----------------

// She implements a segmented range
// and indicates its traversal_category
namespace her
{
  struct range
  {
      typedef segmented::traversal_tag traversal_category;
  };
}

// -----------------

// Test code
my::range mine;
her::range hers;

int* x1 = algorithm::copy(mine, mine);
her::range x2 = algorithm::copy(mine, hers);
my::range x3 = algorithm::copy(hers, mine);
her::range x4 = algorithm::copy(hers, hers);

int main() {}


