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