Skip to content

Commit 182defb

Browse files
committed
SafePtr: enhance mv ut
1 parent e6e5825 commit 182defb

File tree

3 files changed

+190
-52
lines changed

3 files changed

+190
-52
lines changed

src/log/UniBaseLog.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ using LogName = std::string;
3535
// . under single thread, can change cout back to oneLog() for smart log
3636
// - HID() is MT safe also upon UniSmartLog
3737
#if WITH_HID_LOG
38-
#define HID(content) { std::cout << "cout[" << mt_timestamp() << "/HID/" << std::this_thread::get_id() << "] " \
39-
<< BUF(content) << std::dec; }
38+
#define HID(content) { std::cout << "cout[" << rlib::mt_timestamp() << "/HID/" \
39+
<< std::this_thread::get_id() << "] " << BUF(content) << std::dec; }
4040
#else
4141
#define HID(content) {}
4242
#endif

src/safe_mem/SafePtr.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ SafePtr<T>::SafePtr(const SafePtr<From>& aSafeFrom) noexcept // cp
9292
: pT_(aSafeFrom.pT_) // faster than get()
9393
, realType_(pT_ ? aSafeFrom.realType_ : typeid(T)) // init list is faster
9494
, lastType_(pT_ ? aSafeFrom.template genLastType_<T>() : typeid(T)) // init list is faster
95-
{
96-
}
95+
{}
9796

9897
// ***********************************************************************************************
9998
// - safe mv (self/base/void), otherwise compile-err (by shared_ptr's mv which is safe)
@@ -112,6 +111,7 @@ SafePtr<T>::SafePtr(SafePtr<From>&& aSafeFrom) noexcept // mv - MtQ need
112111
}
113112

114113
// ***********************************************************************************************
114+
// - for safe_cast; constructor is faster; private is safe
115115
template<typename T>
116116
constexpr SafePtr<T>::SafePtr(std::shared_ptr<T>&& aPtr, const std::type_index& aReal, const std::type_index& aLast) noexcept
117117
: pT_(aPtr)
@@ -165,15 +165,17 @@ template<typename To>
165165
std::type_index SafePtr<T>::genLastType_() const noexcept
166166
{
167167
if constexpr(std::is_same_v<To, void>) { // compile opt
168-
HID("T->void, recursive T.lastType() is the most diff type before T");
168+
HID("T->void, recursive T.lastType_ is the most diff type before To=void");
169169
return lastType_; // eg Derive->Base->void = Base
170170
}
171171
else if (realType_ == typeid(To)) {
172172
HID("To->T->To, T.lastType is the most diff type");
173173
return lastType_; // eg Derive->Base->Derive = Base
174174
}
175-
else
175+
else {
176+
HID("most diff type=" << typeid(To).name());
176177
return typeid(To); // eg Derive->Base = Base
178+
}
177179
}
178180

179181

ut/safe_mem/SafePtrTest.cpp

Lines changed: 182 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
// ***********************************************************************************************
77
#include <gtest/gtest.h>
88
#include <map>
9-
#include <type_traits>
109
#include <typeindex>
1110
#include <unordered_map>
1211

