]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSStringJoiner.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / JSStringJoiner.cpp
index 7e20d21959604b66fa37f85e07ec3d013d0fdafa..6f19593881966e93e4a39f266eb7bce6d7f9c5a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "config.h"
 #include "JSStringJoiner.h"
 
-#include "ExceptionHelpers.h"
-#include "JSScope.h"
-#include "JSString.h"
-#include "Operations.h"
-#include <wtf/text/StringImpl.h>
+#include "JSCInlines.h"
 
 namespace JSC {
 
-// The destination is 16bits, at least one string is 16 bits.
-static inline void appendStringToData(UChar*& data, const String& string)
+template<typename CharacterType>
+static inline void appendStringToData(CharacterType*& data, StringView string)
 {
-    if (string.isNull())
-        return;
+    string.getCharactersWithUpconvert(data);
+    data += string.length();
+}
 
-    unsigned length = string.length();
-    const StringImpl* stringImpl = string.impl();
+template<typename CharacterType>
+static inline String joinStrings(const Vector<StringViewWithUnderlyingString>& strings, StringView separator, unsigned joinedLength)
+{
+    ASSERT(joinedLength);
 
-    if (stringImpl->is8Bit()) {
-        for (unsigned i = 0; i < length; ++i) {
-            *data = stringImpl->characters8()[i];
-            ++data;
+    CharacterType* data;
+    String result = StringImpl::tryCreateUninitialized(joinedLength, data);
+    if (result.isNull())
+        return result;
+
+    appendStringToData(data, strings[0].view);
+
+    unsigned size = strings.size();
+
+    switch (separator.length()) {
+    case 0:
+        for (unsigned i = 1; i < size; ++i)
+            appendStringToData(data, strings[i].view);
+        break;
+    case 1: {
+        CharacterType separatorCharacter = separator[0];
+        for (unsigned i = 1; i < size; ++i) {
+            *data++ = separatorCharacter;
+            appendStringToData(data, strings[i].view);
         }
-    } else {
-        for (unsigned i = 0; i < length; ++i) {
-            *data = stringImpl->characters16()[i];
-            ++data;
+        break;
+    }
+    default:
+        for (unsigned i = 1; i < size; ++i) {
+            appendStringToData(data, separator);
+            appendStringToData(data, strings[i].view);
         }
     }
+    ASSERT(data == result.characters<CharacterType>() + joinedLength);
+
+    return result;
 }
 
-// If the destination is 8bits, we know every string has to be 8bit.
-static inline void appendStringToData(LChar*& data, const String& string)
+inline unsigned JSStringJoiner::joinedLength(ExecState& state) const
 {
-    if (string.isNull())
-        return;
-    ASSERT(string.is8Bit());
-
-    unsigned length = string.length();
-    const StringImpl* stringImpl = string.impl();
-
-    for (unsigned i = 0; i < length; ++i) {
-        *data = stringImpl->characters8()[i];
-        ++data;
+    unsigned numberOfStrings = m_strings.size();
+    if (!numberOfStrings)
+        return 0;
+
+    Checked<unsigned, RecordOverflow> separatorLength = m_separator.length();
+    Checked<unsigned, RecordOverflow> totalSeparatorsLength = separatorLength * (numberOfStrings - 1);
+    Checked<unsigned, RecordOverflow> totalLength = totalSeparatorsLength + m_accumulatedStringsLength;
+
+    unsigned result;
+    if (totalLength.safeGet(result) == CheckedState::DidOverflow) {
+        throwOutOfMemoryError(&state);
+        return 0;
     }
+    return result;
 }
 
-template<typename CharacterType>
-static inline PassRefPtr<StringImpl> joinStrings(const Vector<String>& strings, const String& separator, unsigned outputLength)
+JSValue JSStringJoiner::join(ExecState& state)
 {
-    ASSERT(outputLength);
-
-    CharacterType* data;
-    RefPtr<StringImpl> outputStringImpl = StringImpl::tryCreateUninitialized(outputLength, data);
-    if (!outputStringImpl)
-        return PassRefPtr<StringImpl>();
+    ASSERT(m_strings.size() <= m_strings.capacity());
 
-    const String firstString = strings.first();
-    appendStringToData(data, firstString);
+    unsigned length = joinedLength(state);
+    if (state.hadException())
+        return jsUndefined();
 
-    for (size_t i = 1; i < strings.size(); ++i) {
-        appendStringToData(data, separator);
-        appendStringToData(data, strings[i]);
-    }
-
-    ASSERT(data == (outputStringImpl->getCharacters<CharacterType>() + outputStringImpl->length()));
-    return outputStringImpl.release();
-}
+    if (!length)
+        return jsEmptyString(&state);
 
-JSValue JSStringJoiner::join(ExecState* exec)
-{
-    if (!m_isValid)
-        return throwOutOfMemoryError(exec);
-
-    if (!m_strings.size())
-        return jsEmptyString(exec);
-
-    Checked<size_t, RecordOverflow> separatorLength = m_separator.length();
-    // FIXME: add special cases of joinStrings() for (separatorLength == 0) and (separatorLength == 1).
-    ASSERT(m_strings.size() > 0);
-    Checked<size_t, RecordOverflow> totalSeparactorsLength = separatorLength * (m_strings.size() - 1);
-    Checked<size_t, RecordOverflow> outputStringSize = totalSeparactorsLength + m_accumulatedStringsLength;
-
-    size_t finalSize;
-    if (outputStringSize.safeGet(finalSize) == CheckedState::DidOverflow)
-        return throwOutOfMemoryError(exec);
-        
-    if (!outputStringSize)
-        return jsEmptyString(exec);
-
-    RefPtr<StringImpl> outputStringImpl;
-    if (m_is8Bits)
-        outputStringImpl = joinStrings<LChar>(m_strings, m_separator, finalSize);
+    String result;
+    if (m_isAll8Bit)
+        result = joinStrings<LChar>(m_strings, m_separator, length);
     else
-        outputStringImpl = joinStrings<UChar>(m_strings, m_separator, finalSize);
+        result = joinStrings<UChar>(m_strings, m_separator, length);
 
-    if (!outputStringImpl)
-        return throwOutOfMemoryError(exec);
+    if (result.isNull())
+        return throwOutOfMemoryError(&state);
 
-    return JSString::create(exec->vm(), outputStringImpl.release());
+    return jsString(&state, WTF::move(result));
 }
 
 }