xpcom/ds/nsAtom.h
author L10n Bumper Bot <release+l10nbumper@mozilla.com>
Thu, 08 Nov 2018 03:00:11 -0800
changeset 501100 1cd4f2d571554c4dc89cf1be1d98683c0d14f797
parent 498945 3924e39ce03a0004287b06dc478b90d257e1dd45
child 504736 e9267d39ec81476831da99bd3b98557877962ca3
permissions -rw-r--r--
no bug - Bumping Fennec l10n changesets r=release a=l10n-bump DONTBUILD an -> 336e061995b9 ar -> f6834a7d7374 as -> d2c76e616a66 ast -> fcb8f3455237 az -> c4caf3b07cf2 be -> 697eb1022498 bg -> 7bf1f448f743 bn-BD -> 5f7a87adee06 bn-IN -> 49ce3195c4c2 br -> 41cf35b7c5b5 bs -> 4a14aee27904 ca -> 9373e8ce86d4 cak -> a40d767541ba cs -> 4b99defb0525 cy -> 4c948fed2584 de -> 017a7e7a267a dsb -> aadebeccf5ba el -> 2d28a78dcef5 en-CA -> 55ad9171a9f0 en-GB -> 296422b495e9 en-ZA -> c1b5d2128914 eo -> c68e87667d9f es-AR -> bff0a788c711 es-CL -> 1d3efd2532ea es-ES -> 4d1feb70b0e2 es-MX -> fceda607d0f4 et -> 58a8262a0cc7 eu -> 7cebfd46208b fa -> cbc040d58476 ff -> 46f5aec275ea fi -> 235ab13d261e fr -> 8ee417b64f99

