Add StringBuilder member function which allows makeString() style variadic argument...
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Jul 2019 21:18:30 +0000 (21:18 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Jul 2019 21:18:30 +0000 (21:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=198997

Reviewed by Darin Adler.

Source/WTF:

Adds new StringBuilder::flexibleAppend(...) member function which allows passing one or more
string-adaptable (in the sense that there is StringTypeAdapter specialization for the
type) parameters. This re-ususes the variadic template infrastructure in StringConcatenate.h
that is used for makeString(...) allowing for improvements in one to benefit the other.

The advantage of StringBuilder::flexibleAppend(...) over calling StringBuilder::append(...)
multiple times (beyond the code sharing with makeString(...) is that it can avoid unnecessary
additional re-allocations when the StringBuilder needs to expand it's capacity. It does this
by computing the complete required length for all the passed arguments and then ensuring enough
capacity is available. It also reduces the allocation overhead versus the anti-pattern of
builder.append(makeString(...)).

Ideally, this member function should eventually just be called StringBuilder::append(...), but
the current overload set for StringBuilder::append(...) makes this complicated due to overloads
that take two arguments such as StringBuilder::append(const UChar*, unsigned). Going forward, we
should rename or remove those overloads and move to a standard interface.

* wtf/posix/FileSystemPOSIX.cpp:
(WTF::FileSystemImpl::pathByAppendingComponents):
Adopt StringBuilder::flexibleAppend, using to combine the append of '/' and component.

* wtf/text/StringBuilder.cpp:
(WTF::StringBuilder::appendUninitialized):
(WTF::StringBuilder::appendUninitializedWithoutOverflowCheck):
Extract the part of appendUnitialized that doesn't do the overflow check
into it's own member function to allow callers that have already done the
overflow check to bypass it.

(WTF::StringBuilder::appendUninitializedWithoutOverflowCheckForUChar):
(WTF::StringBuilder::appendUninitializedWithoutOverflowCheckForLChar):
Added to allow template member function flexibleAppendFromAdapters to call
appendUninitializedWithoutOverflowCheck without moving it to the header.

* wtf/text/StringBuilder.h:
(WTF::StringBuilder::flexibleAppendFromAdapters):
(WTF::StringBuilder::flexibleAppend):
Modeled on tryMakeStringFromAdapters in StringConcatenate.h, these
eagerly compute the required length, expand the buffer and then use
the existing string type adaptor accumulation functions used by makeString.

* wtf/text/StringConcatenate.h:
(WTF::stringTypeAdapterAccumulator):
(WTF::tryMakeStringFromAdapters):
(WTF::makeStringAccumulator): Deleted.
Renames makeStringAccumulator to stringTypeAdapterAccumulator now that it is used
by more than just makeString.

Tools:

* TestWebKitAPI/Tests/WTF/StringBuilder.cpp:
Add basic test showing that StringBuilder::flexibleAppend can be used to
append one or more string adaptable types.

* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
Add WTFStringUtilities.cpp

* TestWebKitAPI/Tests/WTF/StringBuilder.cpp:
Add basic test showing that StringBuilder::flexibleAppend can be used to
append one or more string adaptable types.

* TestWebKitAPI/Tests/WTF/StringOperators.cpp:
* TestWebKitAPI/WTFStringUtilities.cpp: Added.
* TestWebKitAPI/WTFStringUtilities.h:
Move WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING() and wtfStringCopyCount to WTFStringUtilities.h/cpp
to allow for a single definition of StringTypeAdapter<String, void> which is required for ODR.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247537 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
Source/WTF/ChangeLog
Source/WTF/wtf/posix/FileSystemPOSIX.cpp
Source/WTF/wtf/text/StringBuilder.cpp
Source/WTF/wtf/text/StringBuilder.h
Source/WTF/wtf/text/StringConcatenate.h
Tools/ChangeLog
Tools/TestWebKitAPI/CMakeLists.txt
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp
Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp
Tools/TestWebKitAPI/WTFStringUtilities.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/WTFStringUtilities.h

index b661aff..a1ffd83 100644 (file)
@@ -1,3 +1,57 @@
+2019-07-17  Sam Weinig  <weinig@apple.com>
+
+        Add StringBuilder member function which allows makeString() style variadic argument construction
+        https://bugs.webkit.org/show_bug.cgi?id=198997
+
+        Reviewed by Darin Adler.
+
+        Adds new StringBuilder::flexibleAppend(...) member function which allows passing one or more 
+        string-adaptable (in the sense that there is StringTypeAdapter specialization for the 
+        type) parameters. This re-ususes the variadic template infrastructure in StringConcatenate.h
+        that is used for makeString(...) allowing for improvements in one to benefit the other.
+
+        The advantage of StringBuilder::flexibleAppend(...) over calling StringBuilder::append(...)
+        multiple times (beyond the code sharing with makeString(...) is that it can avoid unnecessary
+        additional re-allocations when the StringBuilder needs to expand it's capacity. It does this
+        by computing the complete required length for all the passed arguments and then ensuring enough
+        capacity is available. It also reduces the allocation overhead versus the anti-pattern of
+        builder.append(makeString(...)).
+
+        Ideally, this member function should eventually just be called StringBuilder::append(...), but
+        the current overload set for StringBuilder::append(...) makes this complicated due to overloads
+        that take two arguments such as StringBuilder::append(const UChar*, unsigned). Going forward, we
+        should rename or remove those overloads and move to a standard interface. 
+
+        * wtf/posix/FileSystemPOSIX.cpp:
+        (WTF::FileSystemImpl::pathByAppendingComponents):
+        Adopt StringBuilder::flexibleAppend, using to combine the append of '/' and component.
+
+        * wtf/text/StringBuilder.cpp:
+        (WTF::StringBuilder::appendUninitialized):
+        (WTF::StringBuilder::appendUninitializedWithoutOverflowCheck):
+        Extract the part of appendUnitialized that doesn't do the overflow check
+        into it's own member function to allow callers that have already done the
+        overflow check to bypass it.
+
+        (WTF::StringBuilder::appendUninitializedWithoutOverflowCheckForUChar):
+        (WTF::StringBuilder::appendUninitializedWithoutOverflowCheckForLChar):
+        Added to allow template member function flexibleAppendFromAdapters to call
+        appendUninitializedWithoutOverflowCheck without moving it to the header.
+        
+        * wtf/text/StringBuilder.h:
+        (WTF::StringBuilder::flexibleAppendFromAdapters):
+        (WTF::StringBuilder::flexibleAppend):
+        Modeled on tryMakeStringFromAdapters in StringConcatenate.h, these
+        eagerly compute the required length, expand the buffer and then use
+        the existing string type adaptor accumulation functions used by makeString. 
+
+        * wtf/text/StringConcatenate.h:
+        (WTF::stringTypeAdapterAccumulator):
+        (WTF::tryMakeStringFromAdapters):
+        (WTF::makeStringAccumulator): Deleted.
+        Renames makeStringAccumulator to stringTypeAdapterAccumulator now that it is used
+        by more than just makeString.
+
 2019-07-17  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r247505.
index ad3c926..c030f9c 100644 (file)
@@ -301,10 +301,8 @@ String pathByAppendingComponents(StringView path, const Vector<StringView>& comp
 {
     StringBuilder builder;
     builder.append(path);
-    for (auto& component : components) {
-        builder.append('/');
-        builder.append(component);
-    }
+    for (auto& component : components)
+        builder.flexibleAppend('/', component);
     return builder.toString();
 }
 
index da1d4a4..89e16ef 100644 (file)
@@ -163,7 +163,7 @@ void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsi
     ASSERT(m_buffer->length() == requiredLength);
 }
 
-template <>
+template<>
 void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength)
 {
     // If the buffer has only one ref (by this StringBuilder), reallocate it,
@@ -183,7 +183,7 @@ void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength)
     ASSERT(hasOverflowed() || m_buffer->length() == requiredLength);
 }
 
-template <>
+template<>
 void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength)
 {
     // If the buffer has only one ref (by this StringBuilder), reallocate it,
@@ -231,37 +231,55 @@ void StringBuilder::reserveCapacity(unsigned newCapacity)
     ASSERT(hasOverflowed() || !newCapacity || m_buffer->length() >= newCapacity);
 }
 
-// Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
+// Make 'additionalLength' additional capacity be available in m_buffer, update m_string & m_length,
 // return a pointer to the newly allocated storage.
 // Returns nullptr if the size of the new builder would have overflowed
-template <typename CharType>
-ALWAYS_INLINE CharType* StringBuilder::appendUninitialized(unsigned length)
+template<typename CharacterType>
+ALWAYS_INLINE CharacterType* StringBuilder::appendUninitialized(unsigned additionalLength)
 {
-    ASSERT(length);
+    ASSERT(additionalLength);
 
     // Calculate the new size of the builder after appending.
-    CheckedInt32 requiredLength = m_length + length;
+    CheckedInt32 requiredLength = m_length + additionalLength;
     if (requiredLength.hasOverflowed()) {
         didOverflow();
         return nullptr;
     }
 
+    return appendUninitializedWithoutOverflowCheck<CharacterType>(requiredLength);
+}
+
+template<typename CharacterType>
+ALWAYS_INLINE CharacterType* StringBuilder::appendUninitializedWithoutOverflowCheck(CheckedInt32 requiredLength)
+{
+    ASSERT(!requiredLength.hasOverflowed());
+
     if (m_buffer && (requiredLength.unsafeGet<unsigned>() <= m_buffer->length())) {
         // If the buffer is valid it must be at least as long as the current builder contents!
         ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
         unsigned currentLength = m_length.unsafeGet();
         m_string = String();
         m_length = requiredLength;
-        return getBufferCharacters<CharType>() + currentLength;
+        return getBufferCharacters<CharacterType>() + currentLength;
     }
     
-    return appendUninitializedSlow<CharType>(requiredLength.unsafeGet());
+    return appendUninitializedSlow<CharacterType>(requiredLength.unsafeGet());
+}
+
+UChar* StringBuilder::appendUninitializedWithoutOverflowCheckForUChar(CheckedInt32 requiredLength)
+{
+    return appendUninitializedWithoutOverflowCheck<UChar>(requiredLength);
+}
+
+LChar* StringBuilder::appendUninitializedWithoutOverflowCheckForLChar(CheckedInt32 requiredLength)
+{
+    return appendUninitializedWithoutOverflowCheck<LChar>(requiredLength);
 }
 
-// Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
+// Make 'requiredLength' capacity be available in m_buffer, update m_string & m_length,
 // return a pointer to the newly allocated storage.
-template <typename CharType>
-CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength)
+template<typename CharacterType>
+CharacterType* StringBuilder::appendUninitializedSlow(unsigned requiredLength)
 {
     ASSERT(!hasOverflowed());
     ASSERT(requiredLength);
@@ -270,15 +288,15 @@ CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength)
         // If the buffer is valid it must be at least as long as the current builder contents!
         ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
         
