/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2022 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. The code included in this file is provided under the terms of the ISC license http://www.isc.org/downloads/software-support-policy/isc-license. Permission To use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted provided that the above copyright notice and this permission notice appear in all copies. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ namespace juce { using Nullopt = std::nullopt_t; constexpr auto nullopt = std::nullopt; // Without this, our tests can emit "unreachable code" warnings during // link time code generation. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4702) #define JUCE_OPTIONAL_OPERATORS X(==) X(!=) X(<) X(<=) X(>) X(>=) /** A simple optional type. In new code, you should probably prefer using std::optional directly. This is intended to stand-in for std::optional while JUCE's minimum supported language standard is lower than C++17. When the minimum language standard moves to C++17, this class will probably be deprecated, in much the same way that juce::ScopedPointer was deprecated in favour of std::unique_ptr after C++11. This isn't really intended to be used by JUCE clients. Instead, it's to be used internally in JUCE code, with an API close-enough to std::optional that the types can be swapped with fairly minor disruption at some point in the future, but *without breaking any public APIs*. @tags{Core} */ template class Optional { template struct IsOptional : std::false_type {}; template struct IsOptional> : std::true_type {}; public: Optional() = default; Optional (const Optional&) = default; Optional (Optional&&) = default; Optional& operator= (const Optional&) = default; Optional& operator= (Optional&&) = default; Optional (Nullopt) noexcept {} template >::value, int> = 0> Optional (Head&& head, Tail&&... tail) noexcept (std::is_nothrow_constructible_v, Head, Tail...>) : opt (std::forward (head), std::forward (tail)...) {} template Optional (const Optional& other) noexcept (std::is_nothrow_constructible_v, const std::optional&>) : opt (other.opt) {} template Optional (Optional&& other) noexcept (std::is_nothrow_constructible_v, std::optional&&>) : opt (std::move (other.opt)) {} template >::value, int> = 0> Optional& operator= (Other&& other) noexcept (std::is_nothrow_assignable_v, Other>) { opt = std::forward (other); return *this; } template Optional& operator= (const Optional& other) noexcept (std::is_nothrow_assignable_v, const std::optional&>) { opt = other.opt; return *this; } template Optional& operator= (Optional&& other) noexcept (std::is_nothrow_assignable_v, std::optional&&>) { opt = std::move (other.opt); return *this; } template auto& emplace (Other&&... other) { return opt.emplace (std::forward (other)...); } void reset() noexcept { opt.reset(); } void swap (Optional& other) noexcept (std::is_nothrow_swappable_v>) { opt.swap (other.opt); } decltype (auto) operator->() { return opt.operator->(); } decltype (auto) operator->() const { return opt.operator->(); } decltype (auto) operator* () { return opt.operator* (); } decltype (auto) operator* () const { return opt.operator* (); } explicit operator bool() const noexcept { return opt.has_value(); } bool hasValue() const noexcept { return opt.has_value(); } template decltype (auto) orFallback (U&& fallback) const& { return opt.value_or (std::forward (fallback)); } template decltype (auto) orFallback (U&& fallback) & { return opt.value_or (std::forward (fallback)); } #define X(op) \ template friend bool operator op (const Optional&, const Optional&); \ template friend bool operator op (const Optional&, Nullopt); \ template friend bool operator op (Nullopt, const Optional&); \ template friend bool operator op (const Optional&, const U&); \ template friend bool operator op (const T&, const Optional&); JUCE_OPTIONAL_OPERATORS #undef X private: template friend class Optional; std::optional opt; }; JUCE_END_IGNORE_WARNINGS_MSVC template Optional> makeOptional (Value&& v) { return std::forward (v); } #define X(op) \ template bool operator op (const Optional& lhs, const Optional& rhs) { return lhs.opt op rhs.opt; } \ template bool operator op (const Optional& lhs, Nullopt rhs) { return lhs.opt op rhs; } \ template bool operator op (Nullopt lhs, const Optional& rhs) { return lhs op rhs.opt; } \ template bool operator op (const Optional& lhs, const U& rhs) { return lhs.opt op rhs; } \ template bool operator op (const T& lhs, const Optional& rhs) { return lhs op rhs.opt; } JUCE_OPTIONAL_OPERATORS #undef X #undef JUCE_OPTIONAL_OPERATORS } // namespace juce