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