Skip to content

Commit 299cea9

Browse files
committed
Added const_pointer_cast
1 parent 831bae7 commit 299cea9

File tree

3 files changed

+188
-4
lines changed

3 files changed

+188
-4
lines changed

include/oup/observable_unique_ptr.hpp

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,9 +1377,6 @@ class enable_observer_from_this : public virtual details::enable_observer_from_t
13771377
};
13781378

13791379
public:
1380-
1381-
using observer_element_type = T;
1382-
13831380
/// Return an observer pointer to 'this'.
13841381
/** \return A new observer pointer pointing to 'this'.
13851382
* \note If 'this' is not owned by a unique or sealed pointer, i.e., if
@@ -1451,6 +1448,48 @@ observer_ptr<U> static_pointer_cast(observer_ptr<T>&& ptr) {
14511448
return observer_ptr<U>(std::move(ptr), static_cast<U*>(ptr.raw_get()));
14521449
}
14531450

1451+
/// Perform a `const_cast` for an `observable_unique_ptr`.
1452+
/** \param ptr The pointer to cast
1453+
* \note Ownership will be transfered to the returned pointer.
1454+
If the input pointer is null, the output pointer will also be null.
1455+
*/
1456+
template<typename U, typename T>
1457+
observable_unique_ptr<U> const_pointer_cast(observable_unique_ptr<T>&& ptr) {
1458+
return observable_unique_ptr<U>(std::move(ptr), const_cast<U*>(ptr.get()));
1459+
}
1460+
1461+
/// Perform a `const_cast` for an `observable_unique_ptr`.
1462+
/** \param ptr The pointer to cast
1463+
* \note Ownership will be transfered to the returned pointer.
1464+
If the input pointer is null, the output pointer will also be null.
1465+
*/
1466+
template<typename U, typename T>
1467+
observable_sealed_ptr<U> const_pointer_cast(observable_sealed_ptr<T>&& ptr) {
1468+
return observable_sealed_ptr<U>(std::move(ptr), const_cast<U*>(ptr.get()));
1469+
}
1470+
1471+
/// Perform a `const_cast` for an `observer_ptr`.
1472+
/** \param ptr The pointer to cast
1473+
* \note A new observer is returned, the input observer is not modified.
1474+
If the input pointer is null, the output pointer will also be null.
1475+
*/
1476+
template<typename U, typename T>
1477+
observer_ptr<U> const_pointer_cast(const observer_ptr<T>& ptr) {
1478+
// NB: can use raw_get() as const cast of an expired pointer is fine
1479+
return observer_ptr<U>(ptr, const_cast<U*>(ptr.raw_get()));
1480+
}
1481+
1482+
/// Perform a `const_cast` for an `observer_ptr`.
1483+
/** \param ptr The pointer to cast
1484+
* \note A new observer is returned, the input observer is set to null.
1485+
If the input pointer is null, the output pointer will also be null.
1486+
*/
1487+
template<typename U, typename T>
1488+
observer_ptr<U> const_pointer_cast(observer_ptr<T>&& ptr) {
1489+
// NB: can use raw_get() as const cast of an expired pointer is fine
1490+
return observer_ptr<U>(std::move(ptr), const_cast<U*>(ptr.raw_get()));
1491+
}
1492+
14541493
}
14551494

14561495
#endif

tests/runtime_tests.cpp

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3589,7 +3589,6 @@ TEST_CASE("static pointer cast observer copy from null", "[pointer_cast]") {
35893589
REQUIRE(mem_track.double_del() == 0u);
35903590
}
35913591

