blob: f96703717625353359cdf9a52dbbe9e3aee49290 [file]
// Copyright 2026 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FXJS_GC_CONTAINERS_H_
#define FXJS_GC_CONTAINERS_H_
#include <list>
#include <map>
#include <set>
#include <type_traits>
#include <vector>
#include "fxjs/gc/container_trace.h"
#include "v8/include/cppgc/garbage-collected.h"
#include "v8/include/cppgc/member.h"
#include "v8/include/cppgc/type-traits.h"
#include "v8/include/cppgc/visitor.h"
// These container wrappers are intended to replace stack-local containers
// (e.g. `std::vector`, `std::set`, `std::map`) of garbage-collected objects.
// On the stack, instances should generally be held via `cppgc::Persistent<>`.
// Although holding `cppgc::Persistent<>` handles on the stack is typically an
// anti-pattern in garbage-collected environments, it is required here due to
// the "malloc'd" backing-stores. Holding a single persistent handle
// to a wrapper minimizes overhead compared to holding individual handles for
// every element.
namespace fxgc {
namespace internal {
template <typename T>
using MemberIfNeeded =
std::conditional_t<cppgc::IsGarbageCollectedOrMixinTypeV<T>,
cppgc::Member<T>,
T>;
} // namespace internal
template <typename T>
class GCedVector final : public cppgc::GarbageCollected<GCedVector<T>> {
public:
template <typename V = cppgc::Visitor>
void Trace(V* visitor) const {
ContainerTrace(visitor, storage);
}
std::vector<cppgc::Member<T>> storage;
};
template <typename T>
class GCedSet final : public cppgc::GarbageCollected<GCedSet<T>> {
public:
template <typename V = cppgc::Visitor>
void Trace(V* visitor) const {
ContainerTrace(visitor, storage);
}
std::set<cppgc::Member<T>> storage;
};
template <typename T>
class GCedList final : public cppgc::GarbageCollected<GCedList<T>> {
public:
template <typename V = cppgc::Visitor>
void Trace(V* visitor) const {
ContainerTrace(visitor, storage);
}
std::list<cppgc::Member<T>> storage;
};
template <typename Key, typename Value>
class GCedMap final : public cppgc::GarbageCollected<GCedMap<Key, Value>> {
public:
static_assert(cppgc::IsGarbageCollectedOrMixinTypeV<Key> ||
cppgc::IsGarbageCollectedOrMixinTypeV<Value>,
"Use std::map instead for non-gc'd key-value pairs");
template <typename V = cppgc::Visitor>
void Trace(V* visitor) const {
ContainerTrace(visitor, storage);
}
std::map<internal::MemberIfNeeded<Key>, internal::MemberIfNeeded<Value>>
storage;
};
} // namespace fxgc
using fxgc::GCedList;
using fxgc::GCedMap;
using fxgc::GCedSet;
using fxgc::GCedVector;
#endif // FXJS_GC_CONTAINERS_H_