Skip to content

Commit

Permalink
SafePtr: dynamic_pointer_cast to dynPtrCast
Browse files Browse the repository at this point in the history
  • Loading branch information
fchn289 committed Oct 16, 2024
1 parent a1ea538 commit 4b2479a
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 57 deletions.
3 changes: 2 additions & 1 deletion src/domino/DataDomino.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#pragma once

#include "DataStore.hpp"
#include "SafePtr.hpp"
#include "UniLog.hpp"

namespace rlib
Expand Down Expand Up @@ -80,7 +81,7 @@ void DataDomino<aDominoType>::rmEv_(const Domino::Event& aValidEv)
template<typename aDataDominoType, typename aDataType>
auto getData(aDataDominoType& aDom, const Domino::EvName& aEvName)
{
return std::static_pointer_cast<aDataType>(aDom.getData(aEvName));
return staticPtrCast<aDataType>(aDom.getData(aEvName));
}

// ***********************************************************************************************
Expand Down
4 changes: 3 additions & 1 deletion src/domino/WbasicDatDom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#pragma once

#include <vector>

#include "SafePtr.hpp"
#include "UniLog.hpp"

namespace rlib
Expand Down Expand Up @@ -134,7 +136,7 @@ bool WbasicDatDom<aDominoType>::wrCtrlOk(const Domino::EvName& aEvName, const bo
template<typename aDataDominoType, typename aDataType>
SafePtr<aDataType> wbasic_getData(aDataDominoType& aDom, const Domino::EvName& aEvName)
{
return std::static_pointer_cast<aDataType>(aDom.wbasic_getData(aEvName));
return staticPtrCast<aDataType>(aDom.wbasic_getData(aEvName));
}

// ***********************************************************************************************
Expand Down
4 changes: 2 additions & 2 deletions src/obj_anywhere/DataStore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <unordered_map>

#include "SafePtr.hpp" // can't UniPtr.hpp since ut(=req) build-err
#include "UniLog.hpp" // debug
#include "UniLog.hpp"

namespace rlib
{
Expand Down Expand Up @@ -80,7 +80,7 @@ SafePtr<aDataT> DataStore<aDataKey>::get(const aDataKey& aKey) const
HID("(DataStore) can't find key=" << aKey);
return nullptr;
}
return std::dynamic_pointer_cast<aDataT>(key_data->second);
return dynPtrCast<aDataT>(key_data->second);
}

// ***********************************************************************************************
Expand Down
22 changes: 11 additions & 11 deletions src/safe_mem/SafePtr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ class SafePtr
template<typename U, typename... ConstructArgs> friend SafePtr<U> make_safe(ConstructArgs&&... aArgs);

// safe-only cast (vs shared_ptr, eg static_pointer_cast<any> is not safe)
template<typename From> SafePtr(const SafePtr<From>&) noexcept; // cp ok or compile err
template<typename From> SafePtr(SafePtr<From>&&) noexcept; // mv ok or compile err
template<typename To> std::shared_ptr<To> cast() const noexcept; // ret ok or null
template<typename From> SafePtr(const SafePtr<From>&) noexcept; // cp ok or compile err
template<typename From> SafePtr(SafePtr<From>&&) noexcept; // mv ok or compile err
template<typename To> std::shared_ptr<To> cast() const noexcept; // ret ok or null
template<typename To, typename From>
friend SafePtr<To> std::dynamic_pointer_cast(const SafePtr<From>&) noexcept; // ret ok or null
friend SafePtr<To> dynPtrCast(const SafePtr<From>&) noexcept; // ret ok or null

// safe usage: convenient(compatible shared_ptr), equivalent & min
// . ret shared_ptr is safer than T* (but not safest since to call T's func easily)
Expand Down Expand Up @@ -191,11 +191,10 @@ bool operator<(SafePtr<T> lhs, SafePtr<U> rhs)
{
return lhs.get() < rhs.get();
}
} // namespace

