Skip to content

Instantly share code, notes, and snippets.

Created August 4, 2014 21:02
Show Gist options
  • Save anonymous/c166c14e0bdb9f02aa08 to your computer and use it in GitHub Desktop.
Save anonymous/c166c14e0bdb9f02aa08 to your computer and use it in GitHub Desktop.
/* -*- 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