blob: 7b686d002f7fd09f4de9e5649e8c6338bd3bf4a3 [file]
// optional<T&> -*- C++ -*-
// Copyright (C) 2013-2026 Free Software Foundation, Inc.
// Copyright The GNU Toolchain Authors.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
#ifndef GCC_BACKPORT_GLIBCXX_OPTIONAL_REF
#define GCC_BACKPORT_GLIBCXX_OPTIONAL_REF 1
#include <type_traits>
#include <utility>
#include "inplace_tags.h"
namespace gcc
{
/**
* @addtogroup utilities
* @{
*/
template<typename G_Tp>
class optional;
/// Tag type to disengage optional objects.
struct nullopt_t
{
// Do not user-declare default constructor at all for
// optional_value = {} syntax to work.
// nullopt_t() = delete;
// Used for constructing nullopt.
enum class G_Construct { G_Token };
// Must be constexpr for nullopt_t to be literal.
explicit constexpr nullopt_t(G_Construct) noexcept { }
};
/// Tag to disengage optional objects.
static constexpr nullopt_t nullopt { nullopt_t::G_Construct::G_Token };
template<typename G_Fn> struct G_Optional_func { G_Fn& m_f; };
template<typename G_Tp>
static constexpr bool g_is_valid_contained_type_for_optional =
(
std::is_lvalue_reference<G_Tp>::value ||
(std::is_object<G_Tp>::value && std::is_destructible<G_Tp>::value && !std::is_array<G_Tp>::value)
)
&& !std::is_same<std::remove_cv_t<std::remove_reference_t<G_Tp>>, nullopt_t>::value
&& !std::is_same<std::remove_cv_t<std::remove_reference_t<G_Tp>>, in_place_t>::value;
template<typename G_Tp>
class optional<G_Tp&>;
template<typename G_Tp>
struct g_is_optional_ref : std::false_type {};
template<typename G_Tp>
struct g_is_optional_ref<optional<G_Tp&>> : std::true_type {};
template<typename G_Tp>
struct g_optional_ref_base
{};
template<typename G_Tp>
class optional<G_Tp&> : public g_optional_ref_base<G_Tp>
{
static_assert(g_is_valid_contained_type_for_optional<G_Tp&>,
"Given type not valid for an optional");
public:
using value_type = G_Tp;
constexpr static optional
G_S_from_ptr(G_Tp* g_ptr)
{
optional g_res;
g_res.m_val = g_ptr;
return g_res;
}
// Constructors.
constexpr optional() noexcept = default;
constexpr optional(nullopt_t) noexcept : optional() {}
constexpr optional(const optional&) noexcept = default;
template<typename G_Arg,
G_Requires<
std::is_constructible<G_Tp&, G_Arg>,
not_<reference_constructs_from_temporary<G_Tp&, G_Arg>>
> = false>
explicit constexpr
optional(in_place_t, G_Arg&& g_arg)
{
g_convert_ref_init_val(std::forward<G_Arg>(g_arg));
}
template<typename G_Up,
G_Requires<
not_<std::is_same<remove_cvref_t<G_Up>, optional>>,
not_<std::is_same<remove_cvref_t<G_Up>, in_place_t>>,
std::is_constructible<G_Tp&, G_Up>,
not_<reference_constructs_from_temporary<G_Tp&, G_Up>>,
// Explicit:
not_<std::is_convertible<G_Up, G_Tp&>>
> = false>
explicit
constexpr
optional(G_Up&& g_u)
noexcept(std::is_nothrow_constructible<G_Tp&, G_Up>::value)
{
g_convert_ref_init_val(std::forward<G_Up>(g_u));
}
template<typename G_Up,
G_Requires<
not_<std::is_same<remove_cvref_t<G_Up>, optional>>,
not_<std::is_same<remove_cvref_t<G_Up>, in_place_t>>,
std::is_constructible<G_Tp&, G_Up>,
not_<reference_constructs_from_temporary<G_Tp&, G_Up>>,
// !Explicit:
std::is_convertible<G_Up, G_Tp&>
> = false>
constexpr
optional(G_Up&& g_u)
noexcept(std::is_nothrow_constructible<G_Tp&, G_Up>::value)
{
g_convert_ref_init_val(std::forward<G_Up>(g_u));
}
template<typename G_Up,
G_Requires<
not_<std::is_same<remove_cvref_t<G_Up>, optional>>,
not_<std::is_same<remove_cvref_t<G_Up>, in_place_t>>,
std::is_constructible<G_Tp&, G_Up>,
reference_constructs_from_temporary<G_Tp&, G_Up>,
// Explicit:
not_<std::is_convertible<G_Up, G_Tp&>>
> = false>
explicit
constexpr
optional(G_Up&& g_u) = delete;
template<typename G_Up,
G_Requires<
not_<std::is_same<remove_cvref_t<G_Up>, optional>>,
not_<std::is_same<remove_cvref_t<G_Up>, in_place_t>>,
std::is_constructible<G_Tp&, G_Up>,
reference_constructs_from_temporary<G_Tp&, G_Up>,
// !Explicit:
std::is_convertible<G_Up, G_Tp&>
> = false>
constexpr
optional(G_Up&& g_u) = delete;
// optional<U> &
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, G_Up&>,
not_<reference_constructs_from_temporary<G_Tp&, G_Up&>>,
// Explicit:
not_<std::is_convertible<G_Up&, G_Tp&>>
> = false>
explicit
constexpr
optional(optional<G_Up>& g_rhs)
noexcept(std::is_nothrow_constructible<G_Tp&, G_Up&>::value)
{
if (g_rhs)
g_convert_ref_init_val(g_rhs.m_fwd());
}
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, G_Up&>,
not_<reference_constructs_from_temporary<G_Tp&, G_Up&>>,
// !Explicit:
std::is_convertible<G_Up&, G_Tp&>
> = false>
constexpr
optional(optional<G_Up>& g_rhs)
noexcept(std::is_nothrow_constructible<G_Tp&, G_Up&>::value)
{
if (g_rhs)
g_convert_ref_init_val(g_rhs.m_fwd());
}
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, G_Up&>,
reference_constructs_from_temporary<G_Tp&, G_Up&>,
// Explicit:
not_<std::is_convertible<G_Up&, G_Tp&>>
> = false>
explicit
constexpr
optional(optional<G_Up>& g_rhs) = delete;
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, G_Up&>,
reference_constructs_from_temporary<G_Tp&, G_Up&>,
// !Explicit:
std::is_convertible<G_Up&, G_Tp&>
> = false>
constexpr
optional(optional<G_Up>& g_rhs) = delete;
// const optional<U>&
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, const G_Up&>,
not_<reference_constructs_from_temporary<G_Tp&, const G_Up&>>,
// Explicit:
not_<std::is_convertible<const G_Up&, G_Tp&>>
> = false>
explicit
constexpr
optional(const optional<G_Up>& g_rhs)
noexcept(std::is_nothrow_constructible<G_Tp&, G_Up&>::value)
{
if (g_rhs)
g_convert_ref_init_val(g_rhs.m_fwd());
}
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, const G_Up&>,
not_<reference_constructs_from_temporary<G_Tp&, const G_Up&>>,
// !Explicit:
std::is_convertible<const G_Up&, G_Tp&>
> = false>
constexpr
optional(const optional<G_Up>& g_rhs)
noexcept(std::is_nothrow_constructible<G_Tp&, G_Up&>::value)
{
if (g_rhs)
g_convert_ref_init_val(g_rhs.m_fwd());
}
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, const G_Up&>,
reference_constructs_from_temporary<G_Tp&, const G_Up&>,
// Explicit:
not_<std::is_convertible<const G_Up&, G_Tp&>>
> = false>
explicit
constexpr
optional(const optional<G_Up>& g_rhs) = delete;
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, const G_Up&>,
reference_constructs_from_temporary<G_Tp&, const G_Up&>,
// !Explicit:
std::is_convertible<const G_Up&, G_Tp&>
> = false>
constexpr
optional(const optional<G_Up>& g_rhs) = delete;
// optional<U>&&
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, G_Up>,
not_<reference_constructs_from_temporary<G_Tp&, G_Up>>,
// Explicit:
not_<std::is_convertible<G_Up, G_Tp&>>
> = false>
explicit
constexpr
optional(optional<G_Up>&& g_rhs)
noexcept(std::is_nothrow_constructible<G_Tp&, G_Up>::value)
{
if (g_rhs)
g_convert_ref_init_val(std::move(g_rhs).m_fwd());
}
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, G_Up>,
not_<reference_constructs_from_temporary<G_Tp&, G_Up>>,
// !Explicit:
std::is_convertible<G_Up, G_Tp&>
> = false>
constexpr
optional(optional<G_Up>&& g_rhs)
noexcept(std::is_nothrow_constructible<G_Tp&, G_Up>::value)
{
if (g_rhs)
g_convert_ref_init_val(std::move(g_rhs).m_fwd());
}
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, G_Up>,
reference_constructs_from_temporary<G_Tp&, G_Up>,
// Explicit:
not_<std::is_convertible<G_Up, G_Tp&>>
> = false>
explicit
constexpr
optional(optional<G_Up>&& g_rhs) = delete;
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, G_Up>,
reference_constructs_from_temporary<G_Tp&, G_Up>,
// !Explicit:
std::is_convertible<G_Up, G_Tp&>
> = false>
constexpr
optional(optional<G_Up>&& g_rhs) = delete;
// const optional<U>&&
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, const G_Up>,
not_<reference_constructs_from_temporary<G_Tp&, G_Up>>,
// Explicit:
not_<std::is_convertible<const G_Up, G_Tp&>>
> = false>
explicit
constexpr
optional(const optional<G_Up>&& g_rhs)
noexcept(std::is_nothrow_constructible<G_Tp&, const G_Up>::value)
{
if (g_rhs)
g_convert_ref_init_val(std::move(g_rhs).m_fwd());
}
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, const G_Up>,
not_<reference_constructs_from_temporary<G_Tp&, G_Up>>,
// !Explicit:
std::is_convertible<const G_Up, G_Tp&>
> = false>
constexpr
optional(const optional<G_Up>&& g_rhs)
noexcept(std::is_nothrow_constructible<G_Tp&, const G_Up>::value)
{
if (g_rhs)
g_convert_ref_init_val(std::move(g_rhs).m_fwd());
}
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, const G_Up>,
reference_constructs_from_temporary<G_Tp&, const G_Up>,
// Explicit:
not_<std::is_convertible<const G_Up, G_Tp&>>
> = false>
explicit
constexpr
optional(const optional<G_Up>&& g_rhs) = delete;
template<typename G_Up,
G_Requires<
not_<std::is_same<std::remove_cv_t<G_Tp>, optional<G_Up>>>,
not_<std::is_same<G_Tp&, G_Up>>,
std::is_constructible<G_Tp&, const G_Up>,
reference_constructs_from_temporary<G_Tp&, const G_Up>,
// !Explicit:
std::is_convertible<const G_Up, G_Tp&>
> = false>
constexpr
optional(const optional<G_Up>&& g_rhs) = delete;
GCC_BACKPORT20_CONSTEXPR ~optional() = default;
// Assignment.
constexpr optional& operator=(nullopt_t) noexcept
{
m_val = nullptr;
return *this;
}
constexpr optional& operator=(const optional&) noexcept = default;
template<typename G_Up,
G_Requires<
std::is_constructible<G_Tp&, G_Up>,
not_<reference_constructs_from_temporary<G_Tp&, G_Up>>
> = false>
constexpr G_Tp&
emplace(G_Up&& g_u)
noexcept(std::is_nothrow_constructible<G_Tp&, G_Up>::value)
{
g_convert_ref_init_val(std::forward<G_Up>(g_u));
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4300. Missing Returns: element in optional<T&>::emplace
return *m_val;
}
// Swap.
constexpr void swap(optional& g_rhs) noexcept
{ std::swap(m_val, g_rhs.m_val); }
// Observers.
constexpr G_Tp* operator->() const noexcept
{
__glibcxx_assert(m_val); // hardened precondition
return m_val;
}
constexpr G_Tp& operator*() const noexcept
{
__glibcxx_assert(m_val); // hardened precondition
return *m_val;
}
constexpr explicit operator bool() const noexcept
{
return m_val;
}
constexpr bool has_value() const noexcept
{
return m_val;
}
constexpr G_Tp& value() const;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4304. std::optional<NonReturnable&> is ill-formed due to value_or
template<typename G_Up = std::remove_cv_t<G_Tp>,
typename G_Tp_ = G_Tp,
G_Requires<
std::is_object<G_Tp_>,
not_<std::is_array<G_Tp_>>
> = false>
constexpr std::decay_t<G_Tp>
value_or(G_Up&& g_u) const;
// Monadic operations.
template<typename G_Fn>
constexpr auto
and_then(G_Fn&& g_f) const;
template<typename G_Fn>
constexpr
optional<std::remove_cv_t<g_invoke_result_t<G_Fn, G_Tp&>>>
transform(G_Fn&& g_f) const;
template<typename G_Fn,
G_Requires<g_is_invocable<G_Fn>> = false>
constexpr
optional
or_else(G_Fn&& g_f) const;
// Modifiers.
constexpr void reset() noexcept
{
m_val = nullptr;
}
private:
G_Tp *m_val = nullptr;
[[__gnu__::__always_inline__]]
constexpr G_Tp&
m_fwd() const noexcept
{ return *m_val; }
template<typename G_Up> friend class optional;
template<typename G_Up>
constexpr
void
g_convert_ref_init_val(G_Up&& g_u)
noexcept
{
G_Tp& g_r(std::forward<G_Up>(g_u));
m_val = std::addressof(g_r);
}
template<typename G_Fn, typename G_Value>
explicit constexpr
optional(G_Optional_func<G_Fn> g_f, G_Value&& g_v);
};
} // namespace gcc
#endif // GCC_BACKPORT_GLIBCXX_OPTIONAL_REF