// ***********************************************************************************************
template<typename To, typename From>
rlib::SafePtr<To> std::dynamic_pointer_cast(const rlib::SafePtr<From>& aSafeFrom) noexcept
rlib::SafePtr<To> dynPtrCast(const rlib::SafePtr<From>& aSafeFrom) noexcept
{
rlib::SafePtr<To> safeTo;
safeTo.pT_ = aSafeFrom.template cast<To>();
Expand All @@ -205,10 +204,11 @@ rlib::SafePtr<To> std::dynamic_pointer_cast(const rlib::SafePtr<From>& aSafeFrom

// ***********************************************************************************************
template<typename To, typename From>
rlib::SafePtr<To> std::static_pointer_cast(const rlib::SafePtr<From>& aSafeFrom) noexcept
rlib::SafePtr<To> staticPtrCast(const rlib::SafePtr<From>& aSafeFrom) noexcept
{
return std::dynamic_pointer_cast<To>(aSafeFrom);
return dynPtrCast<To>(aSafeFrom);
}
} // namespace

// ***********************************************************************************************
template<typename T>
Expand All @@ -225,6 +225,7 @@ struct std::hash<rlib::SafePtr<T>>
// 2024-04-17 CSZ 3)strict constructor - illegal->compile-err (while *cast() can ret null)
// 2024-05-06 CSZ - AI-gen-code
// 2024-06-28 CSZ - dynamic_pointer_cast ok or ret null
// 2024-10-16 CSZ - dynamic_pointer_cast to dynPtrCast since std not allowed
// ***********************************************************************************************
// - Q&A
// . How to solve safety issue:
Expand Down Expand Up @@ -254,12 +255,11 @@ struct std::hash<rlib::SafePtr<T>>
// . it's possible but rare to use T* unsafely - SafePtr has this risk to exchange convenient
// . shared_ptr reduces mem-lifecycle-mgmt(1 major-possible-bug) - so worth
//
// . why dynamic_pointer_cast?
// . why dynPtrCast?
// . cast all possible eg base->derived (more than cp constructor)
// . explicit cast so ok or nullptr (cp constructor is implicit & ok/compile-err)
// . unified-ret is predictable & simple
// . dynamic_cast & dynamic_pointer_cast follow the same rule
// . align/compatible with shared_ptr
// . std not allow overload dynamic_pointer_cast so dynPtrCast & DYN_PTR_CAST
// . why cp constructor?
// . dyn-cast & cp cover diff scenario - implicit convert is useful/convenient also
// . why mv constructor?
Expand Down
16 changes: 10 additions & 6 deletions src/safe_mem/UniPtr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@
namespace rlib
{
// std::~, or ambiguous with boost::~
using UniPtr = std::shared_ptr<void>;
#define MAKE_PTR std::make_shared
#define PTR std::shared_ptr
using UniPtr = std::shared_ptr<void>;
#define MAKE_PTR std::make_shared
#define PTR std::shared_ptr
#define DYN_PTR_CAST std::dynamic_pointer_cast
#define STATIC_PTR_CAST std::static_pointer_cast

#else
#include "SafePtr.hpp"
namespace rlib
{
using UniPtr = SafePtr<void>;
#define MAKE_PTR make_safe
#define PTR SafePtr
using UniPtr = SafePtr<void>;
#define MAKE_PTR make_safe
#define PTR SafePtr
#define DYN_PTR_CAST rlib::dynPtrCast
#define STATIC_PTR_CAST rlib::staticPtrCast
// 4th req: SafePtr.get() return same as shared_ptr
#endif

Expand Down
2 changes: 1 addition & 1 deletion src/thread/MtInQueue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ PTR<aEleType> MtInQueue::pop()
// pop
auto ele = std::move(it->first);
cache_.pop_front();
return std::static_pointer_cast<aEleType>(ele);
return STATIC_PTR_CAST<aEleType>(ele);
}

// ***********************************************************************************************
Expand Down
5 changes: 3 additions & 2 deletions ut/domino/DataDominoTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <set>
#include <string>

#include "SafePtr.hpp"
#include "UtInitObjAnywhere.hpp"

namespace rlib
Expand Down Expand Up @@ -42,7 +43,7 @@ TYPED_TEST_P(DataDominoTest, setShared_thenGetIt_thenRmIt)
EXPECT_EQ(nullptr, PARA_DOM->getData("ev0").get()) << "REQ: get null since ev0 not exist";

PARA_DOM->replaceData("ev0", make_safe<string>("ev0's data")); // req: any type data (2nd=string)
auto pString = static_pointer_cast<string>(PARA_DOM->getData("ev0")); // directly get() will destruct shared_ptr afterward
auto pString = staticPtrCast<string>(PARA_DOM->getData("ev0")); // directly get() will destruct shared_ptr afterward
ASSERT_NE(nullptr, pString.get());
EXPECT_EQ("ev0's data", *(pString.get())) << "REQ: get = set";

Expand All @@ -51,7 +52,7 @@ TYPED_TEST_P(DataDominoTest, setShared_thenGetIt_thenRmIt)

PARA_DOM->replaceData("ev0", make_safe<string>("replace ev0's data"));
EXPECT_EQ("replace ev0's data", *(getData<TypeParam, string>(*PARA_DOM, "ev0").get())) << "REQ: get replaced";
EXPECT_NE(pString.get(), static_pointer_cast<string>(PARA_DOM->getData("ev0")).get()) << "REQ: replace != old";
EXPECT_NE(pString.get(), staticPtrCast<string>(PARA_DOM->getData("ev0")).get()) << "REQ: replace != old";

PARA_DOM->replaceData("ev0"); // req: rm data
EXPECT_EQ(nullptr, PARA_DOM->getData("ev0").get()) << "REQ: get null";
Expand Down
54 changes: 27 additions & 27 deletions ut/safe_mem/SafePtrTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,29 +73,29 @@ struct Derive : public Base { int value() const override { return 1; } };
TEST(SafePtrTest, GOLD_safeCast_self_base_void_back)
{
auto d = make_safe<Derive>();
EXPECT_EQ(1, dynamic_pointer_cast<Derive>(d)->value()) << "REQ: cast to self";
EXPECT_EQ(1, dynamic_pointer_cast<Base >(d)->value()) << "REQ: cast to base";
EXPECT_EQ(1, dynPtrCast<Derive>(d)->value()) << "REQ: cast to self";
EXPECT_EQ(1, dynPtrCast<Base >(d)->value()) << "REQ: cast to base";

EXPECT_EQ(1, dynamic_pointer_cast<Derive>(dynamic_pointer_cast<Base>(d))->value()) << "REQ: (derived->)base->derived";
EXPECT_EQ(1, dynPtrCast<Derive>(dynPtrCast<Base>(d))->value()) << "REQ: (derived->)base->derived";

EXPECT_EQ(1, dynamic_pointer_cast<Derive>(dynamic_pointer_cast<void>(dynamic_pointer_cast<Base>(d)))->value()) << "REQ: ->void & void->origin";
EXPECT_EQ(1, dynamic_pointer_cast<Base >(dynamic_pointer_cast<void>(dynamic_pointer_cast<Base>(d)))->value()) << "REQ: ->void & void->preVoid";
EXPECT_EQ(1, dynPtrCast<Derive>(dynPtrCast<void>(dynPtrCast<Base>(d)))->value()) << "REQ: ->void & void->origin";
EXPECT_EQ(1, dynPtrCast<Base >(dynPtrCast<void>(dynPtrCast<Base>(d)))->value()) << "REQ: ->void & void->preVoid";

//EXPECT_EQ(1, dynamic_pointer_cast<Base>(dynamic_pointer_cast<void>(make_safe<Derive>())).get()) << "safe cast, but not support";
//EXPECT_EQ(1, dynPtrCast<Base>(dynPtrCast<void>(make_safe<Derive>())).get()) << "safe cast, but not support";
}
struct D_protect : protected Derive { int value() const override { return 2; } };
struct D_private : private Derive { int value() const override { return 3; } };
TEST(SafePtrTest, invalidCast_retNull)
{
EXPECT_EQ(nullptr, dynamic_pointer_cast<char >(make_safe<int >(7)).get()) << "REQ: invalid int ->char";
EXPECT_EQ(nullptr, dynamic_pointer_cast<Derive>(make_safe<Base>() ).get()) << "REQ: invalid base->derived";
EXPECT_EQ(nullptr, dynPtrCast<char >(make_safe<int >(7)).get()) << "REQ: invalid int ->char";
EXPECT_EQ(nullptr, dynPtrCast<Derive>(make_safe<Base>() ).get()) << "REQ: invalid base->derived";

//EXPECT_EQ(nullptr, dynamic_pointer_cast<Base>(make_safe<D_private>()).get()); // invalid, not ret null but compile err
//EXPECT_EQ(nullptr, dynamic_pointer_cast<Base>(make_safe<D_protect>()).get()); // invalid, not ret null but compile err
//EXPECT_EQ(nullptr, dynPtrCast<Base>(make_safe<D_private>()).get()); // invalid, not ret null but compile err
//EXPECT_EQ(nullptr, dynPtrCast<Base>(make_safe<D_protect>()).get()); // invalid, not ret null but compile err

auto msgInQ = SafePtr<void>(SafePtr<Base>(make_safe<Derive>()));
auto msgOutQ = dynamic_pointer_cast<char>(msgInQ);
EXPECT_EQ(1, dynamic_pointer_cast<Base>(msgInQ)->value ()) << "REQ: failed cast -> keep src";
auto msgOutQ = dynPtrCast<char>(msgInQ);
EXPECT_EQ(1, dynPtrCast<Base>(msgInQ)->value ()) << "REQ: failed cast -> keep src";
EXPECT_EQ(type_index(typeid(Derive)), msgInQ.realType()) << "REQ: failed cast -> keep src";
EXPECT_EQ(type_index(typeid(Base )), msgInQ.lastType()) << "REQ: failed cast -> keep src";

Expand All @@ -108,8 +108,8 @@ TEST(SafePtrTest, safe_cast_bugFix)
{
SafePtr<Base> b = make_safe<D2>(); // realType_ is D2
SafePtr<void> v = b; // diffType_ is Base
auto vv = dynamic_pointer_cast<void>(v); // bug fix for multi-void
EXPECT_EQ(2, static_pointer_cast<Base>(vv)->value()) << "REQ: can cast D2->Base->void->void->Base";
auto vv = dynPtrCast<void>(v); // bug fix for multi-void
EXPECT_EQ(2, staticPtrCast<Base>(vv)->value()) << "REQ: can cast D2->Base->void->void->Base";
}

#define COPY
Expand All @@ -132,21 +132,21 @@ TEST(SafePtrTest, GOLD_safeCp_self_base_void)
EXPECT_EQ(1, SafePtr<Derive>(d)->value()) << "REQ: cp to self";
EXPECT_EQ(1, SafePtr<Base >(d)->value()) << "REQ: cp to base";

EXPECT_EQ(0, dynamic_pointer_cast<Base >(SafePtr<void>(make_safe<Base >()))->value()) << "REQ: cp any->void";
EXPECT_EQ(1, dynamic_pointer_cast<Derive>(SafePtr<void>(make_safe<Derive>()))->value()) << "req: cp any->void";
EXPECT_EQ(0, dynPtrCast<Base >(SafePtr<void>(make_safe<Base >()))->value()) << "REQ: cp any->void";
EXPECT_EQ(1, dynPtrCast<Derive>(SafePtr<void>(make_safe<Derive>()))->value()) << "req: cp any->void";
}
TEST(SafePtrTest, invalidCp_compileErr) // cp's compile-err is safer than dynamic_pointer_cast that may ret nullptr
TEST(SafePtrTest, invalidCp_compileErr) // cp's compile-err is safer than dynPtrCast that may ret nullptr
{
//SafePtr<Derive>(SafePtr<Base>(make_safe<Derive>())); // derived->base->derive: cp compile err, can dynamic_pointer_cast instead
//SafePtr<Derive>(SafePtr<void>(make_safe<Derive>())); // void->origin: cp compile err, can dynamic_pointer_cast instead
//SafePtr<Base >(SafePtr<void>(make_safe<Derive>())); // derive->void->base: cp compile err, dynamic_pointer_cast ret nullptr
//SafePtr<Derive>(SafePtr<Base>(make_safe<Derive>())); // derived->base->derive: cp compile err, can dynPtrCast instead
//SafePtr<Derive>(SafePtr<void>(make_safe<Derive>())); // void->origin: cp compile err, can dynPtrCast instead
//SafePtr<Base >(SafePtr<void>(make_safe<Derive>())); // derive->void->base: cp compile err, dynPtrCast ret nullptr

//SafePtr<Derive>(make_safe<Base>()); // base->derived: cp compile-err; dynamic_pointer_cast ret nullptr
//SafePtr<Derive>(make_safe<Base>()); // base->derived: cp compile-err; dynPtrCast ret nullptr

//SafePtr<char>(make_safe<int>(7)); // int->char: both cp & dynamic_pointer_cast will compile err
//SafePtr<char>(make_safe<int>(7)); // int->char: both cp & dynPtrCast will compile err

//SafePtr<Base>(make_safe<D_private>()); // private->base: both cp & dynamic_pointer_cast will compile err
//SafePtr<Base>(make_safe<D_protect>()); // protect->base: both cp & dynamic_pointer_cast will compile err
//SafePtr<Base>(make_safe<D_private>()); // private->base: both cp & dynPtrCast will compile err
//SafePtr<Base>(make_safe<D_protect>()); // protect->base: both cp & dynPtrCast will compile err
}
TEST(SafePtrTest, GOLD_const_and_back)
{
Expand Down Expand Up @@ -188,9 +188,9 @@ TEST(SafePtrTest, GOLD_mtQ_req_mv)
EXPECT_EQ(type_index(typeid(Base)), msg.realType()) << "REQ: reset src all";
EXPECT_EQ(type_index(typeid(Base)), msg.lastType()) << "REQ: reset src all";

EXPECT_EQ(1 , dynamic_pointer_cast<Base>(msgInQ)->value() ) << "REQ: takeover msg";
EXPECT_EQ(type_index(typeid(Derive)), dynamic_pointer_cast<Base>(msgInQ).realType()) << "REQ: reset src all";
EXPECT_EQ(type_index(typeid(Base )), dynamic_pointer_cast<Base>(msgInQ).lastType()) << "REQ: reset src all";
EXPECT_EQ(1 , dynPtrCast<Base>(msgInQ)->value() ) << "REQ: takeover msg";
EXPECT_EQ(type_index(typeid(Derive)), dynPtrCast<Base>(msgInQ).realType()) << "REQ: reset src all";
EXPECT_EQ(type_index(typeid(Base )), dynPtrCast<Base>(msgInQ).lastType()) << "REQ: reset src all";
}
TEST(SafePtrTest, nothing_cp_mv_assign)
{
Expand Down
3 changes: 2 additions & 1 deletion ut/thread/MtInQueueTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "MT_Semaphore.hpp"
#include "UniLog.hpp"
#include "UniPtr.hpp"

#define IN_GTEST
#include "MT_PingMainTH.hpp"
Expand Down Expand Up @@ -280,7 +281,7 @@ TEST_F(MtInQueueTest, handle_via_base)
EXPECT_TRUE(mt_getQ().setHdlrOK<Base>([](UniPtr aEle)
{
static int exp = 1;
auto ele = static_pointer_cast<Base>(aEle);
auto ele = STATIC_PTR_CAST<Base>(aEle);
EXPECT_NE(nullptr, ele.get());
EXPECT_EQ(exp++, ele.get()->value());
}));
Expand Down
10 changes: 5 additions & 5 deletions ut/thread/ThreadBackTest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ TEST_F(THREAD_BACK_TEST, GOLD_entryFnResult_toBackFn_withoutTimedWait)
// TaskBackFN
[idxThread](SafePtr<void> aRet)
{
EXPECT_EQ(idxThread % 2 != 0, *(dynamic_pointer_cast<bool>(aRet).get())) << "REQ: check true & false";
EXPECT_EQ(idxThread % 2 != 0, *(dynPtrCast<bool>(aRet).get())) << "REQ: check true & false";
}
));
}
Expand Down Expand Up @@ -227,7 +227,7 @@ TEST_F(THREAD_BACK_TEST, GOLD_integrate_MsgSelf_ThreadBack_MtInQueue) // simula
msgSelf_->newMsg( // REQ: via MsgSelf
[aMsg, &cb_info]
{
EXPECT_EQ("a", *(static_pointer_cast<string>(aMsg).get()));
EXPECT_EQ("a", *(staticPtrCast<string>(aMsg).get()));
cb_info.emplace("REQ: a's Q hdlr via MsgSelf");
}
);
Expand All @@ -238,7 +238,7 @@ TEST_F(THREAD_BACK_TEST, GOLD_integrate_MsgSelf_ThreadBack_MtInQueue) // simula
msgSelf_->newMsg(
[aMsg, &cb_info]
{
EXPECT_EQ(2, *(static_pointer_cast<int>(aMsg).get()));
EXPECT_EQ(2, *(staticPtrCast<int>(aMsg).get()));
cb_info.emplace("REQ: 2's Q hdlr via MsgSelf");
}
);
Expand All @@ -258,7 +258,7 @@ TEST_F(THREAD_BACK_TEST, GOLD_integrate_MsgSelf_ThreadBack_MtInQueue) // simula
viaMsgSelf( // REQ: via MsgSelf
[this, &cb_info](SafePtr<void> aRet)
{
EXPECT_TRUE(*(dynamic_pointer_cast<bool>(aRet).get())) << "entryFn succ";
EXPECT_TRUE(*(dynPtrCast<bool>(aRet).get())) << "entryFn succ";
cb_info.emplace("REQ: a's backFn via MsgSelf");
}
)
Expand All @@ -273,7 +273,7 @@ TEST_F(THREAD_BACK_TEST, GOLD_integrate_MsgSelf_ThreadBack_MtInQueue) // simula
viaMsgSelf(
[this, &cb_info](SafePtr<void> aRet)
{
EXPECT_TRUE(*(dynamic_pointer_cast<bool>(aRet).get())) << "entryFn succ";
EXPECT_TRUE(*(dynPtrCast<bool>(aRet).get())) << "entryFn succ";
cb_info.emplace("REQ: 2's backFn via MsgSelf");
}
)
Expand Down

0 comments on commit 4b2479a

Please sign in to comment.