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__
11 #include "nsStringBuffer.h"
12 #include "mozilla/RefPtr.h"
13 #include "mozilla/Span.h"
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.
23 : mDataFlags(nsString::DataFlags::TERMINATED
),
24 mClassFlags(nsString::ClassFlags(0)) {}
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
);
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
41 void ShareOrDependUpon(const nsAString
& aString
) {
42 RefPtr
<nsStringBuffer
> sharedBuffer
= nsStringBuffer::FromString(aString
);
44 Rebind(aString
.Data(), aString
.Length());
46 AssignFromStringBuffer(sharedBuffer
.forget());
47 mLength
= aString
.Length();
52 MOZ_ASSERT(mDataFlags
== nsString::DataFlags::TERMINATED
);
53 mData
= nsString::char_traits::sEmptyBuffer
;
57 void SetIsVoid(bool aValue
) {
58 MOZ_ASSERT(aValue
, "We don't support SetIsVoid(false) on FakeString!");
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());
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
);
87 RefPtr
<nsStringBuffer
> buf
=
88 nsStringBuffer::Alloc((aLength
+ 1) * sizeof(nsString::char_type
));
89 if (MOZ_UNLIKELY(!buf
)) {
93 AssignFromStringBuffer(buf
.forget());
96 mData
[mLength
] = char16_t(0);
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);
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()));
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
{
145 static void StaticAsserts() {
146 static_assert(offsetof(FakeString
, mInlineStorage
) == sizeof(nsString
),
147 "FakeString should include all nsString members");
149 offsetof(FakeString
, mData
) == offsetof(StringAsserter
, mData
),
150 "Offset of mData should match");
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
165 } // namespace mozilla
167 #endif /* mozilla_dom_FakeString_h__ */