/work/obj-fuzz/dist/include/mozilla/dom/FakeString.h
Line | Count | Source (jump to first uncovered line) |
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/. */ |
6 | | |
7 | | #ifndef mozilla_dom_FakeString_h__ |
8 | | #define mozilla_dom_FakeString_h__ |
9 | | |
10 | | #include "nsString.h" |
11 | | #include "nsStringBuffer.h" |
12 | | #include "mozilla/RefPtr.h" |
13 | | #include "mozilla/Span.h" |
14 | | |
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)) |
25 | 14 | { |
26 | 14 | } |
27 | | |
28 | 14 | ~FakeString() { |
29 | 14 | if (mDataFlags & nsString::DataFlags::REFCOUNTED) { |
30 | 0 | nsStringBuffer::FromData(mData)->Release(); |
31 | 0 | } |
32 | 14 | } |
33 | | |
34 | 0 | void Rebind(const nsString::char_type* aData, nsString::size_type aLength) { |
35 | 0 | MOZ_ASSERT(mDataFlags == nsString::DataFlags::TERMINATED); |
36 | 0 | mData = const_cast<nsString::char_type*>(aData); |
37 | 0 | mLength = aLength; |
38 | 0 | } |
39 | | |
40 | | // Share aString's string buffer, if it has one; otherwise, make this string |
41 | | // depend upon aString's data. aString should outlive this instance of |
42 | | // FakeString. |
43 | 0 | void ShareOrDependUpon(const nsAString& aString) { |
44 | 0 | RefPtr<nsStringBuffer> sharedBuffer = nsStringBuffer::FromString(aString); |
45 | 0 | if (!sharedBuffer) { |
46 | 0 | Rebind(aString.Data(), aString.Length()); |
47 | 0 | } else { |
48 | 0 | AssignFromStringBuffer(sharedBuffer.forget()); |
49 | 0 | mLength = aString.Length(); |
50 | 0 | } |
51 | 0 | } |
52 | | |
53 | 0 | void Truncate() { |
54 | 0 | MOZ_ASSERT(mDataFlags == nsString::DataFlags::TERMINATED); |
55 | 0 | mData = nsString::char_traits::sEmptyBuffer; |
56 | 0 | mLength = 0; |
57 | 0 | } |
58 | | |
59 | 0 | void SetIsVoid(bool aValue) { |
60 | 0 | MOZ_ASSERT(aValue, |
61 | 0 | "We don't support SetIsVoid(false) on FakeString!"); |
62 | 0 | Truncate(); |
63 | 0 | mDataFlags |= nsString::DataFlags::VOIDED; |
64 | 0 | } |
65 | | |
66 | | const nsString::char_type* Data() const |
67 | 0 | { |
68 | 0 | return mData; |
69 | 0 | } |
70 | | |
71 | | nsString::char_type* BeginWriting() |
72 | 14 | { |
73 | 14 | MOZ_ASSERT(!(mDataFlags & nsString::DataFlags::REFCOUNTED) || |
74 | 14 | !nsStringBuffer::FromData(mData)->IsReadonly()); |
75 | 14 | return mData; |
76 | 14 | } |
77 | | |
78 | | nsString::size_type Length() const |
79 | 0 | { |
80 | 0 | return mLength; |
81 | 0 | } |
82 | | |
83 | | operator mozilla::Span<const nsString::char_type>() const |
84 | 0 | { |
85 | 0 | return mozilla::MakeSpan(Data(), Length()); |
86 | 0 | } |
87 | | |
88 | | operator mozilla::Span<nsString::char_type>() |
89 | 0 | { |
90 | 0 | return mozilla::MakeSpan(BeginWriting(), Length()); |
91 | 0 | } |
92 | | |
93 | | // Reserve space to write aLength chars, not including null-terminator. |
94 | 14 | bool SetLength(nsString::size_type aLength, mozilla::fallible_t const&) { |
95 | 14 | // Use mInlineStorage for small strings. |
96 | 14 | if (aLength < sInlineCapacity) { |
97 | 14 | SetData(mInlineStorage); |
98 | 14 | } else { |
99 | 0 | RefPtr<nsStringBuffer> buf = nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type)); |
100 | 0 | if (MOZ_UNLIKELY(!buf)) { |
101 | 0 | return false; |
102 | 0 | } |
103 | 0 | |
104 | 0 | AssignFromStringBuffer(buf.forget()); |
105 | 0 | } |
106 | 14 | mLength = aLength; |
107 | 14 | mData[mLength] = char16_t(0); |
108 | 14 | return true; |
109 | 14 | } |
110 | | |
111 | | // If this ever changes, change the corresponding code in the |
112 | | // Optional<nsAString> specialization as well. |
113 | 0 | const nsAString* ToAStringPtr() const { |
114 | 0 | return reinterpret_cast<const nsString*>(this); |
115 | 0 | } |
116 | | |
117 | 14 | operator const nsAString& () const { |
118 | 14 | return *reinterpret_cast<const nsString*>(this); |
119 | 14 | } |
120 | | |
121 | | private: |
122 | 0 | nsAString* ToAStringPtr() { |
123 | 0 | return reinterpret_cast<nsString*>(this); |
124 | 0 | } |
125 | | |
126 | | // mData is left uninitialized for optimization purposes. |
127 | | MOZ_INIT_OUTSIDE_CTOR nsString::char_type* mData; |
128 | | // mLength is left uninitialized for optimization purposes. |
129 | | MOZ_INIT_OUTSIDE_CTOR nsString::size_type mLength; |
130 | | nsString::DataFlags mDataFlags; |
131 | | nsString::ClassFlags mClassFlags; |
132 | | |
133 | | static const size_t sInlineCapacity = 64; |
134 | | nsString::char_type mInlineStorage[sInlineCapacity]; |
135 | | |
136 | | FakeString(const FakeString& other) = delete; |
137 | | void operator=(const FakeString& other) = delete; |
138 | | |
139 | 14 | void SetData(nsString::char_type* aData) { |
140 | 14 | MOZ_ASSERT(mDataFlags == nsString::DataFlags::TERMINATED); |
141 | 14 | mData = const_cast<nsString::char_type*>(aData); |
142 | 14 | } |
143 | 0 | void AssignFromStringBuffer(already_AddRefed<nsStringBuffer> aBuffer) { |
144 | 0 | SetData(static_cast<nsString::char_type*>(aBuffer.take()->Data())); |
145 | 0 | mDataFlags = nsString::DataFlags::REFCOUNTED | nsString::DataFlags::TERMINATED; |
146 | 0 | } |
147 | | |
148 | | friend class NonNull<nsAString>; |
149 | | |
150 | | // A class to use for our static asserts to ensure our object layout |
151 | | // matches that of nsString. |
152 | | class StringAsserter; |
153 | | friend class StringAsserter; |
154 | | |
155 | | class StringAsserter : public nsString { |
156 | | public: |
157 | 0 | static void StaticAsserts() { |
158 | 0 | static_assert(offsetof(FakeString, mInlineStorage) == |
159 | 0 | sizeof(nsString), |
160 | 0 | "FakeString should include all nsString members"); |
161 | 0 | static_assert(offsetof(FakeString, mData) == |
162 | 0 | offsetof(StringAsserter, mData), |
163 | 0 | "Offset of mData should match"); |
164 | 0 | static_assert(offsetof(FakeString, mLength) == |
165 | 0 | offsetof(StringAsserter, mLength), |
166 | 0 | "Offset of mLength should match"); |
167 | 0 | static_assert(offsetof(FakeString, mDataFlags) == |
168 | 0 | offsetof(StringAsserter, mDataFlags), |
169 | 0 | "Offset of mDataFlags should match"); |
170 | 0 | static_assert(offsetof(FakeString, mClassFlags) == |
171 | 0 | offsetof(StringAsserter, mClassFlags), |
172 | 0 | "Offset of mClassFlags should match"); |
173 | 0 | } |
174 | | }; |
175 | | }; |
176 | | } // namespace binding_detail |
177 | | } // namespace dom |
178 | | } // namespace mozilla |
179 | | |
180 | | #endif /* mozilla_dom_FakeString_h__ */ |