blob: 8e33771a8f6a511c4c62fa5e04e30a1511aaab63 [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/>.
/** @file bits/optional_ref.h
* This is an internal header file, included by other library headers.
* Do not attempt to use it directly. @headername{optional}
*/
#ifndef _GLIBCXX_OPTIONAL_REF
#define _GLIBCXX_OPTIONAL_REF 1
#ifdef _GLIBCXX_SYSHDR
#pragma GCC system_header
#endif
#ifdef __glibcxx_optional // C++ >= 17
#include <type_traits>
#include <bits/move.h>
#include <bits/inplace_tags.h>
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Iterator, typename _Container>
class __normal_iterator;
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace __gnu_cxx
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/**
* @addtogroup utilities
* @{
*/
template<typename _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 _Construct { _Token };
// Must be constexpr for nullopt_t to be literal.
explicit constexpr nullopt_t(_Construct) noexcept { }
};
/// Tag to disengage optional objects.
inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token };
template<typename _Fn> struct _Optional_func { _Fn& _M_f; };
template<typename _Tp>
inline constexpr bool __is_valid_contained_type_for_optional =
(
#if __glibcxx_optional >= 202506L
is_lvalue_reference_v<_Tp> ||
#endif
(is_object_v<_Tp> && is_destructible_v<_Tp> && !is_array_v<_Tp>)
)
&& !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, nullopt_t>
&& !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, in_place_t>;
#if __glibcxx_optional >= 202506L // C++26
template<typename _Tp>
class optional<_Tp&>;
template<typename _Tp>
constexpr bool __is_optional_ref_v = false;
template<typename _Tp>
constexpr bool __is_optional_ref_v<optional<_Tp&>> = true;
template<typename _Tp>
struct __optional_ref_base
{};
#ifdef __glibcxx_optional_range_support // >= C++26
template<typename _Tp>
struct __optional_ref_base<_Tp[]>
{};
template<typename _Tp>
requires is_object_v<_Tp>
struct __optional_ref_base<_Tp>
{
using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional<_Tp&>>;
};
#endif // __glibcxx_optional_range_support
template<typename _Tp>
class optional<_Tp&> : public __optional_ref_base<_Tp>
{
static_assert(__is_valid_contained_type_for_optional<_Tp&>);
public:
using value_type = _Tp;
constexpr static optional
_S_from_ptr(_Tp* __ptr)
{
optional __res;
__res._M_val = __ptr;
return __res;
}
// Constructors.
constexpr optional() noexcept = default;
constexpr optional(nullopt_t) noexcept : optional() {}
constexpr optional(const optional&) noexcept = default;
template<typename _Arg>
requires is_constructible_v<_Tp&, _Arg>
&& (!reference_constructs_from_temporary_v<_Tp&, _Arg>)
explicit constexpr
optional(in_place_t, _Arg&& __arg)
{
__convert_ref_init_val(std::forward<_Arg>(__arg));
}
template<typename _Up>
requires (!is_same_v<remove_cvref_t<_Up>, optional>)
&& (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
&& is_constructible_v<_Tp&, _Up>
&& (!reference_constructs_from_temporary_v<_Tp&, _Up>)
explicit(!is_convertible_v<_Up, _Tp&>)
constexpr
optional(_Up&& __u)
noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
{
__convert_ref_init_val(std::forward<_Up>(__u));
}
template<typename _Up>
requires (!is_same_v<remove_cvref_t<_Up>, optional>)
&& (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
&& is_constructible_v<_Tp&, _Up>
&& reference_constructs_from_temporary_v<_Tp&, _Up>
explicit(!is_convertible_v<_Up, _Tp&>)
constexpr
optional(_Up&& __u) = delete;
// optional<U> &
template<typename _Up>
requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
&& (!is_same_v<_Tp&, _Up>)
&& is_constructible_v<_Tp&, _Up&>
&& (!reference_constructs_from_temporary_v<_Tp&, _Up&>)
explicit(!is_convertible_v<_Up&, _Tp&>)
constexpr
optional(optional<_Up>& __rhs)
noexcept(is_nothrow_constructible_v<_Tp&, _Up&>)
{
if (__rhs)
__convert_ref_init_val(__rhs._M_fwd());
}
template<typename _Up>
requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
&& (!is_same_v<_Tp&, _Up>)
&& is_constructible_v<_Tp&, _Up&>
&& reference_constructs_from_temporary_v<_Tp&, _Up&>
explicit(!is_convertible_v<_Up&, _Tp&>)
constexpr
optional(optional<_Up>& __rhs) = delete;
// const optional<U>&
template<typename _Up>
requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
&& (!is_same_v<_Tp&, _Up>)
&& is_constructible_v<_Tp&, const _Up&>
&& (!reference_constructs_from_temporary_v<_Tp&, const _Up&>)
explicit(!is_convertible_v<const _Up&, _Tp&>)
constexpr
optional(const optional<_Up>& __rhs)
noexcept(is_nothrow_constructible_v<_Tp&, _Up&>)
{
if (__rhs)
__convert_ref_init_val(__rhs._M_fwd());
}
template<typename _Up>
requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
&& (!is_same_v<_Tp&, _Up>)
&& is_constructible_v<_Tp&, const _Up&>
&& reference_constructs_from_temporary_v<_Tp&, const _Up&>
explicit(!is_convertible_v<const _Up&, _Tp&>)
constexpr
optional(const optional<_Up>& __rhs) = delete;
// optional<U>&&
template<typename _Up>
requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
&& (!is_same_v<_Tp&, _Up>)
&& is_constructible_v<_Tp&, _Up>
&& (!reference_constructs_from_temporary_v<_Tp&, _Up>)
explicit(!is_convertible_v<_Up, _Tp&>)
constexpr
optional(optional<_Up>&& __rhs)
noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
{
if (__rhs)
__convert_ref_init_val(std::move(__rhs)._M_fwd());
}
template<typename _Up>
requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
&& (!is_same_v<_Tp&, _Up>)
&& is_constructible_v<_Tp&, _Up>
&& reference_constructs_from_temporary_v<_Tp&, _Up>
explicit(!is_convertible_v<_Up, _Tp&>)
constexpr
optional(optional<_Up>&& __rhs) = delete;
// const optional<U>&&
template<typename _Up>
requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
&& (!is_same_v<_Tp&, _Up>)
&& is_constructible_v<_Tp&, const _Up>
&& (!reference_constructs_from_temporary_v<_Tp&, _Up>)
explicit(!is_convertible_v<const _Up, _Tp&>)
constexpr
optional(const optional<_Up>&& __rhs)
noexcept(is_nothrow_constructible_v<_Tp&, const _Up>)
{
if (__rhs)
__convert_ref_init_val(std::move(__rhs)._M_fwd());
}
template<typename _Up>
requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
&& (!is_same_v<_Tp&, _Up>)
&& is_constructible_v<_Tp&, const _Up>
&& reference_constructs_from_temporary_v<_Tp&, const _Up>
explicit(!is_convertible_v<const _Up, _Tp&>)
constexpr
optional(const optional<_Up>&& __rhs) = delete;
constexpr ~optional() = default;
// Assignment.
constexpr optional& operator=(nullopt_t) noexcept
{
_M_val = nullptr;
return *this;
}
constexpr optional& operator=(const optional&) noexcept = default;
template<typename _Up>
requires is_constructible_v<_Tp&, _Up>
&& (!reference_constructs_from_temporary_v<_Tp&, _Up>)
constexpr _Tp&
emplace(_Up&& __u)
noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
{
__convert_ref_init_val(std::forward<_Up>(__u));
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4300. Missing Returns: element in optional<T&>::emplace
return *_M_val;
}
// Swap.
constexpr void swap(optional& __rhs) noexcept
{ std::swap(_M_val, __rhs._M_val); }
#ifdef __glibcxx_optional_range_support // >= C++26
// Iterator support.
constexpr auto begin() const noexcept
requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>);
constexpr auto end() const noexcept
requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>);
#endif // __glibcxx_optional_range_support
// Observers.
constexpr _Tp* operator->() const noexcept
{
__glibcxx_assert(_M_val); // hardened precondition
return _M_val;
}
constexpr _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 _Tp& value() const;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4304. std::optional<NonReturnable&> is ill-formed due to value_or
template<typename _Up = remove_cv_t<_Tp>>
requires is_object_v<_Tp> && (!is_array_v<_Tp>)
constexpr decay_t<_Tp>
value_or(_Up&& __u) const;
// Monadic operations.
template<typename _Fn>
constexpr auto
and_then(_Fn&& __f) const;
template<typename _Fn>
constexpr
optional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>>
transform(_Fn&& __f) const;
template<typename _Fn>
requires is_invocable_v<_Fn>
constexpr
optional
or_else(_Fn&& __f) const;
// Modifiers.
constexpr void reset() noexcept
{
_M_val = nullptr;
}
private:
_Tp *_M_val = nullptr;
[[__gnu__::__always_inline__]]
constexpr _Tp&
_M_fwd() const noexcept
{ return *_M_val; }
template<typename _Up> friend class optional;
template<typename _Up>
constexpr
void
__convert_ref_init_val(_Up&& __u)
noexcept
{
_Tp& __r(std::forward<_Up>(__u));
_M_val = std::addressof(__r);
}
template<typename _Fn, typename _Value>
explicit constexpr
optional(_Optional_func<_Fn> __f, _Value&& __v);
};
#endif // __glibcxx_optional >= 202506L
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // __glibcxx_optional
#endif // _GLIBCXX_OPTIONAL_REF