3592-
35933592
TEST_CASE("static pointer cast observer move from valid", "[pointer_cast]") {
35943593
memory_tracker mem_track;
35953594

@@ -3625,3 +3624,146 @@ TEST_CASE("static pointer cast observer move from null", "[pointer_cast]") {
36253624
REQUIRE(mem_track.leaks() == 0u);
36263625
REQUIRE(mem_track.double_del() == 0u);
36273626
}
3627+
3628+
TEST_CASE("const pointer cast unique from valid", "[pointer_cast]") {
3629+
memory_tracker mem_track;
3630+
3631+
{
3632+
test_object* raw_ptr = new test_object;
3633+
test_ptr_const ptr_orig{raw_ptr};
3634+
test_ptr ptr = oup::const_pointer_cast<test_object>(std::move(ptr_orig));
3635+
3636+
REQUIRE(instances == 1);
3637+
REQUIRE(ptr_orig == nullptr);
3638+
REQUIRE(ptr.get() == raw_ptr);
3639+
}
3640+
3641+
REQUIRE(instances == 0);
3642+
REQUIRE(mem_track.leaks() == 0u);
3643+
REQUIRE(mem_track.double_del() == 0u);
3644+
}
3645+
3646+
TEST_CASE("const pointer cast unique from null", "[pointer_cast]") {
3647+
memory_tracker mem_track;
3648+
3649+
{
3650+
test_ptr_const ptr_orig;
3651+
test_ptr ptr = oup::const_pointer_cast<test_object>(std::move(ptr_orig));
3652+
3653+
REQUIRE(instances == 0);
3654+
REQUIRE(ptr_orig == nullptr);
3655+
REQUIRE(ptr == nullptr);
3656+
}
3657+
3658+
REQUIRE(instances == 0);
3659+
REQUIRE(mem_track.leaks() == 0u);
3660+
REQUIRE(mem_track.double_del() == 0u);
3661+
}
3662+
3663+
TEST_CASE("const pointer cast sealed from valid", "[pointer_cast]") {
3664+
memory_tracker mem_track;
3665+
3666+
{
3667+
test_sptr ptr_init = oup::make_observable_sealed<test_object>();
3668+
test_object* raw_ptr = ptr_init.get();
3669+
test_sptr_const ptr_orig{std::move(ptr_init)};
3670+
test_sptr ptr = oup::const_pointer_cast<test_object>(std::move(ptr_orig));
3671+
3672+
REQUIRE(instances == 1);
3673+
REQUIRE(ptr_orig == nullptr);
3674+
REQUIRE(ptr.get() == raw_ptr);
3675+
}
3676+
3677+
REQUIRE(instances == 0);
3678+
REQUIRE(mem_track.leaks() == 0u);
3679+
REQUIRE(mem_track.double_del() == 0u);
3680+
}
3681+
3682+
TEST_CASE("const pointer cast sealed from null", "[pointer_cast]") {
3683+
memory_tracker mem_track;
3684+
3685+
{
3686+
test_sptr_const ptr_orig;
3687+
test_sptr ptr = oup::const_pointer_cast<test_object>(std::move(ptr_orig));
3688+
3689+
REQUIRE(instances == 0);
3690+
REQUIRE(ptr_orig == nullptr);
3691+
REQUIRE(ptr == nullptr);
3692+
}
3693+
3694+
REQUIRE(instances == 0);
3695+
REQUIRE(mem_track.leaks() == 0u);
3696+
REQUIRE(mem_track.double_del() == 0u);
3697+
}
3698+
3699+
TEST_CASE("const pointer cast observer copy from valid", "[pointer_cast]") {
3700+
memory_tracker mem_track;
3701+
3702+
{
3703+
test_sptr ptr_owner = oup::make_observable_sealed<test_object>();
3704+
test_object* raw_ptr = ptr_owner.get();
3705+
test_optr_const ptr_orig{ptr_owner};
3706+
test_optr ptr = oup::const_pointer_cast<test_object>(ptr_orig);
3707+
3708+
REQUIRE(instances == 1);
3709+
REQUIRE(ptr_orig.get() == raw_ptr);
3710+
REQUIRE(ptr.get() == raw_ptr);
3711+
}
3712+
3713+
REQUIRE(instances == 0);
3714+
REQUIRE(mem_track.leaks() == 0u);
3715+
REQUIRE(mem_track.double_del() == 0u);
3716+
}
3717+
3718+
TEST_CASE("const pointer cast observer copy from null", "[pointer_cast]") {
3719+
memory_tracker mem_track;
3720+
3721+
{
3722+
test_optr_const ptr_orig;
3723+
test_optr ptr = oup::const_pointer_cast<test_object>(ptr_orig);
3724+
3725+
REQUIRE(instances == 0);
3726+
REQUIRE(ptr_orig == nullptr);
3727+
REQUIRE(ptr == nullptr);
3728+
}
3729+
3730+
REQUIRE(instances == 0);
3731+
REQUIRE(mem_track.leaks() == 0u);
3732+
REQUIRE(mem_track.double_del() == 0u);
3733+
}
3734+
3735+
TEST_CASE("const pointer cast observer move from valid", "[pointer_cast]") {
3736+
memory_tracker mem_track;
3737+
3738+
{
3739+
test_sptr ptr_owner = oup::make_observable_sealed<test_object_derived>();
3740+
test_object* raw_ptr = ptr_owner.get();
3741+
test_optr_const ptr_orig{ptr_owner};
3742+
test_optr ptr = oup::const_pointer_cast<test_object>(std::move(ptr_orig));
3743+
3744+
REQUIRE(instances == 1);
3745+
REQUIRE(ptr_orig == nullptr);
3746+
REQUIRE(ptr.get() == raw_ptr);
3747+
}
3748+
3749+
REQUIRE(instances == 0);
3750+
REQUIRE(mem_track.leaks() == 0u);
3751+
REQUIRE(mem_track.double_del() == 0u);
3752+
}
3753+
3754+
TEST_CASE("const pointer cast observer move from null", "[pointer_cast]") {
3755+
memory_tracker mem_track;
3756+
3757+
{
3758+
test_optr_const ptr_orig;
3759+
test_optr ptr = oup::const_pointer_cast<test_object>(std::move(ptr_orig));
3760+
3761+
REQUIRE(instances == 0);
3762+
REQUIRE(ptr_orig == nullptr);
3763+
REQUIRE(ptr == nullptr);
3764+
}
3765+
3766+
REQUIRE(instances == 0);
3767+
REQUIRE(mem_track.leaks() == 0u);
3768+
REQUIRE(mem_track.double_del() == 0u);
3769+
}

tests/tests_common.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ struct test_deleter {
7777

7878
using test_ptr = oup::observable_unique_ptr<test_object>;
7979
using test_sptr = oup::observable_sealed_ptr<test_object>;
80+
using test_ptr_const = oup::observable_unique_ptr<const test_object>;
81+
using test_sptr_const = oup::observable_sealed_ptr<const test_object>;
8082
using test_ptr_derived = oup::observable_unique_ptr<test_object_derived>;
8183
using test_sptr_derived = oup::observable_sealed_ptr<test_object_derived>;
8284
using test_ptr_with_deleter = oup::observable_unique_ptr<test_object,test_deleter>;
@@ -94,6 +96,7 @@ using test_ptr_from_this_multi = oup::observable_unique_ptr<test_object_observer
9496
using test_sptr_from_this_multi = oup::observable_sealed_ptr<test_object_observer_from_this_multi>;
9597

9698
using test_optr = oup::observer_ptr<test_object>;
99+
using test_optr_const = oup::observer_ptr<const test_object>;
97100
using test_optr_derived = oup::observer_ptr<test_object_derived>;
98101
using test_optr_from_this = oup::observer_ptr<test_object_observer_from_this>;
99102
using test_optr_from_this_const = oup::observer_ptr<const test_object_observer_from_this>;

0 commit comments

Comments
 (0)