Skip to content
Permalink
Browse files

Fix wrong namespacing of benchmarking constructor helpers

  • Loading branch information
Tridacnid authored and horenmar committed Nov 19, 2019
1 parent a537cca commit cfba9dce97e8b15f84d4ff329cc065abccf1cea1
@@ -168,7 +168,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
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:

```c++
@@ -189,19 +189,17 @@ construct and destroy objects without dynamic allocation and in a way that lets
you measure construction and destruction separately.

```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());
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());
for(auto&& o : storage)
o.construct("thing");
meter.measure([&](int i) { storage[i].destruct(); });
})
};
```

`Catch::Benchmark::storage_for<T>` objects are just pieces of raw storage suitable for `T`
@@ -14,60 +14,62 @@
#include <type_traits>

namespace Catch {
namespace Detail {
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());
}

ObjectStorage(ObjectStorage&& other)
{
new(&data) T(std::move(other.stored_object()));
}

~ObjectStorage() { destruct_on_exit<T>(); }

template <typename... Args>
void construct(Args&&... args)
namespace Benchmark {
namespace Detail {
template <typename T, bool Destruct>
struct ObjectStorage
{
new (&data) T(std::forward<Args>(args)...);
}

template <bool AllowManualDestruction = !Destruct>
typename std::enable_if<AllowManualDestruction>::type destruct()
{
stored_object().~T();
}

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) { }

T& stored_object()
{
return *static_cast<T*>(static_cast<void*>(&data));
}

TStorage data;
};
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());
}

ObjectStorage(ObjectStorage&& other)
{
new(&data) T(std::move(other.stored_object()));
}

~ObjectStorage() { destruct_on_exit<T>(); }

template <typename... Args>
void construct(Args&&... args)
{
new (&data) T(std::forward<Args>(args)...);
}

template <bool AllowManualDestruction = !Destruct>
typename std::enable_if<AllowManualDestruction>::type destruct()
{
stored_object().~T();
}

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) { }

T& stored_object()
{
return *static_cast<T*>(static_cast<void*>(&data));
}

TStorage data;
};
}

template <typename T>
using storage_for = Detail::ObjectStorage<T, true>;

template <typename T>
using destructable_object = Detail::ObjectStorage<T, false>;
}

template <typename T>
using storage_for = Detail::ObjectStorage<T, true>;

template <typename T>
using destructable_object = Detail::ObjectStorage<T, false>;
}

#endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
@@ -126,5 +126,19 @@ TEST_CASE("Benchmark containers", "[!benchmark]") {
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(); });
};
}
}
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING

0 comments on commit cfba9dc

Please sign in to comment.
You can’t perform that action at this time.