]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - wtf/text/AtomicString.cpp
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / wtf / text / AtomicString.cpp
index 946a6fb00e4516d37a110f29f051527f151ee766..06879770c0bcf0ed0b3b22fd1b4771dac84cf5b0 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
 /*
  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 
 #include "config.h"
 
 
 #include "config.h"
 
-#include <libkern/OSAtomic.h>
-
 #include "AtomicString.h"
 
 #include "StringHash.h"
 #include <wtf/HashSet.h>
 #include <wtf/Threading.h>
 #include <wtf/WTFThreadData.h>
 #include "AtomicString.h"
 
 #include "StringHash.h"
 #include <wtf/HashSet.h>
 #include <wtf/Threading.h>
 #include <wtf/WTFThreadData.h>
+#include <wtf/unicode/UTF8.h>
+
+#include <libkern/OSAtomic.h>
 
 
-namespace WebCore {
+namespace WTF {
+
+using namespace Unicode;
 
 COMPILE_ASSERT(sizeof(AtomicString) == sizeof(String), atomic_string_and_string_must_be_same_size);
 
 
 COMPILE_ASSERT(sizeof(AtomicString) == sizeof(String), atomic_string_and_string_must_be_same_size);
 
@@ -87,10 +91,20 @@ static inline HashSet<StringImpl*>& stringTable()
     return table->table();
 }
 
     return table->table();
 }
 
+template<typename T, typename HashTranslator>
+static inline PassRefPtr<StringImpl> addToStringTable(const T& value)
+{
+    pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<T, HashTranslator>(value);
+
+    // If the string is newly-translated, then we need to adopt it.
+    // The boolean in the pair tells us if that is so.
+    return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+}
+
 struct CStringTranslator {
     static unsigned hash(const char* c)
     {
 struct CStringTranslator {
     static unsigned hash(const char* c)
     {
-        return StringImpl::computeHash(c);
+        return StringHasher::computeHash(c);
     }
 
     static bool equal(StringImpl* r, const char* s)
     }
 
     static bool equal(StringImpl* r, const char* s)
@@ -102,12 +116,12 @@ struct CStringTranslator {
             if (d[i] != c)
                 return false;
         }
             if (d[i] != c)
                 return false;
         }
-        return s[length] == 0;
+        return !s[length];
     }
 
     static void translate(StringImpl*& location, const char* const& c, unsigned hash)
     {
     }
 
     static void translate(StringImpl*& location, const char* const& c, unsigned hash)
     {
-        location = StringImpl::create(c).releaseRef(); 
+        location = StringImpl::create(c).leakRef();
         location->setHash(hash);
         location->setIsAtomic(true);
     }
         location->setHash(hash);
         location->setIsAtomic(true);
     }
@@ -128,12 +142,10 @@ PassRefPtr<StringImpl> AtomicString::add(const char* c)
     if (!c)
         return 0;
     if (!*c)
     if (!c)
         return 0;
     if (!*c)
-        return StringImpl::empty();    
+        return StringImpl::empty();
+
     AtomicStringTableLocker locker;
     AtomicStringTableLocker locker;
-    pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<const char*, CStringTranslator>(c);
-    if (!addResult.second)
-        return *addResult.first;
-    return adoptRef(*addResult.first);
+    return addToStringTable<const char*, CStringTranslator>(c);
 }
 
 struct UCharBuffer {
 }
 
 struct UCharBuffer {
@@ -148,7 +160,7 @@ static inline bool equal(StringImpl* string, const UChar* characters, unsigned l
 
     // FIXME: perhaps we should have a more abstract macro that indicates when
     // going 4 bytes at a time is unsafe
 
     // FIXME: perhaps we should have a more abstract macro that indicates when
     // going 4 bytes at a time is unsafe
-#if CPU(ARM) || CPU(SH4)
+#if CPU(ARM) || CPU(SH4) || CPU(MIPS) || CPU(SPARC)
     const UChar* stringCharacters = string->characters();
     for (unsigned i = 0; i != length; ++i) {
         if (*stringCharacters++ != *characters++)
     const UChar* stringCharacters = string->characters();
     for (unsigned i = 0; i != length; ++i) {
         if (*stringCharacters++ != *characters++)
@@ -174,20 +186,25 @@ static inline bool equal(StringImpl* string, const UChar* characters, unsigned l
 #endif
 }
 
 #endif
 }
 
+bool operator==(const AtomicString& string, const Vector<UChar>& vector)
+{
+    return string.impl() && equal(string.impl(), vector.data(), vector.size());
+}
+
 struct UCharBufferTranslator {
     static unsigned hash(const UCharBuffer& buf)
     {
 struct UCharBufferTranslator {
     static unsigned hash(const UCharBuffer& buf)
     {
-        return StringImpl::computeHash(buf.s, buf.length);
+        return StringHasher::computeHash(buf.s, buf.length);
     }
 
     static bool equal(StringImpl* const& str, const UCharBuffer& buf)
     {
     }
 
     static bool equal(StringImpl* const& str, const UCharBuffer& buf)
     {
-        return WebCore::equal(str, buf.s, buf.length);
+        return WTF::equal(str, buf.s, buf.length);
     }
 
     static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash)
     {
     }
 
     static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash)
     {
-        location = StringImpl::create(buf.s, buf.length).releaseRef(); 
+        location = StringImpl::create(buf.s, buf.length).leakRef();
         location->setHash(hash);
         location->setIsAtomic(true);
     }
         location->setHash(hash);
         location->setIsAtomic(true);
     }
@@ -202,18 +219,65 @@ struct HashAndCharacters {
 struct HashAndCharactersTranslator {
     static unsigned hash(const HashAndCharacters& buffer)
     {
 struct HashAndCharactersTranslator {
     static unsigned hash(const HashAndCharacters& buffer)
     {
-        ASSERT(buffer.hash == StringImpl::computeHash(buffer.characters, buffer.length));
+        ASSERT(buffer.hash == StringHasher::computeHash(buffer.characters, buffer.length));
         return buffer.hash;
     }
 
     static bool equal(StringImpl* const& string, const HashAndCharacters& buffer)
     {
         return buffer.hash;
     }
 
     static bool equal(StringImpl* const& string, const HashAndCharacters& buffer)
     {
-        return WebCore::equal(string, buffer.characters, buffer.length);
+        return WTF::equal(string, buffer.characters, buffer.length);
     }
 
     static void translate(StringImpl*& location, const HashAndCharacters& buffer, unsigned hash)
     {
     }
 
     static void translate(StringImpl*& location, const HashAndCharacters& buffer, unsigned hash)
     {
-        location = StringImpl::create(buffer.characters, buffer.length).releaseRef();
+        location = StringImpl::create(buffer.characters, buffer.length).leakRef();
+        location->setHash(hash);
+        location->setIsAtomic(true);
+    }
+};
+
+struct HashAndUTF8Characters {
+    unsigned hash;
+    const char* characters;
+    unsigned length;
+    unsigned utf16Length;
+};
+
+struct HashAndUTF8CharactersTranslator {
+    static unsigned hash(const HashAndUTF8Characters& buffer)
+    {
+        return buffer.hash;
+    }
+
+    static bool equal(StringImpl* const& string, const HashAndUTF8Characters& buffer)
+    {
+        if (buffer.utf16Length != string->length())
+            return false;
+
+        const UChar* stringCharacters = string->characters();
+
+        // If buffer contains only ASCII characters UTF-8 and UTF16 length are the same.
+        if (buffer.utf16Length != buffer.length)
+            return equalUTF16WithUTF8(stringCharacters, stringCharacters + string->length(), buffer.characters, buffer.characters + buffer.length);
+
+        for (unsigned i = 0; i < buffer.length; ++i) {
+            ASSERT(isASCII(buffer.characters[i]));
+            if (stringCharacters[i] != buffer.characters[i])
+                return false;
+        }
+
+        return true;
+    }
+
+    static void translate(StringImpl*& location, const HashAndUTF8Characters& buffer, unsigned hash)
+    {
+        UChar* target;
+        location = StringImpl::createUninitialized(buffer.utf16Length, target).releaseRef();
+
+        const char* source = buffer.characters;
+        if (convertUTF8ToUTF16(&source, source + buffer.length, &target, target + buffer.utf16Length) != conversionOK)
+            ASSERT_NOT_REACHED();
+
         location->setHash(hash);
         location->setIsAtomic(true);
     }
         location->setHash(hash);
         location->setIsAtomic(true);
     }
@@ -224,16 +288,12 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length)
     if (!s)
         return 0;
 
     if (!s)
         return 0;
 
-    if (length == 0)
+    if (!length)
         return StringImpl::empty();
     
         return StringImpl::empty();
     
-    UCharBuffer buf = { s, length }; 
+    UCharBuffer buffer = { s, length };
     AtomicStringTableLocker locker;
     AtomicStringTableLocker locker;
-    pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf);
-
-    // If the string is newly-translated, then we need to adopt it.
-    // The boolean in the pair tells us if that is so.
-    return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+    return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer);
 }
 
 PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length, unsigned existingHash)
 }
 
 PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length, unsigned existingHash)
@@ -241,15 +301,12 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length, unsign
     ASSERT(s);
     ASSERT(existingHash);
 
     ASSERT(s);
     ASSERT(existingHash);
 
-    if (length == 0)
+    if (!length)
         return StringImpl::empty();
         return StringImpl::empty();
-    
-    HashAndCharacters buffer = { existingHash, s, length }; 
+
+    HashAndCharacters buffer = { existingHash, s, length };
     AtomicStringTableLocker locker;
     AtomicStringTableLocker locker;
-    pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<HashAndCharacters, HashAndCharactersTranslator>(buffer);
-    if (!addResult.second)
-        return *addResult.first;
-    return adoptRef(*addResult.first);
+    return addToStringTable<HashAndCharacters, HashAndCharactersTranslator>(buffer);
 }
 
 PassRefPtr<StringImpl> AtomicString::add(const UChar* s)
 }
 
 PassRefPtr<StringImpl> AtomicString::add(const UChar* s)
@@ -261,16 +318,12 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s)
     while (s[length] != UChar(0))
         length++;
 
     while (s[length] != UChar(0))
         length++;
 
-    if (length == 0)
+    if (!length)
         return StringImpl::empty();
 
         return StringImpl::empty();
 
-    UCharBuffer buf = {s, length}; 
+    UCharBuffer buffer = { s, length };
     AtomicStringTableLocker locker;
     AtomicStringTableLocker locker;
-    pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf);
-
-    // If the string is newly-translated, then we need to adopt it.
-    // The boolean in the pair tells us if that is so.
-    return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+    return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer);
 }
 
 PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* r)
 }
 
 PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* r)
@@ -278,7 +331,7 @@ PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* r)
     if (!r || r->isAtomic())
         return r;
 
     if (!r || r->isAtomic())
         return r;
 
-    if (r->length() == 0)
+    if (!r->length())
         return StringImpl::empty();
 
     AtomicStringTableLocker locker;
         return StringImpl::empty();
 
     AtomicStringTableLocker locker;
@@ -293,7 +346,7 @@ AtomicStringImpl* AtomicString::find(const UChar* s, unsigned length, unsigned e
     ASSERT(s);
     ASSERT(existingHash);
 
     ASSERT(s);
     ASSERT(existingHash);
 
-    if (length == 0)
+    if (!length)
         return static_cast<AtomicStringImpl*>(StringImpl::empty());
 
     HashAndCharacters buffer = { existingHash, s, length }; 
         return static_cast<AtomicStringImpl*>(StringImpl::empty());
 
     HashAndCharacters buffer = { existingHash, s, length }; 
@@ -309,15 +362,32 @@ void AtomicString::remove(StringImpl* r)
     AtomicStringTableLocker locker;
     stringTable().remove(r);
 }
     AtomicStringTableLocker locker;
     stringTable().remove(r);
 }
-    
+
 AtomicString AtomicString::lower() const
 {
     // Note: This is a hot function in the Dromaeo benchmark.
     StringImpl* impl = this->impl();
 AtomicString AtomicString::lower() const
 {
     // Note: This is a hot function in the Dromaeo benchmark.
     StringImpl* impl = this->impl();
+    if (UNLIKELY(!impl))
+        return *this;
     RefPtr<StringImpl> newImpl = impl->lower();
     if (LIKELY(newImpl == impl))
         return *this;
     return AtomicString(newImpl);
 }
 
     RefPtr<StringImpl> newImpl = impl->lower();
     if (LIKELY(newImpl == impl))
         return *this;
     return AtomicString(newImpl);
 }
 
+AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const char* charactersEnd)
+{
+    HashAndUTF8Characters buffer;
+    buffer.characters = charactersStart;
+    buffer.hash = calculateStringHashAndLengthFromUTF8(charactersStart, charactersEnd, buffer.length, buffer.utf16Length);
+
+    if (!buffer.hash)
+        return nullAtom;
+
+    AtomicString atomicString;
+    AtomicStringTableLocker locker;
+    atomicString.m_string = addToStringTable<HashAndUTF8Characters, HashAndUTF8CharactersTranslator>(buffer);
+    return atomicString;
 }
 }
+
+} // namespace WTF