blob: 3e3af061590ead9f959bab99c31c2780c6e3ad79 [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::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))
28namespace std{ using :: memset; }
29#endif
30
31using std::cout;
32using std::endl;
33using std::cin;
34
35namespace opt{
36//
37// fill
38// same as std::fill, but uses memset where appropriate
39//
40namespace detail{
41
42template <typename I, typename T, bool b>
43void 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
52template <typename T>
53void 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
60template <class I, class T>
61inline 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
74namespace non_opt{
75
76template <class I, class T>
77inline 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//
87const int array_size = 1000;
88int i_array_[array_size] = {0,};
89const int ci_array_[array_size] = {0,};
90char c_array_[array_size] = {0,};
91const 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*).
97int* i_array = i_array_;
98const int* ci_array = ci_array_;
99char* c_array = c_array_;
100const char* cc_array = cc_array_;
101
102const int iter_count = 1000000;
103
104int 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