-        reallocateBuffer<CharType>(expandedCapacity(capacity(), requiredLength));
+        reallocateBuffer<CharacterType>(expandedCapacity(capacity(), requiredLength));
     } else {
         ASSERT(m_string.length() == m_length.unsafeGet<unsigned>());
-        allocateBuffer(m_length ? m_string.characters<CharType>() : nullptr, expandedCapacity(capacity(), requiredLength));
+        allocateBuffer(m_length ? m_string.characters<CharacterType>() : nullptr, expandedCapacity(capacity(), requiredLength));
     }
     if (UNLIKELY(hasOverflowed()))
         return nullptr;
 
-    CharType* result = getBufferCharacters<CharType>() + m_length.unsafeGet();
+    CharacterType* result = getBufferCharacters<CharacterType>() + m_length.unsafeGet();
     m_length = requiredLength;
     ASSERT(!hasOverflowed());
     ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
index 998b857..18b66de 100644 (file)
@@ -231,6 +231,9 @@ public:
     WTF_EXPORT_PRIVATE void appendFixedWidthNumber(float, unsigned decimalPlaces);
     WTF_EXPORT_PRIVATE void appendFixedWidthNumber(double, unsigned decimalPlaces);
 
+    // FIXME: Rename to append(...) after renaming any overloads of append that take more than one argument.
+    template<typename... StringTypes> void flexibleAppend(StringTypes...);
+
     String toString()
     {
         if (!m_string.isNull()) {
@@ -350,16 +353,19 @@ private:
     void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength);
     void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
     void allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength);
