Skip to content

Commit

Permalink
Merge pull request capnproto#747 from capnproto/overload-operatoreq
Browse files Browse the repository at this point in the history
Overload Maybe::operator=() to match all copy constructors.
  • Loading branch information
kentonv authored Sep 27, 2018
2 parents a00ccd9 + f693e2e commit 9f31cd4
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 19 deletions.
32 changes: 32 additions & 0 deletions c++/src/kj/common-test.c++
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ struct ImplicitToInt {
}
};

struct Immovable {
Immovable() = default;
KJ_DISALLOW_COPY(Immovable);
};

TEST(Common, Maybe) {
{
Maybe<int> m = 123;
Expand All @@ -63,6 +68,23 @@ TEST(Common, Maybe) {
EXPECT_EQ(123, m.orDefault(456));
}

{
Maybe<int> m = 0;
EXPECT_FALSE(m == nullptr);
EXPECT_TRUE(m != nullptr);
KJ_IF_MAYBE(v, m) {
EXPECT_EQ(0, *v);
} else {
ADD_FAILURE();
}
KJ_IF_MAYBE(v, mv(m)) {
EXPECT_EQ(0, *v);
} else {
ADD_FAILURE();
}
EXPECT_EQ(0, m.orDefault(456));
}

{
Maybe<int> m = nullptr;
EXPECT_TRUE(m == nullptr);
Expand Down Expand Up @@ -216,6 +238,16 @@ TEST(Common, Maybe) {
ADD_FAILURE();
}
}

{
// Test usage of immovable types.
Maybe<Immovable> m;
KJ_EXPECT(m == nullptr);
m.emplace();
KJ_EXPECT(m != nullptr);
m = nullptr;
KJ_EXPECT(m == nullptr);
}
}

TEST(Common, MaybeConstness) {
Expand Down
110 changes: 91 additions & 19 deletions c++/src/kj/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ class NullableValue {
// boolean flag indicating nullness.

public:
inline NullableValue(NullableValue&& other) noexcept(noexcept(T(instance<T&&>())))
inline NullableValue(NullableValue&& other)
: isSet(other.isSet) {
if (isSet) {
ctor(value, kj::mv(other.value));
Expand Down Expand Up @@ -922,8 +922,8 @@ class NullableValue {
return value;
}

inline NullableValue() noexcept: isSet(false) {}
inline NullableValue(T&& t) noexcept(noexcept(T(instance<T&&>())))
inline NullableValue(): isSet(false) {}
inline NullableValue(T&& t)
: isSet(true) {
ctor(value, kj::mv(t));
}
Expand All @@ -940,7 +940,7 @@ class NullableValue {
if (isSet) ctor(value, *t);
}
template <typename U>
inline NullableValue(NullableValue<U>&& other) noexcept(noexcept(T(instance<U&&>())))
inline NullableValue(NullableValue<U>&& other)
: isSet(other.isSet) {
if (isSet) {
ctor(value, kj::mv(other.value));
Expand Down Expand Up @@ -1007,6 +1007,52 @@ class NullableValue {
return *this;
}

inline NullableValue& operator=(T&& other) { emplace(kj::mv(other)); return *this; }
inline NullableValue& operator=(T& other) { emplace(other); return *this; }
inline NullableValue& operator=(const T& other) { emplace(other); return *this; }
inline NullableValue& operator=(const T* other) {
if (other == nullptr) {
*this = nullptr;
} else {
emplace(*other);
}
return *this;
}
template <typename U>
inline NullableValue& operator=(NullableValue<U>&& other) {
if (other.isSet) {
emplace(kj::mv(other.value));
} else {
*this = nullptr;
}
return *this;
}
template <typename U>
inline NullableValue& operator=(const NullableValue<U>& other) {
if (other.isSet) {
emplace(other.value);
} else {
*this = nullptr;
}
return *this;
}
template <typename U>
inline NullableValue& operator=(const NullableValue<U&>& other) {
if (other.isSet) {
emplace(other.value);
} else {
*this = nullptr;
}
return *this;
}
inline NullableValue& operator=(decltype(nullptr)) {
if (isSet) {
isSet = false;
dtor(value);
}
return *this;
}

inline bool operator==(decltype(nullptr)) const { return !isSet; }
inline bool operator!=(decltype(nullptr)) const { return isSet; }

Expand Down Expand Up @@ -1060,16 +1106,16 @@ class Maybe {

public:
Maybe(): ptr(nullptr) {}
Maybe(T&& t) noexcept(noexcept(T(instance<T&&>()))): ptr(kj::mv(t)) {}
Maybe(T&& t): ptr(kj::mv(t)) {}
Maybe(T& t): ptr(t) {}
Maybe(const T& t): ptr(t) {}
Maybe(const T* t) noexcept: ptr(t) {}
Maybe(Maybe&& other) noexcept(noexcept(T(instance<T&&>()))): ptr(kj::mv(other.ptr)) {}
Maybe(const T* t): ptr(t) {}
Maybe(Maybe&& other): ptr(kj::mv(other.ptr)) {}
Maybe(const Maybe& other): ptr(other.ptr) {}
Maybe(Maybe& other): ptr(other.ptr) {}

template <typename U>
Maybe(Maybe<U>&& other) noexcept(noexcept(T(instance<U&&>()))) {
Maybe(Maybe<U>&& other) {
KJ_IF_MAYBE(val, kj::mv(other)) {
ptr.emplace(kj::mv(*val));
}
Expand All @@ -1081,7 +1127,7 @@ class Maybe {
}
}

Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {}
Maybe(decltype(nullptr)): ptr(nullptr) {}

template <typename... Params>
inline T& emplace(Params&&... params) {
Expand All @@ -1092,10 +1138,36 @@ class Maybe {
return ptr.emplace(kj::fwd<Params>(params)...);
}

inline Maybe& operator=(T&& other) { ptr = kj::mv(other); return *this; }
inline Maybe& operator=(T& other) { ptr = other; return *this; }
inline Maybe& operator=(const T& other) { ptr = other; return *this; }
inline Maybe& operator=(const T* other) { ptr = other; return *this; }

inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; }
inline Maybe& operator=(Maybe& other) { ptr = other.ptr; return *this; }
inline Maybe& operator=(const Maybe& other) { ptr = other.ptr; return *this; }

template <typename U>
Maybe& operator=(Maybe<U>&& other) {
KJ_IF_MAYBE(val, kj::mv(other)) {
ptr.emplace(kj::mv(*val));
} else {
ptr = nullptr;
}
return *this;
}
template <typename U>
Maybe& operator=(const Maybe<U>& other) {
KJ_IF_MAYBE(val, other) {
ptr.emplace(*val);
} else {
ptr = nullptr;
}
return *this;
}

inline Maybe& operator=(decltype(nullptr)) { ptr = nullptr; return *this; }

inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; }
inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; }

Expand Down Expand Up @@ -1180,22 +1252,22 @@ class Maybe {
template <typename T>
class Maybe<T&>: public DisallowConstCopyIfNotConst<T> {
public:
Maybe() noexcept: ptr(nullptr) {}
Maybe(T& t) noexcept: ptr(&t) {}
Maybe(T* t) noexcept: ptr(t) {}
Maybe(): ptr(nullptr) {}
Maybe(T& t): ptr(&t) {}
Maybe(T* t): ptr(t) {}

template <typename U>
inline Maybe(Maybe<U&>& other) noexcept: ptr(other.ptr) {}
inline Maybe(Maybe<U&>& other): ptr(other.ptr) {}
template <typename U>
inline Maybe(const Maybe<U&>& other) noexcept: ptr(const_cast<const U*>(other.ptr)) {}
inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {}
inline Maybe(const Maybe<U&>& other): ptr(const_cast<const U*>(other.ptr)) {}
inline Maybe(decltype(nullptr)): ptr(nullptr) {}

inline Maybe& operator=(T& other) noexcept { ptr = &other; return *this; }
inline Maybe& operator=(T* other) noexcept { ptr = other; return *this; }
inline Maybe& operator=(T& other) { ptr = &other; return *this; }
inline Maybe& operator=(T* other) { ptr = other; return *this; }
template <typename U>
inline Maybe& operator=(Maybe<U&>& other) noexcept { ptr = other.ptr; return *this; }
inline Maybe& operator=(Maybe<U&>& other) { ptr = other.ptr; return *this; }
template <typename U>
inline Maybe& operator=(const Maybe<const U&>& other) noexcept { ptr = other.ptr; return *this; }
inline Maybe& operator=(const Maybe<const U&>& other) { ptr = other.ptr; return *this; }

inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; }
inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; }
Expand Down

0 comments on commit 9f31cd4

Please sign in to comment.