diff options
Diffstat (limited to 'dom/bindings/FakeString.h')
-rw-r--r-- | dom/bindings/FakeString.h | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/dom/bindings/FakeString.h b/dom/bindings/FakeString.h new file mode 100644 index 000000000..bd92a1bca --- /dev/null +++ b/dom/bindings/FakeString.h @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FakeString_h__ +#define mozilla_dom_FakeString_h__ + +#include "nsString.h" +#include "nsStringBuffer.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { +namespace dom { +namespace binding_detail { +// A struct that has the same layout as an nsString but much faster +// constructor and destructor behavior. FakeString uses inline storage +// for small strings and a nsStringBuffer for longer strings. +struct FakeString { + FakeString() : + mFlags(nsString::F_TERMINATED) + { + } + + ~FakeString() { + if (mFlags & nsString::F_SHARED) { + nsStringBuffer::FromData(mData)->Release(); + } + } + + void Rebind(const nsString::char_type* aData, nsString::size_type aLength) { + MOZ_ASSERT(mFlags == nsString::F_TERMINATED); + mData = const_cast<nsString::char_type*>(aData); + mLength = aLength; + } + + // Share aString's string buffer, if it has one; otherwise, make this string + // depend upon aString's data. aString should outlive this instance of + // FakeString. + void ShareOrDependUpon(const nsAString& aString) { + RefPtr<nsStringBuffer> sharedBuffer = nsStringBuffer::FromString(aString); + if (!sharedBuffer) { + Rebind(aString.Data(), aString.Length()); + } else { + AssignFromStringBuffer(sharedBuffer.forget()); + mLength = aString.Length(); + } + } + + void Truncate() { + MOZ_ASSERT(mFlags == nsString::F_TERMINATED); + mData = nsString::char_traits::sEmptyBuffer; + mLength = 0; + } + + void SetIsVoid(bool aValue) { + MOZ_ASSERT(aValue, + "We don't support SetIsVoid(false) on FakeString!"); + Truncate(); + mFlags |= nsString::F_VOIDED; + } + + const nsString::char_type* Data() const + { + return mData; + } + + nsString::char_type* BeginWriting() + { + return mData; + } + + nsString::size_type Length() const + { + return mLength; + } + + // Reserve space to write aLength chars, not including null-terminator. + bool SetLength(nsString::size_type aLength, mozilla::fallible_t const&) { + // Use mInlineStorage for small strings. + if (aLength < sInlineCapacity) { + SetData(mInlineStorage); + } else { + RefPtr<nsStringBuffer> buf = nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type)); + if (MOZ_UNLIKELY(!buf)) { + return false; + } + + AssignFromStringBuffer(buf.forget()); + } + mLength = aLength; + mData[mLength] = char16_t(0); + return true; + } + + // If this ever changes, change the corresponding code in the + // Optional<nsAString> specialization as well. + const nsAString* ToAStringPtr() const { + return reinterpret_cast<const nsString*>(this); + } + +operator const nsAString& () const { + return *reinterpret_cast<const nsString*>(this); + } + +private: + nsAString* ToAStringPtr() { + return reinterpret_cast<nsString*>(this); + } + + nsString::char_type* mData; + nsString::size_type mLength; + uint32_t mFlags; + + static const size_t sInlineCapacity = 64; + nsString::char_type mInlineStorage[sInlineCapacity]; + + FakeString(const FakeString& other) = delete; + void operator=(const FakeString& other) = delete; + + void SetData(nsString::char_type* aData) { + MOZ_ASSERT(mFlags == nsString::F_TERMINATED); + mData = const_cast<nsString::char_type*>(aData); + } + void AssignFromStringBuffer(already_AddRefed<nsStringBuffer> aBuffer) { + SetData(static_cast<nsString::char_type*>(aBuffer.take()->Data())); + mFlags = nsString::F_SHARED | nsString::F_TERMINATED; + } + + friend class NonNull<nsAString>; + + // A class to use for our static asserts to ensure our object layout + // matches that of nsString. + class StringAsserter; + friend class StringAsserter; + + class StringAsserter : public nsString { + public: + static void StaticAsserts() { + static_assert(offsetof(FakeString, mInlineStorage) == + sizeof(nsString), + "FakeString should include all nsString members"); + static_assert(offsetof(FakeString, mData) == + offsetof(StringAsserter, mData), + "Offset of mData should match"); + static_assert(offsetof(FakeString, mLength) == + offsetof(StringAsserter, mLength), + "Offset of mLength should match"); + static_assert(offsetof(FakeString, mFlags) == + offsetof(StringAsserter, mFlags), + "Offset of mFlags should match"); + } + }; +}; +} // namespace binding_detail +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_FakeString_h__ */
\ No newline at end of file |