-    template <typename CharType>
-    void reallocateBuffer(unsigned requiredLength);
-    template <typename CharType>
-    ALWAYS_INLINE CharType* appendUninitialized(unsigned length);
-    template <typename CharType>
-    CharType* appendUninitializedSlow(unsigned length);
-    template <typename CharType>
-    ALWAYS_INLINE CharType * getBufferCharacters();
+    template<typename CharacterType> void reallocateBuffer(unsigned requiredLength);
+    template<typename CharacterType> ALWAYS_INLINE CharacterType* appendUninitialized(unsigned additionalLength);
+    template<typename CharacterType> ALWAYS_INLINE CharacterType* appendUninitializedWithoutOverflowCheck(CheckedInt32 requiredLength);
+    template<typename CharacterType> CharacterType* appendUninitializedSlow(unsigned requiredLength);
+    
+    WTF_EXPORT_PRIVATE UChar* appendUninitializedWithoutOverflowCheckForUChar(CheckedInt32 requiredLength);
+    WTF_EXPORT_PRIVATE LChar* appendUninitializedWithoutOverflowCheckForLChar(CheckedInt32 requiredLength);
+    
+    template<typename CharacterType> ALWAYS_INLINE CharacterType* getBufferCharacters();
     WTF_EXPORT_PRIVATE void reifyString() const;
 
