mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-12 17:32:19 +00:00
Allow llvm::Optional to work with types without default constructors.
This generalizes Optional to require less from the T type by using aligned storage for backing & placement new/deleting the T into it when necessary. Also includes unit tests. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175580 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
9bc2c99482
commit
a28eda7e40
@ -17,6 +17,7 @@
|
||||
#define LLVM_ADT_OPTIONAL_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include <cassert>
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
@ -27,14 +28,22 @@ namespace llvm {
|
||||
|
||||
template<typename T>
|
||||
class Optional {
|
||||
T x;
|
||||
AlignedCharArrayUnion<T> storage;
|
||||
bool hasVal;
|
||||
public:
|
||||
explicit Optional() : x(), hasVal(false) {}
|
||||
Optional(const T &y) : x(y), hasVal(true) {}
|
||||
explicit Optional() : hasVal(false) {}
|
||||
Optional(const T &y) : hasVal(true) {
|
||||
new (storage.buffer) T(y);
|
||||
}
|
||||
Optional(const Optional &O) : hasVal(O.hasVal) {
|
||||
if (hasVal)
|
||||
new (storage.buffer) T(*O);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
Optional(T &&y) : x(std::forward<T>(y)), hasVal(true) {}
|
||||
Optional(T &&y) : hasVal(true) {
|
||||
new (storage.buffer) T(std::forward<T>(y));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline Optional create(const T* y) {
|
||||
@ -42,22 +51,49 @@ public:
|
||||
}
|
||||
|
||||
Optional &operator=(const T &y) {
|
||||
x = y;
|
||||
hasVal = true;
|
||||
if (hasVal)
|
||||
**this = y;
|
||||
else {
|
||||
new (storage.buffer) T(y);
|
||||
hasVal = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Optional &operator=(const Optional &O) {
|
||||
if (!O)
|
||||
Reset();
|
||||
else
|
||||
*this = *O;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
if (hasVal) {
|
||||
(*this)->~T();
|
||||
hasVal = false;
|
||||
}
|
||||
}
|
||||
|
||||
~Optional() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
const T* getPointer() const { assert(hasVal); return &x; }
|
||||
const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return x; }
|
||||
const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); }
|
||||
T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); }
|
||||
const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
|
||||
operator bool() const { return hasVal; }
|
||||
bool hasValue() const { return hasVal; }
|
||||
const T* operator->() const { return getPointer(); }
|
||||
const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return x; }
|
||||
T* operator->() { return getPointer(); }
|
||||
const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
T&& getValue() && { assert(hasVal); return std::move(x); }
|
||||
T&& operator*() && { assert(hasVal); return std::move(x); }
|
||||
T&& getValue() && { assert(hasVal); return std::move(*getPointer()); }
|
||||
T&& operator*() && { assert(hasVal); return std::move(*getPointer()); }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@ set(ADTSources
|
||||
IntervalMapTest.cpp
|
||||
IntrusiveRefCntPtrTest.cpp
|
||||
MapVectorTest.cpp
|
||||
OptionalTest.cpp
|
||||
PackedVectorTest.cpp
|
||||
SCCIteratorTest.cpp
|
||||
SmallPtrSetTest.cpp
|
||||
|
173
unittests/ADT/OptionalTest.cpp
Normal file
173
unittests/ADT/OptionalTest.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
//===- llvm/unittest/ADT/OptionalTest.cpp - Optional unit tests -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
struct NonDefaultConstructible {
|
||||
static unsigned CopyConstructions;
|
||||
static unsigned Destructions;
|
||||
static unsigned CopyAssignments;
|
||||
explicit NonDefaultConstructible(int) {
|
||||
}
|
||||
NonDefaultConstructible(const NonDefaultConstructible&) {
|
||||
++CopyConstructions;
|
||||
}
|
||||
NonDefaultConstructible &operator=(const NonDefaultConstructible&) {
|
||||
++CopyAssignments;
|
||||
return *this;
|
||||
}
|
||||
~NonDefaultConstructible() {
|
||||
++Destructions;
|
||||
}
|
||||
static void ResetCounts() {
|
||||
CopyConstructions = 0;
|
||||
Destructions = 0;
|
||||
CopyAssignments = 0;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned NonDefaultConstructible::CopyConstructions = 0;
|
||||
unsigned NonDefaultConstructible::Destructions = 0;
|
||||
unsigned NonDefaultConstructible::CopyAssignments = 0;
|
||||
|
||||
// Test fixture
|
||||
class OptionalTest : public testing::Test {
|
||||
};
|
||||
|
||||
TEST_F(OptionalTest, NonDefaultConstructibleTest) {
|
||||
Optional<NonDefaultConstructible> O;
|
||||
EXPECT_FALSE(O);
|
||||
}
|
||||
|
||||
TEST_F(OptionalTest, ResetTest) {
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
Optional<NonDefaultConstructible> O(NonDefaultConstructible(3));
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
O.Reset();
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
|
||||
}
|
||||
|
||||
TEST_F(OptionalTest, InitializationLeakTest) {
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
Optional<NonDefaultConstructible>(NonDefaultConstructible(3));
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
|
||||
}
|
||||
|
||||
TEST_F(OptionalTest, CopyConstructionTest) {
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
{
|
||||
Optional<NonDefaultConstructible> A(NonDefaultConstructible(3));
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
Optional<NonDefaultConstructible> B(A);
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
}
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
|
||||
}
|
||||
|
||||
TEST_F(OptionalTest, ConstructingCopyAssignmentTest) {
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
{
|
||||
Optional<NonDefaultConstructible> A(NonDefaultConstructible(3));
|
||||
Optional<NonDefaultConstructible> B;
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
B = A;
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
}
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
|
||||
}
|
||||
|
||||
TEST_F(OptionalTest, CopyingCopyAssignmentTest) {
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
{
|
||||
Optional<NonDefaultConstructible> A(NonDefaultConstructible(3));
|
||||
Optional<NonDefaultConstructible> B(NonDefaultConstructible(4));
|
||||
EXPECT_EQ(2u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
B = A;
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
}
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
|
||||
}
|
||||
|
||||
TEST_F(OptionalTest, DeletingCopyAssignmentTest) {
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
{
|
||||
Optional<NonDefaultConstructible> A;
|
||||
Optional<NonDefaultConstructible> B(NonDefaultConstructible(3));
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
B = A;
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
}
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
|
||||
}
|
||||
|
||||
TEST_F(OptionalTest, NullCopyConstructionTest) {
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
{
|
||||
Optional<NonDefaultConstructible> A;
|
||||
Optional<NonDefaultConstructible> B;
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
B = A;
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
|
||||
NonDefaultConstructible::ResetCounts();
|
||||
}
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
|
||||
EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user