From 3d52feadb4282053fbfc5b3d1dbe00f1c8ad7815 Mon Sep 17 00:00:00 2001 From: Martin Nowack Date: Wed, 3 Apr 2019 16:02:43 +0100 Subject: Add move assignment operator and move construct for `ref` class. --- include/klee/util/Ref.h | 37 +++++++++++++++++++ unittests/Ref/RefTest.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/include/klee/util/Ref.h b/include/klee/util/Ref.h index f6d66d16..4dafdf8e 100644 --- a/include/klee/util/Ref.h +++ b/include/klee/util/Ref.h @@ -123,6 +123,14 @@ public: inc(); } + // normal move constructor: invoke the move assignment operator + ref(ref &&r) noexcept : ptr(nullptr) { *this = std::move(r); } + + // conversion move constructors: invoke the move assignment operator + template ref(ref &&r) noexcept : ptr(nullptr) { + *this = std::move(r); + } + // pointer operations T *get () const { return ptr; @@ -171,6 +179,35 @@ public: return *this; } + // Move assignment operator + ref &operator=(ref &&r) noexcept { + if (this == &r) + return *this; + dec(); + ptr = r.ptr; + r.ptr = nullptr; + return *this; + } + + // Move assignment operator + template ref &operator=(ref &&r) noexcept { + if (static_cast(this) == static_cast(&r)) + return *this; + + // Do not swap as the types might be not compatible + // Decrement local counter to not hold reference anymore + dec(); + + // Assign to this ref + ptr = cast_or_null(r.ptr); + + // Invalidate old ptr + r.ptr = nullptr; + + // Return this pointer + return *this; + } + T& operator*() const { return *ptr; } diff --git a/unittests/Ref/RefTest.cpp b/unittests/Ref/RefTest.cpp index 3548da85..066ecc58 100644 --- a/unittests/Ref/RefTest.cpp +++ b/unittests/Ref/RefTest.cpp @@ -46,6 +46,32 @@ struct SelfRefExpr { ~SelfRefExpr() { finished_counter++; } }; +struct ParentExpr { + /// @brief Required by klee::ref-managed objects + class klee::ReferenceCounter _refCount; + + enum ExprKind { + EK_Parent, + EK_Child, + }; + + const ExprKind Kind; + ExprKind getKind() const { return Kind; } + + ParentExpr(ExprKind K) : Kind(K) {} + + virtual ~ParentExpr() { + EXPECT_EQ(finished, 1); + finished_counter++; + } +}; + +struct ChildExpr : public ParentExpr { + ChildExpr() : ParentExpr(EK_Child) {} + + static bool classof(const ParentExpr *S) { return S->getKind() == EK_Child; } +}; + TEST(RefTest, SelfAssign) { finished = 0; finished_counter = 0; @@ -61,6 +87,72 @@ TEST(RefTest, SelfAssign) { EXPECT_EQ(1, finished_counter); } +TEST(RefTest, SelfMove) { + finished = 0; + finished_counter = 0; + { + struct Expr *r_e = new Expr(); + ref r(r_e); + + // Check self move + r = std::move(r); + finished = 1; + } + EXPECT_EQ(1, finished_counter); +} + +TEST(RefTest, MoveAssignment) { + finished = 0; + finished_counter = 0; + { + struct Expr *r_e = new Expr(); + ref r(r_e); + + struct Expr *q_e = new Expr(); + ref q(q_e); + + finished = 1; + + // Move the object + q = std::move(r); + + // Re-assign new object + r = new Expr(); + } + EXPECT_EQ(3, finished_counter); +} + +TEST(RefTest, MoveCastingAssignment) { + finished = 0; + finished_counter = 0; + { + ref r(new ChildExpr()); + + struct ChildExpr *child = new ChildExpr(); + ref ce(child); + + finished = 1; + + // Move the object + r = std::move(child); + } + EXPECT_EQ(2, finished_counter); +} + +TEST(RefTest, MoveConstructor) { + finished = 0; + finished_counter = 0; + { + struct Expr *r_e = new Expr(); + ref r(r_e); + + ref q(std::move(r_e)); + + finished = 1; + } + EXPECT_EQ(1, finished_counter); +} + TEST(RefTest, SelfRef) { struct SelfRefExpr *e_1 = new SelfRefExpr(nullptr); ref r_e_1(e_1); -- cgit 1.4.1