@@ -39,11 +38,11 @@ TEST(SafePtrTest, GOLD_safeCreate_normal)
3938
TEST(SafePtrTest, GOLD_unsafeCreate_forbid)
4039
{
4140
// SafePtr<int> ptr(raw); // compile-err
42-
static_assert(!std::is_constructible<SafePtr<int>, int*>::value,
41+
static_assert(!is_constructible<SafePtr<int>, int*>::value,
4342
"REQ: forbid unsafe raw pointer construction");
4443

4544
// SafePtr<int> ptr(make_shared<int>()); // compile-err
46-
static_assert(!std::is_constructible<SafePtr<int>, std::shared_ptr<int>>::value,
45+
static_assert(!is_constructible<SafePtr<int>, shared_ptr<int>>::value,
4746
"REQ: forbid unsafe shared_ptr construction");
4847
}
4948
TEST(SafePtrTest, safeCreate_default)
@@ -169,32 +168,88 @@ TEST(SafePtrTest, GOLD_safeCp_toSameType)
169168
}
170169
TEST(SafePtrTest, GOLD_safeCp_toVoid)
171170
{
172-
auto b = make_safe<Base>();
173-
SafePtr<void> bv(b);
174-
EXPECT_EQ(0, safe_cast<Base>(bv)->value()) << "REQ: simple cp";
175-
EXPECT_EQ(2, bv.use_count()) << "REQ: shared ownership";
176-
177-
SafePtr<const void> cv(b);
178-
EXPECT_EQ(0, safe_cast<const Base>(cv)->value()) << "REQ: safe cp any->const void->const any";
171+
auto db = SafePtr<Base>(make_safe<Derive>());
172+
SafePtr<void> dbv(db);
173+
// check target
174+
EXPECT_EQ(1, safe_cast<Base>(dbv)->value ()) << "req: cp Derive->Base->void";
175+
EXPECT_EQ(type_index(typeid(Derive)), dbv.realType()) << "REQ: cp to target";
176+
EXPECT_EQ(type_index(typeid(Base )), dbv.lastType()) << "REQ: cp to target";
177+
// check src
178+
EXPECT_EQ(2, db.use_count()) << "REQ: cp is shared";
179+
EXPECT_EQ(1, safe_cast<Base>(db)->value ()) << "REQ: keep src after cp";
180+
EXPECT_EQ(type_index(typeid(Derive)), db.realType ()) << "REQ: keep src after cp";
181+
EXPECT_EQ(type_index(typeid(Base )), db.lastType ()) << "REQ: keep src after cp";
182+
183+
auto dbd = safe_cast<Derive>(db);
184+
SafePtr<void> dbdv(dbd);
185+
// check target
186+
EXPECT_EQ(1, safe_cast<Base>(dbdv)->value ()) << "req: cp Derive->Base->Derive->void";
187+
EXPECT_EQ(type_index(typeid(Derive)), dbdv.realType()) << "REQ: cp to target";
188+
EXPECT_EQ(type_index(typeid(Base )), dbdv.lastType()) << "REQ: cp to target";
189+
// check src
190+
EXPECT_EQ(4, dbd.use_count()) << "REQ: cp is shared";
191+
EXPECT_EQ(1, safe_cast<Base>(dbd)->value ()) << "REQ: keep src after cp";
192+
EXPECT_EQ(type_index(typeid(Derive)), dbd.realType ()) << "REQ: keep src after cp";
193+
EXPECT_EQ(type_index(typeid(Base )), dbd.lastType ()) << "REQ: keep src after cp";
179194
}
180195
TEST(SafePtrTest, GOLD_safeCp_toPolyBase)
181196
{
182197
auto d = make_safe<Derive>();
183-
EXPECT_EQ(1, SafePtr< Base>(d)->value()) << "REQ: cp to Base";
184-
EXPECT_EQ(1, SafePtr<const Base>(d)->value()) << "REQ: cp to const Base";
198+
SafePtr<Base> db(d);
199+
// check target
200+
EXPECT_EQ(1, db->value ()) << "REQ: cp to Base";
201+
EXPECT_EQ(type_index(typeid(Derive)), db.realType()) << "REQ: cp to Base";
202+
EXPECT_EQ(type_index(typeid(Base )), db.lastType()) << "REQ: keep diff";
203+
// check src
204+
EXPECT_EQ(2, d.use_count()) << "REQ: cp is shared";
205+
EXPECT_EQ(1, d->value ()) << "REQ: keep src after cp";
206+
EXPECT_EQ(type_index(typeid(Derive)), d.realType ()) << "REQ: keep src after cp";
207+
EXPECT_EQ(type_index(typeid(Derive)), d.lastType ()) << "REQ: keep src after cp";
208+
209+
SafePtr<const Base> dbc(d);
210+
// check target
211+
EXPECT_EQ(1, dbc->value ()) << "REQ: cp to const Base";
212+
EXPECT_EQ(type_index(typeid(Derive)), dbc.realType()) << "REQ: cp to const Base";
213+
EXPECT_EQ(type_index(typeid(const Base)), dbc.lastType()) << "REQ: keep diff";
214+
// check src
215+
EXPECT_EQ(3, d.use_count()) << "REQ: cp is shared";
216+
EXPECT_EQ(1, d->value ()) << "REQ: keep src after cp";
217+
EXPECT_EQ(type_index(typeid(Derive)), d.realType ()) << "req: keep src after cp";
218+
EXPECT_EQ(type_index(typeid(Derive)), d.lastType ()) << "req: keep src after cp";
185219
}
186220
struct BS { int i = 10; };
187-
struct DS : public BS { DS() { i = 11; } };
221+
struct DS : public BS { DS() { i = 20; } };
188222
TEST(SafePtrTest, safeCp_toStaticBase)
189223
{
190224
auto d = make_safe<DS>();
191-
EXPECT_EQ(11, SafePtr< BS>(d)->i) << "REQ: cp to static Base";
192-
EXPECT_EQ(11, SafePtr<const BS>(d)->i) << "REQ: cp to const static Base";
225+
SafePtr<BS> db(d);
226+
// check target
227+
EXPECT_EQ(20, db->i ) << "REQ: cp to static Base";
228+
EXPECT_EQ(type_index(typeid(DS)), db.realType()) << "REQ: cp to static Base";
229+
EXPECT_EQ(type_index(typeid(BS)), db.lastType()) << "REQ: diff";
230+
// check src
231+
EXPECT_EQ(2, d.use_count()) << "REQ: cp is shared";
232+
EXPECT_EQ(20, d->i ) << "REQ: access same member";
233+
EXPECT_EQ(type_index(typeid(DS)), d.realType ()) << "req: keep src after cp";
234+
EXPECT_EQ(type_index(typeid(DS)), d.lastType ()) << "req: keep src after cp";
235+
SafePtr<const BS> dbc(db);
236+
EXPECT_EQ(20, dbc->i ) << "REQ: cp to const static Base";
237+
EXPECT_EQ(3, dbc.use_count()) << "REQ: share";
238+
}
239+
TEST(SafePtrTest, safeCp_nullptr)
240+
{
241+
auto d = SafePtr<Derive>();
242+
SafePtr<void> dv(d);
243+
EXPECT_EQ(nullptr, dv.get());
244+
EXPECT_EQ(type_index(typeid(void)), dv.realType()) << "REQ: cp nullptr as if cp fail, avoid confuse usr";
245+
EXPECT_EQ(type_index(typeid(void)), dv.lastType()) << "REQ: cp nullptr as if cp fail, avoid confuse usr";
246+
EXPECT_EQ(0, dv.use_count()) << "REQ: none";
247+
EXPECT_EQ(0, d .use_count()) << "REQ: none";
193248
}
194249
TEST(SafePtrTest, unsafeCp_toDiffType)
195250
{
196251
auto i = make_safe<int>(7);
197-
//SafePtr<char>(i); // REQ: compile err for diff types
252+
//auto c = SafePtr<char>(i); // REQ: compile err for diff types
198253
}
199254
struct D_private : private Base {};
200255
struct D_protected : protected Base {};
@@ -223,44 +278,125 @@ TEST(SafePtrTest, unssafeCp_constToNon)
223278
auto bc = make_safe<const Base>();
224279
//auto b = SafePtr<Base>(bc); // REQ: unsafe cp, compile err
225280
}
226-
TEST(SafePtrTest, invalidCp_compileErr) // cp's compile-err is safer than safe_cast that may ret nullptr
227-
{
228-
//auto dv = SafePtr<void>(d);
229-
//SafePtr<Derive>(dv); // bld err; safe but unsupport
230-
231-
//SafePtr<Derive>(SafePtr<void>(make_safe<Derive>())); // void->origin: cp compile err, can safe_cast instead
232-
//SafePtr<Base >(SafePtr<void>(make_safe<Derive>())); // Derive->void->Base: cp compile err, safe_cast ret nullptr
233-
234-
// SafePtr<D> safe_dd = safe_const_d; // REQ: compile err to cp from const to non
235-
// shared_ptr<D> share_dd = share_const_d; // REQ: compile err to cp from const to non
236-
}
237281