+    template<typename... StringTypeAdapters> void flexibleAppendFromAdapters(StringTypeAdapters...);
+
     mutable String m_string;
     RefPtr<StringImpl> m_buffer;
     union {
@@ -374,22 +380,54 @@ private:
 #endif
 };
 
-template <>
+template<>
 ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters<LChar>()
 {
     ASSERT(m_is8Bit);
     return m_bufferCharacters8;
 }
 
-template <>
+template<>
 ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>()
 {
     ASSERT(!m_is8Bit);
     return m_bufferCharacters16;
 }
 
-template <typename CharType>
-bool equal(const StringBuilder& s, const CharType* buffer, unsigned length)
+template<typename... StringTypeAdapters>
+void StringBuilder::flexibleAppendFromAdapters(StringTypeAdapters... adapters)
+{
+    auto requiredLength = checkedSum<int32_t>(m_length, adapters.length()...);
+    if (requiredLength.hasOverflowed()) {
+        didOverflow();
+        return;
+    }
+
+    if (m_is8Bit && are8Bit(adapters...)) {
+        LChar* dest = appendUninitializedWithoutOverflowCheckForLChar(requiredLength);
+        if (!dest) {
+            ASSERT(hasOverflowed());
+            return;
+        }
+        stringTypeAdapterAccumulator(dest, adapters...);
+    } else {
+        UChar* dest = appendUninitializedWithoutOverflowCheckForUChar(requiredLength);
+        if (!dest) {
+            ASSERT(hasOverflowed());
+            return;
+        }
+        stringTypeAdapterAccumulator(dest, adapters...);
+    }
+}
+
+template<typename... StringTypes>
+void StringBuilder::flexibleAppend(StringTypes... strings)
+{
+    flexibleAppendFromAdapters(StringTypeAdapter<StringTypes>(strings)...);
+}
+
+template<typename CharacterType>
+bool equal(const StringBuilder& s, const CharacterType* buffer, unsigned length)
 {
     if (s.length() != length)
         return false;
@@ -400,7 +438,7 @@ bool equal(const StringBuilder& s, const CharType* buffer, unsigned length)
     return equal(s.characters16(), buffer, length);
 }
 
