blob: 2ba60a821976b48e94f866decbaa0e4539849ad6 [file] [log] [blame]
Brian Silverman4a2409e2018-08-04 23:24:02 -07001
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::copy - optimised for trivial copy (cf std::copy)
13 *
14 */
15
16#include <iostream>
17#include <typeinfo>
18#include <algorithm>
19#include <iterator>
20#include <memory>
21
22#include <boost/test/included/prg_exec_monitor.hpp>
23#include <boost/timer.hpp>
24#include <boost/type_traits.hpp>
25
26using std::cout;
27using std::endl;
28using std::cin;
29
30namespace opt{
31
32//
33// opt::copy
34// same semantics as std::copy
35// calls memcpy where appropriate.
36//
37
38namespace detail{
39
40template<typename I1, typename I2, bool b>
41I2 copy_imp(I1 first, I1 last, I2 out, const boost::integral_constant<bool, b>&)
42{
43 while(first != last)
44 {
45 *out = *first;
46 ++out;
47 ++first;
48 }
49 return out;
50}
51
52template<typename T>
53T* copy_imp(const T* first, const T* last, T* out, const boost::true_type&)
54{
55 memmove(out, first, (last-first)*sizeof(T));
56 return out+(last-first);
57}
58
59
60}
61
62template<typename I1, typename I2>
63inline I2 copy(I1 first, I1 last, I2 out)
64{
65 //
66 // We can copy with memcpy if T has a trivial assignment operator,
67 // and if the iterator arguments are actually pointers (this last
68 // requirement we detect with overload resolution):
69 //
70 typedef typename std::iterator_traits<I1>::value_type value_type;
71 return detail::copy_imp(first, last, out, boost::has_trivial_assign<value_type>());
72}
73
74} // namespace opt
75
76namespace non_opt
77{
78
79template<typename I1, typename I2>
80inline I2 copy(I1 first, I1 last, I2 out)
81{
82 return opt::detail::copy_imp(first, last, out, boost::false_type());
83}
84
85}
86
87//
88// define some global data:
89//
90const int array_size = 1000;
91int i_array_[array_size] = {0,};
92const int ci_array_[array_size] = {0,};
93char c_array_[array_size] = {0,};
94const char cc_array_[array_size] = { 0,};
95//
96// since arrays aren't iterators we define a set of pointer
97// aliases into the arrays (otherwise the compiler is entitled
98// to deduce the type passed to the template functions as
99// T (&)[N] rather than T*).
100int* i_array = i_array_;
101const int* ci_array = ci_array_;
102char* c_array = c_array_;
103const char* cc_array = cc_array_;
104
105const int iter_count = 1000000;
106
107int cpp_main(int argc, char* argv[])
108{
109 boost::timer t;
110 double result;
111 int i;
112 cout << "Measuring times in micro-seconds per 1000 elements processed" << endl << endl;
113 cout << "testing copy...\n"
114 "[Some standard library versions may already perform this optimisation.]" << endl;
115
116 // cache load:
117 opt::copy(ci_array, ci_array + array_size, i_array);
118
119 // time optimised version:
120 t.restart();
121 for(i = 0; i < iter_count; ++i)
122 {
123 opt::copy(ci_array, ci_array + array_size, i_array);
124 }
125 result = t.elapsed();
126 cout << "opt::copy<const int*, int*>: " << result << endl;
127
128 // cache load:
129 non_opt::copy(ci_array, ci_array + array_size, i_array);
130
131 // time non-optimised version:
132 t.restart();
133 for(i = 0; i < iter_count; ++i)
134 {
135 non_opt::copy(ci_array, ci_array + array_size, i_array);
136 }
137 result = t.elapsed();
138 cout << "non_opt::copy<const int*, int*>: " << result << endl;
139
140 // cache load:
141 std::copy(ci_array, ci_array + array_size, i_array);
142
143 // time standard version:
144 t.restart();
145 for(i = 0; i < iter_count; ++i)
146 {
147 std::copy(ci_array, ci_array + array_size, i_array);
148 }
149 result = t.elapsed();
150 cout << "std::copy<const int*, int*>: " << result << endl;
151
152 // cache load:
153 opt::copy(cc_array, cc_array + array_size, c_array);
154
155 // time optimised version:
156 t.restart();
157 for(i = 0; i < iter_count; ++i)
158 {
159 opt::copy(cc_array, cc_array + array_size, c_array);
160 }
161 result = t.elapsed();
162 cout << "opt::copy<const char*, char*>: " << result << endl;
163
164 // cache load:
165 non_opt::copy(cc_array, cc_array + array_size, c_array);
166
167 // time optimised version:
168 t.restart();
169 for(i = 0; i < iter_count; ++i)
170 {
171 non_opt::copy(cc_array, cc_array + array_size, c_array);
172 }
173 result = t.elapsed();
174 cout << "non_opt::copy<const char*, char*>: " << result << endl;
175
176 // cache load:
177 std::copy(cc_array, cc_array + array_size, c_array);
178
179 // time standard version:
180 t.restart();
181 for(i = 0; i < iter_count; ++i)
182 {
183 std::copy(cc_array, cc_array + array_size, c_array);
184 }
185 result = t.elapsed();
186 cout << "std::copy<const char*, char*>: " << result << endl;
187
188 return 0;
189}
190
191
192
193
194
195
196
197