Skip to content

Commit

Permalink
SafePtr: default cast_get() ret T than void
Browse files Browse the repository at this point in the history
  • Loading branch information
fchn289 committed Feb 16, 2024
1 parent 333ca89 commit ecb242e
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/domino/DataDomino.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// - Req: Domino to store any type of data
// - core: dataStore_
// - scope: provide min interface (& extend by non-member func)
// - mem-safe: true
// - mem-safe: true (when use SafePtr instead of shared_ptr)
// ***********************************************************************************************
#pragma once

Expand Down
2 changes: 1 addition & 1 deletion src/domino/WbasicDatDom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// - what: simple/easy write-protect for DataDomino
// - why: eg Yang RW para need write-protect
// - core: wrCtrl_
// - mem-safe: true
// - mem-safe: true (when use SafePtr instead of shared_ptr)
// ***********************************************************************************************
#pragma once

Expand Down
32 changes: 22 additions & 10 deletions src/safe_mem/SafePtr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ using namespace std;
namespace RLib
{
// ***********************************************************************************************
template<typename T = void> class SafePtr
template<typename T = void>
class SafePtr
{
public:
// create
Expand All @@ -42,7 +43,7 @@ template<typename T = void> class SafePtr
// cast
template<typename From> SafePtr(const SafePtr<From>&);
template<typename To> shared_ptr<To> cast_get() const;
shared_ptr<void> cast_get() const;
shared_ptr<T> cast_get() const;

// use
T* get() const { return pT_.get(); } // same interface as shared_ptr
Expand Down Expand Up @@ -85,6 +86,12 @@ SafePtr<T>::SafePtr(const SafePtr<From>& aSafeFrom)

// ***********************************************************************************************
template<typename T>
shared_ptr<T> SafePtr<T>::cast_get() const
{
HID("(SafePtr) to self");
return pT_;
}
template<typename T>
template<typename To>
shared_ptr<To> SafePtr<T>::cast_get() const
{
Expand All @@ -103,26 +110,27 @@ shared_ptr<To> SafePtr<T>::cast_get() const
HID("(SafePtr) any to type-before-cast-to-void");
return static_pointer_cast<To>(pT_);
}
if (is_same<To, void>::value)
{
HID("(SafePtr) any to void (for container to store diff types)");
return static_pointer_cast<To>(pT_);
}
HID("(SafePtr) unsupported cast");
return nullptr;
}
template<typename T>
shared_ptr<void> SafePtr<T>::cast_get() const
{
HID("(SafePtr) any to void (for container to store diff types)");
return pT_;
}

// ***********************************************************************************************
template<typename U, typename... Args> SafePtr<U> make_safe(Args&&... aArgs)
template<typename U, typename... Args>
SafePtr<U> make_safe(Args&&... aArgs)
{
SafePtr<U> sptr;
sptr.pT_ = make_shared<U>(forward<Args>(aArgs)...);
return sptr; // !!! valgrind failed when HID() here
}

// ***********************************************************************************************
template<typename To, typename From> auto static_pointer_cast(const SafePtr<From>& aFromPtr) noexcept
template<typename To, typename From>
auto static_pointer_cast(const SafePtr<From>& aFromPtr) noexcept
{
return SafePtr<To>(aFromPtr);
}
Expand All @@ -145,6 +153,10 @@ template<typename To, typename From> auto static_pointer_cast(const SafePtr<From
// . shared_ptr[out-bound] is NOT safe, so still need SafePtr to support array
// . g++12 full support T[]
//
// . T* get() is mem-safe?
// . T shall be mem-safe to avoid abuse mem via T*
// . so yes, get() is mem-safe
//
// . T not ref/ptr/const?
// . SafeRef? or like this?
// . how about class' this?
30 changes: 15 additions & 15 deletions ut/safe_mem/SafePtrTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,47 @@ namespace RLib
TEST(SafePtrTest, GOLD_construct_get)
{
auto one = make_safe<int>(42);
EXPECT_EQ(42, *(one.cast_get<int>())) << "REQ: valid construct & get";
EXPECT_EQ(42, *(one.cast_get())) << "REQ: valid construct & get";

*(one.cast_get<int>()) = 43;
EXPECT_EQ(43, *(one.cast_get<int>())) << "REQ: valid update";
*(one.cast_get()) = 43;
EXPECT_EQ(43, *(one.cast_get())) << "REQ: valid update";

EXPECT_EQ(one.cast_get<void>(), one.cast_get<int>()) << "REQ: valid get (void)";
EXPECT_EQ(one.cast_get<void>(), one.cast_get()) << "REQ: valid get (void)";
// one.cast_get<unsigned>(); // REQ: invalid cast_get() will fail compile
}
TEST(SafePtrTest, GOLD_cp_get)
{
auto one = make_safe<int>(42);
auto two(one);
EXPECT_EQ(42, *(two.cast_get<int>())) << "REQ: valid cp & get";
EXPECT_EQ(42, *(two.cast_get())) << "REQ: valid cp & get";

*(one.cast_get<int>()) = 43;
EXPECT_EQ(43, *(two.cast_get<int>())) << "REQ: valid update via sharing";
*(one.cast_get()) = 43;
EXPECT_EQ(43, *(two.cast_get())) << "REQ: valid update via sharing";
}
TEST(SafePtrTest, GOLD_assign_get)
{
SafePtr<int> one;
EXPECT_EQ(nullptr, one.cast_get<int>()) << "REQ: construct null";
EXPECT_EQ(nullptr, one.cast_get()) << "REQ: construct null";

auto two = make_safe<int>(42);
one = two;
EXPECT_EQ(42, *(one.cast_get<int>())) << "REQ: valid assign & get";
EXPECT_EQ(42, *(one.cast_get())) << "REQ: valid assign & get";

two = SafePtr<int>();
EXPECT_EQ(42, *(one.cast_get<int>())) << "REQ: valid get after shared is reset";
EXPECT_EQ(nullptr, two.cast_get<int>()) << "REQ: assign to null";
EXPECT_EQ(42, *(one.cast_get())) << "REQ: valid get after shared is reset";
EXPECT_EQ(nullptr, two.cast_get()) << "REQ: assign to null";
}
TEST(SafePtrTest, GOLD_mv_get)
{
SafePtr<int> one;
auto two = make_safe<int>(42);
one = move(two);
EXPECT_EQ(42, *(one.cast_get<int>())) << "REQ: valid move assignment & get";
EXPECT_EQ(nullptr, two.cast_get<int>()) << "REQ: move src is null";
EXPECT_EQ(42, *(one.cast_get())) << "REQ: valid move assignment & get";
EXPECT_EQ(nullptr, two.cast_get()) << "REQ: move src is null";

SafePtr<int> three(move(one));
EXPECT_EQ(42, *(three.cast_get<int>())) << "REQ: valid move cp & get";
EXPECT_EQ(nullptr, one.cast_get<int>()) << "REQ: move src is null";
EXPECT_EQ(42, *(three.cast_get())) << "REQ: valid move cp & get";
EXPECT_EQ(nullptr, one.cast_get()) << "REQ: move src is null";
}

#define DERIVE_VOID
Expand Down

0 comments on commit ecb242e

Please sign in to comment.