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