mirror of
https://github.com/catchorg/Catch2.git
synced 2025-04-29 04:03:51 +00:00
Compare commits
No commits in common. "9a8963133fb7ce9ce31802160d8e351e0ac5527c" and "a537ccae224691bb43ecc89b1ddd3a14a784e5cf" have entirely different histories.
9a8963133f
...
a537ccae22
@ -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
|
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++
|
||||||
@ -189,17 +189,19 @@ 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,62 +14,60 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Benchmark {
|
namespace Detail {
|
||||||
namespace Detail {
|
template <typename T, bool Destruct>
|
||||||
template <typename T, bool Destruct>
|
struct ObjectStorage
|
||||||
struct ObjectStorage
|
{
|
||||||
|
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
|
||||||
|
|
||||||
|
ObjectStorage() : data() {}
|
||||||
|
|
||||||
|
ObjectStorage(const ObjectStorage& other)
|
||||||
{
|
{
|
||||||
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
|
new(&data) T(other.stored_object());
|
||||||
|
}
|
||||||
|
|
||||||
ObjectStorage() : data() {}
|
ObjectStorage(ObjectStorage&& other)
|
||||||
|
{
|
||||||
|
new(&data) T(std::move(other.stored_object()));
|
||||||
|
}
|
||||||
|
|
||||||
ObjectStorage(const ObjectStorage& other)
|
~ObjectStorage() { destruct_on_exit<T>(); }
|
||||||
{
|
|
||||||
new(&data) T(other.stored_object());
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectStorage(ObjectStorage&& other)
|
template <typename... Args>
|
||||||
{
|
void construct(Args&&... args)
|
||||||
new(&data) T(std::move(other.stored_object()));
|
{
|
||||||
}
|
new (&data) T(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
~ObjectStorage() { destruct_on_exit<T>(); }
|
template <bool AllowManualDestruction = !Destruct>
|
||||||
|
typename std::enable_if<AllowManualDestruction>::type destruct()
|
||||||
|
{
|
||||||
|
stored_object().~T();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
private:
|
||||||
void construct(Args&&... args)
|
// If this is a constructor benchmark, destruct the underlying object
|
||||||
{
|
template <typename U>
|
||||||
new (&data) T(std::forward<Args>(args)...);
|
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 <bool AllowManualDestruction = !Destruct>
|
T& stored_object()
|
||||||
typename std::enable_if<AllowManualDestruction>::type destruct()
|
{
|
||||||
{
|
return *static_cast<T*>(static_cast<void*>(&data));
|
||||||
stored_object().~T();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
TStorage data;
|
||||||
// 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
|
#endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||||
|
@ -126,19 +126,5 @@ 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(); });
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
||||||
|
@ -23,7 +23,6 @@ def generate(v):
|
|||||||
blankParser = re.compile( r'^\s*$')
|
blankParser = re.compile( r'^\s*$')
|
||||||
|
|
||||||
seenHeaders = set([])
|
seenHeaders = set([])
|
||||||
possibleHeaders = set([])
|
|
||||||
rootPath = os.path.join( catchPath, 'include/' )
|
rootPath = os.path.join( catchPath, 'include/' )
|
||||||
outputPath = os.path.join( catchPath, 'single_include/catch2/catch.hpp' )
|
outputPath = os.path.join( catchPath, 'single_include/catch2/catch.hpp' )
|
||||||
|
|
||||||
@ -53,20 +52,8 @@ def generate(v):
|
|||||||
if globals['includeImpl'] or globals['implIfDefs'] == -1:
|
if globals['includeImpl'] or globals['implIfDefs'] == -1:
|
||||||
out.write( line )
|
out.write( line )
|
||||||
|
|
||||||
def getDirsToSearch( ):
|
|
||||||
return [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters', 'internal/benchmark', 'internal/benchmark/detail']]
|
|
||||||
|
|
||||||
def collectPossibleHeaders():
|
|
||||||
dirs = getDirsToSearch()
|
|
||||||
for dir in dirs:
|
|
||||||
hpps = glob(os.path.join(dir, '*.hpp'))
|
|
||||||
hs = glob(os.path.join(dir, '*.h'))
|
|
||||||
possibleHeaders.update( hpp.rpartition( os.sep )[2] for hpp in hpps )
|
|
||||||
possibleHeaders.update( h.rpartition( os.sep )[2] for h in hs )
|
|
||||||
|
|
||||||
|
|
||||||
def insertCpps():
|
def insertCpps():
|
||||||
dirs = getDirsToSearch()
|
dirs = [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters', 'internal/benchmark', 'internal/benchmark/detail']]
|
||||||
cppFiles = []
|
cppFiles = []
|
||||||
for dir in dirs:
|
for dir in dirs:
|
||||||
cppFiles += glob(os.path.join(dir, '*.cpp'))
|
cppFiles += glob(os.path.join(dir, '*.cpp'))
|
||||||
@ -116,13 +103,6 @@ def generate(v):
|
|||||||
write( line.rstrip() + "\n" )
|
write( line.rstrip() + "\n" )
|
||||||
write( u'// end {}\n'.format(filename) )
|
write( u'// end {}\n'.format(filename) )
|
||||||
|
|
||||||
def warnUnparsedHeaders():
|
|
||||||
unparsedHeaders = possibleHeaders.difference( seenHeaders )
|
|
||||||
# These headers aren't packaged into the unified header, exclude them from any warning
|
|
||||||
whitelist = ['catch.hpp', 'catch_reporter_teamcity.hpp', 'catch_with_main.hpp', 'catch_reporter_automake.hpp', 'catch_reporter_tap.hpp', 'catch_reporter_sonarqube.hpp']
|
|
||||||
unparsedHeaders = unparsedHeaders.difference( whitelist )
|
|
||||||
if unparsedHeaders:
|
|
||||||
print( "WARNING: unparsed headers detected\n{0}\n".format( unparsedHeaders ) )
|
|
||||||
|
|
||||||
write( u"/*\n" )
|
write( u"/*\n" )
|
||||||
write( u" * Catch v{0}\n".format( v.getVersionString() ) )
|
write( u" * Catch v{0}\n".format( v.getVersionString() ) )
|
||||||
@ -137,13 +117,11 @@ def generate(v):
|
|||||||
write( u"#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
|
write( u"#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
|
||||||
write( u"#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
|
write( u"#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
|
||||||
|
|
||||||
collectPossibleHeaders()
|
|
||||||
parseFile( rootPath, 'catch.hpp' )
|
parseFile( rootPath, 'catch.hpp' )
|
||||||
warnUnparsedHeaders()
|
|
||||||
|
|
||||||
write( u"#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
|
write( u"#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
|
||||||
out.close()
|
out.close()
|
||||||
print( "Generated single include for Catch v{0}\n".format( v.getVersionString() ) )
|
print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) )
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
x
Reference in New Issue
Block a user