
/*
 *
 * (C) Copyright John Maddock 1999. 
 * Use, modification and distribution are subject to 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)
 *
 * This file provides some example of type_traits usage -
 * by "optimising" various algorithms:
 *
 * opt::destroy_array - an example of optimisation based upon omitted destructor calls
 *
 */


#include <iostream>

#include <boost/timer.hpp>
#include <boost/type_traits.hpp>

using std::cout;
using std::endl;
using std::cin;

namespace opt{

//
// algorithm destroy_array:
// The reverse of std::unitialized_copy, takes a block of
// initialized memory and calls destructors on all objects therein.
//

namespace detail{

template <bool>
struct array_destroyer
{
   template <class T>
   static void destroy_array(T* i, T* j){ do_destroy_array(i, j); }
};

template <>
struct array_destroyer<true>
{
   template <class T>
   static void destroy_array(T*, T*){}
};

template <class T>
void do_destroy_array(T* first, T* last)
{
   while(first != last)
   {
      first->~T();
      ++first;
   }
}

} // namespace detail

template <class T>
inline void destroy_array(T* p1, T* p2)
{
   detail::array_destroyer<boost::has_trivial_destructor<T>::value>::destroy_array(p1, p2);
}

//
// unoptimised versions of destroy_array:
//
template <class T>
void destroy_array1(T* first, T* last)
{
   while(first != last)
   {
      first->~T();
      ++first;
   }
}
template <class T>
void destroy_array2(T* first, T* last)
{
   for(; first != last; ++first) first->~T();
}

} // namespace opt

//
// define some global data:
//
const int array_size = 1000;
int i_array[array_size] = {0,};
const int ci_array[array_size] = {0,};
char c_array[array_size] = {0,};
const char cc_array[array_size] = { 0,};

const int iter_count = 1000000;


int cpp_main(int argc, char* argv[])
{
   boost::timer t;
   double result;
   int i;
   //
   // test destroy_array,
   // compare destruction time of an array of ints
   // with unoptimised form.
   //
   cout << "Measuring times in micro-seconds per 1000 elements processed" << endl << endl;
   cout << "testing destroy_array...\n"
    "[Some compilers may be able to optimise the \"unoptimised\"\n versions as well as type_traits does.]" << endl;
   
   // cache load:
   opt::destroy_array(i_array, i_array + array_size);

   // time optimised version:
   t.restart();
   for(i = 0; i < iter_count; ++i)
   {
      opt::destroy_array(i_array, i_array + array_size);
   }
   result = t.elapsed();
   cout << "destroy_array<int>: " << result << endl;

   // cache load:
   opt::destroy_array1(i_array, i_array + array_size);

   // time unoptimised version #1:
   t.restart();
   for(i = 0; i < iter_count; ++i)
   {
      opt::destroy_array1(i_array, i_array + array_size);
   }
   result = t.elapsed();
   cout << "destroy_array<int>(unoptimised#1): " << result << endl;

   // cache load:
   opt::destroy_array2(i_array, i_array + array_size);

   // time unoptimised version #2:
   t.restart();
   for(i = 0; i < iter_count; ++i)
   {
      opt::destroy_array2(i_array, i_array + array_size);
   }
   result = t.elapsed();
   cout << "destroy_array<int>(unoptimised#2): " << result << endl << endl;

   return 0;
}











