gecko-dev/xpcom/ds/nsStaticAtom.h
Narcis Beleuzu d20e8e7674 Backed out 8 changesets (bug 1483121, bug 1482782) for build bustages on nsDirectoryService.cpp. CLOSED TREE
Backed out changeset 0a8334bbcf45 (bug 1483121)
Backed out changeset cb2dcb859071 (bug 1482782)
Backed out changeset c834d4ca2eef (bug 1482782)
Backed out changeset 887de0efbb67 (bug 1482782)
Backed out changeset 018fdb50a6be (bug 1482782)
Backed out changeset 33a8aa8096c9 (bug 1482782)
Backed out changeset e3632354f16e (bug 1482782)
Backed out changeset 46f8319bee82 (bug 1482782)
2018-08-15 09:14:41 +03:00

259 lines
9.1 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 nsStaticAtom_h__
#define nsStaticAtom_h__
#include <stdint.h>
#include "nsAtom.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Maybe.h"
// Static atoms are structured carefully to satisfy a lot of constraints.
//
// - We have ~2700 static atoms. They are divided across ~4 classes, with the
// majority in nsGkAtoms.
//
// - 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.
//
// The macros below are used to define static atoms in a way that satisfies
// these constraints. They are used in conjunction with a .h file that defines
// the names and values of the atoms.
//
// For example, the .h file might be called MyAtomList.h and look like this:
//
// MY_ATOM(one, "one")
// MY_ATOM(two, "two")
// MY_ATOM(three, "three")
//
// The code defining the static atoms should look something like the following.
// ("<<<"/"---"/">>>" markers are used below to indicate what the macros look
// like before and after expansion.)
//
// ====> MyAtoms.h <====
//
// // A `detail` namespace is used because the things within it aren't
// // directly referenced by external users of these static atoms.
// 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.
// struct MyAtoms
// {
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// const char16_t one_string[4];
// const char16_t two_string[4];
// const char16_t three_string[6];
// >>>
//
// enum class Atoms {
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_ENUM(name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// one,
// two,
// three,
// >>>
// AtomsCount
// };
//
// const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
// };
//
// } // namespace detail
//
// // This class holds the pointers to the individual atoms.
// class nsMyAtoms
// {
// 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:
// // The type is not `nsStaticAtom* const` -- 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.
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(nsStaticAtom, name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// static nsStaticAtom* one;
// static nsStaticAtom* two;
// static nsStaticAtom* three;
// >>>
// };
//
// ====> MyAtoms.cpp <====
//
// 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 MyAtoms gMyAtoms = {
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_STRING(value_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// u"one",
// u"two",
// u"three",
// >>>
// {
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_ATOM(nsStaticAtom, MyAtoms, name_, value_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// nsStaticAtom(
// u"one", 3,
// offsetof(MyAtoms, mAtoms[static_cast<size_t>(MyAtoms::Atoms::one)]) -
// offsetof(MyAtoms, one_string)),
// nsStaticAtom(
// u"two", 3,
// offsetof(MyAtoms, mAtoms[static_cast<size_t>(MyAtoms::Atoms::two)]) -
// offsetof(MyAtoms, two_string)),
// nsStaticAtom(
// u"three", 3,
// offsetof(MyAtoms, mAtoms[static_cast<size_t>(MyAtoms::Atoms::three)]) -
// offsetof(MyAtoms, three_string)),
// >>>
// }
// };
// MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
//
// } // namespace detail
//
// const nsStaticAtom* const nsMyAtoms::sAtoms =
// mozilla::detail::gMyAtoms.mAtoms;
//
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DEFN_PTR(nsStaticAtom, detail::MyAtoms, detail::gMyAtoms, nsMyAtoms, name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// nsStaticAtom* nsMyAtoms::one =
// const_cast<nsStaticAtom*>(&detail::gMyAtoms.mAtoms[
// static_cast<size_t>(detail::MyAtoms::Atoms::one)]);
// nsStaticAtom* nsMyAtoms::two =
// const_cast<nsStaticAtom*>(&detail::gMyAtoms.mAtoms[
// static_cast<size_t>(detail::MyAtoms::Atoms::two)]);
// nsStaticAtom* nsMyAtoms::three =
// const_cast<nsStaticAtom*>(&detail::gMyAtoms.mAtoms[
// static_cast<size_t>(detail::MyAtoms::Atoms::three)]);
// >>>
//
// When NS_RegisterStaticAtoms(sAtoms, sAtomsLen) is called it iterates
// over the atoms, inserting them into the atom table.
// The declaration of the atom's string.
#define NS_STATIC_ATOM_DECL_STRING(name_, value_) \
const char16_t name_##_string[sizeof(value_)];
// The enum value for the atom.
#define NS_STATIC_ATOM_ENUM(name_) \
name_,
// The declaration of the pointer to the static atom. `type_` must be
// `nsStaticAtom` or a subclass thereof.
// XXX: Eventually this should be combined with NS_STATIC_ATOM_DEFN_PTR and the
// pointer should be made `constexpr`. See bug 1449787.
#define NS_STATIC_ATOM_DECL_PTR(type_, name_) \
static type_* name_;
// The initialization of the atom's string.
#define NS_STATIC_ATOM_INIT_STRING(value_) \
u"" value_,
// The initialization of the atom itself. `type_` must be `nsStaticAtom` or a
// subclass thereof.
//
// Note that |value_| is an 8-bit string, and so |sizeof(value_)| is equal
// to the number of chars (including the terminating '\0'). The |u""| prefix
// converts |value_| to a 16-bit string.
#define NS_STATIC_ATOM_INIT_ATOM(type_, detailClass_, name_, value_) \
type_(u"" value_, \
sizeof(value_) - 1, \
offsetof(detailClass_, \
mAtoms[static_cast<size_t>(detailClass_::Atoms::name_)]) - \
offsetof(detailClass_, name_##_string)),
// Definition of the pointer to the static atom. `type_` must be `nsStaticAtom`
// or a subclass thereof.
#define NS_STATIC_ATOM_DEFN_PTR(type_, detailClass_, detailObj_, class_, name_) \
type_* class_::name_ = const_cast<type_*>( \
&detailObj_.mAtoms[static_cast<size_t>(detailClass_::Atoms::name_)]);
// Register an array of static atoms with the atom table.
void
NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen);
// This class holds basic operations on arrays of static atoms.
class nsStaticAtomUtils {
public:
static mozilla::Maybe<uint32_t> Lookup(nsAtom* aAtom,
const nsStaticAtom* aAtoms,
uint32_t aCount)
{
for (uint32_t i = 0; i < aCount; i++) {
if (aAtom == &aAtoms[i]) {
return mozilla::Some(i);
}
}
return mozilla::Nothing();
}
static bool IsMember(nsAtom* aAtom, const nsStaticAtom* aAtoms,
uint32_t aCount)
{
return Lookup(aAtom, aAtoms, aCount).isSome();
}
};
#endif