Index: third_party/WebKit/Source/wtf/text/StringView.h |
diff --git a/third_party/WebKit/Source/wtf/text/StringView.h b/third_party/WebKit/Source/wtf/text/StringView.h |
index 692053b2afc85632bb0b260864d29e6f33d0ac0e..7b4793192c31a5d43ba83e969dd8017b2f39077f 100644 |
--- a/third_party/WebKit/Source/wtf/text/StringView.h |
+++ b/third_party/WebKit/Source/wtf/text/StringView.h |
@@ -6,6 +6,7 @@ |
#define WTF_StringView_h |
#include "wtf/Allocator.h" |
+#include "wtf/GetPtr.h" |
#if DCHECK_IS_ON() |
#include "wtf/RefPtr.h" |
#endif |
@@ -21,7 +22,7 @@ namespace WTF { |
// and keeps track of the length and the type, it does NOT own the bytes. |
// |
// Since StringView does not own the bytes creating a StringView from a String, |
-// then calling clear() on the string will result in a use-after-free. Asserts |
+// then calling clear() on the String will result in a use-after-free. Asserts |
// in ~StringView attempt to enforce this for most common cases. |
// |
// See base/strings/string_piece.h for more details. |
@@ -47,7 +48,7 @@ public: |
StringView(const String& string, unsigned offset) |
: StringView(string.impl(), offset) {} |
StringView(const String& string) |
- : StringView(string, 0, string.length()) {} |
+ : StringView(string.impl()) {} |
// From an AtomicString: |
StringView(const AtomicString& string, unsigned offset, unsigned length) |
@@ -55,10 +56,11 @@ public: |
StringView(const AtomicString& string, unsigned offset) |
: StringView(string.impl(), offset) {} |
StringView(const AtomicString& string) |
- : StringView(string, 0, string.length()) {} |
+ : StringView(string.impl()) {} |
// From a literal string or LChar buffer: |
- StringView(const LChar* chars, unsigned length); |
+ StringView(const LChar* chars, unsigned length) |
+ : StringView(reinterpret_cast<const void*>(chars), length, true) {} |
StringView(const char* chars, unsigned length) |
: StringView(reinterpret_cast<const LChar*>(chars), length) {} |
StringView(const LChar* chars) |
@@ -67,27 +69,26 @@ public: |
: StringView(reinterpret_cast<const LChar*>(chars)) {} |
// From a wide literal string or UChar buffer. |
+ StringView(const UChar* chars, unsigned length) |
+ : StringView(reinterpret_cast<const void*>(chars), length, false) {} |
StringView(const UChar* chars); |
- StringView(const UChar* chars, unsigned length); |
// From a byte pointer. |
StringView(const void* bytes, unsigned length, bool is8Bit) |
- : m_length(length) |
- , m_is8Bit(is8Bit) |
- { |
- m_data.bytes = bytes; |
- } |
+ : m_impl(is8Bit ? StringImpl::empty() : StringImpl::empty16Bit()) |
+ , m_bytes(bytes) |
+ , m_length(length) {} |
#if DCHECK_IS_ON() |
~StringView(); |
#endif |
- bool isNull() const { return !m_data.bytes; } |
+ bool isNull() const { return !m_bytes; } |
bool isEmpty() const { return !m_length; } |
unsigned length() const { return m_length; } |
- bool is8Bit() const { return m_is8Bit; } |
+ bool is8Bit() const { DCHECK(m_impl); return m_impl->is8Bit(); } |
void clear(); |
@@ -101,17 +102,31 @@ public: |
const LChar* characters8() const |
{ |
- ASSERT(is8Bit()); |
- return m_data.characters8; |
+ DCHECK(is8Bit()); |
+ return m_characters8; |
} |
const UChar* characters16() const |
{ |
- ASSERT(!is8Bit()); |
- return m_data.characters16; |
+ DCHECK(!is8Bit()); |
+ return m_characters16; |
} |
- const void* bytes() const { return m_data.bytes; } |
+ const void* bytes() const { return m_bytes; } |
+ |
+ // This is not named impl() like String because it has different semantics. |
+ // String::impl() is never null if String::isNull() is false. For StringView |
+ // sharedImpl() can be null if the StringView was created with a non-zero |
+ // offset, or a length that made it shorter than the underlying impl. |
+ StringImpl* sharedImpl() const |
+ { |
+ // If this StringView is backed by a StringImpl, and was constructed |
+ // with a zero offset and the same length we can just access the impl |
+ // directly since this == StringView(m_impl). |
+ if (m_impl->bytes() == bytes() && m_length == m_impl->length()) |
haraken
2016/06/06 02:28:52
Would you help me understand why do you need to ch
esprehn
2016/06/06 04:42:21
A StringView can be a shorter length than the unde
|
+ return getPtr(m_impl); |
+ return nullptr; |
+ } |
String toString() const; |
AtomicString toAtomicString() const; |
@@ -119,32 +134,42 @@ public: |
private: |
void set(StringImpl&, unsigned offset, unsigned length); |
+ // We use the StringImpl to mark for 8bit or 16bit, even for strings where |
+ // we were constructed from a char pointer. So m_impl->bytes() might have |
+ // nothing to do with this view's bytes(). |
#if DCHECK_IS_ON() |
RefPtr<StringImpl> m_impl; |
+#else |
+ StringImpl* m_impl; |
haraken
2016/06/06 02:28:52
Who guarantees that someone else keeps a reference
esprehn
2016/06/06 04:42:21
The caller does, this is the same as base::StringP
haraken
2016/06/06 05:02:35
Thanks for the details. Makes sense.
The assertio
|
#endif |
- union DataUnion { |
- const LChar* characters8; |
- const UChar* characters16; |
- const void* bytes; |
- } m_data; |
+ union { |
+ const LChar* m_characters8; |
+ const UChar* m_characters16; |
+ const void* m_bytes; |
haraken
2016/06/06 02:28:52
Worth adding a comment that how each of the fields
esprehn
2016/06/06 04:42:21
This is the same as String's semantics. In the nex
haraken
2016/06/06 05:02:35
That sounds great.
|
+ }; |
unsigned m_length; |
- unsigned m_is8Bit : 1; |
}; |
inline StringView::StringView(const StringView& view, unsigned offset, unsigned length) |
- : m_length(length) |
- , m_is8Bit(view.is8Bit()) |
+ : m_impl(view.m_impl) |
+ , m_length(length) |
{ |
SECURITY_DCHECK(offset + length <= view.length()); |
if (is8Bit()) |
- m_data.characters8 = view.characters8() + offset; |
+ m_characters8 = view.characters8() + offset; |
else |
- m_data.characters16 = view.characters16() + offset; |
+ m_characters16 = view.characters16() + offset; |
} |
inline StringView::StringView(StringImpl* impl) |
{ |
- impl ? set(*impl, 0, impl->length()) : clear(); |
+ if (!impl) { |
+ clear(); |
+ return; |
+ } |
+ m_impl = impl; |
+ m_length = impl->length(); |
+ m_bytes = impl->bytes(); |
} |
inline StringView::StringView(StringImpl* impl, unsigned offset) |
@@ -157,35 +182,22 @@ inline StringView::StringView(StringImpl* impl, unsigned offset, unsigned length |
impl ? set(*impl, offset, length) : clear(); |
} |
-inline StringView::StringView(const LChar* chars, unsigned length) |
- : m_length(length) |
- , m_is8Bit(true) |
-{ |
- m_data.characters8 = chars; |
-} |
- |
inline void StringView::clear() |
{ |
m_length = 0; |
- m_is8Bit = true; |
- m_data.bytes = nullptr; |
-#if DCHECK_IS_ON() |
- m_impl = nullptr; |
-#endif |
+ m_bytes = nullptr; |
+ m_impl = StringImpl::empty(); // mark as 8 bit. |
} |
inline void StringView::set(StringImpl& impl, unsigned offset, unsigned length) |
{ |
SECURITY_DCHECK(offset + length <= impl.length()); |
m_length = length; |
- m_is8Bit = impl.is8Bit(); |
-#if DCHECK_IS_ON() |
m_impl = &impl; |
-#endif |
- if (m_is8Bit) |
- m_data.characters8 = impl.characters8() + offset; |
+ if (impl.is8Bit()) |
+ m_characters8 = impl.characters8() + offset; |
else |
- m_data.characters16 = impl.characters16() + offset; |
+ m_characters16 = impl.characters16() + offset; |
} |
WTF_EXPORT bool equalIgnoringASCIICase(const StringView& a, const StringView& b); |