-template <typename StringType>
+template<typename StringType>
 bool equal(const StringBuilder& a, const StringType& b)
 {
     if (a.length() != b.length())
index c8cba07..0537b10 100644 (file)
@@ -248,16 +248,16 @@ inline bool are8Bit(Adapter adapter, Adapters ...adapters)
 }
 
 template<typename ResultType, typename Adapter>
-inline void makeStringAccumulator(ResultType* result, Adapter adapter)
+inline void stringTypeAdapterAccumulator(ResultType* result, Adapter adapter)
 {
     adapter.writeTo(result);
 }
 
 template<typename ResultType, typename Adapter, typename... Adapters>
-inline void makeStringAccumulator(ResultType* result, Adapter adapter, Adapters ...adapters)
+inline void stringTypeAdapterAccumulator(ResultType* result, Adapter adapter, Adapters ...adapters)
 {
     adapter.writeTo(result);
-    makeStringAccumulator(result + adapter.length(), adapters...);
+    stringTypeAdapterAccumulator(result + adapter.length(), adapters...);
 }
 
 template<typename StringTypeAdapter, typename... StringTypeAdapters>
@@ -276,7 +276,7 @@ String tryMakeStringFromAdapters(StringTypeAdapter adapter, StringTypeAdapters .
         if (!resultImpl)
             return String();
 
-        makeStringAccumulator(buffer, adapter, adapters...);
+        stringTypeAdapterAccumulator(buffer, adapter, adapters...);
 
         return resultImpl;
     }
@@ -286,7 +286,7 @@ String tryMakeStringFromAdapters(StringTypeAdapter adapter, StringTypeAdapters .
     if (!resultImpl)
         return String();
 
-    makeStringAccumulator(buffer, adapter, adapters...);
+    stringTypeAdapterAccumulator(buffer, adapter, adapters...);
 
     return resultImpl;
 }
index e1a5033..f0b9e97 100644 (file)
@@ -1,3 +1,28 @@
+2019-07-17  Sam Weinig  <weinig@apple.com>
+
+        Add StringBuilder member function which allows makeString() style variadic argument construction
+        https://bugs.webkit.org/show_bug.cgi?id=198997
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/Tests/WTF/StringBuilder.cpp:
+        Add basic test showing that StringBuilder::flexibleAppend can be used to 
+        append one or more string adaptable types. 
+
+        * TestWebKitAPI/CMakeLists.txt:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        Add WTFStringUtilities.cpp
+
+        * TestWebKitAPI/Tests/WTF/StringBuilder.cpp:
+        Add basic test showing that StringBuilder::flexibleAppend can be used to 
+        append one or more string adaptable types. 
+
+        * TestWebKitAPI/Tests/WTF/StringOperators.cpp:
+        * TestWebKitAPI/WTFStringUtilities.cpp: Added.
+        * TestWebKitAPI/WTFStringUtilities.h:
+        Move WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING() and wtfStringCopyCount to WTFStringUtilities.h/cpp
+        to allow for a single definition of StringTypeAdapter<String, void> which is required for ODR.
+
 2019-07-17  Ryosuke Niwa  <rniwa@webkit.org>
 
         Remove the file superfluously added in r247535.
