[llvm] r175580 - Allow llvm::Optional to work with types without default constructors.
David Blaikie
dblaikie at gmail.com
Wed Feb 20 08:01:36 PST 2013
On Feb 20, 2013 12:48 AM, "Timur Iskhodzhanov" <timurrrr at google.com> wrote:
>
> FYI
> I think this has broken compilation on Windows, VS2010:
> llvm\include\llvm/ADT/Optional.h(73): error C2839: invalid return
> type 'unsigned int *' for overloaded 'operator ->'
Yep, sorry about that. Takumi has fixed this in r175626.
- David
>
> --
> Timur
>
> 2013/2/20 David Blaikie <dblaikie at gmail.com>:
> > Author: dblaikie
> > Date: Tue Feb 19 18:26:04 2013
> > New Revision: 175580
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=175580&view=rev
> > Log:
> > 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.
> >
> > Added:
> > llvm/trunk/unittests/ADT/OptionalTest.cpp
> > Modified:
> > llvm/trunk/include/llvm/ADT/Optional.h
> > llvm/trunk/unittests/ADT/CMakeLists.txt
> >
> > Modified: llvm/trunk/include/llvm/ADT/Optional.h
> > URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/Optional.h?rev=175580&r1=175579&r2=175580&view=diff
> >
==============================================================================
> > --- llvm/trunk/include/llvm/ADT/Optional.h (original)
> > +++ llvm/trunk/include/llvm/ADT/Optional.h Tue Feb 19 18:26:04 2013
> > @@ -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
> > };
> >
> >
> > Modified: llvm/trunk/unittests/ADT/CMakeLists.txt
> > URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/CMakeLists.txt?rev=175580&r1=175579&r2=175580&view=diff
> >
==============================================================================
> > --- llvm/trunk/unittests/ADT/CMakeLists.txt (original)
> > +++ llvm/trunk/unittests/ADT/CMakeLists.txt Tue Feb 19 18:26:04 2013
> > @@ -19,6 +19,7 @@ set(ADTSources
> > IntervalMapTest.cpp
> > IntrusiveRefCntPtrTest.cpp
> > MapVectorTest.cpp
> > + OptionalTest.cpp
> > PackedVectorTest.cpp
> > SCCIteratorTest.cpp
> > SmallPtrSetTest.cpp
> >
> > Added: llvm/trunk/unittests/ADT/OptionalTest.cpp
> > URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/OptionalTest.cpp?rev=175580&view=auto
> >
==============================================================================
> > --- llvm/trunk/unittests/ADT/OptionalTest.cpp (added)
> > +++ llvm/trunk/unittests/ADT/OptionalTest.cpp Tue Feb 19 18:26:04 2013
> > @@ -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
> > +
> >
> >
> > _______________________________________________
> > llvm-commits mailing list
> > llvm-commits at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130220/39b54e30/attachment.html>
More information about the llvm-commits
mailing list