Changeset View
Changeset View
Standalone View
Standalone View
libraries/source/spidermonkey/include-win32-debug/js/GCVariant.h
- This file was added.
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | |||||
* vim: set ts=8 sts=4 et sw=4 tw=99: | |||||
* 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 |
Wildfire Games · Phabricator