<p dir="ltr"><br>
On Feb 20, 2013 12:48 AM, "Timur Iskhodzhanov" <<a href="mailto:timurrrr@google.com">timurrrr@google.com</a>> wrote:<br>
><br>
> FYI<br>
> I think this has broken compilation on Windows, VS2010:<br>
> llvm\include\llvm/ADT/Optional.h(73): error C2839: invalid return<br>
> type 'unsigned int *' for overloaded 'operator ->'</p>
<p dir="ltr">Yep, sorry about that. Takumi has fixed this in r175626.</p>
<p dir="ltr">- David</p>
<p dir="ltr">><br>
> --<br>
> Timur<br>
><br>
> 2013/2/20 David Blaikie <<a href="mailto:dblaikie@gmail.com">dblaikie@gmail.com</a>>:<br>
> > Author: dblaikie<br>
> > Date: Tue Feb 19 18:26:04 2013<br>
> > New Revision: 175580<br>
> ><br>
> > URL: <a href="http://llvm.org/viewvc/llvm-project?rev=175580&view=rev">http://llvm.org/viewvc/llvm-project?rev=175580&view=rev</a><br>
> > Log:<br>
> > Allow llvm::Optional to work with types without default constructors.<br>
> ><br>
> > This generalizes Optional to require less from the T type by using aligned<br>
> > storage for backing & placement new/deleting the T into it when necessary.<br>
> ><br>
> > Also includes unit tests.<br>
> ><br>
> > Added:<br>
> > llvm/trunk/unittests/ADT/OptionalTest.cpp<br>
> > Modified:<br>
> > llvm/trunk/include/llvm/ADT/Optional.h<br>
> > llvm/trunk/unittests/ADT/CMakeLists.txt<br>
> ><br>
> > Modified: llvm/trunk/include/llvm/ADT/Optional.h<br>
> > URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/Optional.h?rev=175580&r1=175579&r2=175580&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/Optional.h?rev=175580&r1=175579&r2=175580&view=diff</a><br>
> > ==============================================================================<br>
> > --- llvm/trunk/include/llvm/ADT/Optional.h (original)<br>
> > +++ llvm/trunk/include/llvm/ADT/Optional.h Tue Feb 19 18:26:04 2013<br>
> > @@ -17,6 +17,7 @@<br>
> > #define LLVM_ADT_OPTIONAL_H<br>
> ><br>
> > #include "llvm/Support/Compiler.h"<br>
> > +#include "llvm/Support/AlignOf.h"<br>
> > #include <cassert><br>
> ><br>
> > #if LLVM_HAS_RVALUE_REFERENCES<br>
> > @@ -27,14 +28,22 @@ namespace llvm {<br>
> ><br>
> > template<typename T><br>
> > class Optional {<br>
> > - T x;<br>
> > + AlignedCharArrayUnion<T> storage;<br>
> > bool hasVal;<br>
> > public:<br>
> > - explicit Optional() : x(), hasVal(false) {}<br>
> > - Optional(const T &y) : x(y), hasVal(true) {}<br>
> > + explicit Optional() : hasVal(false) {}<br>
> > + Optional(const T &y) : hasVal(true) {<br>
> > + new (storage.buffer) T(y);<br>
> > + }<br>
> > + Optional(const Optional &O) : hasVal(O.hasVal) {<br>
> > + if (hasVal)<br>
> > + new (storage.buffer) T(*O);<br>
> > + }<br>
> ><br>
> > #if LLVM_HAS_RVALUE_REFERENCES<br>
> > - Optional(T &&y) : x(std::forward<T>(y)), hasVal(true) {}<br>
> > + Optional(T &&y) : hasVal(true) {<br>
> > + new (storage.buffer) T(std::forward<T>(y));<br>
> > + }<br>
> > #endif<br>
> ><br>
> > static inline Optional create(const T* y) {<br>
> > @@ -42,22 +51,49 @@ public:<br>
> > }<br>
> ><br>
> > Optional &operator=(const T &y) {<br>
> > - x = y;<br>
> > - hasVal = true;<br>
> > + if (hasVal)<br>
> > + **this = y;<br>
> > + else {<br>
> > + new (storage.buffer) T(y);<br>
> > + hasVal = true;<br>
> > + }<br>
> > + return *this;<br>
> > + }<br>
> > +<br>
> > + Optional &operator=(const Optional &O) {<br>
> > + if (!O)<br>
> > + Reset();<br>
> > + else<br>
> > + *this = *O;<br>
> > return *this;<br>
> > }<br>
> > +<br>
> > + void Reset() {<br>
> > + if (hasVal) {<br>
> > + (*this)->~T();<br>
> > + hasVal = false;<br>
> > + }<br>
> > + }<br>
> > +<br>
> > + ~Optional() {<br>
> > + Reset();<br>
> > + }<br>
> ><br>
> > - const T* getPointer() const { assert(hasVal); return &x; }<br>
> > - const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return x; }<br>
> > + const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); }<br>
> > + T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); }<br>
> > + const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }<br>
> > + T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }<br>
> ><br>
> > operator bool() const { return hasVal; }<br>
> > bool hasValue() const { return hasVal; }<br>
> > const T* operator->() const { return getPointer(); }<br>
> > - const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return x; }<br>
> > + T* operator->() { return getPointer(); }<br>
> > + const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }<br>
> > + T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }<br>
> ><br>
> > #if LLVM_HAS_RVALUE_REFERENCE_THIS<br>
> > - T&& getValue() && { assert(hasVal); return std::move(x); }<br>
> > - T&& operator*() && { assert(hasVal); return std::move(x); }<br>
> > + T&& getValue() && { assert(hasVal); return std::move(*getPointer()); }<br>
> > + T&& operator*() && { assert(hasVal); return std::move(*getPointer()); }<br>
> > #endif<br>
> > };<br>
> ><br>
> ><br>
> > Modified: llvm/trunk/unittests/ADT/CMakeLists.txt<br>
> > URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/CMakeLists.txt?rev=175580&r1=175579&r2=175580&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/CMakeLists.txt?rev=175580&r1=175579&r2=175580&view=diff</a><br>
> > ==============================================================================<br>
> > --- llvm/trunk/unittests/ADT/CMakeLists.txt (original)<br>
> > +++ llvm/trunk/unittests/ADT/CMakeLists.txt Tue Feb 19 18:26:04 2013<br>
> > @@ -19,6 +19,7 @@ set(ADTSources<br>
> > IntervalMapTest.cpp<br>
> > IntrusiveRefCntPtrTest.cpp<br>
> > MapVectorTest.cpp<br>
> > + OptionalTest.cpp<br>
> > PackedVectorTest.cpp<br>
> > SCCIteratorTest.cpp<br>
> > SmallPtrSetTest.cpp<br>
> ><br>
> > Added: llvm/trunk/unittests/ADT/OptionalTest.cpp<br>
> > URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/OptionalTest.cpp?rev=175580&view=auto">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/OptionalTest.cpp?rev=175580&view=auto</a><br>
> > ==============================================================================<br>
> > --- llvm/trunk/unittests/ADT/OptionalTest.cpp (added)<br>
> > +++ llvm/trunk/unittests/ADT/OptionalTest.cpp Tue Feb 19 18:26:04 2013<br>
> > @@ -0,0 +1,173 @@<br>
> > +//===- llvm/unittest/ADT/OptionalTest.cpp - Optional unit tests -----------===//<br>
> > +//<br>
> > +// The LLVM Compiler Infrastructure<br>
> > +//<br>
> > +// This file is distributed under the University of Illinois Open Source<br>
> > +// License. See LICENSE.TXT for details.<br>
> > +//<br>
> > +//===----------------------------------------------------------------------===//<br>
> > +<br>
> > +#include "gtest/gtest.h"<br>
> > +#include "llvm/ADT/Optional.h"<br>
> > +using namespace llvm;<br>
> > +<br>
> > +namespace {<br>
> > +<br>
> > +struct NonDefaultConstructible {<br>
> > + static unsigned CopyConstructions;<br>
> > + static unsigned Destructions;<br>
> > + static unsigned CopyAssignments;<br>
> > + explicit NonDefaultConstructible(int) {<br>
> > + }<br>
> > + NonDefaultConstructible(const NonDefaultConstructible&) {<br>
> > + ++CopyConstructions;<br>
> > + }<br>
> > + NonDefaultConstructible &operator=(const NonDefaultConstructible&) {<br>
> > + ++CopyAssignments;<br>
> > + return *this;<br>
> > + }<br>
> > + ~NonDefaultConstructible() {<br>
> > + ++Destructions;<br>
> > + }<br>
> > + static void ResetCounts() {<br>
> > + CopyConstructions = 0;<br>
> > + Destructions = 0;<br>
> > + CopyAssignments = 0;<br>
> > + }<br>
> > +};<br>
> > +<br>
> > +unsigned NonDefaultConstructible::CopyConstructions = 0;<br>
> > +unsigned NonDefaultConstructible::Destructions = 0;<br>
> > +unsigned NonDefaultConstructible::CopyAssignments = 0;<br>
> > +<br>
> > +// Test fixture<br>
> > +class OptionalTest : public testing::Test {<br>
> > +};<br>
> > +<br>
> > +TEST_F(OptionalTest, NonDefaultConstructibleTest) {<br>
> > + Optional<NonDefaultConstructible> O;<br>
> > + EXPECT_FALSE(O);<br>
> > +}<br>
> > +<br>
> > +TEST_F(OptionalTest, ResetTest) {<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + Optional<NonDefaultConstructible> O(NonDefaultConstructible(3));<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + O.Reset();<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::Destructions);<br>
> > +}<br>
> > +<br>
> > +TEST_F(OptionalTest, InitializationLeakTest) {<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + Optional<NonDefaultConstructible>(NonDefaultConstructible(3));<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(2u, NonDefaultConstructible::Destructions);<br>
> > +}<br>
> > +<br>
> > +TEST_F(OptionalTest, CopyConstructionTest) {<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + {<br>
> > + Optional<NonDefaultConstructible> A(NonDefaultConstructible(3));<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + Optional<NonDefaultConstructible> B(A);<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + }<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(2u, NonDefaultConstructible::Destructions);<br>
> > +}<br>
> > +<br>
> > +TEST_F(OptionalTest, ConstructingCopyAssignmentTest) {<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + {<br>
> > + Optional<NonDefaultConstructible> A(NonDefaultConstructible(3));<br>
> > + Optional<NonDefaultConstructible> B;<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + B = A;<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + }<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(2u, NonDefaultConstructible::Destructions);<br>
> > +}<br>
> > +<br>
> > +TEST_F(OptionalTest, CopyingCopyAssignmentTest) {<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + {<br>
> > + Optional<NonDefaultConstructible> A(NonDefaultConstructible(3));<br>
> > + Optional<NonDefaultConstructible> B(NonDefaultConstructible(4));<br>
> > + EXPECT_EQ(2u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(2u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + B = A;<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + }<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(2u, NonDefaultConstructible::Destructions);<br>
> > +}<br>
> > +<br>
> > +TEST_F(OptionalTest, DeletingCopyAssignmentTest) {<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + {<br>
> > + Optional<NonDefaultConstructible> A;<br>
> > + Optional<NonDefaultConstructible> B(NonDefaultConstructible(3));<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + B = A;<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(1u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + }<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::Destructions);<br>
> > +}<br>
> > +<br>
> > +TEST_F(OptionalTest, NullCopyConstructionTest) {<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + {<br>
> > + Optional<NonDefaultConstructible> A;<br>
> > + Optional<NonDefaultConstructible> B;<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + B = A;<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::Destructions);<br>
> > + NonDefaultConstructible::ResetCounts();<br>
> > + }<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);<br>
> > + EXPECT_EQ(0u, NonDefaultConstructible::Destructions);<br>
> > +}<br>
> > +<br>
> > +} // end anonymous namespace<br>
> > +<br>
> ><br>
> ><br>
> > _______________________________________________<br>
> > llvm-commits mailing list<br>
> > <a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
> > <a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</p>