Towards 8 Bit Strings: Templatize JSC::Lexer class by character type
[WebKit-https.git] / Source / JavaScriptCore / runtime / Identifier.h
1 /*
2  *  Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Library General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Library General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Library General Public License
15  *  along with this library; see the file COPYING.LIB.  If not, write to
16  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  *  Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #ifndef Identifier_h
22 #define Identifier_h
23
24 #include "JSGlobalData.h"
25 #include "ThreadSpecific.h"
26 #include "UString.h"
27 #include <wtf/WTFThreadData.h>
28 #include <wtf/text/CString.h>
29
30 namespace JSC {
31
32     class ExecState;
33
34     class Identifier {
35         friend class Structure;
36     public:
37         Identifier() { }
38
39         Identifier(ExecState* exec, const char* s) : m_string(add(exec, s)) { } // Only to be used with string literals.
40         Identifier(ExecState* exec, StringImpl* rep) : m_string(add(exec, rep)) { } 
41         Identifier(ExecState* exec, const UString& s) : m_string(add(exec, s.impl())) { }
42
43         Identifier(JSGlobalData* globalData, const char* s) : m_string(add(globalData, s)) { } // Only to be used with string literals.
44         Identifier(JSGlobalData* globalData, const LChar* s, int length) : m_string(add(globalData, s, length)) { }
45         Identifier(JSGlobalData* globalData, const UChar* s, int length) : m_string(add(globalData, s, length)) { }
46         Identifier(JSGlobalData* globalData, StringImpl* rep) : m_string(add(globalData, rep)) { } 
47         Identifier(JSGlobalData* globalData, const UString& s) : m_string(add(globalData, s.impl())) { }
48
49         const UString& ustring() const { return m_string; }
50         StringImpl* impl() const { return m_string.impl(); }
51         
52         const UChar* characters() const { return m_string.characters(); }
53         int length() const { return m_string.length(); }
54         
55         CString ascii() const { return m_string.ascii(); }
56
57         static Identifier createLCharFromUChar(JSGlobalData* globalData, const UChar* s, int length) { return Identifier(globalData, add8(globalData, s, length)); }
58
59         static Identifier from(ExecState* exec, unsigned y);
60         static Identifier from(ExecState* exec, int y);
61         static Identifier from(ExecState* exec, double y);
62         static Identifier from(JSGlobalData*, unsigned y);
63         static Identifier from(JSGlobalData*, int y);
64         static Identifier from(JSGlobalData*, double y);
65
66         static uint32_t toUInt32(const UString&, bool& ok);
67         uint32_t toUInt32(bool& ok) const { return toUInt32(m_string, ok); }
68         unsigned toArrayIndex(bool& ok) const;
69
70         bool isNull() const { return m_string.isNull(); }
71         bool isEmpty() const { return m_string.isEmpty(); }
72         
73         friend bool operator==(const Identifier&, const Identifier&);
74         friend bool operator!=(const Identifier&, const Identifier&);
75
76         friend bool operator==(const Identifier&, const LChar*);
77         friend bool operator==(const Identifier&, const char*);
78         friend bool operator!=(const Identifier&, const LChar*);
79         friend bool operator!=(const Identifier&, const char*);
80     
81         static bool equal(const StringImpl*, const LChar*);
82         static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
83         static bool equal(const StringImpl*, const LChar*, unsigned length);
84         static bool equal(const StringImpl*, const UChar*, unsigned length);
85         static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
86
87         static PassRefPtr<StringImpl> add(ExecState*, const char*); // Only to be used with string literals.
88         static PassRefPtr<StringImpl> add(JSGlobalData*, const char*); // Only to be used with string literals.
89
90     private:
91         UString m_string;
92         
93         static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
94         static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
95
96         template <typename T> static PassRefPtr<StringImpl> add(JSGlobalData*, const T*, int length);
97         static PassRefPtr<StringImpl> add8(JSGlobalData*, const UChar*, int length);
98         template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T);
99
100         static PassRefPtr<StringImpl> add(ExecState* exec, StringImpl* r)
101         {
102 #ifndef NDEBUG
103             checkCurrentIdentifierTable(exec);
104 #endif
105             if (r->isIdentifier())
106                 return r;
107             return addSlowCase(exec, r);
108         }
109         static PassRefPtr<StringImpl> add(JSGlobalData* globalData, StringImpl* r)
110         {
111 #ifndef NDEBUG
112             checkCurrentIdentifierTable(globalData);
113 #endif
114             if (r->isIdentifier())
115                 return r;
116             return addSlowCase(globalData, r);
117         }
118
119         static PassRefPtr<StringImpl> addSlowCase(ExecState*, StringImpl* r);
120         static PassRefPtr<StringImpl> addSlowCase(JSGlobalData*, StringImpl* r);
121
122         static void checkCurrentIdentifierTable(ExecState*);
123         static void checkCurrentIdentifierTable(JSGlobalData*);
124     };
125
126     template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar)
127     {
128         ASSERT(maxSingleCharacterString == 0xff);
129         return true;
130     }
131
132     template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
133     {
134         return (c <= maxSingleCharacterString);
135     }
136
137     template <typename T>
138     struct CharBuffer {
139         const T* s;
140         unsigned int length;
141     };
142     
143     template <typename T>
144     struct IdentifierCharBufferTranslator {
145         static unsigned hash(const CharBuffer<T>& buf)
146         {
147             return StringHasher::computeHash<T>(buf.s, buf.length);
148         }
149         
150         static bool equal(StringImpl* str, const CharBuffer<T>& buf)
151         {
152             return Identifier::equal(str, buf.s, buf.length);
153         }
154
155         static void translate(StringImpl*& location, const CharBuffer<T>& buf, unsigned hash)
156         {
157             T* d;
158             StringImpl* r = StringImpl::createUninitialized(buf.length, d).leakRef();
159             for (unsigned i = 0; i != buf.length; i++)
160                 d[i] = buf.s[i];
161             r->setHash(hash);
162             location = r; 
163         }
164     };
165
166     template <typename T>
167     PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const T* s, int length)
168     {
169         if (length == 1) {
170             T c = s[0];
171             if (canUseSingleCharacterString(c))
172                 return add(globalData, globalData->smallStrings.singleCharacterStringRep(c));
173         }
174         
175         if (!length)
176             return StringImpl::empty();
177         CharBuffer<T> buf = {s, length}; 
178         pair<HashSet<StringImpl*>::iterator, bool> addResult = globalData->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T> >(buf);
179         
180         // If the string is newly-translated, then we need to adopt it.
181         // The boolean in the pair tells us if that is so.
182         return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
183     }
184
185     inline bool operator==(const Identifier& a, const Identifier& b)
186     {
187         return Identifier::equal(a, b);
188     }
189
190     inline bool operator!=(const Identifier& a, const Identifier& b)
191     {
192         return !Identifier::equal(a, b);
193     }
194
195     inline bool operator==(const Identifier& a, const LChar* b)
196     {
197         return Identifier::equal(a, b);
198     }
199
200     inline bool operator==(const Identifier& a, const char* b)
201     {
202         return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
203     }
204     
205     inline bool operator!=(const Identifier& a, const LChar* b)
206     {
207         return !Identifier::equal(a, b);
208     }
209
210     inline bool operator!=(const Identifier& a, const char* b)
211     {
212         return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
213     }
214     
215     inline bool Identifier::equal(const StringImpl* r, const LChar* s)
216     {
217         return WTF::equal(r, s);
218     }
219
220     inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length)
221     {
222         return WTF::equal(r, s, length);
223     }
224
225     inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
226     {
227         return WTF::equal(r, s, length);
228     }
229     
230     IdentifierTable* createIdentifierTable();
231     void deleteIdentifierTable(IdentifierTable*);
232
233     struct IdentifierRepHash : PtrHash<RefPtr<StringImpl> > {
234         static unsigned hash(const RefPtr<StringImpl>& key) { return key->existingHash(); }
235         static unsigned hash(StringImpl* key) { return key->existingHash(); }
236     };
237
238     struct IdentifierMapIndexHashTraits {
239         typedef int TraitType;
240         typedef IdentifierMapIndexHashTraits StorageTraits;
241         static int emptyValue() { return std::numeric_limits<int>::max(); }
242         static const bool emptyValueIsZero = false;
243         static const bool needsDestruction = false;
244         static const bool needsRef = false;
245     };
246
247     typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, IdentifierMapIndexHashTraits> IdentifierMap;
248
249     template<typename U, typename V>
250     std::pair<HashSet<StringImpl*>::iterator, bool> IdentifierTable::add(U value)
251     {
252         std::pair<HashSet<StringImpl*>::iterator, bool> result = m_table.add<U, V>(value);
253         (*result.first)->setIsIdentifier(true);
254         return result;
255     }
256
257 } // namespace JSC
258
259 #endif // Identifier_h