mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 12:17:11 +01:00 
			
		
		
		
	Move-enable Catch::optional
This avoids copies in couple places through Catch2, e.g. reporter spec handling, and moving around `AssertionResult` in `RunContext`.
This commit is contained in:
		| @@ -8,6 +8,8 @@ | |||||||
| #ifndef CATCH_OPTIONAL_HPP_INCLUDED | #ifndef CATCH_OPTIONAL_HPP_INCLUDED | ||||||
| #define CATCH_OPTIONAL_HPP_INCLUDED | #define CATCH_OPTIONAL_HPP_INCLUDED | ||||||
|  |  | ||||||
|  | #include <catch2/internal/catch_move_and_forward.hpp> | ||||||
|  |  | ||||||
| #include <cassert> | #include <cassert> | ||||||
|  |  | ||||||
| namespace Catch { | namespace Catch { | ||||||
| @@ -16,35 +18,50 @@ namespace Catch { | |||||||
|     template<typename T> |     template<typename T> | ||||||
|     class Optional { |     class Optional { | ||||||
|     public: |     public: | ||||||
|         Optional() : nullableValue( nullptr ) {} |         Optional(): nullableValue( nullptr ) {} | ||||||
|         Optional( T const& _value ) |         ~Optional() { reset(); } | ||||||
|         : nullableValue( new( storage ) T( _value ) ) |  | ||||||
|         {} |  | ||||||
|         Optional( Optional const& _other ) |  | ||||||
|         : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) |  | ||||||
|         {} |  | ||||||
|  |  | ||||||
|         ~Optional() { |         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(); |             reset(); | ||||||
|  |             nullableValue = new ( storage ) T( _value ); | ||||||
|  |             return *this; | ||||||
|  |         } | ||||||
|  |         Optional& operator=( T&& _value ) { | ||||||
|  |             reset(); | ||||||
|  |             nullableValue = new ( storage ) T( CATCH_MOVE( _value ) ); | ||||||
|  |             return *this; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Optional& operator= ( Optional const& _other ) { |         Optional( Optional const& _other ): | ||||||
|             if( &_other != this ) { |             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 ) { | ||||||
|                 reset(); |                 reset(); | ||||||
|                 if( _other ) |                 if ( _other ) { nullableValue = new ( storage ) T( *_other ); } | ||||||
|                     nullableValue = new( storage ) T( *_other ); |  | ||||||
|             } |             } | ||||||
|             return *this; |             return *this; | ||||||
|         } |         } | ||||||
|         Optional& operator = ( T const& _value ) { |         Optional& operator=( Optional&& _other ) { | ||||||
|             reset(); |             if ( &_other != this ) { | ||||||
|             nullableValue = new( storage ) T( _value ); |                 reset(); | ||||||
|  |                 if ( _other ) { | ||||||
|  |                     nullableValue = new ( storage ) T( CATCH_MOVE( *_other ) ); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|             return *this; |             return *this; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         void reset() { |         void reset() { | ||||||
|             if( nullableValue ) |             if ( nullableValue ) { nullableValue->~T(); } | ||||||
|                 nullableValue->~T(); |  | ||||||
|             nullableValue = nullptr; |             nullableValue = nullptr; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -91,7 +108,7 @@ namespace Catch { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         T *nullableValue; |         T* nullableValue; | ||||||
|         alignas(alignof(T)) char storage[sizeof(T)]; |         alignas(alignof(T)) char storage[sizeof(T)]; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 " | TEST_CASE( "Decomposer checks that the argument is 0 when handling " | ||||||
|            "only-0-comparable types", |            "only-0-comparable types", | ||||||
|            "[decomposition][approvals]" ) { |            "[decomposition][approvals]" ) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Martin Hořeňovský
					Martin Hořeňovský