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 { FakeStringFakeString21 FakeString() : 22 mFlags(nsString::F_TERMINATED) 23 { 24 } 25 ~FakeStringFakeString26 ~FakeString() { 27 if (mFlags & nsString::F_SHARED) { 28 nsStringBuffer::FromData(mData)->Release(); 29 } 30 } 31 RebindFakeString32 void Rebind(const nsString::char_type* aData, nsString::size_type aLength) { 33 MOZ_ASSERT(mFlags == nsString::F_TERMINATED); 34 mData = const_cast<nsString::char_type*>(aData); 35 mLength = aLength; 36 } 37 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. ShareOrDependUponFakeString41 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(); 48 } 49 } 50 TruncateFakeString51 void Truncate() { 52 MOZ_ASSERT(mFlags == nsString::F_TERMINATED); 53 mData = nsString::char_traits::sEmptyBuffer; 54 mLength = 0; 55 } 56 SetIsVoidFakeString57 void SetIsVoid(bool aValue) { 58 MOZ_ASSERT(aValue, 59 "We don't support SetIsVoid(false) on FakeString!"); 60 Truncate(); 61 mFlags |= nsString::F_VOIDED; 62 } 63 DataFakeString64 const nsString::char_type* Data() const 65 { 66 return mData; 67 } 68 BeginWritingFakeString69 nsString::char_type* BeginWriting() 70 { 71 return mData; 72 } 73 LengthFakeString74 nsString::size_type Length() const 75 { 76 return mLength; 77 } 78 79 // Reserve space to write aLength chars, not including null-terminator. SetLengthFakeString80 bool SetLength(nsString::size_type aLength, mozilla::fallible_t const&) { 81 // Use mInlineStorage for small strings. 82 if (aLength < sInlineCapacity) { 83 SetData(mInlineStorage); 84 } else { 85 RefPtr<nsStringBuffer> buf = nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type)); 86 if (MOZ_UNLIKELY(!buf)) { 87 return false; 88 } 89 90 AssignFromStringBuffer(buf.forget()); 91 } 92 mLength = aLength; 93 mData[mLength] = char16_t(0); 94 return true; 95 } 96 97 // If this ever changes, change the corresponding code in the 98 // Optional<nsAString> specialization as well. ToAStringPtrFakeString99 const nsAString* ToAStringPtr() const { 100 return reinterpret_cast<const nsString*>(this); 101 } 102 103 operator const nsAString& () const { 104 return *reinterpret_cast<const nsString*>(this); 105 } 106 107 private: ToAStringPtrFakeString108 nsAString* ToAStringPtr() { 109 return reinterpret_cast<nsString*>(this); 110 } 111 112 nsString::char_type* mData; 113 nsString::size_type mLength; 114 uint32_t mFlags; 115 116 static const size_t sInlineCapacity = 64; 117 nsString::char_type mInlineStorage[sInlineCapacity]; 118 119 FakeString(const FakeString& other) = delete; 120 void operator=(const FakeString& other) = delete; 121 SetDataFakeString122 void SetData(nsString::char_type* aData) { 123 MOZ_ASSERT(mFlags == nsString::F_TERMINATED); 124 mData = const_cast<nsString::char_type*>(aData); 125 } AssignFromStringBufferFakeString126 void AssignFromStringBuffer(already_AddRefed<nsStringBuffer> aBuffer) { 127 SetData(static_cast<nsString::char_type*>(aBuffer.take()->Data())); 128 mFlags = nsString::F_SHARED | nsString::F_TERMINATED; 129 } 130 131 friend class NonNull<nsAString>; 132 133 // A class to use for our static asserts to ensure our object layout 134 // matches that of nsString. 135 class StringAsserter; 136 friend class StringAsserter; 137 138 class StringAsserter : public nsString { 139 public: StaticAssertsFakeString140 static void StaticAsserts() { 141 static_assert(offsetof(FakeString, mInlineStorage) == 142 sizeof(nsString), 143 "FakeString should include all nsString members"); 144 static_assert(offsetof(FakeString, mData) == 145 offsetof(StringAsserter, mData), 146 "Offset of mData should match"); 147 static_assert(offsetof(FakeString, mLength) == 148 offsetof(StringAsserter, mLength), 149 "Offset of mLength should match"); 150 static_assert(offsetof(FakeString, mFlags) == 151 offsetof(StringAsserter, mFlags), 152 "Offset of mFlags should match"); 153 } 154 }; 155 }; 156 } // namespace binding_detail 157 } // namespace dom 158 } // namespace mozilla 159 160 #endif /* mozilla_dom_FakeString_h__ */