238282
#define MOVE
239283
// ***********************************************************************************************
240-
TEST(SafePtrTest, GOLD_mtQ_req_mv)
284+
TEST(SafePtrTest, GOLD_safeMv_toSameType)
241285
{
242-
auto msg = SafePtr<Base>(make_safe<Derive>()); // Derive->Base
243-
SafePtr<void> msgInQ = move(msg);
244-
EXPECT_EQ(nullptr, msg.get()) << "REQ: src giveup";
245-
EXPECT_EQ(type_index(typeid(Base)), msg.realType()) << "REQ: reset src all";
246-
EXPECT_EQ(type_index(typeid(Base)), msg.lastType()) << "REQ: reset src all";
286+
auto i = make_safe<int>(42);
287+
SafePtr<int> i2(move(i));
288+
EXPECT_EQ(42, *i2.get()) << "REQ: mv to self";
289+
EXPECT_EQ(1, i2.use_count()) << "REQ: mv ownership";
290+
EXPECT_EQ(nullptr, i.get()) << "REQ: source is empty after move";
247291

248-
EXPECT_EQ(1 , safe_cast<Base>(msgInQ)->value() ) << "REQ: takeover msg";
249-
EXPECT_EQ(type_index(typeid(Derive)), safe_cast<Base>(msgInQ).realType()) << "REQ: reset src all";
250-
EXPECT_EQ(type_index(typeid(Base )), safe_cast<Base>(msgInQ).lastType()) << "REQ: reset src all";
292+
auto a = make_safe<A>();
293+
SafePtr<const A> ac(move(a));
294+
EXPECT_EQ(0, ac->value()) << "REQ: mv to const";
295+
EXPECT_EQ(nullptr, a.get()) << "REQ: source is empty after mv";
251296
}
252-
TEST(SafePtrTest, nothing_cp_mv_assign)
297+
TEST(SafePtrTest, GOLD_safeMv_toVoid)
253298
{
254-
SafePtr<Base> cp = SafePtr<Derive>(); // cp nullptr
255-
EXPECT_EQ(type_index(typeid(Base)), cp.realType()) << "REQ/cov: cp-nothing=fail so origin is Base instead of Derive";
256-
257-
SafePtr<Base> mv = move(SafePtr<Derive>()); // mv nullptr
258-
EXPECT_EQ(type_index(typeid(Base)), mv.realType()) << "REQ/cov: mv-nothing=fail so origin is Base instead of Derive";
299+
auto db = SafePtr<Base>(make_safe<Derive>());
300+
SafePtr<void> dbv(move(db));
301+
// check target
302+
EXPECT_EQ(1, safe_cast<Base>(dbv)->value ()) << "req: mv Derive->Base->void";
303+
EXPECT_EQ(type_index(typeid(Derive)), dbv.realType()) << "REQ: mv to target";
304+
EXPECT_EQ(type_index(typeid(Base )), dbv.lastType()) << "REQ: mv to target";
305+
// check src
306+
EXPECT_EQ(nullptr, db.get ()) << "REQ: reset src after mv";
307+
EXPECT_EQ(type_index(typeid(Base)), db.realType()) << "REQ: reset src after mv";
308+
EXPECT_EQ(type_index(typeid(Base)), db.lastType()) << "REQ: reset src after mv";
309+
310+
auto dbd = safe_cast<Derive>(SafePtr<Base>(make_safe<Derive>()));
311+
SafePtr<void> dbdv(move(dbd));
312+
// check target
313+
EXPECT_EQ(1, safe_cast<Base>(dbdv)->value ()) << "req: mv Derive->Base->Derive->void";
314+
EXPECT_EQ(type_index(typeid(Derive)), dbdv.realType()) << "REQ: mv to target";
315+
EXPECT_EQ(type_index(typeid(Base )), dbdv.lastType()) << "REQ: mv to target";
316+
// check src
317+
EXPECT_EQ(nullptr, dbd.get ()) << "REQ: reset src after mv";
318+
EXPECT_EQ(type_index(typeid(Derive)), dbd.realType()) << "REQ: reset src after mv";
319+
EXPECT_EQ(type_index(typeid(Derive)), dbd.lastType()) << "REQ: reset src after mv";
320+
}
321+
TEST(SafePtrTest, GOLD_safeMv_toPolyBase)
322+
{
323+
auto d = make_safe<Derive>();
324+
SafePtr<Base> db(move(d));
325+
// check target
326+
EXPECT_EQ(1, SafePtr<Base>(db)->value ()) << "REQ: mv to Base";
327+
EXPECT_EQ(type_index(typeid(Derive)), db.realType()) << "REQ: mv to Base";
328+
EXPECT_EQ(type_index(typeid(Base )), db.lastType()) << "REQ: keep diff";
329+
// check src
330+
EXPECT_EQ(nullptr, d.get ()) << "REQ: reset src after mv";
331+
EXPECT_EQ(type_index(typeid(Derive)), d.realType()) << "REQ: reset src after mv";
332+
EXPECT_EQ(type_index(typeid(Derive)), d.lastType()) << "REQ: reset src after mv";
333+
334+
SafePtr<const Base> dbc(move(db));
335+
// check target
336+
EXPECT_EQ(1, dbc->value ()) << "REQ: mv to const Base";
337+
EXPECT_EQ(type_index(typeid(Derive )), dbc.realType()) << "REQ: mv to const Base";
338+
EXPECT_EQ(type_index(typeid(const Base)), dbc.lastType()) << "REQ: keep diff";
339+
// check src
340+
EXPECT_EQ(nullptr, db.get ()) << "req: reset src after mv";
341+
EXPECT_EQ(type_index(typeid(Base)), db.realType()) << "REQ: reset src after mv";
342+
EXPECT_EQ(type_index(typeid(Base)), db.lastType()) << "REQ: reset src after mv";
343+
}
344+
TEST(SafePtrTest, safeMv_toStaticBase)
345+
{
346+
auto d = make_safe<DS>();
347+
SafePtr<BS> db(move(d));
348+
// check target
349+
EXPECT_EQ(20, db->i ) << "REQ: mv to static Base";
350+
EXPECT_EQ(type_index(typeid(DS)), db.realType()) << "REQ: mv to static Base";
351+
EXPECT_EQ(type_index(typeid(BS)), db.lastType()) << "REQ: diff";
352+
// check src
353+
EXPECT_EQ(nullptr, d.get ()) << "REQ: reset src after mv";
354+
EXPECT_EQ(type_index(typeid(DS)), d.realType()) << "req: reset src after mv";
355+
EXPECT_EQ(type_index(typeid(DS)), d.lastType()) << "req: reset src after mv";
356+
357+
SafePtr<const BS> dbc(move(db));
358+
EXPECT_EQ(20, dbc->i ) << "REQ: mv to const static Base";
359+
EXPECT_EQ(1, dbc.use_count()) << "REQ: mv ownership";
360+
}
361+
TEST(SafePtrTest, safeMv_nullptr)
362+
{
363+
auto d = SafePtr<Derive>();
364+
SafePtr<void> dv(move(d));
365+
EXPECT_EQ(nullptr, dv.get());
366+
EXPECT_EQ(type_index(typeid(void)), dv.realType ()) << "REQ: mv nullptr as if mv fail, avoid confuse usr";
367+
EXPECT_EQ(type_index(typeid(void)), dv.lastType ()) << "REQ: mv nullptr as if mv fail, avoid confuse usr";
368+
EXPECT_EQ(0, dv.use_count()) << "REQ: none";
369+
EXPECT_EQ(0, d .use_count()) << "REQ: none";
370+
}
371+
TEST(SafePtrTest, unsafeMv_toDiffType)
372+
{
373+
auto i = make_safe<int>(7);
374+
//auto c = SafePtr<char>(move(i)); // REQ: compile err for diff types
375+
}
376+
TEST(SafePtrTest, unsupportMv_toBase)
377+
{
378+
auto b_pri = make_safe<D_private >();
379+
//auto b = SafePtr<Base>(move(b_pri)); // c++ not allow
380+
auto b_pro = make_safe<D_protected>();
381+
//auto b = SafePtr<Base>(move(b_pro)); // c++ not allow
382+
}
383+
TEST(SafePtrTest, unsupportMv_toDerive)
384+
{
385+
auto b = make_safe<Base>();
386+
//auto bd = SafePtr<Derive>(move(b)); // REQ: compile err Base->Derive - unsafe
259387

260-
SafePtr<Base> as;
261-
EXPECT_EQ(type_index(typeid(Base)), mv.realType());
262-
as = SafePtr<Derive>();
263-
EXPECT_EQ(type_index(typeid(Base)), mv.realType()) << "REQ/cov: assign-nothing=fail so keep origin";
388+
auto db = SafePtr<Base>(make_safe<Derive>());
389+
//auto dbd = SafePtr<Derive>(move(db)); // safe but unsupport since need dynamic_cast that can't bld err if fail
390+
}
391+
TEST(SafePtrTest, unsupportMv_voidToNon)
392+
{
393+
auto bv = SafePtr<void>(make_safe<Base>());
394+
//auto bvb = SafePtr<Base>(move(bv)); // safe but unsupport since need dynamic check that can't bld err if fail
395+
}
396+
TEST(SafePtrTest, unssafeMv_constToNon)
397+
{
398+
auto bc = make_safe<const Base>();
399+
//auto b = SafePtr<Base>(move(bc)); // REQ: unsafe cp, compile err
264400
}
265401

266402
#define ASSIGN

0 commit comments

Comments
 (0)