gecko-dev/xpcom/ds/nsGkAtoms.h

235 строки
8.2 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 nsGkAtoms_h___
#define nsGkAtoms_h___
#include "nsAtom.h"
// Static atoms are structured carefully to satisfy a lot of constraints.
//
// - We have ~2300 static atoms.
//
// - We want them to be constexpr so they end up in .rodata, and thus shared
// between processes, minimizing memory usage.
//
// - We need them to be in an array, so we can iterate over them (for
// registration and lookups).
//
// - Each static atom has a string literal associated with it. We can't use a
// pointer to the string literal because then the atoms won't end up in
// .rodata. Therefore the string literals and the atoms must be arranged in a
// way such that a numeric index can be used instead. This numeric index
// (nsStaticAtom::mStringOffset) must be computable at compile-time to keep
// the static atom constexpr. It should also not be too large (a uint32_t is
// reasonable).
//
// - Each static atom stores the hash value of its associated string literal;
// it's used in various ways. The hash value must be computed at
// compile-time, to keep the static atom constexpr.
//
// - As well as accessing each static atom via array indexing, we need an
// individual pointer, e.g. nsGkAtoms::foo. Ideally this would be constexpr
// so it doesn't take up any space in memory. Unfortunately MSVC's constexpr
// support is buggy and so this isn't possible yet. See bug 1449787.
//
// - The array of static atoms can't be in a .h file, because it's a huge
// constexpr expression, which would blow out compile times. But the
// individual pointers for the static atoms must be in a .h file so they are
// public.
//
// nsGkAtoms below defines static atoms in a way that satisfies these
// constraints. It uses nsGkAtomList.h, which defines the names and values of
// the atoms.
//
// nsGkAtomList.h is generated by StaticAtoms.py and has entries that look
// like this:
//
// GK_ATOM(one, "one", 0x01234567, nsStaticAtom, Atom)
// GK_ATOM(two, "two", 0x12345678, nsICSSPseudoElement, PseudoElementAtom)
// GK_ATOM(three, "three", 0x23456789, nsICSSAnonBoxPseudo, InheritingAnonBoxAtom)
//
// After macro expansion, the atom definitions look like the following:
//
// ====> nsGkAtoms.h <====
//
// namespace mozilla {
// namespace detail {
//
// struct GkAtoms
// {
// // The declaration of each atom's string.
// const char16_t one_string[sizeof("one")];
// const char16_t two_string[sizeof("two")];
// const char16_t three_string[sizeof("three")];
//
// // The enum value for each atom.
// enum class Atoms {
// one_,
// two_,
// three_,
// AtomsCount
// };
//
// const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
// };
//
// } // namespace detail
// } // namespace mozilla
//
// // This class holds the pointers to the individual atoms.
// class nsGkAtoms
// {
// private:
// // This is a useful handle to the array of atoms, used below and also
// // possibly by Rust code.
// static const nsStaticAtom* const sAtoms;
//
// // The number of atoms, used below.
// static constexpr size_t sAtomsLen =
// static_cast<size_t>(detail::MyAtoms::Atoms::AtomsCount);
//
// public:
// // These types are not `nsStaticAtom* const`, etc. -- even though these
// // atoms are immutable -- because they are often passed to functions with
// // `nsAtom*` parameters, i.e. that can be passed both dynamic and
// // static.
// static nsStaticAtom* one;
// static nsICSSPseudoElement* two;
// static nsICSSAnonBoxPseudo* three;
// };
//
// ====> nsGkAtoms.cpp <====
//
// namespace mozilla {
// namespace detail {
//
// // Need to suppress some MSVC warning weirdness with WrappingMultiply().
// MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
// // Because this is `constexpr` it ends up in read-only memory where it can
// // be shared between processes.
// static constexpr GkAtoms gGkAtoms = {
// // The initialization of each atom's string.
// u"one",
// u"two",
// u"three",
// {
// // The initialization of the atoms themselves.
// nsStaticAtom(
// u"one", 3,
// 0x01234567,
// offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::one)]) -
// offsetof(GkAtoms, one_string)),
// nsStaticAtom(
// u"two", 3,
// 0x12345678,
// offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::two)]) -
// offsetof(GkAtoms, two_string)),
// nsStaticAtom(
// u"three", 3,
// 0x23456789,
// offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::three)]) -
// offsetof(GkAtoms, three_string)),
// }
// };
// MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
//
// } // namespace detail
// } // namespace mozilla
//
// const nsStaticAtom* const nsGkAtoms::sAtoms =
// mozilla::detail::gGkAtoms.mAtoms;
//
// // Definition of the pointer to the static atom.
// nsStaticAtom* nsGkAtoms::one =
// const_cast<nsStaticAtom*>(static_cast<const nsStaticAtom*>(
// &detail::gGkAtoms.mAtoms[
// static_cast<size_t>(detail::GkAtoms::Atoms::one)]);
// nsICSSPseudoElement* nsGkAtoms::two =
// const_cast<nsICSSPseudoElement*>(static_cast<const nsICSSPseudoElement*>(
// &detail::gGkAtoms.mAtoms[
// static_cast<size_t>(detail::GkAtoms::Atoms::two)]);
// nsICSSAnonBoxPseudo* nsGkAtoms::three =
// const_cast<nsICSSAnonBoxPseudo*>(static_cast<const nsICSSAnonBoxPseudo*>(
// &detail::gGkAtoms.mAtoms[
// static_cast<size_t>(detail::GkAtoms::Atoms::three)]);
// Trivial subclasses of nsStaticAtom so that function signatures can require
// an atom from a specific atom list.
#define DEFINE_STATIC_ATOM_SUBCLASS(name_) \
class name_ : public nsStaticAtom \
{ \
public: \
constexpr name_(const char16_t* aStr, uint32_t aLength, \
uint32_t aHash, uint32_t aOffset) \
: nsStaticAtom(aStr, aLength, aHash, aOffset) {} \
};
DEFINE_STATIC_ATOM_SUBCLASS(nsICSSAnonBoxPseudo)
DEFINE_STATIC_ATOM_SUBCLASS(nsICSSPseudoElement)
#undef DEFINE_STATIC_ATOM_SUBCLASS
namespace mozilla {
namespace detail {
// This `detail` class contains the atom strings and the atom objects.
// Because they are together in a class, the mStringOffset field of the
// atoms will be small and can be initialized at compile time.
//
// A `detail` namespace is used because the things within it aren't directly
// referenced by external users of these static atoms.
struct GkAtoms
{
// The declaration of each atom's string.
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
const char16_t name_##_string[sizeof(value_)];
#include "nsGkAtomList.h"
#undef GK_ATOM
// The enum value for each atom.
enum class Atoms {
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
name_,
#include "nsGkAtomList.h"
#undef GK_ATOM
AtomsCount
};
const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
};
} // namespace detail
} // namespace mozilla
class nsGkAtoms
{
private:
static const nsStaticAtom* const sAtoms;
static constexpr size_t sAtomsLen =
static_cast<size_t>(mozilla::detail::GkAtoms::Atoms::AtomsCount);
public:
static void RegisterStaticAtoms();
static nsStaticAtom* GetAtomByIndex(size_t aIndex)
{
MOZ_ASSERT(aIndex < sAtomsLen);
return const_cast<nsStaticAtom*>(&sAtoms[aIndex]);
}
// The declaration of the pointer to each static atom.
//
// XXX: Eventually this should be combined with its definition and the
// pointer should be made `constexpr`. See bug 1449787.
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
static type_* name_;
#include "nsGkAtomList.h"
#undef GK_ATOM
};
#endif /* nsGkAtoms_h___ */