Bug 1523562 [wpt PR 15079] - Pass the full path to the flake8 config files, a=testonly
[gecko.git] / dom / bindings / FakeString.h
blobb10a2c75fc8943acbdc52a2bb03bad71a8635a6d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_FakeString_h__
8 #define mozilla_dom_FakeString_h__
10 #include "nsString.h"
11 #include "nsStringBuffer.h"
12 #include "mozilla/RefPtr.h"
13 #include "mozilla/Span.h"
15 namespace mozilla {
16 namespace dom {
17 namespace binding_detail {
18 // A struct that has the same layout as an nsString but much faster
19 // constructor and destructor behavior. FakeString uses inline storage
20 // for small strings and a nsStringBuffer for longer strings.
21 struct FakeString {
22 FakeString()
23 : mDataFlags(nsString::DataFlags::TERMINATED),
24 mClassFlags(nsString::ClassFlags(0)) {}
26 ~FakeString() {
27 if (mDataFlags & nsString::DataFlags::REFCOUNTED) {
28 nsStringBuffer::FromData(mData)->Release();
32 void Rebind(const nsString::char_type* aData, nsString::size_type aLength) {
33 MOZ_ASSERT(mDataFlags == nsString::DataFlags::TERMINATED);
34 mData = const_cast<nsString::char_type*>(aData);
35 mLength = aLength;
38 // Share aString's string buffer, if it has one; otherwise, make this string
39 // depend upon aString's data. aString should outlive this instance of
40 // FakeString.
41 void ShareOrDependUpon(const nsAString& aString) {
42 RefPtr<nsStringBuffer> sharedBuffer = nsStringBuffer::FromString(aString);
43 if (!sharedBuffer) {
44 Rebind(aString.Data(), aString.Length());
45 } else {
46 AssignFromStringBuffer(sharedBuffer.forget());
47 mLength = aString.Length();
51 void Truncate() {
52 MOZ_ASSERT(mDataFlags == nsString::DataFlags::TERMINATED);
53 mData = nsString::char_traits::sEmptyBuffer;
54 mLength = 0;
57 void SetIsVoid(bool aValue) {
58 MOZ_ASSERT(aValue, "We don't support SetIsVoid(false) on FakeString!");
59 Truncate();
60 mDataFlags |= nsString::DataFlags::VOIDED;
63 const nsString::char_type* Data() const { return mData; }
65 nsString::char_type* BeginWriting() {
66 MOZ_ASSERT(!(mDataFlags & nsString::DataFlags::REFCOUNTED) ||
67 !nsStringBuffer::FromData(mData)->IsReadonly());
68 return mData;
71 nsString::size_type Length() const { return mLength; }
73 operator mozilla::Span<const nsString::char_type>() const {
74 return mozilla::MakeSpan(Data(), Length());
77 operator mozilla::Span<nsString::char_type>() {
78 return mozilla::MakeSpan(BeginWriting(), Length());
81 // Reserve space to write aLength chars, not including null-terminator.
82 bool SetLength(nsString::size_type aLength, mozilla::fallible_t const&) {
83 // Use mInlineStorage for small strings.
84 if (aLength < sInlineCapacity) {
85 SetData(mInlineStorage);
86 } else {
87 RefPtr<nsStringBuffer> buf =
88 nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type));
89 if (MOZ_UNLIKELY(!buf)) {
90 return false;
93 AssignFromStringBuffer(buf.forget());
95 mLength = aLength;
96 mData[mLength] = char16_t(0);
97 return true;
100 // If this ever changes, change the corresponding code in the
101 // Optional<nsAString> specialization as well.
102 const nsAString* ToAStringPtr() const {
103 return reinterpret_cast<const nsString*>(this);
106 operator const nsAString&() const {
107 return *reinterpret_cast<const nsString*>(this);
110 private:
111 nsAString* ToAStringPtr() { return reinterpret_cast<nsString*>(this); }
113 // mData is left uninitialized for optimization purposes.
114 MOZ_INIT_OUTSIDE_CTOR nsString::char_type* mData;
115 // mLength is left uninitialized for optimization purposes.
116 MOZ_INIT_OUTSIDE_CTOR nsString::size_type mLength;
117 nsString::DataFlags mDataFlags;
118 nsString::ClassFlags mClassFlags;
120 static const size_t sInlineCapacity = 64;
121 nsString::char_type mInlineStorage[sInlineCapacity];
123 FakeString(const FakeString& other) = delete;
124 void operator=(const FakeString& other) = delete;
126 void SetData(nsString::char_type* aData) {
127 MOZ_ASSERT(mDataFlags == nsString::DataFlags::TERMINATED);
128 mData = const_cast<nsString::char_type*>(aData);
130 void AssignFromStringBuffer(already_AddRefed<nsStringBuffer> aBuffer) {
131 SetData(static_cast<nsString::char_type*>(aBuffer.take()->Data()));
132 mDataFlags =
133 nsString::DataFlags::REFCOUNTED | nsString::DataFlags::TERMINATED;
136 friend class NonNull<nsAString>;
138 // A class to use for our static asserts to ensure our object layout
139 // matches that of nsString.
140 class StringAsserter;
141 friend class StringAsserter;
143 class StringAsserter : public nsString {
144 public:
145 static void StaticAsserts() {
146 static_assert(offsetof(FakeString, mInlineStorage) == sizeof(nsString),
147 "FakeString should include all nsString members");
148 static_assert(
149 offsetof(FakeString, mData) == offsetof(StringAsserter, mData),
150 "Offset of mData should match");
151 static_assert(
152 offsetof(FakeString, mLength) == offsetof(StringAsserter, mLength),
153 "Offset of mLength should match");
154 static_assert(offsetof(FakeString, mDataFlags) ==
155 offsetof(StringAsserter, mDataFlags),
156 "Offset of mDataFlags should match");
157 static_assert(offsetof(FakeString, mClassFlags) ==
158 offsetof(StringAsserter, mClassFlags),
159 "Offset of mClassFlags should match");
163 } // namespace binding_detail
164 } // namespace dom
165 } // namespace mozilla
167 #endif /* mozilla_dom_FakeString_h__ */