Skip to content

Add casting from owner constructor to basic_observer_ptr #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- name: Setup Emscripten cache
if: matrix.platform.compiler == 'em++'
id: cache-system-libraries
uses: actions/cache@v2.1.7
uses: actions/cache@v3.0.4
with:
path: ${{env.EM_CACHE_FOLDER}}
key: ${{env.EM_VERSION}}-${{ runner.os }}
Expand Down
42 changes: 30 additions & 12 deletions include/oup/observable_unique_ptr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,10 @@ class basic_observer_ptr final {
}
}

/// Create an observer pointer from an owning pointer.
/**
* \brief Create an observer pointer from an owning pointer of a convertible type.
* \param owner The owner pointer to observe (can be null)
*/
template<
typename U,
typename D,
Expand All @@ -983,6 +986,26 @@ class basic_observer_ptr final {
}
}

/**
* \brief Create an observer pointer from an owning pointer of a different type.
* \param manager The owner pointer to copy the observed data from
* \param value The casted pointer value to observe
* \note The raw pointer `value` may or may not be related to the raw pointer
* owner by `manager`. This could be a pointer to any other object which is known
* to have the same lifetime.
*/
template<
typename U,
typename D,
typename P,
typename enable = std::enable_if_t<std::is_same_v<Policy, typename P::observer_policy>>>
basic_observer_ptr(const basic_observable_ptr<U, D, P>& manager, T* value) noexcept :
block(manager.block), data(value) {
if (block) {
block->push_ref();
}
}

/**
* \brief Copy an existing @ref basic_observer_ptr instance
* \param value The existing observer pointer to copy
Expand Down Expand Up @@ -1010,12 +1033,9 @@ class basic_observer_ptr final {
* \brief Copy an existing @ref basic_observer_ptr instance with explicit casting
* \param manager The observer pointer to copy the observed data from
* \param value The casted pointer value to observe
* \note After this smart pointer is created, the source
* pointer is set to null and looses ownership. The deleter
* is default constructed. The raw pointer `value` may or may
* not be related to the raw pointer observed by `manager`.
* This could be a pointer to any other object which is known to
* have the same lifetime.
* \note The raw pointer `value` may or may not be related to the raw pointer
* observed by `manager`. This could be a pointer to any other object which is known
* to have the same lifetime.
*/
template<typename U>
basic_observer_ptr(const basic_observer_ptr<U, Policy>& manager, T* value) noexcept :
Expand Down Expand Up @@ -1054,11 +1074,9 @@ class basic_observer_ptr final {
* \brief Move from an existing @ref basic_observer_ptr instance with explicit casting
* \param manager The observer pointer to copy the observed data from
* \param value The casted pointer value to observe
* \note After this smart pointer is created, the source
* pointer is set to null and looses ownership. The deleter
* is default constructed. The raw pointer `value` may or may
* not be related to the raw pointer observed by `manager`.
* This could be a pointer to any other object which is known to
* \note After this smart pointer is created, the source pointer `manager` is set to
* null. The raw pointer `value` may or may not be related to the raw pointer observed
* by `manager`. This could be a pointer to any other object which is known to
* have the same lifetime.
*/
template<typename U>
Expand Down
88 changes: 88 additions & 0 deletions tests/runtime_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,94 @@ TEST_CASE("observer explicit conversion copy constructor subobject", "[observer_
REQUIRE(mem_track.double_del() == 0u);
}

TEST_CASE("observer from null owner constructor", "[observer_construction]") {
memory_tracker mem_track;

{
test_ptr ptr_owner;
{
test_optr ptr{ptr_owner};
REQUIRE(instances == 0);
REQUIRE(ptr.get() == ptr_owner.get());
REQUIRE(ptr.expired() == true);
}

REQUIRE(instances == 0);
}

REQUIRE(instances == 0);
REQUIRE(mem_track.leaks() == 0u);
REQUIRE(mem_track.double_del() == 0u);
}

TEST_CASE("observer from owner constructor", "[observer_construction]") {
memory_tracker mem_track;

{
test_ptr ptr_owner{new test_object};
{
test_optr ptr{ptr_owner};
REQUIRE(instances == 1);
REQUIRE(ptr.get() == ptr_owner.get());
REQUIRE(ptr.expired() == false);

ptr_owner.reset();
REQUIRE(ptr.get() == nullptr);
REQUIRE(ptr.expired() == true);
}

REQUIRE(instances == 0);
}

REQUIRE(instances == 0);
REQUIRE(mem_track.leaks() == 0u);
REQUIRE(mem_track.double_del() == 0u);
}

TEST_CASE("observer from null owner casting constructor", "[observer_construction]") {
memory_tracker mem_track;

{
test_ptr ptr_owner;
{
test_optr ptr{ptr_owner, static_cast<test_object*>(nullptr)};
REQUIRE(instances == 0);
REQUIRE(ptr.get() == ptr_owner.get());
REQUIRE(ptr.expired() == true);
}

REQUIRE(instances == 0);
}

REQUIRE(instances == 0);
REQUIRE(mem_track.leaks() == 0u);
REQUIRE(mem_track.double_del() == 0u);
}

TEST_CASE("observer from owner casting constructor", "[observer_construction]") {
memory_tracker mem_track;

{
test_ptr ptr_owner{new test_object_derived};
{
test_optr ptr{ptr_owner, dynamic_cast<test_object_derived*>(ptr_owner.get())};
REQUIRE(instances == 1);
REQUIRE(ptr.get() == ptr_owner.get());
REQUIRE(ptr.expired() == false);

ptr_owner.reset();
REQUIRE(ptr.get() == nullptr);
REQUIRE(ptr.expired() == true);
}

REQUIRE(instances == 0);
}

REQUIRE(instances == 0);
REQUIRE(mem_track.leaks() == 0u);
REQUIRE(mem_track.double_del() == 0u);
}

TEST_CASE("observer move constructor", "[observer_construction]") {
memory_tracker mem_track;

Expand Down