tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

GCVariant.h (5576B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef js_GCVariant_h
      8 #define js_GCVariant_h
      9 
     10 #include "mozilla/Variant.h"
     11 
     12 #include <type_traits>
     13 
     14 #include "js/GCPolicyAPI.h"
     15 #include "js/RootingAPI.h"
     16 #include "js/TracingAPI.h"
     17 
     18 namespace JS {
     19 
     20 // These template specializations allow Variant to be used inside GC wrappers.
     21 //
     22 // When matching on GC wrappers around Variants, matching should be done on
     23 // the wrapper itself. The matcher class's methods should take Handles or
     24 // MutableHandles. For example,
     25 //
     26 //   struct MyMatcher
     27 //   {
     28 //        using ReturnType = const char*;
     29 //        ReturnType match(HandleObject o) { return "object"; }
     30 //        ReturnType match(HandleScript s) { return "script"; }
     31 //   };
     32 //
     33 //   Rooted<Variant<JSObject*, JSScript*>> v(cx, someScript);
     34 //   MyMatcher mm;
     35 //   v.match(mm);
     36 //
     37 // If you get compile errors about inability to upcast subclasses (e.g., from
     38 // NativeObject* to JSObject*) and are inside js/src, be sure to also include
     39 // "gc/Policy.h".
     40 
     41 namespace detail {
     42 
     43 template <typename... Ts>
     44 struct GCVariantImplementation;
     45 
     46 // The base case.
     47 template <typename T>
     48 struct GCVariantImplementation<T> {
     49  template <typename ConcreteVariant>
     50  static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
     51    T& thing = v->template as<T>();
     52    GCPolicy<T>::trace(trc, &thing, name);
     53  }
     54 
     55  template <typename Matcher, typename ConcreteVariant>
     56  static typename Matcher::ReturnType match(Matcher& matcher,
     57                                            Handle<ConcreteVariant> v) {
     58    const T& thing = v.get().template as<T>();
     59    return matcher.match(Handle<T>::fromMarkedLocation(&thing));
     60  }
     61 
     62  template <typename Matcher, typename ConcreteVariant>
     63  static typename Matcher::ReturnType match(Matcher& matcher,
     64                                            MutableHandle<ConcreteVariant> v) {
     65    T& thing = v.get().template as<T>();
     66    return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
     67  }
     68 };
     69 
     70 // The inductive case.
     71 template <typename T, typename... Ts>
     72 struct GCVariantImplementation<T, Ts...> {
     73  using Next = GCVariantImplementation<Ts...>;
     74 
     75  template <typename ConcreteVariant>
     76  static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
     77    if (v->template is<T>()) {
     78      T& thing = v->template as<T>();
     79      GCPolicy<T>::trace(trc, &thing, name);
     80    } else {
     81      Next::trace(trc, v, name);
     82    }
     83  }
     84 
     85  template <typename Matcher, typename ConcreteVariant>
     86  static typename Matcher::ReturnType match(Matcher& matcher,
     87                                            Handle<ConcreteVariant> v) {
     88    if (v.get().template is<T>()) {
     89      const T& thing = v.get().template as<T>();
     90      return matcher.match(Handle<T>::fromMarkedLocation(&thing));
     91    }
     92    return Next::match(matcher, v);
     93  }
     94 
     95  template <typename Matcher, typename ConcreteVariant>
     96  static typename Matcher::ReturnType match(Matcher& matcher,
     97                                            MutableHandle<ConcreteVariant> v) {
     98    if (v.get().template is<T>()) {
     99      T& thing = v.get().template as<T>();
    100      return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
    101    }
    102    return Next::match(matcher, v);
    103  }
    104 };
    105 
    106 }  // namespace detail
    107 
    108 template <typename... Ts>
    109 struct GCPolicy<mozilla::Variant<Ts...>> {
    110  using Impl = detail::GCVariantImplementation<Ts...>;
    111 
    112  static void trace(JSTracer* trc, mozilla::Variant<Ts...>* v,
    113                    const char* name) {
    114    Impl::trace(trc, v, name);
    115  }
    116 
    117  static bool isValid(const mozilla::Variant<Ts...>& v) {
    118    return v.match([](auto& v) {
    119      return GCPolicy<std::remove_reference_t<decltype(v)>>::isValid(v);
    120    });
    121  }
    122 };
    123 
    124 }  // namespace JS
    125 
    126 namespace js {
    127 
    128 template <typename Wrapper, typename... Ts>
    129 class WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper> {
    130  using Impl = JS::detail::GCVariantImplementation<Ts...>;
    131  using Variant = mozilla::Variant<Ts...>;
    132 
    133  const Variant& variant() const {
    134    return static_cast<const Wrapper*>(this)->get();
    135  }
    136 
    137 public:
    138  template <typename T>
    139  bool is() const {
    140    return variant().template is<T>();
    141  }
    142 
    143  template <typename T>
    144  JS::Handle<T> as() const {
    145    return JS::Handle<T>::fromMarkedLocation(&variant().template as<T>());
    146  }
    147 
    148  template <typename Matcher>
    149  typename Matcher::ReturnType match(Matcher& matcher) const {
    150    return Impl::match(matcher,
    151                       JS::Handle<Variant>::fromMarkedLocation(&variant()));
    152  }
    153 };
    154 
    155 template <typename Wrapper, typename... Ts>
    156 class MutableWrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
    157    : public WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper> {
    158  using Impl = JS::detail::GCVariantImplementation<Ts...>;
    159  using Variant = mozilla::Variant<Ts...>;
    160 
    161  const Variant& variant() const {
    162    return static_cast<const Wrapper*>(this)->get();
    163  }
    164  Variant& variant() { return static_cast<Wrapper*>(this)->get(); }
    165 
    166 public:
    167  template <typename T>
    168  JS::MutableHandle<T> as() {
    169    return JS::MutableHandle<T>::fromMarkedLocation(
    170        &variant().template as<T>());
    171  }
    172 
    173  template <typename Matcher>
    174  typename Matcher::ReturnType match(Matcher& matcher) {
    175    return Impl::match(
    176        matcher, JS::MutableHandle<Variant>::fromMarkedLocation(&variant()));
    177  }
    178 };
    179 
    180 }  // namespace js
    181 
    182 #endif  // js_GCVariant_h