mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 13:26:10 +01:00
Fix wrong namespacing of benchmarking constructor helpers
This commit is contained in:
parent
ad3f50bbc1
commit
0fbf4f3e15
@ -164,7 +164,7 @@ Note that it is not possible to simply use the same instance for different runs
|
|||||||
and resetting it between each run since that would pollute the measurements with
|
and resetting it between each run since that would pollute the measurements with
|
||||||
the resetting code.
|
the resetting code.
|
||||||
|
|
||||||
It is also possible to just provide an argument name to the simple `BENCHMARK` macro to get
|
It is also possible to just provide an argument name to the simple `BENCHMARK` macro to get
|
||||||
the same semantics as providing a callable to `meter.measure` with `int` argument:
|
the same semantics as providing a callable to `meter.measure` with `int` argument:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
@ -185,19 +185,17 @@ construct and destroy objects without dynamic allocation and in a way that lets
|
|||||||
you measure construction and destruction separately.
|
you measure construction and destruction separately.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter)
|
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
|
||||||
{
|
|
||||||
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
|
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
|
||||||
meter.measure([&](int i) { storage[i].construct("thing"); });
|
meter.measure([&](int i) { storage[i].construct("thing"); });
|
||||||
})
|
};
|
||||||
|
|
||||||
BENCHMARK_ADVANCED("destroy", [](Catch::Benchmark::Chronometer meter)
|
BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
|
||||||
{
|
|
||||||
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
|
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
|
||||||
for(auto&& o : storage)
|
for(auto&& o : storage)
|
||||||
o.construct("thing");
|
o.construct("thing");
|
||||||
meter.measure([&](int i) { storage[i].destruct(); });
|
meter.measure([&](int i) { storage[i].destruct(); });
|
||||||
})
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
`Catch::Benchmark::storage_for<T>` objects are just pieces of raw storage suitable for `T`
|
`Catch::Benchmark::storage_for<T>` objects are just pieces of raw storage suitable for `T`
|
||||||
|
@ -14,60 +14,62 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Detail {
|
namespace Benchmark {
|
||||||
template <typename T, bool Destruct>
|
namespace Detail {
|
||||||
struct ObjectStorage
|
template <typename T, bool Destruct>
|
||||||
{
|
struct ObjectStorage
|
||||||
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
|
|
||||||
|
|
||||||
ObjectStorage() : data() {}
|
|
||||||
|
|
||||||
ObjectStorage(const ObjectStorage& other)
|
|
||||||
{
|
{
|
||||||
new(&data) T(other.stored_object());
|
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
|
||||||
}
|
|
||||||
|
|
||||||
ObjectStorage(ObjectStorage&& other)
|
ObjectStorage() : data() {}
|
||||||
{
|
|
||||||
new(&data) T(std::move(other.stored_object()));
|
|
||||||
}
|
|
||||||
|
|
||||||
~ObjectStorage() { destruct_on_exit<T>(); }
|
ObjectStorage(const ObjectStorage& other)
|
||||||
|
{
|
||||||
|
new(&data) T(other.stored_object());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
ObjectStorage(ObjectStorage&& other)
|
||||||
void construct(Args&&... args)
|
{
|
||||||
{
|
new(&data) T(std::move(other.stored_object()));
|
||||||
new (&data) T(std::forward<Args>(args)...);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <bool AllowManualDestruction = !Destruct>
|
~ObjectStorage() { destruct_on_exit<T>(); }
|
||||||
typename std::enable_if<AllowManualDestruction>::type destruct()
|
|
||||||
{
|
|
||||||
stored_object().~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
template <typename... Args>
|
||||||
// If this is a constructor benchmark, destruct the underlying object
|
void construct(Args&&... args)
|
||||||
template <typename U>
|
{
|
||||||
void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
|
new (&data) T(std::forward<Args>(args)...);
|
||||||
// Otherwise, don't
|
}
|
||||||
template <typename U>
|
|
||||||
void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
|
|
||||||
|
|
||||||
T& stored_object()
|
template <bool AllowManualDestruction = !Destruct>
|
||||||
{
|
typename std::enable_if<AllowManualDestruction>::type destruct()
|
||||||
return *static_cast<T*>(static_cast<void*>(&data));
|
{
|
||||||
}
|
stored_object().~T();
|
||||||
|
}
|
||||||
|
|
||||||
TStorage data;
|
private:
|
||||||
};
|
// If this is a constructor benchmark, destruct the underlying object
|
||||||
}
|
template <typename U>
|
||||||
|
void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
|
||||||
|
// Otherwise, don't
|
||||||
|
template <typename U>
|
||||||
|
void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
|
||||||
|
|
||||||
template <typename T>
|
T& stored_object()
|
||||||
using storage_for = Detail::ObjectStorage<T, true>;
|
{
|
||||||
|
return *static_cast<T*>(static_cast<void*>(&data));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
TStorage data;
|
||||||
using destructable_object = Detail::ObjectStorage<T, false>;
|
};
|
||||||
}
|
} // namespace Detail
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using storage_for = Detail::ObjectStorage<T, true>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using destructable_object = Detail::ObjectStorage<T, false>;
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||||
|
#include <catch2/benchmark/catch_constructor.hpp>
|
||||||
#include <catch2/catch_generators_specific.hpp>
|
#include <catch2/catch_generators_specific.hpp>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -127,4 +128,18 @@ TEST_CASE("Benchmark containers", "[!benchmark]") {
|
|||||||
REQUIRE(v[i] == generated);
|
REQUIRE(v[i] == generated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("construct and destroy example") {
|
||||||
|
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
|
||||||
|
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
|
||||||
|
meter.measure([&](int i) { storage[i].construct("thing"); });
|
||||||
|
};
|
||||||
|
|
||||||
|
BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
|
||||||
|
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
|
||||||
|
for(auto&& o : storage)
|
||||||
|
o.construct("thing");
|
||||||
|
meter.measure([&](int i) { storage[i].destruct(); });
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user