index 619e78d..b78fc2c 100644 (file)
@@ -23,6 +23,7 @@ endmacro()
 set(TestWTF_SOURCES
     Counters.cpp
     TestsController.cpp
+    WTFStringUtilities.cpp
 
     Tests/WTF/AtomString.cpp
     Tests/WTF/BloomFilter.cpp
@@ -116,6 +117,7 @@ WEBKIT_EXECUTABLE_DECLARE(TestWTF)
 if (ENABLE_WEBCORE)
     set(TestWebCore_SOURCES
         TestsController.cpp
+        WTFStringUtilities.cpp
 
         Tests/WebCore/AffineTransform.cpp
         Tests/WebCore/CSSParser.cpp
@@ -165,6 +167,7 @@ endif ()
 if (ENABLE_WEBKIT_LEGACY)
     set(TestWebKitLegacy_SOURCES
         TestsController.cpp
+        WTFStringUtilities.cpp
     )
 
     set(TestWebKitLegacy_LIBRARIES
@@ -266,6 +269,7 @@ if (ENABLE_WEBKIT)
         JavaScriptTest.cpp
         PlatformUtilities.cpp
         TestsController.cpp
+        WTFStringUtilities.cpp
     )
     target_compile_definitions(TestWebKitAPIBase PRIVATE BUILDING_TestWebKit)
     target_include_directories(TestWebKitAPIBase PRIVATE ${TestWebKit_PRIVATE_INCLUDE_DIRECTORIES})
index 53660a1..5afb901 100644 (file)
                7C3DB8E41D12129B00AE8CC3 /* CommandBackForward.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7C3DB8E21D12129B00AE8CC3 /* CommandBackForward.mm */; };
                7C417F331D19E14800B8EF53 /* WKWebViewDefaultNavigationDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7C417F311D19E14800B8EF53 /* WKWebViewDefaultNavigationDelegate.mm */; };
                7C486BA11AA12567003F6F9B /* bundle-file.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7C486BA01AA1254B003F6F9B /* bundle-file.html */; };
+               7C74C8FA22DFBA9600DA2DAB /* WTFStringUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CBD5A2222DE42A6004A9E32 /* WTFStringUtilities.cpp */; };
                7C83DE991D0A590C00FEBCF3 /* AtomString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F1B44215CA434F00D1E4BF /* AtomString.cpp */; };
                7C83DE9C1D0A590C00FEBCF3 /* BloomFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E40019301ACE9B5C001B0A2A /* BloomFilter.cpp */; };
                7C83DEA01D0A590C00FEBCF3 /* CheckedArithmeticOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7A966DA140ECCC8005EF9B4 /* CheckedArithmeticOperations.cpp */; };
                7C89D2AC1A69B80D003A5FDE /* WKPageConfiguration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C89D2AA1A69B80D003A5FDE /* WKPageConfiguration.cpp */; };
                7C9ED98B17A19F4B00E4DC33 /* attributedStringStrikethrough.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7C9ED98A17A19D0600E4DC33 /* attributedStringStrikethrough.html */; };
                7CB184C61AA3F2100066EDFD /* ContentExtensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CB184C41AA3F2100066EDFD /* ContentExtensions.cpp */; };
+               7CBD5A2322DE42A6004A9E32 /* WTFStringUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CBD5A2222DE42A6004A9E32 /* WTFStringUtilities.cpp */; };
                7CCB4DA91C83AE7300CC6918 /* PageGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CCB4DA71C83AE7300CC6918 /* PageGroup.cpp */; };
                7CCB99211D3B41F6003922F6 /* UserInitiatedActionInNavigationAction.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7CCB99201D3B41F6003922F6 /* UserInitiatedActionInNavigationAction.mm */; };
                7CCB99231D3B4A46003922F6 /* open-multiple-external-url.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7CCB99221D3B44E7003922F6 /* open-multiple-external-url.html */; };
                7C9ED98A17A19D0600E4DC33 /* attributedStringStrikethrough.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = attributedStringStrikethrough.html; sourceTree = "<group>"; };
                7CB184C41AA3F2100066EDFD /* ContentExtensions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentExtensions.cpp; sourceTree = "<group>"; };
                7CBBA07619BB8A9100BBF025 /* OSObjectPtr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OSObjectPtr.cpp; sourceTree = "<group>"; };
+               7CBD5A2222DE42A6004A9E32 /* WTFStringUtilities.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WTFStringUtilities.cpp; sourceTree = "<group>"; };
                7CC3E1FA197E234100BE6252 /* UserContentController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UserContentController.mm; sourceTree = "<group>"; };
                7CCB4DA71C83AE7300CC6918 /* PageGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageGroup.cpp; sourceTree = "<group>"; };
                7CCB99201D3B41F6003922F6 /* UserInitiatedActionInNavigationAction.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UserInitiatedActionInNavigationAction.mm; sourceTree = "<group>"; };
                                BCB9E7C711234E3A00A137E0 /* TestsController.h */,
                                7C83E0361D0A5F7000FEBCF3 /* Utilities.h */,
                                44A622C114A0E2B60048515B /* WTFStringUtilities.h */,
