11cb0ef41Sopenharmony_ci// Copyright 2021 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef INCLUDE_V8_MAYBE_H_
61cb0ef41Sopenharmony_ci#define INCLUDE_V8_MAYBE_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include <type_traits>
91cb0ef41Sopenharmony_ci#include <utility>
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#include "v8-internal.h"  // NOLINT(build/include_directory)
121cb0ef41Sopenharmony_ci#include "v8config.h"     // NOLINT(build/include_directory)
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cinamespace v8 {
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_cinamespace api_internal {
171cb0ef41Sopenharmony_ci// Called when ToChecked is called on an empty Maybe.
181cb0ef41Sopenharmony_ciV8_EXPORT void FromJustIsNothing();
191cb0ef41Sopenharmony_ci}  // namespace api_internal
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci/**
221cb0ef41Sopenharmony_ci * A simple Maybe type, representing an object which may or may not have a
231cb0ef41Sopenharmony_ci * value, see https://hackage.haskell.org/package/base/docs/Data-Maybe.html.
241cb0ef41Sopenharmony_ci *
251cb0ef41Sopenharmony_ci * If an API method returns a Maybe<>, the API method can potentially fail
261cb0ef41Sopenharmony_ci * either because an exception is thrown, or because an exception is pending,
271cb0ef41Sopenharmony_ci * e.g. because a previous API call threw an exception that hasn't been caught
281cb0ef41Sopenharmony_ci * yet, or because a TerminateExecution exception was thrown. In that case, a
291cb0ef41Sopenharmony_ci * "Nothing" value is returned.
301cb0ef41Sopenharmony_ci */
311cb0ef41Sopenharmony_citemplate <class T>
321cb0ef41Sopenharmony_ciclass Maybe {
331cb0ef41Sopenharmony_ci public:
341cb0ef41Sopenharmony_ci  V8_INLINE bool IsNothing() const { return !has_value_; }
351cb0ef41Sopenharmony_ci  V8_INLINE bool IsJust() const { return has_value_; }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  /**
381cb0ef41Sopenharmony_ci   * An alias for |FromJust|. Will crash if the Maybe<> is nothing.
391cb0ef41Sopenharmony_ci   */
401cb0ef41Sopenharmony_ci  V8_INLINE T ToChecked() const { return FromJust(); }
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  /**
431cb0ef41Sopenharmony_ci   * Short-hand for ToChecked(), which doesn't return a value. To be used, where
441cb0ef41Sopenharmony_ci   * the actual value of the Maybe is not needed like Object::Set.
451cb0ef41Sopenharmony_ci   */
461cb0ef41Sopenharmony_ci  V8_INLINE void Check() const {
471cb0ef41Sopenharmony_ci    if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing();
481cb0ef41Sopenharmony_ci  }
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci  /**
511cb0ef41Sopenharmony_ci   * Converts this Maybe<> to a value of type T. If this Maybe<> is
521cb0ef41Sopenharmony_ci   * nothing (empty), |false| is returned and |out| is left untouched.
531cb0ef41Sopenharmony_ci   */
541cb0ef41Sopenharmony_ci  V8_WARN_UNUSED_RESULT V8_INLINE bool To(T* out) const {
551cb0ef41Sopenharmony_ci    if (V8_LIKELY(IsJust())) *out = value_;
561cb0ef41Sopenharmony_ci    return IsJust();
571cb0ef41Sopenharmony_ci  }
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci  /**
601cb0ef41Sopenharmony_ci   * Converts this Maybe<> to a value of type T. If this Maybe<> is
611cb0ef41Sopenharmony_ci   * nothing (empty), V8 will crash the process.
621cb0ef41Sopenharmony_ci   */
631cb0ef41Sopenharmony_ci  V8_INLINE T FromJust() const& {
641cb0ef41Sopenharmony_ci    if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing();
651cb0ef41Sopenharmony_ci    return value_;
661cb0ef41Sopenharmony_ci  }
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci  /**
691cb0ef41Sopenharmony_ci   * Converts this Maybe<> to a value of type T. If this Maybe<> is
701cb0ef41Sopenharmony_ci   * nothing (empty), V8 will crash the process.
711cb0ef41Sopenharmony_ci   */
721cb0ef41Sopenharmony_ci  V8_INLINE T FromJust() && {
731cb0ef41Sopenharmony_ci    if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing();
741cb0ef41Sopenharmony_ci    return std::move(value_);
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  /**
781cb0ef41Sopenharmony_ci   * Converts this Maybe<> to a value of type T, using a default value if this
791cb0ef41Sopenharmony_ci   * Maybe<> is nothing (empty).
801cb0ef41Sopenharmony_ci   */
811cb0ef41Sopenharmony_ci  V8_INLINE T FromMaybe(const T& default_value) const {
821cb0ef41Sopenharmony_ci    return has_value_ ? value_ : default_value;
831cb0ef41Sopenharmony_ci  }
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci  V8_INLINE bool operator==(const Maybe& other) const {
861cb0ef41Sopenharmony_ci    return (IsJust() == other.IsJust()) &&
871cb0ef41Sopenharmony_ci           (!IsJust() || FromJust() == other.FromJust());
881cb0ef41Sopenharmony_ci  }
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  V8_INLINE bool operator!=(const Maybe& other) const {
911cb0ef41Sopenharmony_ci    return !operator==(other);
921cb0ef41Sopenharmony_ci  }
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci private:
951cb0ef41Sopenharmony_ci  Maybe() : has_value_(false) {}
961cb0ef41Sopenharmony_ci  explicit Maybe(const T& t) : has_value_(true), value_(t) {}
971cb0ef41Sopenharmony_ci  explicit Maybe(T&& t) : has_value_(true), value_(std::move(t)) {}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  bool has_value_;
1001cb0ef41Sopenharmony_ci  T value_;
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  template <class U>
1031cb0ef41Sopenharmony_ci  friend Maybe<U> Nothing();
1041cb0ef41Sopenharmony_ci  template <class U>
1051cb0ef41Sopenharmony_ci  friend Maybe<U> Just(const U& u);
1061cb0ef41Sopenharmony_ci  template <class U, std::enable_if_t<!std::is_lvalue_reference_v<U>>*>
1071cb0ef41Sopenharmony_ci  friend Maybe<U> Just(U&& u);
1081cb0ef41Sopenharmony_ci};
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_citemplate <class T>
1111cb0ef41Sopenharmony_ciinline Maybe<T> Nothing() {
1121cb0ef41Sopenharmony_ci  return Maybe<T>();
1131cb0ef41Sopenharmony_ci}
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_citemplate <class T>
1161cb0ef41Sopenharmony_ciinline Maybe<T> Just(const T& t) {
1171cb0ef41Sopenharmony_ci  return Maybe<T>(t);
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci// Don't use forwarding references here but instead use two overloads.
1211cb0ef41Sopenharmony_ci// Forwarding references only work when type deduction takes place, which is not
1221cb0ef41Sopenharmony_ci// the case for callsites such as Just<Type>(t).
1231cb0ef41Sopenharmony_citemplate <class T, std::enable_if_t<!std::is_lvalue_reference_v<T>>* = nullptr>
1241cb0ef41Sopenharmony_ciinline Maybe<T> Just(T&& t) {
1251cb0ef41Sopenharmony_ci  return Maybe<T>(std::move(t));
1261cb0ef41Sopenharmony_ci}
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci// A template specialization of Maybe<T> for the case of T = void.
1291cb0ef41Sopenharmony_citemplate <>
1301cb0ef41Sopenharmony_ciclass Maybe<void> {
1311cb0ef41Sopenharmony_ci public:
1321cb0ef41Sopenharmony_ci  V8_INLINE bool IsNothing() const { return !is_valid_; }
1331cb0ef41Sopenharmony_ci  V8_INLINE bool IsJust() const { return is_valid_; }
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  V8_INLINE bool operator==(const Maybe& other) const {
1361cb0ef41Sopenharmony_ci    return IsJust() == other.IsJust();
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  V8_INLINE bool operator!=(const Maybe& other) const {
1401cb0ef41Sopenharmony_ci    return !operator==(other);
1411cb0ef41Sopenharmony_ci  }
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci private:
1441cb0ef41Sopenharmony_ci  struct JustTag {};
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  Maybe() : is_valid_(false) {}
1471cb0ef41Sopenharmony_ci  explicit Maybe(JustTag) : is_valid_(true) {}
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  bool is_valid_;
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  template <class U>
1521cb0ef41Sopenharmony_ci  friend Maybe<U> Nothing();
1531cb0ef41Sopenharmony_ci  friend Maybe<void> JustVoid();
1541cb0ef41Sopenharmony_ci};
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ciinline Maybe<void> JustVoid() { return Maybe<void>(Maybe<void>::JustTag()); }
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci}  // namespace v8
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci#endif  // INCLUDE_V8_MAYBE_H_
161