// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP_OPTIONAL
#define _LIBCPP_OPTIONAL

/*
    optional synopsis

// C++1z

namespace std {
  // [optional.optional], class template optional
  template <class T>
    class optional;

  template<class T>
   constexpr bool ranges::enable_view<optional<T>> = true;
  template<class T>
   constexpr auto format_kind<optional<T>> = range_format::disabled;

  template<class T>
    concept is-derived-from-optional = requires(const T& t) {       // exposition only
      []<class U>(const optional<U>&){ }(t);
    };

  // [optional.nullopt], no-value state indicator
  struct nullopt_t{see below };
  inline constexpr nullopt_t nullopt(unspecified );

  // [optional.bad.access], class bad_optional_access
  class bad_optional_access;

  // [optional.relops], relational operators
  template <class T, class U>
    constexpr bool operator==(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator!=(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator<(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator>(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator<=(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator>=(const optional<T>&, const optional<U>&);
  template<class T, three_way_comparable_with<T> U>
    constexpr compare_three_way_result_t<T, U>
      operator<=>(const optional<T>&, const optional<U>&); // since C++20

  // [optional.nullops], comparison with nullopt
  template<class T> constexpr bool operator==(const optional<T>&, nullopt_t) noexcept;
  template<class T> constexpr bool operator==(nullopt_t, const optional<T>&) noexcept; // until C++17
  template<class T> constexpr bool operator!=(const optional<T>&, nullopt_t) noexcept; // until C++17
  template<class T> constexpr bool operator!=(nullopt_t, const optional<T>&) noexcept; // until C++17
  template<class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept;  // until C++17
  template<class T> constexpr bool operator<(nullopt_t, const optional<T>&) noexcept;  // until C++17
  template<class T> constexpr bool operator<=(const optional<T>&, nullopt_t) noexcept; // until C++17
  template<class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept; // until C++17
  template<class T> constexpr bool operator>(const optional<T>&, nullopt_t) noexcept;  // until C++17
  template<class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept;  // until C++17
  template<class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept; // until C++17
  template<class T> constexpr bool operator>=(nullopt_t, const optional<T>&) noexcept; // until C++17
  template<class T>
    constexpr strong_ordering operator<=>(const optional<T>&, nullopt_t) noexcept;     // since C++20

  // [optional.comp.with.t], comparison with T
  template<class T, class U> constexpr bool operator==(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator==(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator!=(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator!=(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator<(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator<(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator<=(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator<=(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator>(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator>(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator>=(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&);
  template<class T, class U>
      requires (!is-derived-from-optional<U>) && three_way_comparable_with<T, U>
    constexpr compare_three_way_result_t<T, U>
      operator<=>(const optional<T>&, const U&);                                       // since C++20

  // [optional.specalg], specialized algorithms
  template<class T>
    void swap(optional<T>&, optional<T>&) noexcept(see below ); // constexpr in C++20

  template<class T>
    constexpr optional<see below > make_optional(T&&);
  template<class T, class... Args>
    constexpr optional<T> make_optional(Args&&... args);
  template<class T, class U, class... Args>
    constexpr optional<T> make_optional(initializer_list<U> il, Args&&... args);

  // [optional.hash], hash support
  template<class T> struct hash;
  template<class T> struct hash<optional<T>>;

  template<class T>
  class optional {
  public:
    using value_type = T;
    using iterator               = implementation-defined; // see [optional.iterators]
    using const_iterator         = implementation-defined; // see [optional.iterators]

    // [optional.ctor], constructors
    constexpr optional() noexcept;
    constexpr optional(nullopt_t) noexcept;
    constexpr optional(const optional &);
    constexpr optional(optional &&) noexcept(see below);
    template<class... Args>
      constexpr explicit optional(in_place_t, Args &&...);
    template<class U, class... Args>
      constexpr explicit optional(in_place_t, initializer_list<U>, Args &&...);
    template<class U = remove_cv_t<T>>
      constexpr explicit(see-below) optional(U &&);
    template<class U>
      explicit(see-below) optional(const optional<U> &);                          // constexpr in C++20
    template<class U>
      explicit(see-below) optional(optional<U> &&);                               // constexpr in C++20

    // [optional.dtor], destructor
    ~optional(); // constexpr in C++20

    // [optional.assign], assignment
    optional &operator=(nullopt_t) noexcept;                                      // constexpr in C++20
    constexpr optional &operator=(const optional &);
    constexpr optional &operator=(optional &&) noexcept(see below);
    template<class U = remove_cv_t<T>> optional &operator=(U &&);                              // constexpr in C++20
    template<class U> optional &operator=(const optional<U> &);                   // constexpr in C++20
    template<class U> optional &operator=(optional<U> &&);                        // constexpr in C++20
    template<class... Args> T& emplace(Args &&...);                               // constexpr in C++20
    template<class U, class... Args> T& emplace(initializer_list<U>, Args &&...); // constexpr in C++20

    // [optional.swap], swap
    void swap(optional &) noexcept(see below ); // constexpr in C++20

    // [optional.iterators], iterator support
    constexpr iterator begin() noexcept;
    constexpr const_iterator begin() const noexcept;
    constexpr iterator end() noexcept;
    constexpr const_iterator end() const noexcept;

    // [optional.observe], observers
    constexpr T const *operator->() const noexcept;
    constexpr T *operator->() noexcept;
    constexpr T const &operator*() const & noexcept;
    constexpr T &operator*() & noexcept;
    constexpr T &&operator*() && noexcept;
    constexpr const T &&operator*() const && noexcept;
    constexpr explicit operator bool() const noexcept;
    constexpr bool has_value() const noexcept;
    constexpr T const &value() const &;
    constexpr T &value() &;
    constexpr T &&value() &&;
    constexpr const T &&value() const &&;
    template<class U = remove_cv_t<T>> constexpr T value_or(U &&) const &;
    template<class U = remove_cv_t<T>> constexpr T value_or(U &&) &&;

    // [optional.monadic], monadic operations
    template<class F> constexpr auto and_then(F&& f) &;         // since C++23
    template<class F> constexpr auto and_then(F&& f) &&;        // since C++23
    template<class F> constexpr auto and_then(F&& f) const&;    // since C++23
    template<class F> constexpr auto and_then(F&& f) const&&;   // since C++23
    template<class F> constexpr auto transform(F&& f) &;        // since C++23
    template<class F> constexpr auto transform(F&& f) &&;       // since C++23
    template<class F> constexpr auto transform(F&& f) const&;   // since C++23
    template<class F> constexpr auto transform(F&& f) const&&;  // since C++23
    template<class F> constexpr optional or_else(F&& f) &&;     // since C++23
    template<class F> constexpr optional or_else(F&& f) const&; // since C++23

    // [optional.mod], modifiers
    void reset() noexcept;                                      // constexpr in C++20

  private:
    T *val;         // exposition only
  };

  template<class T>
    optional(T) -> optional<T>;

  template<class T>
  class optional<T&> { // since C++26
  public:
    using value_type     = T;
    using iterator       = implementation-defined;              // see [optional.ref.iterators]

  public:
    // [optional.ref.ctor], constructors
    constexpr optional() noexcept = default;
    constexpr optional(nullopt_t) noexcept : optional() {}
    constexpr optional(const optional& rhs) noexcept = default;

    template<class Arg>
      constexpr explicit optional(in_place_t, Arg&& arg);
    template<class U>
      constexpr explicit(see below) optional(U&& u) noexcept(see below);
    template<class U>
      constexpr explicit(see below) optional(optional<U>& rhs) noexcept(see below);
    template<class U>
      constexpr explicit(see below) optional(const optional<U>& rhs) noexcept(see below);
    template<class U>
      constexpr explicit(see below) optional(optional<U>&& rhs) noexcept(see below);
    template<class U>
      constexpr explicit(see below) optional(const optional<U>&& rhs) noexcept(see below);

    constexpr ~optional() = default;

    // [optional.ref.assign], assignment
    constexpr optional& operator=(nullopt_t) noexcept;
    constexpr optional& operator=(const optional& rhs) noexcept = default;

    template<class U> constexpr T& emplace(U&& u) noexcept(see below);

    // [optional.ref.swap], swap
    constexpr void swap(optional& rhs) noexcept;

    // [optional.ref.iterators], iterator support
    constexpr iterator begin() const noexcept;
    constexpr iterator end() const noexcept;

    // [optional.ref.observe], observers
    constexpr T*       operator->() const noexcept;
    constexpr T&       operator*() const noexcept;
    constexpr explicit operator bool() const noexcept;
    constexpr bool     has_value() const noexcept;
    constexpr T&       value() const;                           // freestanding-deleted
    template<class U = remove_cv_t<T>>
      constexpr remove_cv_t<T> value_or(U&& u) const;

    // [optional.ref.monadic], monadic operations
    template<class F> constexpr auto and_then(F&& f) const;
    template<class F> constexpr optional<invoke_result_t<F, T&>> transform(F&& f) const;
    template<class F> constexpr optional or_else(F&& f) const;

    // [optional.ref.mod], modifiers
    constexpr void reset() noexcept;

  private:
    T* val = nullptr;                                           // exposition only

    // [optional.ref.expos], exposition only helper functions
    template<class U>
      constexpr void convert-ref-init-val(U&& u);               // exposition only
  };

} // namespace std

*/

#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
#  include <__cxx03/__config>
#else
#  include <__config>
#  include <version>

#  include <__optional/common.h>
#  include <__optional/comparison.h>
#  include <__optional/hash.h>
#  include <__optional/make_optional.h>
#  include <__optional/optional.h>
#  include <__optional/optional_ref.h>
#  include <__optional/swap.h>

#  include <initializer_list>

// standard-mandated includes
// [optional.syn]
#  include <compare>

// [iterator.range]
#  include <__iterator/access.h>
#  include <__iterator/data.h>
#  include <__iterator/empty.h>
#  include <__iterator/reverse_access.h>
#  include <__iterator/size.h>

#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#    pragma GCC system_header
#  endif

#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)

#endif // _LIBCPP_OPTIONAL
