Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMartin Hořeňovský2023-05-06 14:31:29 +0200
committerMartin Hořeňovský2023-05-06 15:22:02 +0200
commitc57b5cdf432b1983c6f1b1fd9fb1f7ff11397391 (patch)
tree265388000fe49146a56ac24e81dbe42560cd6ce4
parentd84777c9cbf5b1b7d0e9ef2e14606ece254adf7a (diff)
downloadcatch3-c57b5cdf432b1983c6f1b1fd9fb1f7ff11397391.tar.gz
Move-enable Catch::optional
This avoids copies in couple places through Catch2, e.g. reporter spec handling, and moving around `AssertionResult` in `RunContext`.
-rw-r--r--src/catch2/internal/catch_optional.hpp55
-rw-r--r--tests/SelfTest/IntrospectiveTests/Details.tests.cpp41
2 files changed, 77 insertions, 19 deletions
diff --git a/src/catch2/internal/catch_optional.hpp b/src/catch2/internal/catch_optional.hpp
index ac3714ee..d1e953ad 100644
--- a/src/catch2/internal/catch_optional.hpp
+++ b/src/catch2/internal/catch_optional.hpp
@@ -8,6 +8,8 @@
#ifndef CATCH_OPTIONAL_HPP_INCLUDED
#define CATCH_OPTIONAL_HPP_INCLUDED
+#include <catch2/internal/catch_move_and_forward.hpp>
+
#include <cassert>
namespace Catch {
@@ -16,35 +18,50 @@ namespace Catch {
template<typename T>
class Optional {
public:
- Optional() : nullableValue( nullptr ) {}
- Optional( T const& _value )
- : nullableValue( new( storage ) T( _value ) )
- {}
- Optional( Optional const& _other )
- : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
- {}
-
- ~Optional() {
+ Optional(): nullableValue( nullptr ) {}
+ ~Optional() { reset(); }
+
+ Optional( T const& _value ):
+ nullableValue( new ( storage ) T( _value ) ) {}
+ Optional( T&& _value ):
+ nullableValue( new ( storage ) T( CATCH_MOVE( _value ) ) ) {}
+
+ Optional& operator=( T const& _value ) {
reset();
+ nullableValue = new ( storage ) T( _value );
+ return *this;
}
+ Optional& operator=( T&& _value ) {
+ reset();
+ nullableValue = new ( storage ) T( CATCH_MOVE( _value ) );
+ return *this;
+ }
+
+ Optional( Optional const& _other ):
+ nullableValue( _other ? new ( storage ) T( *_other ) : nullptr ) {}
+ Optional( Optional&& _other ):
+ nullableValue( _other ? new ( storage ) T( CATCH_MOVE( *_other ) )
+ : nullptr ) {}
- Optional& operator= ( Optional const& _other ) {
- if( &_other != this ) {
+ Optional& operator=( Optional const& _other ) {
+ if ( &_other != this ) {
reset();
- if( _other )
- nullableValue = new( storage ) T( *_other );
+ if ( _other ) { nullableValue = new ( storage ) T( *_other ); }
}
return *this;
}
- Optional& operator = ( T const& _value ) {
- reset();
- nullableValue = new( storage ) T( _value );
+ Optional& operator=( Optional&& _other ) {
+ if ( &_other != this ) {
+ reset();
+ if ( _other ) {
+ nullableValue = new ( storage ) T( CATCH_MOVE( *_other ) );
+ }
+ }
return *this;
}
void reset() {
- if( nullableValue )
- nullableValue->~T();
+ if ( nullableValue ) { nullableValue->~T(); }
nullableValue = nullptr;
}
@@ -91,7 +108,7 @@ namespace Catch {
}
private:
- T *nullableValue;
+ T* nullableValue;
alignas(alignof(T)) char storage[sizeof(T)];
};
diff --git a/tests/SelfTest/IntrospectiveTests/Details.tests.cpp b/tests/SelfTest/IntrospectiveTests/Details.tests.cpp
index a5a43926..80eb647b 100644
--- a/tests/SelfTest/IntrospectiveTests/Details.tests.cpp
+++ b/tests/SelfTest/IntrospectiveTests/Details.tests.cpp
@@ -89,6 +89,47 @@ TEST_CASE("Optional comparison ops", "[optional][approvals]") {
}
}
+namespace {
+ struct MoveChecker {
+ bool has_moved = false;
+ MoveChecker() = default;
+ MoveChecker( MoveChecker const& rhs ) = default;
+ MoveChecker& operator=( MoveChecker const& rhs ) = default;
+ MoveChecker( MoveChecker&& rhs ) { rhs.has_moved = true; }
+ MoveChecker& operator=( MoveChecker&& rhs ) {
+ rhs.has_moved = true;
+ return *this;
+ }
+ };
+}
+
+TEST_CASE( "Optional supports move ops", "[optional][approvals]" ) {
+ using Catch::Optional;
+ MoveChecker a;
+ Optional<MoveChecker> opt_A( a );
+ REQUIRE_FALSE( a.has_moved );
+ REQUIRE_FALSE( opt_A->has_moved );
+
+ SECTION( "Move construction from element" ) {
+ Optional<MoveChecker> opt_B( CATCH_MOVE( a ) );
+ REQUIRE( a.has_moved );
+ }
+ SECTION( "Move assignment from element" ) {
+ opt_A = CATCH_MOVE( a );
+ REQUIRE( a.has_moved );
+ }
+ SECTION( "Move construction from optional" ) {
+ Optional<MoveChecker> opt_B( CATCH_MOVE( opt_A ) );
+ REQUIRE( opt_A->has_moved );
+ }
+ SECTION( "Move assignment from optional" ) {
+ Optional<MoveChecker> opt_B( opt_A );
+ REQUIRE_FALSE( opt_A->has_moved );
+ opt_B = CATCH_MOVE( opt_A );
+ REQUIRE( opt_A->has_moved );
+ }
+}
+
TEST_CASE( "Decomposer checks that the argument is 0 when handling "
"only-0-comparable types",
"[decomposition][approvals]" ) {