|
12 | 12 | #define BOOST_CONTAINER_BENCH_UTILS_HPP |
13 | 13 |
|
14 | 14 | #include <boost/move/detail/nsec_clock.hpp> |
| 15 | +#include <boost/move/utility_core.hpp> |
15 | 16 | #include <boost/container/detail/workaround.hpp> |
| 17 | +#include <algorithm> |
| 18 | +#include <cstddef> |
| 19 | +#include <cstring> |
16 | 20 | #include <vector> |
17 | 21 |
|
18 | 22 | volatile int bench_utils_sink = 0; |
@@ -124,4 +128,110 @@ typedef boost::move_detail::cpu_timer cpu_timer; |
124 | 128 | BOOST_CONTAINER_FORCEINLINE void clobber() { BOOST_CONTAINER_BENCH_CLOBBER(); } |
125 | 129 | BOOST_CONTAINER_FORCEINLINE void escape(void* p) { BOOST_CONTAINER_BENCH_ESCAPE(p); } |
126 | 130 |
|
| 131 | +/////////////////////////////////////////////////////////////////////////////// |
| 132 | +// Shared benchmark element types. |
| 133 | +// |
| 134 | +// MyInt: a non-trivial "int wrapper" used by several benchmarks to exercise the |
| 135 | +// non-trivially-copyable element code paths (its user-provided copy ctor, copy |
| 136 | +// assignment and destructor disable the trivial memcpy/relocation fast paths), |
| 137 | +// as opposed to a plain int. This single definition replaces the per-benchmark |
| 138 | +// copies that used to define their own MyInt. A benchmark that additionally |
| 139 | +// wants the "trivial destructor after move" optimization can still specialize |
| 140 | +// boost::has_trivial_destructor_after_move<MyInt> in its own translation unit. |
| 141 | +/////////////////////////////////////////////////////////////////////////////// |
| 142 | +class MyInt |
| 143 | +{ |
| 144 | + int int_; |
| 145 | + |
| 146 | + public: |
| 147 | + MyInt(int i = 0) |
| 148 | + : int_(i) |
| 149 | + {} |
| 150 | + |
| 151 | + MyInt(const MyInt &other) |
| 152 | + : int_(other.int_) |
| 153 | + {} |
| 154 | + |
| 155 | + MyInt & operator=(const MyInt &other) |
| 156 | + { |
| 157 | + int_ = other.int_; |
| 158 | + return *this; |
| 159 | + } |
| 160 | + |
| 161 | + ~MyInt() |
| 162 | + { |
| 163 | + int_ = 0; |
| 164 | + } |
| 165 | + |
| 166 | + int int_value() const { return int_; } |
| 167 | + |
| 168 | + friend bool operator==(const MyInt& a, const MyInt& b) { return a.int_ == b.int_; } |
| 169 | + friend bool operator!=(const MyInt& a, const MyInt& b) { return a.int_ != b.int_; } |
| 170 | + friend bool operator< (const MyInt& a, const MyInt& b) { return a.int_ < b.int_; } |
| 171 | + friend bool operator> (const MyInt& a, const MyInt& b) { return a.int_ > b.int_; } |
| 172 | + friend bool operator<=(const MyInt& a, const MyInt& b) { return a.int_ <= b.int_; } |
| 173 | + friend bool operator>=(const MyInt& a, const MyInt& b) { return a.int_ >= b.int_; } |
| 174 | +}; |
| 175 | + |
| 176 | +//Benchmark element. The NonTrivial boolean (chosen by the caller, true by |
| 177 | +//default) selects between two layouts of identical size: |
| 178 | +// - NonTrivial == true: a move-only element whose user-defined special members |
| 179 | +// do measurable work (memset/memcpy of the payload, kept alive by a compiler |
| 180 | +// barrier). It uses Boost.Move so the definition is also valid in C++03. |
| 181 | +// - NonTrivial == false: a trivially copyable element carrying only the payload. |
| 182 | +template<std::size_t Size, bool NonTrivial = true> |
| 183 | +struct element_t; |
| 184 | + |
| 185 | +template<std::size_t Size> |
| 186 | +struct element_t<Size, true> |
| 187 | +{ |
| 188 | + BOOST_MOVABLE_BUT_NOT_COPYABLE(element_t) |
| 189 | + |
| 190 | + public: |
| 191 | + element_t(int n_) : n(n_) |
| 192 | + { |
| 193 | + std::memset(payload, 0, sizeof(payload)); |
| 194 | + clobber(); //The barrier keeps previous writes as real work. |
| 195 | + } |
| 196 | + |
| 197 | + ~element_t() |
| 198 | + { |
| 199 | + std::memset(payload, 0, sizeof(payload)); |
| 200 | + clobber(); //The barrier keeps previous writes as real work. |
| 201 | + } |
| 202 | + |
| 203 | + element_t(BOOST_RV_REF(element_t) x) : n(x.n) |
| 204 | + { |
| 205 | + std::memcpy(payload, x.payload, sizeof(payload)); |
| 206 | + std::memset(x.payload, 0, sizeof(payload)); |
| 207 | + clobber(); //The barrier keeps previous writes as real work. |
| 208 | + } |
| 209 | + |
| 210 | + element_t& operator=(BOOST_RV_REF(element_t) x) |
| 211 | + { |
| 212 | + n = x.n; |
| 213 | + std::memcpy(payload, x.payload, sizeof(payload)); |
| 214 | + std::memset(x.payload, 0, sizeof(payload)); |
| 215 | + clobber(); //The barrier keeps previous writes as real work. |
| 216 | + return *this; |
| 217 | + } |
| 218 | + |
| 219 | + operator int() const { return n; } |
| 220 | + |
| 221 | + int n; |
| 222 | + char payload[Size - sizeof(int)]; |
| 223 | +}; |
| 224 | + |
| 225 | +template<std::size_t Size> |
| 226 | +struct element_t<Size, false> |
| 227 | +{ |
| 228 | + element_t(int n_) : n(n_) |
| 229 | + {} |
| 230 | + |
| 231 | + operator int() const { return n; } |
| 232 | + |
| 233 | + int n; |
| 234 | + char payload[Size - sizeof(int)]; |
| 235 | +}; |
| 236 | + |
127 | 237 | #endif //BOOST_CONTAINER_BENCH_UTILS_HPP |
0 commit comments