[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