/* -*- 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 nsAtom_h
#define nsAtom_h

#include "nsISupportsImpl.h"
#include "nsString.h"
#include "mozilla/UniquePtr.h"

namespace mozilla {
struct AtomsSizes;
}

class nsStaticAtom;
class nsDynamicAtom;

// This class encompasses both static and dynamic atoms.
//
// - In places where static and dynamic atoms can be used, use RefPtr<nsAtom>.
//   This is by far the most common case. (The exception to this is the HTML5
//   parser, which does its own weird thing, and uses non-refcounted dynamic
//   atoms.)
//
// - In places where only static atoms can appear, use nsStaticAtom* to avoid
//   unnecessary refcounting. This is a moderately common case.
//
// - In places where only dynamic atoms can appear, it doesn't matter much
//   whether you use RefPtr<nsAtom> or RefPtr<nsDynamicAtom>. This is an
//   extremely rare case.
//
class nsAtom
{
public:
  void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                              mozilla::AtomsSizes& aSizes) const;

  // Dynamic HTML5 atoms are just like vanilla dynamic atoms, but we disallow
  // various operations, the most important of which is AddRef/Release.
  // XXX: we'd like to get rid of dynamic HTML5 atoms. See bug 1392185 for
  // details.
  enum class AtomKind : uint8_t {
    Static = 0,
    DynamicNormal = 1,
    DynamicHTML5 = 2,
  };

  bool Equals(char16ptr_t aString, uint32_t aLength) const
  {
    return mLength == aLength &&
           memcmp(GetUTF16String(), aString, mLength * sizeof(char16_t)) == 0;
  }

  bool Equals(const nsAString& aString) const
  {
    return Equals(aString.BeginReading(), aString.Length());
  }

  AtomKind Kind() const { return static_cast<AtomKind>(mKind); }

  bool IsStatic() const { return Kind() == AtomKind::Static; }
  bool IsDynamic() const
  {
    return Kind() == AtomKind::DynamicNormal ||
           Kind() == AtomKind::DynamicHTML5;
  }
  bool IsDynamicHTML5() const
  {
    return Kind() == AtomKind::DynamicHTML5;
  }

  const nsStaticAtom* AsStatic() const;
  const nsDynamicAtom* AsDynamic() const;
  nsDynamicAtom* AsDynamic();

  char16ptr_t GetUTF16String() const;

  uint32_t GetLength() const { return mLength; }

  operator mozilla::Span<const char16_t>() const
  {
    return mozilla::MakeSpan(static_cast<const char16_t*>(GetUTF16String()), GetLength());
  }

  void ToString(nsAString& aString) const;
  void ToUTF8String(nsACString& aString) const;

  // A hashcode that is better distributed than the actual atom pointer, for
  // use in situations that need a well-distributed hashcode. It's called hash()
  // rather than Hash() so we can use mozilla::BloomFilter<N, nsAtom>, because
  // BloomFilter requires elements to implement a function called hash().
  //
  uint32_t hash() const
  {
    MOZ_ASSERT(!IsDynamicHTML5());
    return mHash;
  }

  // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
  // of this type is special.
  MozExternalRefCountType AddRef();
  MozExternalRefCountType Release();

  typedef mozilla::TrueType HasThreadSafeRefCnt;

protected:
  // Used by nsStaticAtom.
  constexpr nsAtom(uint32_t aLength, uint32_t aHash)
    : mLength(aLength)
    , mKind(static_cast<uint32_t>(nsAtom::AtomKind::Static))
    , mHash(aHash)
  {}

  // Used by nsDynamicAtom.
  nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash)
    : mLength(aString.Length())
    , mKind(static_cast<uint32_t>(aKind))
    , mHash(aHash)
  {
    MOZ_ASSERT(aKind == AtomKind::DynamicNormal ||
               aKind == AtomKind::DynamicHTML5);
  }

  ~nsAtom() = default;

  const uint32_t mLength:30;
  const uint32_t mKind:2; // nsAtom::AtomKind
  const uint32_t mHash;
};

// This class would be |final| if it wasn't for nsCSSAnonBoxPseudoStaticAtom
// and nsCSSPseudoElementStaticAtom, which are trivial subclasses used to
// ensure only certain static atoms are passed to certain functions.
class nsStaticAtom : public nsAtom
{
public:
  // These are deleted so it's impossible to RefPtr<nsStaticAtom>. Raw
  // nsStaticAtom pointers should be used instead.
  MozExternalRefCountType AddRef() = delete;
  MozExternalRefCountType Release() = delete;

  // The static atom's precomputed hash value is an argument here, but it
  // must be the same as would be computed by mozilla::HashString(aStr),
  // which is what we use when atomizing strings. We compute this hash in
  // Atom.py and assert in nsAtomTable::RegisterStaticAtoms that the two
  // hashes match.
  constexpr nsStaticAtom(uint32_t aLength, uint32_t aHash,
                         uint32_t aStringOffset)
    : nsAtom(aLength, aHash)
    , mStringOffset(aStringOffset)
  {}

  const char16_t* String() const
  {
    return reinterpret_cast<const char16_t*>(uintptr_t(this) - mStringOffset);
  }

  already_AddRefed<nsAtom> ToAddRefed() {
    return already_AddRefed<nsAtom>(static_cast<nsAtom*>(this));
  }

private:
  // This is an offset to the string chars, which must be at a lower address in
  // memory.
  uint32_t mStringOffset;
};

class nsDynamicAtom : public nsAtom
{
public:
  // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
  // of this type is special.
  MozExternalRefCountType AddRef();
  MozExternalRefCountType Release();

  const char16_t* String() const
  {
    return reinterpret_cast<const char16_t*>(this + 1);
  }

  static nsDynamicAtom* FromChars(char16_t* chars)
  {
    return reinterpret_cast<nsDynamicAtom*>(chars) - 1;
  }

private:
  friend class nsAtomTable;
  friend class nsAtomSubTable;
  // XXX: we'd like to remove nsHtml5AtomEntry. See bug 1392185.
  friend class nsHtml5AtomEntry;

  // These shouldn't be used directly, even by friend classes. The
  // Create()/Destroy() methods use them.
  static nsDynamicAtom* CreateInner(const nsAString& aString, uint32_t aHash);
  nsDynamicAtom(const nsAString& aString, uint32_t aHash);
  ~nsDynamicAtom() {}

  // Creation/destruction is done by friend classes. The first Create() is for
  // dynamic normal atoms, the second is for dynamic HTML5 atoms.
  static nsDynamicAtom* Create(const nsAString& aString, uint32_t aHash);
  static nsDynamicAtom* Create(const nsAString& aString);
  static void Destroy(nsDynamicAtom* aAtom);

  mozilla::ThreadSafeAutoRefCnt mRefCnt;

  // The atom's chars are stored at the end of the struct.
};

// The four forms of NS_Atomize (for use with |RefPtr<nsAtom>|) return the
// atom for the string given. At any given time there will always be one atom
// representing a given string. Atoms are intended to make string comparison
// cheaper by simplifying it to pointer equality. A pointer to the atom that
// does not own a reference is not guaranteed to be valid.

// Find an atom that matches the given UTF-8 string. The string is assumed to
// be zero terminated. Never returns null.
already_AddRefed<nsAtom> NS_Atomize(const char* aUTF8String);

// Find an atom that matches the given UTF-8 string. Never returns null.
already_AddRefed<nsAtom> NS_Atomize(const nsACString& aUTF8String);

// Find an atom that matches the given UTF-16 string. The string is assumed to
// be zero terminated. Never returns null.
already_AddRefed<nsAtom> NS_Atomize(const char16_t* aUTF16String);

// Find an atom that matches the given UTF-16 string. Never returns null.
already_AddRefed<nsAtom> NS_Atomize(const nsAString& aUTF16String);

// An optimized version of the method above for the main thread.
already_AddRefed<nsAtom> NS_AtomizeMainThread(const nsAString& aUTF16String);

// Return a count of the total number of atoms currently alive in the system.
//
// Note that the result is imprecise and racy if other threads are currently
// operating on atoms. It's also slow, since it triggers a GC before counting.
// Currently this function is only used in tests, which should probably remain
// the case.
nsrefcnt NS_GetNumberOfAtoms();

// Return a pointer for a static atom for the string or null if there's no
// static atom for this string.
nsStaticAtom* NS_GetStaticAtom(const nsAString& aUTF16String);

class nsAtomString : public nsString
{
public:
  explicit nsAtomString(const nsAtom* aAtom) { aAtom->ToString(*this); }
};

class nsAtomCString : public nsCString
{
public:
  explicit nsAtomCString(nsAtom* aAtom) { aAtom->ToUTF8String(*this); }
};

class nsDependentAtomString : public nsDependentString
{
public:
  explicit nsDependentAtomString(const nsAtom* aAtom)
    : nsDependentString(aAtom->GetUTF16String(), aAtom->GetLength())
  {}
};

// Checks if the ascii chars in a given atom are already lowercase.
// If they are, no-op. Otherwise, converts all the ascii uppercase
// chars to lowercase and atomizes, storing the result in the inout
// param.
void ToLowerCaseASCII(RefPtr<nsAtom>& aAtom);

#endif  // nsAtom_h