copy_example.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. *
  3. * (C) Copyright John Maddock 1999-2005.
  4. * Use, modification and distribution are subject to the
  5. * Boost Software License, Version 1.0. (See accompanying file
  6. * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. *
  8. * This file provides some example of type_traits usage -
  9. * by "optimising" various algorithms:
  10. *
  11. * opt::copy - optimised for trivial copy (cf std::copy)
  12. *
  13. */
  14. #include <iostream>
  15. #include <typeinfo>
  16. #include <algorithm>
  17. #include <iterator>
  18. #include <memory>
  19. #include <boost/test/included/prg_exec_monitor.hpp>
  20. #include <boost/timer.hpp>
  21. #include <boost/type_traits.hpp>
  22. using std::cout;
  23. using std::endl;
  24. using std::cin;
  25. namespace opt{
  26. //
  27. // opt::copy
  28. // same semantics as std::copy
  29. // calls memcpy where appropriate.
  30. //
  31. namespace detail{
  32. template<typename I1, typename I2, bool b>
  33. I2 copy_imp(I1 first, I1 last, I2 out, const boost::integral_constant<bool, b>&)
  34. {
  35. while(first != last)
  36. {
  37. *out = *first;
  38. ++out;
  39. ++first;
  40. }
  41. return out;
  42. }
  43. template<typename T>
  44. T* copy_imp(const T* first, const T* last, T* out, const boost::true_type&)
  45. {
  46. memmove(out, first, (last-first)*sizeof(T));
  47. return out+(last-first);
  48. }
  49. }
  50. template<typename I1, typename I2>
  51. inline I2 copy(I1 first, I1 last, I2 out)
  52. {
  53. //
  54. // We can copy with memcpy if T has a trivial assignment operator,
  55. // and if the iterator arguments are actually pointers (this last
  56. // requirement we detect with overload resolution):
  57. //
  58. typedef typename std::iterator_traits<I1>::value_type value_type;
  59. return detail::copy_imp(first, last, out, boost::has_trivial_assign<value_type>());
  60. }
  61. } // namespace opt
  62. namespace non_opt
  63. {
  64. template<typename I1, typename I2>
  65. inline I2 copy(I1 first, I1 last, I2 out)
  66. {
  67. return opt::detail::copy_imp(first, last, out, boost::false_type());
  68. }
  69. }
  70. //
  71. // define some global data:
  72. //
  73. const int array_size = 1000;
  74. int i_array_[array_size] = {0,};
  75. const int ci_array_[array_size] = {0,};
  76. char c_array_[array_size] = {0,};
  77. const char cc_array_[array_size] = { 0,};
  78. //
  79. // since arrays aren't iterators we define a set of pointer
  80. // aliases into the arrays (otherwise the compiler is entitled
  81. // to deduce the type passed to the template functions as
  82. // T (&)[N] rather than T*).
  83. int* i_array = i_array_;
  84. const int* ci_array = ci_array_;
  85. char* c_array = c_array_;
  86. const char* cc_array = cc_array_;
  87. const int iter_count = 1000000;
  88. int cpp_main(int argc, char* argv[])
  89. {
  90. boost::timer t;
  91. double result;
  92. int i;
  93. cout << "Measuring times in micro-seconds per 1000 elements processed" << endl << endl;
  94. cout << "testing copy...\n"
  95. "[Some standard library versions may already perform this optimisation.]" << endl;
  96. // cache load:
  97. opt::copy(ci_array, ci_array + array_size, i_array);
  98. // time optimised version:
  99. t.restart();
  100. for(i = 0; i < iter_count; ++i)
  101. {
  102. opt::copy(ci_array, ci_array + array_size, i_array);
  103. }
  104. result = t.elapsed();
  105. cout << "opt::copy<const int*, int*>: " << result << endl;
  106. // cache load:
  107. non_opt::copy(ci_array, ci_array + array_size, i_array);
  108. // time non-optimised version:
  109. t.restart();
  110. for(i = 0; i < iter_count; ++i)
  111. {
  112. non_opt::copy(ci_array, ci_array + array_size, i_array);
  113. }
  114. result = t.elapsed();
  115. cout << "non_opt::copy<const int*, int*>: " << result << endl;
  116. // cache load:
  117. std::copy(ci_array, ci_array + array_size, i_array);
  118. // time standard version:
  119. t.restart();
  120. for(i = 0; i < iter_count; ++i)
  121. {
  122. std::copy(ci_array, ci_array + array_size, i_array);
  123. }
  124. result = t.elapsed();
  125. cout << "std::copy<const int*, int*>: " << result << endl;
  126. // cache load:
  127. opt::copy(cc_array, cc_array + array_size, c_array);
  128. // time optimised version:
  129. t.restart();
  130. for(i = 0; i < iter_count; ++i)
  131. {
  132. opt::copy(cc_array, cc_array + array_size, c_array);
  133. }
  134. result = t.elapsed();
  135. cout << "opt::copy<const char*, char*>: " << result << endl;
  136. // cache load:
  137. non_opt::copy(cc_array, cc_array + array_size, c_array);
  138. // time optimised version:
  139. t.restart();
  140. for(i = 0; i < iter_count; ++i)
  141. {
  142. non_opt::copy(cc_array, cc_array + array_size, c_array);
  143. }
  144. result = t.elapsed();
  145. cout << "non_opt::copy<const char*, char*>: " << result << endl;
  146. // cache load:
  147. std::copy(cc_array, cc_array + array_size, c_array);
  148. // time standard version:
  149. t.restart();
  150. for(i = 0; i < iter_count; ++i)
  151. {
  152. std::copy(cc_array, cc_array + array_size, c_array);
  153. }
  154. result = t.elapsed();
  155. cout << "std::copy<const char*, char*>: " << result << endl;
  156. return 0;
  157. }