+                               7CBD5A2222DE42A6004A9E32 /* WTFStringUtilities.cpp */,
                        );
                        name = Source;
                        sourceTree = "<group>";
                        files = (
                                7C83DE991D0A590C00FEBCF3 /* AtomString.cpp in Sources */,
                                1ADAD1501D77A9F600212586 /* BlockPtr.mm in Sources */,
+                               7CBD5A2322DE42A6004A9E32 /* WTFStringUtilities.cpp in Sources */,
                                7C83DE9C1D0A590C00FEBCF3 /* BloomFilter.cpp in Sources */,
                                7C83DEA01D0A590C00FEBCF3 /* CheckedArithmeticOperations.cpp in Sources */,
                                0F30CB5C1FCE1796004B5323 /* ConcurrentPtrHashSet.cpp in Sources */,
                                5C3B1D2622A74F6700BCF4D0 /* ContextMenus.mm in Sources */,
                                5C2936931D5BF70D00DEAB1E /* CookieAcceptPolicy.mm in Sources */,
                                51D1249B1E785425002B2820 /* CookieManager.cpp in Sources */,
+                               7C74C8FA22DFBA9600DA2DAB /* WTFStringUtilities.cpp in Sources */,
                                5C19A5241FD0F60100EEA323 /* CookiePrivateBrowsing.mm in Sources */,
                                9B1F6F781F90558400B55744 /* CopyHTML.mm in Sources */,
                                9999108B1F393C96008AD455 /* Copying.mm in Sources */,
index ab67ce1..e4b7c02 100644 (file)
@@ -116,6 +116,29 @@ TEST(StringBuilderTest, Append)
     }
 }
 
+TEST(StringBuilderTest, FlexibleAppend)
+{
+    {
+        StringBuilder builder;
+        builder.flexibleAppend(String("0123456789"));
+        expectBuilderContent("0123456789", builder);
+        builder.flexibleAppend("abcd");
+        expectBuilderContent("0123456789abcd", builder);
+        builder.flexibleAppend('e');
+        expectBuilderContent("0123456789abcde", builder);
+        builder.flexibleAppend("");
+        expectBuilderContent("0123456789abcde", builder);
+    }
+
+    {
+        StringBuilder builder;
+        builder.flexibleAppend(String("0123456789"), "abcd", 'e', "");
+        expectBuilderContent("0123456789abcde", builder);
+        builder.flexibleAppend(String("A"), "B", 'C', "");
+        expectBuilderContent("0123456789abcdeABC", builder);
+    }
+}
+
 TEST(StringBuilderTest, ToString)
 {
     StringBuilder builder;
index 4b927a8..a0d38ab 100644 (file)
@@ -25,9 +25,7 @@
 
 #include "config.h"
 
-#define WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING() (++wtfStringCopyCount)
-
-static int wtfStringCopyCount;
+#include "WTFStringUtilities.h"
 
 #include <wtf/text/StringView.h>
 #include <wtf/text/WTFString.h>
diff --git a/Tools/TestWebKitAPI/WTFStringUtilities.cpp b/Tools/TestWebKitAPI/WTFStringUtilities.cpp
new file mode 100644 (file)
index 0000000..4182d87
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WTFStringUtilities.h"
+
+int wtfStringCopyCount;
index ecba9c4..78d830b 100644 (file)
 
 #pragma once
 
+#define WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING() (++wtfStringCopyCount)
+
+extern int wtfStringCopyCount;
+
 #include <wtf/Assertions.h>
 #include <wtf/text/CString.h>
 #include <wtf/text/StringBuilder.h>