fill_example.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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::fill - optimised for trivial copy/small types (cf std::fill)
  12. *
  13. */
  14. #include <iostream>
  15. #include <typeinfo>
  16. #include <algorithm>
  17. #include <iterator>
  18. #include <memory>
  19. #include <cstring>
  20. #include <boost/test/included/prg_exec_monitor.hpp>
  21. #include <boost/timer.hpp>
  22. #include <boost/type_traits.hpp>
  23. #if defined(BOOST_NO_STDC_NAMESPACE) || (defined(std) && defined(__SGI_STL_PORT))
  24. namespace std{ using :: memset; }
  25. #endif
  26. using std::cout;
  27. using std::endl;
  28. using std::cin;
  29. namespace opt{
  30. //
  31. // fill
  32. // same as std::fill, but uses memset where appropriate
  33. //
  34. namespace detail{
  35. template <typename I, typename T, bool b>
  36. void do_fill(I first, I last, const T& val, const boost::integral_constant<bool, b>&)
  37. {
  38. while(first != last)
  39. {
  40. *first = val;
  41. ++first;
  42. }
  43. }
  44. template <typename T>
  45. void do_fill(T* first, T* last, const T& val, const boost::true_type&)
  46. {
  47. std::memset(first, val, last-first);
  48. }
  49. }
  50. template <class I, class T>
  51. inline void fill(I first, I last, const T& val)
  52. {
  53. //
  54. // We can do an optimised fill if T has a trivial assignment
  55. // operator and if it's size is one:
  56. //
  57. typedef boost::integral_constant<bool,
  58. ::boost::has_trivial_assign<T>::value && (sizeof(T) == 1)> truth_type;
  59. detail::do_fill(first, last, val, truth_type());
  60. }
  61. } // namespace opt
  62. namespace non_opt{
  63. template <class I, class T>
  64. inline void fill(I first, I last, const T& val)
  65. {
  66. opt::detail::do_fill(first, last, val, boost::false_type());
  67. }
  68. }
  69. //
  70. // define some global data:
  71. //
  72. const int array_size = 1000;
  73. int i_array_[array_size] = {0,};
  74. const int ci_array_[array_size] = {0,};
  75. char c_array_[array_size] = {0,};
  76. const char cc_array_[array_size] = { 0,};
  77. //
  78. // since arrays aren't iterators we define a set of pointer
  79. // aliases into the arrays (otherwise the compiler is entitled
  80. // to deduce the type passed to the template functions as
  81. // T (&)[N] rather than T*).
  82. int* i_array = i_array_;
  83. const int* ci_array = ci_array_;
  84. char* c_array = c_array_;
  85. const char* cc_array = cc_array_;
  86. const int iter_count = 1000000;
  87. int cpp_main(int argc, char* argv[])
  88. {
  89. boost::timer t;
  90. double result;
  91. int i;
  92. //
  93. // test destroy_array,
  94. // compare destruction time of an array of ints
  95. // with unoptimised form.
  96. //
  97. cout << "Measuring times in micro-seconds per 1000 elements processed" << endl << endl;
  98. cout << "testing fill(char)...\n"
  99. "[Some standard library versions may already perform this optimisation.]" << endl;
  100. // cache load:
  101. opt::fill(c_array, c_array + array_size, (char)3);
  102. // time optimised version:
  103. t.restart();
  104. for(i = 0; i < iter_count; ++i)
  105. {
  106. opt::fill(c_array, c_array + array_size, (char)3);
  107. }
  108. result = t.elapsed();
  109. cout << "opt::fill<char*, char>: " << result << endl;
  110. // cache load:
  111. non_opt::fill(c_array, c_array + array_size, (char)3);
  112. // time optimised version:
  113. t.restart();
  114. for(i = 0; i < iter_count; ++i)
  115. {
  116. non_opt::fill(c_array, c_array + array_size, (char)3);
  117. }
  118. result = t.elapsed();
  119. cout << "non_opt::fill<char*, char>: " << result << endl;
  120. // cache load:
  121. std::fill(c_array, c_array + array_size, (char)3);
  122. // time standard version:
  123. t.restart();
  124. for(i = 0; i < iter_count; ++i)
  125. {
  126. std::fill(c_array, c_array + array_size, (char)3);
  127. }
  128. result = t.elapsed();
  129. cout << "std::fill<char*, char>: " << result << endl << endl;
  130. cout << "testing fill(int)...\n" << endl;
  131. // cache load:
  132. opt::fill(i_array, i_array + array_size, 3);
  133. // timer optimised version:
  134. t.restart();
  135. for(i = 0; i < iter_count; ++i)
  136. {
  137. opt::fill(i_array, i_array + array_size, 3);
  138. }
  139. result = t.elapsed();
  140. cout << "opt::fill<int*, int>: " << result << endl;
  141. // cache load:
  142. non_opt::fill(i_array, i_array + array_size, 3);
  143. // timer optimised version:
  144. t.restart();
  145. for(i = 0; i < iter_count; ++i)
  146. {
  147. non_opt::fill(i_array, i_array + array_size, 3);
  148. }
  149. result = t.elapsed();
  150. cout << "non_opt::fill<int*, int>: " << result << endl;
  151. // cache load:
  152. std::fill(i_array, i_array + array_size, 3);
  153. // time standard version:
  154. t.restart();
  155. for(i = 0; i < iter_count; ++i)
  156. {
  157. std::fill(i_array, i_array + array_size, 3);
  158. }
  159. result = t.elapsed();
  160. cout << "std::fill<int*, int>: " << result << endl << endl;
  161. return 0;
  162. }