<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>