-
-
Save anonymous/c166c14e0bdb9f02aa08 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
/* This Source Code Form is subject to the terms of the Mozilla Public | |
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | |
* You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
#include "mozilla/Assertions.h" | |
#include "mozilla/Attributes.h" | |
#include "mozilla/Maybe.h" | |
#include "mozilla/Move.h" | |
#include "mozilla/TypeTraits.h" | |
#include "mozilla/UniquePtr.h" | |
using mozilla::IsSame; | |
using mozilla::Maybe; | |
using mozilla::Move; | |
using mozilla::Nothing; | |
using mozilla::Some; | |
using mozilla::Swap; | |
using mozilla::UniquePtr; | |
#define CHECK(c) \ | |
do { \ | |
bool cond = (c); \ | |
MOZ_ASSERT(cond, "Failed assertion: " #c); \ | |
if (!cond) \ | |
return false; \ | |
} while (false) | |
enum Status | |
{ | |
eWasDefaultConstructed, | |
eWasConstructed, | |
eWasCopyConstructed, | |
eWasMoveConstructed, | |
eWasCopyAssigned, | |
eWasMoveAssigned, | |
eWasCopiedFrom, | |
eWasMovedFrom | |
}; | |
struct BasicValue | |
{ | |
BasicValue() : mStatus(eWasDefaultConstructed) { } | |
explicit BasicValue(int) : mStatus(eWasConstructed) { } | |
BasicValue(const BasicValue& aOther) | |
: mStatus(eWasCopyConstructed) | |
{ | |
const_cast<BasicValue&>(aOther).mStatus = eWasCopiedFrom; | |
} | |
BasicValue(BasicValue&& aOther) | |
: mStatus(eWasMoveConstructed) | |
{ | |
aOther.mStatus = eWasMovedFrom; | |
} | |
BasicValue& operator=(const BasicValue& aOther) | |
{ | |
mStatus = eWasCopyAssigned; | |
const_cast<BasicValue&>(aOther).mStatus = eWasCopiedFrom; | |
return *this; | |
} | |
BasicValue& operator=(BasicValue&& aOther) | |
{ | |
mStatus = eWasMoveAssigned; | |
aOther.mStatus = eWasMovedFrom; | |
return *this; | |
} | |
bool operator==(const BasicValue& aOther) const | |
{ | |
return aOther.mStatus == mStatus; | |
} | |
Status GetStatus() const { return mStatus; } | |
private: | |
Status mStatus; | |
}; | |
struct UncopyableValue | |
{ | |
UncopyableValue() : mStatus(eWasDefaultConstructed) { } | |
explicit UncopyableValue(int) : mStatus(eWasConstructed) { } | |
UncopyableValue(UncopyableValue&& aOther) | |
: mStatus(eWasMoveConstructed) | |
{ | |
aOther.mStatus = eWasMovedFrom; | |
} | |
UncopyableValue& operator=(UncopyableValue&& aOther) | |
{ | |
mStatus = eWasMoveAssigned; | |
aOther.mStatus = eWasMovedFrom; | |
return *this; | |
} | |
bool operator==(const UncopyableValue& aOther) const | |
{ | |
return aOther.mStatus == mStatus; | |
} | |
Status GetStatus() { return mStatus; } | |
private: | |
UncopyableValue(const UncopyableValue& aOther); | |
UncopyableValue& operator=(const UncopyableValue& aOther); | |
Status mStatus; | |
}; | |
struct UnmovableValue | |
{ | |
UnmovableValue() : mStatus(eWasDefaultConstructed) { } | |
explicit UnmovableValue(int) : mStatus(eWasConstructed) { } | |
UnmovableValue(const UnmovableValue& aOther) | |
: mStatus(eWasCopyConstructed) | |
{ | |
const_cast<UnmovableValue&>(aOther).mStatus = eWasCopiedFrom; | |
} | |
UnmovableValue& operator=(const UnmovableValue& aOther) | |
{ | |
mStatus = eWasCopyAssigned; | |
const_cast<UnmovableValue&>(aOther).mStatus = eWasCopiedFrom; | |
return *this; | |
} | |
bool operator==(const UnmovableValue& aOther) const | |
{ | |
return aOther.mStatus == mStatus; | |
} | |
Status GetStatus() { return mStatus; } | |
private: | |
UnmovableValue(UnmovableValue&& aOther); | |
UnmovableValue& operator=(UnmovableValue&& aOther); | |
Status mStatus; | |
}; | |
struct UncopyableUnmovableValue | |
{ | |
UncopyableUnmovableValue() : mStatus(eWasDefaultConstructed) { } | |
explicit UncopyableUnmovableValue(int) : mStatus(eWasConstructed) { } | |
bool operator==(const UncopyableUnmovableValue& aOther) const | |
{ | |
return aOther.mStatus == mStatus; | |
} | |
Status GetStatus() { return mStatus; } | |
private: | |
UncopyableUnmovableValue(const UncopyableUnmovableValue& aOther); | |
UncopyableUnmovableValue& operator=(const UncopyableUnmovableValue& aOther); | |
UncopyableUnmovableValue(UncopyableUnmovableValue&& aOther); | |
UncopyableUnmovableValue& operator=(UncopyableUnmovableValue&& aOther); | |
Status mStatus; | |
}; | |
static bool | |
TestBasicFeatures() | |
{ | |
// Check that a Maybe<T> is initialized to Nothing. | |
Maybe<BasicValue> mayBasicValue; | |
static_assert(IsSame<BasicValue, decltype(mayBasicValue)::ValueType>::value, | |
"Should have BasicValue ValueType"); | |
CHECK(!mayBasicValue); | |
CHECK(!mayBasicValue.isSome()); | |
CHECK(mayBasicValue.isNothing()); | |
// Check that emplace() default constructs and the accessors work. | |
mayBasicValue.emplace(); | |
CHECK(mayBasicValue); | |
CHECK(mayBasicValue.isSome()); | |
CHECK(!mayBasicValue.isNothing()); | |
CHECK(*mayBasicValue == BasicValue()); | |
CHECK(mayBasicValue.value() == BasicValue()); | |
static_assert(IsSame<BasicValue, decltype(mayBasicValue.value())>::value, | |
"value() should return a BasicValue"); | |
CHECK(mayBasicValue.ref() == BasicValue()); | |
static_assert(IsSame<BasicValue&, decltype(mayBasicValue.ref())>::value, | |
"ref() should return a BasicValue&"); | |
CHECK(mayBasicValue.ptr() != nullptr); | |
static_assert(IsSame<BasicValue*, decltype(mayBasicValue.ptr())>::value, | |
"ptr() should return a BasicValue*"); | |
CHECK(mayBasicValue->GetStatus() == eWasDefaultConstructed); | |
// Check that reset() works. | |
mayBasicValue.reset(); | |
CHECK(!mayBasicValue); | |
CHECK(!mayBasicValue.isSome()); | |
CHECK(mayBasicValue.isNothing()); | |
// Check that emplace(T1) calls the correct constructor. | |
mayBasicValue.emplace(0); | |
CHECK(mayBasicValue); | |
CHECK(mayBasicValue->GetStatus() == eWasConstructed); | |
mayBasicValue.reset(); | |
CHECK(!mayBasicValue); | |
// Check that the accessors work through a const ref. | |
mayBasicValue.emplace(); | |
const Maybe<BasicValue>& mayBasicValueCRef = mayBasicValue; | |
CHECK(mayBasicValueCRef); | |
CHECK(mayBasicValueCRef.isSome()); | |
CHECK(!mayBasicValueCRef.isNothing()); | |
CHECK(*mayBasicValueCRef == BasicValue()); | |
CHECK(mayBasicValueCRef.value() == BasicValue()); | |
static_assert(IsSame<BasicValue, decltype(mayBasicValueCRef.value())>::value, | |
"value() should return a BasicValue"); | |
CHECK(mayBasicValueCRef.ref() == BasicValue()); | |
static_assert(IsSame<const BasicValue&, | |
decltype(mayBasicValueCRef.ref())>::value, | |
"ref() should return a const BasicValue&"); | |
CHECK(mayBasicValueCRef.ptr() != nullptr); | |
static_assert(IsSame<const BasicValue*, | |
decltype(mayBasicValueCRef.ptr())>::value, | |
"ptr() should return a const BasicValue*"); | |
CHECK(mayBasicValueCRef->GetStatus() == eWasDefaultConstructed); | |
mayBasicValue.reset(); | |
return true; | |
} | |
static bool | |
TestCopyAndMove() | |
{ | |
// Check that we get moves when possible for types that can support both moves | |
// and copies. | |
Maybe<BasicValue> mayBasicValue = Some(BasicValue()); | |
CHECK(mayBasicValue->GetStatus() == eWasMoveConstructed); | |
mayBasicValue = Some(BasicValue()); | |
CHECK(mayBasicValue->GetStatus() == eWasMoveAssigned); | |
mayBasicValue.reset(); | |
mayBasicValue.emplace(BasicValue()); | |
CHECK(mayBasicValue->GetStatus() == eWasMoveConstructed); | |
// Check that we get copies when moves aren't possible. | |
Maybe<BasicValue> mayBasicValue2 = Some(*mayBasicValue); | |
CHECK(mayBasicValue2->GetStatus() == eWasCopyConstructed); | |
mayBasicValue2 = mayBasicValue; | |
CHECK(mayBasicValue2->GetStatus() == eWasCopyAssigned); | |
mayBasicValue2.reset(); | |
mayBasicValue2.emplace(*mayBasicValue); | |
CHECK(mayBasicValue2->GetStatus() == eWasCopyConstructed); | |
// Check that Move() works. (Another sanity check for move support.) | |
Maybe<BasicValue> mayBasicValue3 = Some(Move(*mayBasicValue)); | |
CHECK(mayBasicValue3->GetStatus() == eWasMoveConstructed); | |
CHECK(mayBasicValue->GetStatus() == eWasMovedFrom); | |
mayBasicValue3 = Some(Move(*mayBasicValue2)); | |
CHECK(mayBasicValue3->GetStatus() == eWasMoveAssigned); | |
CHECK(mayBasicValue2->GetStatus() == eWasMovedFrom); | |
Maybe<BasicValue> mayBasicValue4; | |
mayBasicValue4.emplace(Move(*mayBasicValue3)); | |
CHECK(mayBasicValue4->GetStatus() == eWasMoveConstructed); | |
CHECK(mayBasicValue3->GetStatus() == eWasMovedFrom); | |
// Check that we always get copies for types that don't support moves. | |
Maybe<UnmovableValue> mayUnmovableValue = Some(UnmovableValue()); | |
CHECK(mayUnmovableValue->GetStatus() == eWasCopyConstructed); | |
mayUnmovableValue = Some(UnmovableValue()); | |
CHECK(mayUnmovableValue->GetStatus() == eWasCopyAssigned); | |
mayUnmovableValue.reset(); | |
mayUnmovableValue.emplace(UnmovableValue()); | |
CHECK(mayUnmovableValue->GetStatus() == eWasCopyConstructed); | |
// Check that types that only support moves, but not copies, work. | |
Maybe<UncopyableValue> mayUncopyableValue = Some(UncopyableValue()); | |
CHECK(mayUncopyableValue->GetStatus() == eWasMoveConstructed); | |
mayUncopyableValue = Some(UncopyableValue()); | |
CHECK(mayUncopyableValue->GetStatus() == eWasMoveAssigned); | |
mayUncopyableValue.reset(); | |
mayUncopyableValue.emplace(UncopyableValue()); | |
CHECK(mayUncopyableValue->GetStatus() == eWasMoveConstructed); | |
// (Should fail!!!) | |
Maybe<UncopyableValue> mayUncopyableValue2 = Some(*mayUncopyableValue); | |
mayUncopyableValue2 = mayUncopyableValue; | |
mayUncopyableValue2.reset(); | |
mayUncopyableValue2.emplace(mayUncopyableValue); | |
// END (Should fail!!!) | |
// Check that types that support neither moves or copies work. | |
Maybe<UncopyableUnmovableValue> mayUncopyableUnmovableValue; | |
mayUncopyableUnmovableValue.emplace(); | |
CHECK(mayUncopyableUnmovableValue->GetStatus() == eWasDefaultConstructed); | |
mayUncopyableUnmovableValue.reset(); | |
mayUncopyableUnmovableValue.emplace(0); | |
CHECK(mayUncopyableUnmovableValue->GetStatus() == eWasConstructed); | |
return true; | |
} | |
static bool | |
TestFunctionalAccessors() | |
{ | |
return true; | |
} | |
static bool | |
TestApply() | |
{ | |
return true; | |
} | |
static bool | |
TestMap() | |
{ | |
return true; | |
} | |
static bool | |
TestSomeAndNone() | |
{ | |
return true; | |
} | |
static bool | |
TestToMaybe() | |
{ | |
return true; | |
} | |
static bool | |
TestOperators() | |
{ | |
return true; | |
} | |
int | |
main() | |
{ | |
if (!TestBasicFeatures()) | |
return 1; | |
if (!TestCopyAndMove()) | |
return 1; | |
if (!TestFunctionalAccessors()) | |
return 1; | |
if (!TestApply()) | |
return 1; | |
if (!TestMap()) | |
return 1; | |
if (!TestSomeAndNone()) | |
return 1; | |
if (!TestToMaybe()) | |
return 1; | |
if (!TestOperators()) | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment