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