/* * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef Optional_h #define Optional_h #include #include #include // WTF::Optional is a class based on std::optional, described here: // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3527.html // If this ends up in a C++ standard, we should replace our implementation with it. namespace WTF { struct InPlaceTag { }; constexpr InPlaceTag InPlace { }; struct NulloptTag { explicit constexpr NulloptTag(int) { } }; constexpr NulloptTag Nullopt { 0 }; template class Optional { public: Optional() : m_isEngaged(false) { } Optional(NulloptTag) : m_isEngaged(false) { } Optional(const T& value) : m_isEngaged(true) { new (NotNull, &m_value) T(value); } Optional(const Optional& other) : m_isEngaged(other.m_isEngaged) { if (m_isEngaged) new (NotNull, &m_value) T(*other.asPtr()); } Optional(Optional&& other) : m_isEngaged(other.m_isEngaged) { if (m_isEngaged) new (NotNull, &m_value) T(WTFMove(*other.asPtr())); } Optional(T&& value) : m_isEngaged(true) { new (NotNull, &m_value) T(WTFMove(value)); } template Optional(InPlaceTag, Args&&... args) : m_isEngaged(true) { new (NotNull, &m_value) T(std::forward(args)...); } ~Optional() { destroy(); } Optional& operator=(NulloptTag) { destroy(); return *this; } Optional& operator=(const Optional& other) { if (this == &other) return *this; destroy(); if (other.m_isEngaged) { new (NotNull, &m_value) T(*other.asPtr()); m_isEngaged = true; } return *this; } Optional& operator=(Optional&& other) { if (this == &other) return *this; destroy(); if (other.m_isEngaged) { new (NotNull, &m_value) T(WTFMove(*other.asPtr())); m_isEngaged = true; } return *this; } template::type, T>::value>::type> Optional& operator=(U&& u) { destroy(); new (NotNull, &m_value) T(std::forward(u)); m_isEngaged = true; return *this; } explicit operator bool() const { return m_isEngaged; } const T* operator->() const { ASSERT(m_isEngaged); return asPtr(); } T* operator->() { ASSERT(m_isEngaged); return asPtr(); } const T& operator*() const { return value(); } T& operator*() { return value(); } T& value() { ASSERT(m_isEngaged); return *asPtr(); } const T& value() const { ASSERT(m_isEngaged); return *asPtr(); } template T valueOr(U&& value) const { if (m_isEngaged) return *asPtr(); return std::forward(value); } template T valueOrCompute(U callback) const { if (m_isEngaged) return *asPtr(); return callback(); } private: const T* asPtr() const { return reinterpret_cast(&m_value); } T* asPtr() { return reinterpret_cast(&m_value); } void destroy() { if (m_isEngaged) { asPtr()->~T(); m_isEngaged = false; } } bool m_isEngaged; typename std::aligned_storage::value>::type m_value; }; template constexpr bool operator==(const Optional& lhs, const Optional& rhs) { return static_cast(lhs) == static_cast(rhs) && (!static_cast(lhs) || lhs.value() == rhs.value()); } template constexpr bool operator!=(const Optional& lhs, const Optional& rhs) { return !(lhs == rhs); } template constexpr bool operator==(const Optional& opt, NulloptTag) { return !opt; } template constexpr bool operator!=(const Optional& opt, NulloptTag) { return static_cast(opt); } template constexpr bool operator==(NulloptTag, const Optional& opt) { return !opt; } template constexpr bool operator!=(NulloptTag, const Optional& opt) { return static_cast(opt); } template constexpr bool operator==(const Optional& opt, const T& value) { return opt && opt.value() == value; } template constexpr bool operator!=(const Optional& opt, const T& value) { return !(opt == value); } template constexpr bool operator==(const T& value, const Optional& opt) { return opt && opt.value() == value; } template constexpr bool operator!=(const T& value, const Optional& opt) { return !(value == opt); } template Optional::type> makeOptional(T&& value) { return Optional::type>(std::forward(value)); } } // namespace WTF using WTF::InPlace; using WTF::Nullopt; using WTF::Optional; using WTF::makeOptional; #endif // Optional_h