From 41bbaa6d573a598fe0796fd0e391ed57eae62e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Sun, 24 May 2020 23:41:02 +0200 Subject: [PATCH] Implement a simplified variant of std::unique_ptr This simplified variant supports only a subset of the functionality in `std::unique_ptr`. `Catch::Detail::unique_ptr` only supports single element pointer (no array support) with default deleter. By removing the support for custom deleters, we also avoid requiring significant machinery to support EBO, speeding up instantiations of `unique_ptr` significantly. Catch2 also currently does not need to support `unique_ptr`, so that is not supported either. --- src/CMakeLists.txt | 1 + src/catch2/catch_all.hpp | 1 + src/catch2/internal/catch_unique_ptr.hpp | 110 +++++++ tests/CMakeLists.txt | 1 + .../Baselines/automake.sw.approved.txt | 3 + .../Baselines/compact.sw.approved.txt | 28 ++ .../Baselines/console.std.approved.txt | 4 +- .../Baselines/console.sw.approved.txt | 244 ++++++++++++++- .../SelfTest/Baselines/junit.sw.approved.txt | 15 +- .../Baselines/sonarqube.sw.approved.txt | 15 + tests/SelfTest/Baselines/tap.sw.approved.txt | 58 +++- .../Baselines/teamcity.sw.approved.txt | 6 + tests/SelfTest/Baselines/xml.sw.approved.txt | 279 +++++++++++++++++- .../IntrospectiveTests/UniquePtr.tests.cpp | 133 +++++++++ 14 files changed, 890 insertions(+), 8 deletions(-) create mode 100644 src/catch2/internal/catch_unique_ptr.hpp create mode 100644 tests/SelfTest/IntrospectiveTests/UniquePtr.tests.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4f81c000..1be01da7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -125,6 +125,7 @@ set(INTERNAL_HEADERS ${SOURCES_DIR}/catch_totals.hpp ${SOURCES_DIR}/catch_translate_exception.hpp ${SOURCES_DIR}/internal/catch_uncaught_exceptions.hpp + ${SOURCES_DIR}/internal/catch_unique_ptr.hpp ${SOURCES_DIR}/catch_version.hpp ${SOURCES_DIR}/catch_version_macros.hpp ${SOURCES_DIR}/internal/catch_wildcard_pattern.hpp diff --git a/src/catch2/catch_all.hpp b/src/catch2/catch_all.hpp index b0f31196..fab323bd 100644 --- a/src/catch2/catch_all.hpp +++ b/src/catch2/catch_all.hpp @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include diff --git a/src/catch2/internal/catch_unique_ptr.hpp b/src/catch2/internal/catch_unique_ptr.hpp new file mode 100644 index 00000000..f963e9d6 --- /dev/null +++ b/src/catch2/internal/catch_unique_ptr.hpp @@ -0,0 +1,110 @@ +#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED +#define CATCH_UNIQUE_PTR_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + // reimplementation of unique_ptr for improved compilation times + // Does not support custom deleters (and thus does not require EBO) + // Does not support arrays + template + class unique_ptr { + T* m_ptr; + public: + constexpr unique_ptr(std::nullptr_t = nullptr): + m_ptr{} + {} + explicit constexpr unique_ptr(T* ptr): + m_ptr(ptr) + {} + + template ::value>> + unique_ptr(unique_ptr&& from): + m_ptr(from.release()) + {} + + template ::value>> + unique_ptr& operator=(unique_ptr&& from) { + reset(from.release()); + + return *this; + } + + unique_ptr(unique_ptr const&) = delete; + unique_ptr& operator=(unique_ptr const&) = delete; + + unique_ptr(unique_ptr&& rhs) noexcept: + m_ptr(rhs.m_ptr) { + rhs.m_ptr = nullptr; + } + unique_ptr& operator=(unique_ptr&& rhs) noexcept { + reset(rhs.release()); + + return *this; + } + + ~unique_ptr() { + delete m_ptr; + } + + T& operator*() { + assert(m_ptr); + return *m_ptr; + } + T const& operator*() const { + assert(m_ptr); + return *m_ptr; + } + T* operator->() const noexcept { + assert(m_ptr); + return m_ptr; + } + + T* get() { return m_ptr; } + T const* get() const { return m_ptr; } + + void reset(T* ptr = nullptr) { + delete m_ptr; + m_ptr = ptr; + } + + T* release() { + auto temp = m_ptr; + m_ptr = nullptr; + return temp; + } + + explicit operator bool() const { + return m_ptr; + } + + friend void swap(unique_ptr& lhs, unique_ptr& rhs) { + auto temp = lhs.m_ptr; + lhs.m_ptr = rhs.m_ptr; + rhs.m_ptr = temp; + } + }; + + // Purposefully doesn't exist + // We could also rely on compiler warning + werror for calling plain delete + // on a T[], but this seems better. + // Maybe add definition and a static assert? + template + class unique_ptr; + + template + unique_ptr make_unique(Args&&... args) { + // static_cast does the same thing as std::forward in + // this case, but does not require including big header () + // and compiles faster thanks to not requiring template instantiation + // and overload resolution + return unique_ptr(new T(static_cast(args)...)); + } + + +} // end namespace Detail +} // end namespace Catch + +#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8b3c9092..a5fdf802 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,6 +27,7 @@ set(TEST_SOURCES ${SELF_TEST_DIR}/IntrospectiveTests/StringManip.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/ToString.tests.cpp + ${SELF_TEST_DIR}/IntrospectiveTests/UniquePtr.tests.cpp ${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp ${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp ${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp diff --git a/tests/SelfTest/Baselines/automake.sw.approved.txt b/tests/SelfTest/Baselines/automake.sw.approved.txt index 88a43ede..ffde555a 100644 --- a/tests/SelfTest/Baselines/automake.sw.approved.txt +++ b/tests/SelfTest/Baselines/automake.sw.approved.txt @@ -222,6 +222,7 @@ Message from section two :test-result: PASS Tracker :test-result: PASS Trim strings :test-result: FAIL Unexpected exceptions can be translated +:test-result: PASS Upcasting special member functions :test-result: PASS Usage of the SizeIs range matcher :test-result: PASS Use a custom approx :test-result: PASS Variadic macros @@ -268,6 +269,7 @@ loose text artifact :test-result: PASS long long :test-result: FAIL looped SECTION tests :test-result: FAIL looped tests +:test-result: PASS make_unique reimplementation :test-result: PASS mean :test-result: PASS measure :test-result: FAIL mix info, unscoped info and warning @@ -331,6 +333,7 @@ loose text artifact :test-result: PASS tuple :test-result: PASS tuple,tuple<>,float> :test-result: PASS uniform samples +:test-result: PASS unique_ptr reimplementation: basic functionality :test-result: PASS vec> -> toString :test-result: PASS vector -> toString :test-result: PASS vector -> toString diff --git a/tests/SelfTest/Baselines/compact.sw.approved.txt b/tests/SelfTest/Baselines/compact.sw.approved.txt index 4d2fcbe2..d7a756f4 100644 --- a/tests/SelfTest/Baselines/compact.sw.approved.txt +++ b/tests/SelfTest/Baselines/compact.sw.approved.txt @@ -1587,6 +1587,8 @@ StringManip.tests.cpp:: passed: trim(StringRef(whitespace_at_both_e == There is no extra whitespace here Exception.tests.cpp:: failed: unexpected exception with message: '3.14' +UniquePtr.tests.cpp:: passed: bptr->i == 3 for: 3 == 3 +UniquePtr.tests.cpp:: passed: bptr->i == 3 for: 3 == 3 MatchersRanges.tests.cpp:: passed: empty_vec, SizeIs(0) for: { } has size == 0 MatchersRanges.tests.cpp:: passed: empty_vec, !SizeIs(2) for: { } not has size == 2 MatchersRanges.tests.cpp:: passed: empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2 @@ -1794,6 +1796,9 @@ Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 mes Misc.tests.cpp:: passed: ( fib[i] % 2 ) == 0 for: 0 == 0 with 1 message: 'Testing if fib[5] (8) is even' Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[6] (13) is even' Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[7] (21) is even' +UniquePtr.tests.cpp:: passed: !(lval.has_moved) for: !false +UniquePtr.tests.cpp:: passed: rval.has_moved for: true +UniquePtr.tests.cpp:: passed: *ptr == std::tuple{1, 2., 3} for: {?} == {?} InternalBenchmark.tests.cpp:: passed: m == 19. for: 19.0 == 19.0 InternalBenchmark.tests.cpp:: passed: x == 17 for: 17 == 17 InternalBenchmark.tests.cpp:: passed: x == 23 for: 23 == 23 @@ -1990,6 +1995,29 @@ InternalBenchmark.tests.cpp:: passed: e.point == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.upper_bound == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.lower_bound == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.confidence_interval == 0.95 for: 0.95 == 0.95 +UniquePtr.tests.cpp:: passed: !(ptr) for: !{?} +UniquePtr.tests.cpp:: passed: ptr.get() == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: ptr for: {?} +UniquePtr.tests.cpp:: passed: *ptr == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: ptr.get() == naked_ptr for: 0x == 0x +UniquePtr.tests.cpp:: passed: !(ptr) for: !{?} +UniquePtr.tests.cpp:: passed: ptr.get() == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: ptr for: {?} +UniquePtr.tests.cpp:: passed: *ptr == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: ptr.get() == naked_ptr for: 0x == 0x +UniquePtr.tests.cpp:: passed: ptr for: {?} +UniquePtr.tests.cpp:: passed: ptr.get() != 0 for: 0x != 0 +UniquePtr.tests.cpp:: passed: *ptr == 2 for: 2 == 2 +UniquePtr.tests.cpp:: passed: !(ptr) for: !{?} +UniquePtr.tests.cpp:: passed: ptr.get() == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: !(ptr1) for: !{?} +UniquePtr.tests.cpp:: passed: ptr2 for: {?} +UniquePtr.tests.cpp:: passed: *ptr2 == 1 for: 1 == 1 +UniquePtr.tests.cpp:: passed: !(ptr2) for: !{?} +UniquePtr.tests.cpp:: passed: ptr1 for: {?} +UniquePtr.tests.cpp:: passed: *ptr1 == 2 for: 2 == 2 +UniquePtr.tests.cpp:: passed: *ptr1 == 2 for: 2 == 2 +UniquePtr.tests.cpp:: passed: *ptr2 == 1 for: 1 == 1 ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(v) == "{ }" for: "{ }" == "{ }" ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(v) == "{ { \"hello\" }, { \"world\" } }" for: "{ { "hello" }, { "world" } }" == diff --git a/tests/SelfTest/Baselines/console.std.approved.txt b/tests/SelfTest/Baselines/console.std.approved.txt index f92173e5..ee6710d3 100644 --- a/tests/SelfTest/Baselines/console.std.approved.txt +++ b/tests/SelfTest/Baselines/console.std.approved.txt @@ -1380,6 +1380,6 @@ due to unexpected exception with message: Why would you throw a std::string? =============================================================================== -test cases: 334 | 260 passed | 70 failed | 4 failed as expected -assertions: 1896 | 1744 passed | 131 failed | 21 failed as expected +test cases: 337 | 263 passed | 70 failed | 4 failed as expected +assertions: 1924 | 1772 passed | 131 failed | 21 failed as expected diff --git a/tests/SelfTest/Baselines/console.sw.approved.txt b/tests/SelfTest/Baselines/console.sw.approved.txt index 4123232c..450d8025 100644 --- a/tests/SelfTest/Baselines/console.sw.approved.txt +++ b/tests/SelfTest/Baselines/console.sw.approved.txt @@ -11547,6 +11547,30 @@ Exception.tests.cpp:: FAILED: due to unexpected exception with message: 3.14 +------------------------------------------------------------------------------- +Upcasting special member functions + Move constructor +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( bptr->i == 3 ) +with expansion: + 3 == 3 + +------------------------------------------------------------------------------- +Upcasting special member functions + move assignment +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( bptr->i == 3 ) +with expansion: + 3 == 3 + ------------------------------------------------------------------------------- Usage of the SizeIs range matcher Some with stdlib containers @@ -13096,6 +13120,42 @@ with expansion: with message: Testing if fib[7] (21) is even +------------------------------------------------------------------------------- +make_unique reimplementation + From lvalue copies +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( lval.has_moved ) +with expansion: + !false + +------------------------------------------------------------------------------- +make_unique reimplementation + From rvalue moves +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( rval.has_moved ) +with expansion: + true + +------------------------------------------------------------------------------- +make_unique reimplementation + Variadic constructor +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr == std::tuple{1, 2., 3} ) +with expansion: + {?} == {?} + ------------------------------------------------------------------------------- mean ------------------------------------------------------------------------------- @@ -14485,6 +14545,186 @@ InternalBenchmark.tests.cpp:: PASSED: with expansion: 0.95 == 0.95 +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Default constructed unique_ptr is empty +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( ptr ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Take ownership of allocation +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr == 0 ) +with expansion: + 0 == 0 + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() == naked_ptr ) +with expansion: + 0x == 0x + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Take ownership of allocation + Plain reset deallocates +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( ptr ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Take ownership of allocation +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr == 0 ) +with expansion: + 0 == 0 + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() == naked_ptr ) +with expansion: + 0x == 0x + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Take ownership of allocation + Reset replaces ownership +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() != 0 ) +with expansion: + 0x != 0 + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr == 2 ) +with expansion: + 2 == 2 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Release releases ownership +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + CHECK_FALSE( ptr ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + CHECK( ptr.get() == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Move constructor +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( ptr1 ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr2 ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr2 == 1 ) +with expansion: + 1 == 1 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Move assignment +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( ptr2 ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr1 ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr1 == 2 ) +with expansion: + 2 == 2 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + free swap +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr1 == 2 ) +with expansion: + 2 == 2 + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr2 == 1 ) +with expansion: + 1 == 1 + ------------------------------------------------------------------------------- vec> -> toString ------------------------------------------------------------------------------- @@ -14792,6 +15032,6 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 334 | 244 passed | 86 failed | 4 failed as expected -assertions: 1913 | 1744 passed | 148 failed | 21 failed as expected +test cases: 337 | 247 passed | 86 failed | 4 failed as expected +assertions: 1941 | 1772 passed | 148 failed | 21 failed as expected diff --git a/tests/SelfTest/Baselines/junit.sw.approved.txt b/tests/SelfTest/Baselines/junit.sw.approved.txt index 9c4dd7cb..839cf6e6 100644 --- a/tests/SelfTest/Baselines/junit.sw.approved.txt +++ b/tests/SelfTest/Baselines/junit.sw.approved.txt @@ -1,7 +1,7 @@ - + @@ -1256,6 +1256,8 @@ FAILED: Exception.tests.cpp: + + @@ -1577,6 +1579,9 @@ Testing if fib[7] (21) is even Misc.tests.cpp: + + + @@ -1733,6 +1738,14 @@ Exception.tests.cpp: + + + + + + + + diff --git a/tests/SelfTest/Baselines/sonarqube.sw.approved.txt b/tests/SelfTest/Baselines/sonarqube.sw.approved.txt index 42422727..2809f95b 100644 --- a/tests/SelfTest/Baselines/sonarqube.sw.approved.txt +++ b/tests/SelfTest/Baselines/sonarqube.sw.approved.txt @@ -180,6 +180,21 @@ + + + + + + + + + + + + + + + diff --git a/tests/SelfTest/Baselines/tap.sw.approved.txt b/tests/SelfTest/Baselines/tap.sw.approved.txt index b28c70d4..d03b250e 100644 --- a/tests/SelfTest/Baselines/tap.sw.approved.txt +++ b/tests/SelfTest/Baselines/tap.sw.approved.txt @@ -3021,6 +3021,10 @@ ok {test-number} - trim(StringRef(trailing_whitespace)) == StringRef(no_whitespa ok {test-number} - trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here # Unexpected exceptions can be translated not ok {test-number} - unexpected exception with message: '3.14' +# Upcasting special member functions +ok {test-number} - bptr->i == 3 for: 3 == 3 +# Upcasting special member functions +ok {test-number} - bptr->i == 3 for: 3 == 3 # Usage of the SizeIs range matcher ok {test-number} - empty_vec, SizeIs(0) for: { } has size == 0 # Usage of the SizeIs range matcher @@ -3418,6 +3422,12 @@ ok {test-number} - ( fib[i] % 2 ) == 0 for: 0 == 0 with 1 message: 'Testing if f not ok {test-number} - ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[6] (13) is even' # looped tests not ok {test-number} - ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[7] (21) is even' +# make_unique reimplementation +ok {test-number} - !(lval.has_moved) for: !false +# make_unique reimplementation +ok {test-number} - rval.has_moved for: true +# make_unique reimplementation +ok {test-number} - *ptr == std::tuple{1, 2., 3} for: {?} == {?} # mean ok {test-number} - m == 19. for: 19.0 == 19.0 # measure @@ -3742,6 +3752,52 @@ ok {test-number} - e.upper_bound == 23 for: 23.0 == 23 ok {test-number} - e.lower_bound == 23 for: 23.0 == 23 # uniform samples ok {test-number} - e.confidence_interval == 0.95 for: 0.95 == 0.95 +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == naked_ptr for: 0x == 0x +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == naked_ptr for: 0x == 0x +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() != 0 for: 0x != 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr == 2 for: 2 == 2 +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr1) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr2 for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr2 == 1 for: 1 == 1 +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr2) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr1 for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr1 == 2 for: 2 == 2 +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr1 == 2 for: 2 == 2 +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr2 == 1 for: 1 == 1 # vec> -> toString ok {test-number} - ::Catch::Detail::stringify(v) == "{ }" for: "{ }" == "{ }" # vec> -> toString @@ -3818,5 +3874,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0 ok {test-number} - # xmlentitycheck ok {test-number} - -1..1905 +1..1933 diff --git a/tests/SelfTest/Baselines/teamcity.sw.approved.txt b/tests/SelfTest/Baselines/teamcity.sw.approved.txt index b73aa2e9..3f64f272 100644 --- a/tests/SelfTest/Baselines/teamcity.sw.approved.txt +++ b/tests/SelfTest/Baselines/teamcity.sw.approved.txt @@ -547,6 +547,8 @@ Exception.tests.cpp:|nunexpected exception with message:|n "For so ##teamcity[testStarted name='Unexpected exceptions can be translated'] Exception.tests.cpp:|nunexpected exception with message:|n "3.14"'] ##teamcity[testFinished name='Unexpected exceptions can be translated' duration="{duration}"] +##teamcity[testStarted name='Upcasting special member functions'] +##teamcity[testFinished name='Upcasting special member functions' duration="{duration}"] ##teamcity[testStarted name='Usage of the SizeIs range matcher'] ##teamcity[testFinished name='Usage of the SizeIs range matcher' duration="{duration}"] ##teamcity[testStarted name='Use a custom approx'] @@ -671,6 +673,8 @@ Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[6|] (13) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[7|] (21) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] ##teamcity[testFinished name='looped tests' duration="{duration}"] +##teamcity[testStarted name='make_unique reimplementation'] +##teamcity[testFinished name='make_unique reimplementation' duration="{duration}"] ##teamcity[testStarted name='mean'] ##teamcity[testFinished name='mean' duration="{duration}"] ##teamcity[testStarted name='measure'] @@ -807,6 +811,8 @@ Exception.tests.cpp:|nunexpected exception with message:|n "Why wo ##teamcity[testFinished name='tuple,tuple<>,float>' duration="{duration}"] ##teamcity[testStarted name='uniform samples'] ##teamcity[testFinished name='uniform samples' duration="{duration}"] +##teamcity[testStarted name='unique_ptr reimplementation: basic functionality'] +##teamcity[testFinished name='unique_ptr reimplementation: basic functionality' duration="{duration}"] ##teamcity[testStarted name='vec> -> toString'] ##teamcity[testFinished name='vec> -> toString' duration="{duration}"] ##teamcity[testStarted name='vector -> toString'] diff --git a/tests/SelfTest/Baselines/xml.sw.approved.txt b/tests/SelfTest/Baselines/xml.sw.approved.txt index 10d7f304..45d444c1 100644 --- a/tests/SelfTest/Baselines/xml.sw.approved.txt +++ b/tests/SelfTest/Baselines/xml.sw.approved.txt @@ -13944,6 +13944,31 @@ There is no extra whitespace here + +
+ + + bptr->i == 3 + + + 3 == 3 + + + +
+
+ + + bptr->i == 3 + + + 3 == 3 + + + +
+ +
@@ -15773,6 +15798,42 @@ loose text artifact + +
+ + + !(lval.has_moved) + + + !false + + + +
+
+ + + rval.has_moved + + + true + + + +
+
+ + + *ptr == std::tuple<int, double, int>{1, 2., 3} + + + {?} == {?} + + + +
+ +
@@ -17416,6 +17477,220 @@ loose text artifact + +
+ + + !(ptr) + + + !{?} + + + + + ptr.get() == 0 + + + 0 == 0 + + + +
+
+ + + ptr + + + {?} + + + + + *ptr == 0 + + + 0 == 0 + + + + + ptr.get() == naked_ptr + + + 0x == 0x + + +
+ + + !(ptr) + + + !{?} + + + + + ptr.get() == 0 + + + 0 == 0 + + + +
+ +
+
+ + + ptr + + + {?} + + + + + *ptr == 0 + + + 0 == 0 + + + + + ptr.get() == naked_ptr + + + 0x == 0x + + +
+ + + ptr + + + {?} + + + + + ptr.get() != 0 + + + 0x != 0 + + + + + *ptr == 2 + + + 2 == 2 + + + +
+ +
+
+ + + !(ptr) + + + !{?} + + + + + ptr.get() == 0 + + + 0 == 0 + + + +
+
+ + + !(ptr1) + + + !{?} + + + + + ptr2 + + + {?} + + + + + *ptr2 == 1 + + + 1 == 1 + + + +
+
+ + + !(ptr2) + + + !{?} + + + + + ptr1 + + + {?} + + + + + *ptr1 == 2 + + + 2 == 2 + + + +
+
+ + + *ptr1 == 2 + + + 2 == 2 + + + + + *ptr2 == 1 + + + 1 == 1 + + + +
+ +
@@ -17756,7 +18031,7 @@ loose text artifact
- + - + diff --git a/tests/SelfTest/IntrospectiveTests/UniquePtr.tests.cpp b/tests/SelfTest/IntrospectiveTests/UniquePtr.tests.cpp new file mode 100644 index 00000000..bc7fe228 --- /dev/null +++ b/tests/SelfTest/IntrospectiveTests/UniquePtr.tests.cpp @@ -0,0 +1,133 @@ +#include +#include + +#include + +namespace { + struct unique_ptr_test_helper { + bool dummy = false; + }; +} // end unnamed namespace + +TEST_CASE("unique_ptr reimplementation: basic functionality", "[internals][unique-ptr]") { + using Catch::Detail::unique_ptr; + SECTION("Default constructed unique_ptr is empty") { + unique_ptr ptr; + REQUIRE_FALSE(ptr); + REQUIRE(ptr.get() == nullptr); + } + SECTION("Take ownership of allocation") { + auto naked_ptr = new int{ 0 }; + unique_ptr ptr(naked_ptr); + REQUIRE(ptr); + REQUIRE(*ptr == 0); + REQUIRE(ptr.get() == naked_ptr); + SECTION("Plain reset deallocates") { + ptr.reset(); // this makes naked_ptr dangling! + REQUIRE_FALSE(ptr); + REQUIRE(ptr.get() == nullptr); + } + SECTION("Reset replaces ownership") { + ptr.reset(new int{ 2 }); + REQUIRE(ptr); + REQUIRE(ptr.get() != nullptr); + REQUIRE(*ptr == 2); + } + } + SECTION("Release releases ownership") { + auto naked_ptr = new int{ 1 }; + unique_ptr ptr(naked_ptr); + ptr.release(); + CHECK_FALSE(ptr); + CHECK(ptr.get() == nullptr); + delete naked_ptr; + } + SECTION("Move constructor") { + unique_ptr ptr1(new int{ 1 }); + auto ptr2(std::move(ptr1)); + REQUIRE_FALSE(ptr1); + REQUIRE(ptr2); + REQUIRE(*ptr2 == 1); + } + SECTION("Move assignment") { + unique_ptr ptr1(new int{ 1 }), ptr2(new int{ 2 }); + ptr1 = std::move(ptr2); + REQUIRE_FALSE(ptr2); + REQUIRE(ptr1); + REQUIRE(*ptr1 == 2); + } + SECTION("free swap") { + unique_ptr ptr1(new int{ 1 }), ptr2(new int{ 2 }); + swap(ptr1, ptr2); + REQUIRE(*ptr1 == 2); + REQUIRE(*ptr2 == 1); + } +} + + +namespace { + struct base { + int i; + base(int i) :i(i) {} + }; + struct derived : base { using base::base; }; + struct unrelated {}; + +} // end unnamed namespace + +static_assert( std::is_constructible, + Catch::Detail::unique_ptr>::value, "Upcasting is supported"); +static_assert(!std::is_constructible, + Catch::Detail::unique_ptr>::value, "Downcasting is not supported"); +static_assert(!std::is_constructible, + Catch::Detail::unique_ptr>::value, "Cannot just convert one ptr type to another"); + +TEST_CASE("Upcasting special member functions", "[internals][unique-ptr]") { + using Catch::Detail::unique_ptr; + + unique_ptr dptr(new derived{3}); + SECTION("Move constructor") { + unique_ptr bptr(std::move(dptr)); + REQUIRE(bptr->i == 3); + } + SECTION("move assignment") { + unique_ptr bptr(new base{ 1 }); + bptr = std::move(dptr); + REQUIRE(bptr->i == 3); + } +} + +namespace { + struct move_detector { + bool has_moved = false; + move_detector() = default; + move_detector(move_detector const& rhs) = default; + move_detector& operator=(move_detector const& rhs) = default; + + move_detector(move_detector&& rhs) { + rhs.has_moved = true; + } + move_detector& operator=(move_detector&& rhs) { + rhs.has_moved = true; + return *this; + } + }; +} // end unnamed namespace + +TEST_CASE("make_unique reimplementation", "[internals][unique-ptr]") { + using Catch::Detail::make_unique; + SECTION("From lvalue copies") { + move_detector lval; + auto ptr = make_unique(lval); + REQUIRE_FALSE(lval.has_moved); + } + SECTION("From rvalue moves") { + move_detector rval; + auto ptr = make_unique(std::move(rval)); + REQUIRE(rval.has_moved); + } + SECTION("Variadic constructor") { + auto ptr = make_unique>(1, 2., 3); + REQUIRE(*ptr == std::tuple{1, 2., 3}); + } +}