diff options
Diffstat (limited to 'include/llvm/ADT/Optional.h')
-rw-r--r-- | include/llvm/ADT/Optional.h | 132 |
1 files changed, 98 insertions, 34 deletions
diff --git a/include/llvm/ADT/Optional.h b/include/llvm/ADT/Optional.h index f43aeb1..194e53f 100644 --- a/include/llvm/ADT/Optional.h +++ b/include/llvm/ADT/Optional.h @@ -13,13 +13,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_ADT_OPTIONAL -#define LLVM_ADT_OPTIONAL +#ifndef LLVM_ADT_OPTIONAL_H +#define LLVM_ADT_OPTIONAL_H +#include "llvm/ADT/None.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/AlignOf.h" #include <cassert> -#if LLVM_USE_RVALUE_REFERENCES +#if LLVM_HAS_RVALUE_REFERENCES #include <utility> #endif @@ -27,54 +29,116 @@ namespace llvm { template<typename T> class Optional { - T x; - unsigned hasVal : 1; + AlignedCharArrayUnion<T> storage; + bool hasVal; public: - explicit Optional() : x(), hasVal(false) {} - Optional(const T &y) : x(y), hasVal(true) {} + Optional(NoneType) : hasVal(false) {} + 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_USE_RVALUE_REFERENCES - Optional(T &&y) : x(std::forward<T>(y)), hasVal(true) {} +#if LLVM_HAS_RVALUE_REFERENCES + Optional(T &&y) : hasVal(true) { + new (storage.buffer) T(std::forward<T>(y)); + } + Optional(Optional<T> &&O) : hasVal(O) { + if (O) { + new (storage.buffer) T(std::move(*O)); + O.reset(); + } + } + Optional &operator=(T &&y) { + if (hasVal) + **this = std::move(y); + else { + new (storage.buffer) T(std::move(y)); + hasVal = true; + } + return *this; + } + Optional &operator=(Optional &&O) { + if (!O) + reset(); + else { + *this = std::move(*O); + O.reset(); + } + return *this; + } #endif static inline Optional create(const T* y) { return y ? Optional(*y) : Optional(); } + // FIXME: these assignments (& the equivalent const T&/const Optional& ctors) + // could be made more efficient by passing by value, possibly unifying them + // with the rvalue versions above - but this could place a different set of + // requirements (notably: the existence of a default ctor) when implemented + // in that way. Careful SFINAE to avoid such pitfalls would be required. Optional &operator=(const T &y) { - x = y; - hasVal = true; + if (hasVal) + **this = y; + else { + new (storage.buffer) T(y); + hasVal = true; + } return *this; } - - const T* getPointer() const { assert(hasVal); return &x; } - const T& getValue() const { assert(hasVal); return x; } - operator bool() const { return hasVal; } - bool hasValue() const { return hasVal; } - const T* operator->() const { return getPointer(); } - const T& operator*() const { assert(hasVal); return x; } -}; + Optional &operator=(const Optional &O) { + if (!O) + reset(); + else + *this = *O; + return *this; + } -template<typename T> struct simplify_type; + void reset() { + if (hasVal) { + (**this).~T(); + hasVal = false; + } + } -template <typename T> -struct simplify_type<const Optional<T> > { - typedef const T* SimpleType; - static SimpleType getSimplifiedValue(const Optional<T> &Val) { - return Val.getPointer(); + ~Optional() { + reset(); } + + 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(); } + + LLVM_EXPLICIT operator bool() const { return hasVal; } + bool hasValue() const { return hasVal; } + const T* operator->() const { return getPointer(); } + 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(*getPointer()); } + T&& operator*() && { assert(hasVal); return std::move(*getPointer()); } +#endif }; -template <typename T> -struct simplify_type<Optional<T> > - : public simplify_type<const Optional<T> > {}; +template <typename T> struct isPodLike; +template <typename T> struct isPodLike<Optional<T> > { + // An Optional<T> is pod-like if T is. + static const bool value = isPodLike<T>::value; +}; /// \brief Poison comparison between two \c Optional objects. Clients needs to /// explicitly compare the underlying values and account for empty \c Optional /// objects. /// -/// This routine will never be defined. It returns \c void to help diagnose +/// This routine will never be defined. It returns \c void to help diagnose /// errors at compile time. template<typename T, typename U> void operator==(const Optional<T> &X, const Optional<U> &Y); @@ -83,7 +147,7 @@ void operator==(const Optional<T> &X, const Optional<U> &Y); /// explicitly compare the underlying values and account for empty \c Optional /// objects. /// -/// This routine will never be defined. It returns \c void to help diagnose +/// This routine will never be defined. It returns \c void to help diagnose /// errors at compile time. template<typename T, typename U> void operator!=(const Optional<T> &X, const Optional<U> &Y); @@ -92,7 +156,7 @@ void operator!=(const Optional<T> &X, const Optional<U> &Y); /// explicitly compare the underlying values and account for empty \c Optional /// objects. /// -/// This routine will never be defined. It returns \c void to help diagnose +/// This routine will never be defined. It returns \c void to help diagnose /// errors at compile time. template<typename T, typename U> void operator<(const Optional<T> &X, const Optional<U> &Y); @@ -101,7 +165,7 @@ void operator<(const Optional<T> &X, const Optional<U> &Y); /// explicitly compare the underlying values and account for empty \c Optional /// objects. /// -/// This routine will never be defined. It returns \c void to help diagnose +/// This routine will never be defined. It returns \c void to help diagnose /// errors at compile time. template<typename T, typename U> void operator<=(const Optional<T> &X, const Optional<U> &Y); @@ -110,7 +174,7 @@ void operator<=(const Optional<T> &X, const Optional<U> &Y); /// explicitly compare the underlying values and account for empty \c Optional /// objects. /// -/// This routine will never be defined. It returns \c void to help diagnose +/// This routine will never be defined. It returns \c void to help diagnose /// errors at compile time. template<typename T, typename U> void operator>=(const Optional<T> &X, const Optional<U> &Y); @@ -119,7 +183,7 @@ void operator>=(const Optional<T> &X, const Optional<U> &Y); /// explicitly compare the underlying values and account for empty \c Optional /// objects. /// -/// This routine will never be defined. It returns \c void to help diagnose +/// This routine will never be defined. It returns \c void to help diagnose /// errors at compile time. template<typename T, typename U> void operator>(const Optional<T> &X, const Optional<U> &Y); |