Brian Silverman | 4a2409e | 2018-08-04 23:24:02 -0700 | [diff] [blame^] | 1 | [/ |
| 2 | Copyright 2007 John Maddock. |
| 3 | Distributed under the Boost Software License, Version 1.0. |
| 4 | (See accompanying file LICENSE_1_0.txt or copy at |
| 5 | http://www.boost.org/LICENSE_1_0.txt). |
| 6 | ] |
| 7 | |
| 8 | [section:examples Examples] |
| 9 | |
| 10 | [section:copy An Optimized Version of std::copy] |
| 11 | |
| 12 | Demonstrates a version of `std::copy` that uses `__has_trivial_assign` to |
| 13 | determine whether to use `memcpy` to optimise the copy operation |
| 14 | (see [@../../examples/copy_example.cpp copy_example.cpp]): |
| 15 | |
| 16 | // |
| 17 | // opt::copy |
| 18 | // same semantics as std::copy |
| 19 | // calls memcpy where appropriate. |
| 20 | // |
| 21 | |
| 22 | namespace detail{ |
| 23 | |
| 24 | template<typename I1, typename I2, bool b> |
| 25 | I2 copy_imp(I1 first, I1 last, I2 out, const boost::__integral_constant<bool, b>&) |
| 26 | { |
| 27 | while(first != last) |
| 28 | { |
| 29 | *out = *first; |
| 30 | ++out; |
| 31 | ++first; |
| 32 | } |
| 33 | return out; |
| 34 | } |
| 35 | |
| 36 | template<typename T> |
| 37 | T* copy_imp(const T* first, const T* last, T* out, const boost::__true_type&) |
| 38 | { |
| 39 | memmove(out, first, (last-first)*sizeof(T)); |
| 40 | return out+(last-first); |
| 41 | } |
| 42 | |
| 43 | |
| 44 | } |
| 45 | |
| 46 | template<typename I1, typename I2> |
| 47 | inline I2 copy(I1 first, I1 last, I2 out) |
| 48 | { |
| 49 | // |
| 50 | // We can copy with memcpy if T has a trivial assignment operator, |
| 51 | // and if the iterator arguments are actually pointers (this last |
| 52 | // requirement we detect with overload resolution): |
| 53 | // |
| 54 | typedef typename std::iterator_traits<I1>::value_type value_type; |
| 55 | return detail::copy_imp(first, last, out, boost::__has_trivial_assign<value_type>()); |
| 56 | } |
| 57 | |
| 58 | |
| 59 | [endsect] |
| 60 | |
| 61 | [section:fill An Optimised Version of std::fill] |
| 62 | |
| 63 | Demonstrates a version of `std::fill` that uses `__has_trivial_assign` to |
| 64 | determine whether to use `memset` to optimise the fill operation |
| 65 | (see [@../../examples/fill_example.cpp fill_example.cpp]): |
| 66 | |
| 67 | // |
| 68 | // fill |
| 69 | // same as std::fill, but uses memset where appropriate |
| 70 | // |
| 71 | namespace detail{ |
| 72 | |
| 73 | template <typename I, typename T, bool b> |
| 74 | void do_fill(I first, I last, const T& val, const boost::__integral_constant<bool, b>&) |
| 75 | { |
| 76 | while(first != last) |
| 77 | { |
| 78 | *first = val; |
| 79 | ++first; |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | template <typename T> |
| 84 | void do_fill(T* first, T* last, const T& val, const boost::__true_type&) |
| 85 | { |
| 86 | std::memset(first, val, last-first); |
| 87 | } |
| 88 | |
| 89 | } |
| 90 | |
| 91 | template <class I, class T> |
| 92 | inline void fill(I first, I last, const T& val) |
| 93 | { |
| 94 | // |
| 95 | // We can do an optimised fill if T has a trivial assignment |
| 96 | // operator and if it's size is one: |
| 97 | // |
| 98 | typedef boost::__integral_constant<bool, |
| 99 | ::boost::__has_trivial_assign<T>::value && (sizeof(T) == 1)> truth_type; |
| 100 | detail::do_fill(first, last, val, truth_type()); |
| 101 | } |
| 102 | |
| 103 | |
| 104 | [endsect] |
| 105 | |
| 106 | [section:destruct An Example that Omits Destructor Calls For Types with Trivial Destructors] |
| 107 | |
| 108 | Demonstrates a simple algorithm that uses `__has_trivial_destruct` to |
| 109 | determine whether to destructors need to be called |
| 110 | (see [@../../examples/trivial_destructor_example.cpp trivial_destructor_example.cpp]): |
| 111 | |
| 112 | // |
| 113 | // algorithm destroy_array: |
| 114 | // The reverse of std::unitialized_copy, takes a block of |
| 115 | // initialized memory and calls destructors on all objects therein. |
| 116 | // |
| 117 | |
| 118 | namespace detail{ |
| 119 | |
| 120 | template <class T> |
| 121 | void do_destroy_array(T* first, T* last, const boost::__false_type&) |
| 122 | { |
| 123 | while(first != last) |
| 124 | { |
| 125 | first->~T(); |
| 126 | ++first; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | template <class T> |
| 131 | inline void do_destroy_array(T* first, T* last, const boost::__true_type&) |
| 132 | { |
| 133 | } |
| 134 | |
| 135 | } // namespace detail |
| 136 | |
| 137 | template <class T> |
| 138 | inline void destroy_array(T* p1, T* p2) |
| 139 | { |
| 140 | detail::do_destroy_array(p1, p2, ::boost::__has_trivial_destructor<T>()); |
| 141 | } |
| 142 | |
| 143 | |
| 144 | [endsect] |
| 145 | |
| 146 | [section:iter An improved Version of std::iter_swap] |
| 147 | |
| 148 | Demonstrates a version of `std::iter_swap` that use type traits to |
| 149 | determine whether an it's arguments are proxy iterators or not, |
| 150 | if they're not then it just does a `std::swap` of it's dereferenced |
| 151 | arguments (the |
| 152 | same as `std::iter_swap` does), however if they are proxy iterators |
| 153 | then takes special care over the swap to ensure that the algorithm |
| 154 | works correctly for both proxy iterators, and even iterators of |
| 155 | different types |
| 156 | (see [@../../examples/iter_swap_example.cpp iter_swap_example.cpp]): |
| 157 | |
| 158 | // |
| 159 | // iter_swap: |
| 160 | // tests whether iterator is a proxy iterator or not, and |
| 161 | // uses optimal form accordingly: |
| 162 | // |
| 163 | namespace detail{ |
| 164 | |
| 165 | template <typename I> |
| 166 | static void do_swap(I one, I two, const boost::__false_type&) |
| 167 | { |
| 168 | typedef typename std::iterator_traits<I>::value_type v_t; |
| 169 | v_t v = *one; |
| 170 | *one = *two; |
| 171 | *two = v; |
| 172 | } |
| 173 | template <typename I> |
| 174 | static void do_swap(I one, I two, const boost::__true_type&) |
| 175 | { |
| 176 | using std::swap; |
| 177 | swap(*one, *two); |
| 178 | } |
| 179 | |
| 180 | } |
| 181 | |
| 182 | template <typename I1, typename I2> |
| 183 | inline void iter_swap(I1 one, I2 two) |
| 184 | { |
| 185 | // |
| 186 | // See is both arguments are non-proxying iterators, |
| 187 | // and if both iterator the same type: |
| 188 | // |
| 189 | typedef typename std::iterator_traits<I1>::reference r1_t; |
| 190 | typedef typename std::iterator_traits<I2>::reference r2_t; |
| 191 | |
| 192 | typedef boost::__integral_constant<bool, |
| 193 | ::boost::__is_reference<r1_t>::value |
| 194 | && ::boost::__is_reference<r2_t>::value |
| 195 | && ::boost::__is_same<r1_t, r2_t>::value> truth_type; |
| 196 | |
| 197 | detail::do_swap(one, two, truth_type()); |
| 198 | } |
| 199 | |
| 200 | |
| 201 | [endsect] |
| 202 | |
| 203 | [section:to_double Convert Numeric Types and Enums to double] |
| 204 | |
| 205 | Demonstrates a conversion of |
| 206 | [@../../../../libs/numeric/conversion/doc/html/boost_numericconversion/definitions.html#boost_numericconversion.definitions.numeric_types |
| 207 | Numeric Types] |
| 208 | and enum types to double: |
| 209 | |
| 210 | template<class T> |
| 211 | inline double to_double(T const& value) |
| 212 | { |
| 213 | typedef typename boost::promote<T>::type promoted; |
| 214 | return boost::numeric::converter<double,promoted>::convert(value); |
| 215 | } |
| 216 | |
| 217 | [endsect] |
| 218 | |
| 219 | [section:improved_min Improving std::min with common_type] |
| 220 | |
| 221 | An improved `std::min` function could be written like this: |
| 222 | |
| 223 | template <class T, class U> |
| 224 | typename __common_type<T, U>::type min(T t, U u) |
| 225 | { |
| 226 | return t < u ? t : u; |
| 227 | } |
| 228 | |
| 229 | And now expressions such as: |
| 230 | |
| 231 | min(1, 2.0) |
| 232 | |
| 233 | will actually compile and return the correct type! |
| 234 | |
| 235 | [endsect] |
| 236 | [endsect] |
| 237 | |