Files
swift-mirror/include/swift/Basic/Optional.h
Doug Gregor 0043652979 NFC: Replace DeclFilterRange with an elaborate set of iterator and range adaptors.
We're going to want these various adaptors, and helpers built on top
of them, when we replace the array-based storage of members in nominal
types and extensions with something more sane.


Swift SVN r16569
2014-04-19 18:19:59 +00:00

190 lines
5.2 KiB
C++

//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file provides Optional, a template class modeled in the spirit of
// OCaml's 'opt' variant. The idea is to strongly type whether or not
// a value can be optional.
//
// Note that this is a C++11-only re-implementation of LLVM's Optional class,
// which provides the benefit of not constructing the object. This could also
// be implemented in C++98/03 for LLVM (and will eventually be), but it's a
// pain to re-implement unrestricted unions.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_BASIC_OPTIONAL_H
#define SWIFT_BASIC_OPTIONAL_H
#include <type_traits>
#include <utility>
#include <cassert>
namespace swift {
/// An enum whose purpose is to make it easier to initialize an
/// empty optional.
static const enum class Nothing_t { Nothing } Nothing = Nothing_t::Nothing;
static_assert(!std::is_convertible<Nothing_t, bool>::value,
"Nothing must not be implicitly convertible to bool");
template<typename T>
class Optional {
// Place Value in an anonymous union to suppress implicit value semantics.
union {
T Value;
};
unsigned HasValue : 1;
public:
typedef T value_type;
/// \brief Construct an empty instance.
Optional() : HasValue(false) { }
/// \brief Construct an empty instance.
Optional(Nothing_t _) : HasValue(false) { }
/// \brief Construct an instance containing a value of type \c T
/// constructed with the given arguments.
///
/// \param Args The arguments with which the \c T object will be
/// direct-initialized.
template<typename ...ArgTypes>
Optional(ArgTypes &&...Args)
: Value(std::forward<ArgTypes>(Args)...), HasValue(true)
{
}
Optional(Optional &Other) : HasValue(Other.HasValue) {
if (HasValue)
::new ((void*)&Value) T(Other.Value);
}
Optional(const Optional &Other) : HasValue(Other.HasValue) {
if (HasValue)
::new ((void*)&Value) T(Other.Value);
}
Optional(Optional &&Other) : HasValue(Other.HasValue) {
if (HasValue) {
::new ((void*)&Value) T(std::move(Other.Value));
Other.HasValue = false;
}
}
Optional &operator=(const Optional &Other) {
if (HasValue && Other.HasValue) {
Value = Other.Value;
return *this;
}
if (HasValue) {
reset();
return *this;
}
if (Other.HasValue) {
HasValue = true;
::new ((void*)&Value) T(Other.Value);
}
return *this;
}
Optional &operator=(Optional &&Other) {
if (HasValue && Other.HasValue) {
Value = std::move(Other.Value);
Other.reset();
return *this;
}
if (HasValue) {
reset();
return *this;
}
if (Other.HasValue) {
HasValue = true;
::new ((void*)&Value) T(std::move(Other.Value));
Other.reset();
}
return *this;
}
~Optional() { reset(); }
// Create a new object by constructing it in place with the given arguments.
template<typename ...ArgTypes>
void emplace(ArgTypes &&...Args) {
reset();
HasValue = true;
::new ((void*)&Value) T(std::forward<ArgTypes>(Args)...);
}
void reset() {
if (!HasValue)
return;
Value.~T();
HasValue = false;
}
T &getValue() & { assert(HasValue); return Value; }
const T &getValue() const & { assert(HasValue); return Value; }
T getValue() && {
assert(HasValue);
T result = std::move(Value);
reset();
return result;
}
template <typename U>
constexpr T getValueOr(U &&value) const & {
return hasValue() ? getValue() : value;
}
template <typename U>
T getValueOr(U &&value) && {
return hasValue() ? getValue() : value;
}
bool hasValue() const { return HasValue; }
explicit operator bool() const { return HasValue; }
const T* operator->() const { assert(HasValue); return &Value; }
T* operator->() { assert(HasValue); return &Value; }
const T& operator*() const & { assert(HasValue); return Value; }
T& operator*() & { assert(HasValue); return Value; }
T operator*() && {
assert(HasValue);
T result = std::move(Value);
reset();
return result;
}
/// Return the value inside the optional if populated; otherwise, execute
/// the given block, store its result inside the optional, and return it.
template<typename NullaryFunctor>
T const &cache(NullaryFunctor &&f) {
if (hasValue())
return getValue();
emplace(f());
return getValue();
}
};
}
#endif