/*
 * $Id$
 *
 * Created: 24.1.2007
 * Author: jedi
 *
 * Using type traits to determine the optimal copy-algorithm
 */


#include <string>
#include <vector>
#include <iostream>
#include <loki/TypeTraits.h>


// selector (normal means for-loop and fast means memcpy)
enum copy_algorithm_selector { normal, fast };


// the normal copy algorithm implementation
template <typename source, typename target>
target
copy_impl(source first, source last, target result, Loki::Int2Type<normal>)
{
   // debug print
   std::cout << "normal" << std::endl;

   for (; first != last; ++first, ++result)
   {
      *result = *first;
   }

   return result;
}


// the fast copy algorithm implementation
template <typename source, typename target>
target
copy_impl(source first, source last, target result, Loki::Int2Type<fast>)
{
   // debug print
   std::cout << "fast" << std::endl;

   const std::size_t n = last-first;
   memcpy(result, first, n);
   return result + n;
}


// this is the "interface" for the application code. it statically
// selects the suitable copy algorithm based on the type information
template <typename source, typename target>
target
do_copy(source first, source last, target result)
{
   // what are we pointing at?
   typedef typename Loki::TypeTraits<source>::PointeeType source_pointee;
   typedef typename Loki::TypeTraits<target>::PointeeType target_pointee;

   // if pointers and pointing to fundamental types use fast algorithm
   enum
   {
      copy_algorithm =
      Loki::TypeTraits<source>::isPointer &&
      Loki::TypeTraits<target>::isPointer &&
      Loki::TypeTraits<source_pointee>::isStdFundamental &&
      Loki::TypeTraits<target_pointee>::isStdFundamental &&
      sizeof(source_pointee) == sizeof(target_pointee) ? fast : normal
   };

   // invoke the copy implementation
   return copy_impl(first, last, result, Loki::Int2Type<copy_algorithm>());
}


// test program that will use the normal algorithm
void
normal_copy_test()
{
   typedef std::vector<int> intvec;

   intvec source;
   intvec target;

   // insert some dummy data
   source.push_back(1); source.push_back(2); source.push_back(3);

   // do the copy
   do_copy<intvec::iterator, std::back_insert_iterator<intvec> >(
      source.begin(),
      source.end(),
      std::back_inserter(target));
}


// test program that will use the fast algorithm
void
fast_copy_test()
{
   // dummy data
   int source[] = { 1, 2, 3, 4, 5, 6 };
   int target[6];

   // do the copy
   do_copy<int*, int*>(source, source + (6*sizeof(int)), target);
}


// main
//
// *** program output:
//
// normal
// fast
//
int
main()
{
   normal_copy_test();
   fast_copy_test();

   return 0;
}