123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #ifndef js_GCVariant_h
- #define js_GCVariant_h
- #include "mozilla/Variant.h"
- #include "js/GCPolicyAPI.h"
- #include "js/RootingAPI.h"
- #include "js/TracingAPI.h"
- namespace JS {
- // These template specializations allow Variant to be used inside GC wrappers.
- //
- // When matching on GC wrappers around Variants, matching should be done on
- // the wrapper itself. The matcher class's methods should take Handles or
- // MutableHandles. For example,
- //
- // struct MyMatcher
- // {
- // using ReturnType = const char*;
- // ReturnType match(HandleObject o) { return "object"; }
- // ReturnType match(HandleScript s) { return "script"; }
- // };
- //
- // Rooted<Variant<JSObject*, JSScript*>> v(cx, someScript);
- // MyMatcher mm;
- // v.match(mm);
- //
- // If you get compile errors about inability to upcast subclasses (e.g., from
- // NativeObject* to JSObject*) and are inside js/src, be sure to also include
- // "gc/Policy.h".
- namespace detail {
- template <typename... Ts>
- struct GCVariantImplementation;
- // The base case.
- template <typename T>
- struct GCVariantImplementation<T>
- {
- template <typename ConcreteVariant>
- static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
- T& thing = v->template as<T>();
- if (!mozilla::IsPointer<T>::value || thing)
- GCPolicy<T>::trace(trc, &thing, name);
- }
- template <typename Matcher, typename ConcreteVariant>
- static typename Matcher::ReturnType
- match(Matcher& matcher, Handle<ConcreteVariant> v) {
- const T& thing = v.get().template as<T>();
- return matcher.match(Handle<T>::fromMarkedLocation(&thing));
- }
- template <typename Matcher, typename ConcreteVariant>
- static typename Matcher::ReturnType
- match(Matcher& matcher, MutableHandle<ConcreteVariant> v) {
- T& thing = v.get().template as<T>();
- return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
- }
- };
- // The inductive case.
- template <typename T, typename... Ts>
- struct GCVariantImplementation<T, Ts...>
- {
- using Next = GCVariantImplementation<Ts...>;
- template <typename ConcreteVariant>
- static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
- if (v->template is<T>()) {
- T& thing = v->template as<T>();
- if (!mozilla::IsPointer<T>::value || thing)
- GCPolicy<T>::trace(trc, &thing, name);
- } else {
- Next::trace(trc, v, name);
- }
- }
- template <typename Matcher, typename ConcreteVariant>
- static typename Matcher::ReturnType
- match(Matcher& matcher, Handle<ConcreteVariant> v) {
- if (v.get().template is<T>()) {
- const T& thing = v.get().template as<T>();
- return matcher.match(Handle<T>::fromMarkedLocation(&thing));
- }
- return Next::match(matcher, v);
- }
- template <typename Matcher, typename ConcreteVariant>
- static typename Matcher::ReturnType
- match(Matcher& matcher, MutableHandle<ConcreteVariant> v) {
- if (v.get().template is<T>()) {
- T& thing = v.get().template as<T>();
- return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
- }
- return Next::match(matcher, v);
- }
- };
- } // namespace detail
- template <typename... Ts>
- struct GCPolicy<mozilla::Variant<Ts...>>
- {
- using Impl = detail::GCVariantImplementation<Ts...>;
- // Variants do not provide initial(). They do not have a default initial
- // value and one must be provided.
- static void trace(JSTracer* trc, mozilla::Variant<Ts...>* v, const char* name) {
- Impl::trace(trc, v, name);
- }
- };
- } // namespace JS
- namespace js {
- template <typename Outer, typename... Ts>
- class GCVariantOperations
- {
- using Impl = JS::detail::GCVariantImplementation<Ts...>;
- using Variant = mozilla::Variant<Ts...>;
- const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
- public:
- template <typename T>
- bool is() const {
- return variant().template is<T>();
- }
- template <typename T>
- JS::Handle<T> as() const {
- return Handle<T>::fromMarkedLocation(&variant().template as<T>());
- }
- template <typename Matcher>
- typename Matcher::ReturnType
- match(Matcher& matcher) const {
- return Impl::match(matcher, JS::Handle<Variant>::fromMarkedLocation(&variant()));
- }
- };
- template <typename Outer, typename... Ts>
- class MutableGCVariantOperations
- : public GCVariantOperations<Outer, Ts...>
- {
- using Impl = JS::detail::GCVariantImplementation<Ts...>;
- using Variant = mozilla::Variant<Ts...>;
- const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
- Variant& variant() { return static_cast<Outer*>(this)->get(); }
- public:
- template <typename T>
- JS::MutableHandle<T> as() {
- return JS::MutableHandle<T>::fromMarkedLocation(&variant().template as<T>());
- }
- template <typename Matcher>
- typename Matcher::ReturnType
- match(Matcher& matcher) {
- return Impl::match(matcher, JS::MutableHandle<Variant>::fromMarkedLocation(&variant()));
- }
- };
- template <typename... Ts>
- class RootedBase<mozilla::Variant<Ts...>>
- : public MutableGCVariantOperations<JS::Rooted<mozilla::Variant<Ts...>>, Ts...>
- { };
- template <typename... Ts>
- class MutableHandleBase<mozilla::Variant<Ts...>>
- : public MutableGCVariantOperations<JS::MutableHandle<mozilla::Variant<Ts...>>, Ts...>
- { };
- template <typename... Ts>
- class HandleBase<mozilla::Variant<Ts...>>
- : public GCVariantOperations<JS::Handle<mozilla::Variant<Ts...>>, Ts...>
- { };
- template <typename... Ts>
- class PersistentRootedBase<mozilla::Variant<Ts...>>
- : public MutableGCVariantOperations<JS::PersistentRooted<mozilla::Variant<Ts...>>, Ts...>
- { };
- } // namespace js
- #endif // js_GCVariant_h
|