1/*
2 *  Copyright (C) 2003, 2006, 2007, 2008, 2009, 2012 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 "VM.h"
25#include <wtf/ThreadSpecific.h>
26#include <wtf/WTFThreadData.h>
27#include <wtf/text/CString.h>
28#include <wtf/text/WTFString.h>
29
30namespace JSC {
31
32    class ExecState;
33
34    class Identifier {
35        friend class Structure;
36    public:
37        Identifier() { }
38        enum EmptyIdentifierFlag { EmptyIdentifier };
39        Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { ASSERT(m_string.impl()->isAtomic()); }
40
41        // Only to be used with string literals.
42        template<unsigned charactersCount>
43        Identifier(ExecState* exec, const char (&characters)[charactersCount]) : m_string(add(exec, characters)) { ASSERT(m_string.impl()->isAtomic()); }
44        template<unsigned charactersCount>
45        Identifier(VM* vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { ASSERT(m_string.impl()->isAtomic()); }
46
47        Identifier(ExecState* exec, StringImpl* rep) : m_string(add(exec, rep)) { ASSERT(m_string.impl()->isAtomic()); }
48        Identifier(ExecState* exec, const String& s) : m_string(add(exec, s.impl())) { ASSERT(m_string.impl()->isAtomic()); }
49
50        Identifier(VM* vm, const LChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); }
51        Identifier(VM* vm, const UChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); }
52        Identifier(VM* vm, StringImpl* rep) : m_string(add(vm, rep)) { ASSERT(m_string.impl()->isAtomic()); }
53        Identifier(VM* vm, const String& s) : m_string(add(vm, s.impl())) { ASSERT(m_string.impl()->isAtomic()); }
54
55        const String& string() const { return m_string; }
56        StringImpl* impl() const { return m_string.impl(); }
57
58        int length() const { return m_string.length(); }
59
60        CString ascii() const { return m_string.ascii(); }
61        CString utf8() const { return m_string.utf8(); }
62
63        static Identifier from(const PrivateName& name)
64        {
65            Identifier result;
66            result.m_string = name.uid();
67            return result;
68        }
69
70        static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); }
71
72        JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, unsigned y);
73        JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, int y);
74        static Identifier from(ExecState* exec, double y);
75        static Identifier from(VM*, unsigned y);
76        static Identifier from(VM*, int y);
77        static Identifier from(VM*, double y);
78
79        bool isNull() const { return m_string.isNull(); }
80        bool isEmpty() const { return m_string.isEmpty(); }
81
82        friend bool operator==(const Identifier&, const Identifier&);
83        friend bool operator!=(const Identifier&, const Identifier&);
84
85        friend bool operator==(const Identifier&, const LChar*);
86        friend bool operator==(const Identifier&, const char*);
87        friend bool operator!=(const Identifier&, const LChar*);
88        friend bool operator!=(const Identifier&, const char*);
89
90        static bool equal(const StringImpl*, const LChar*);
91        static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
92        static bool equal(const StringImpl*, const LChar*, unsigned length);
93        static bool equal(const StringImpl*, const UChar*, unsigned length);
94        static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
95
96        // Only to be used with string literals.
97        JS_EXPORT_PRIVATE static PassRef<StringImpl> add(VM*, const char*);
98        JS_EXPORT_PRIVATE static PassRef<StringImpl> add(ExecState*, const char*);
99
100    private:
101        String m_string;
102
103        template <typename CharType>
104        ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok);
105
106        static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
107        static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
108
109        template <typename T> static PassRef<StringImpl> add(VM*, const T*, int length);
110        static PassRef<StringImpl> add8(VM*, const UChar*, int length);
111        template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T);
112
113        static PassRef<StringImpl> add(ExecState*, StringImpl*);
114        static PassRef<StringImpl> add(VM*, StringImpl*);
115
116        JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(ExecState*);
117        JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(VM*);
118    };
119
120    template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar)
121    {
122        ASSERT(maxSingleCharacterString == 0xff);
123        return true;
124    }
125
126    template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
127    {
128        return (c <= maxSingleCharacterString);
129    }
130
131    template <typename T>
132    PassRef<StringImpl> Identifier::add(VM* vm, const T* s, int length)
133    {
134        if (length == 1) {
135            T c = s[0];
136            if (canUseSingleCharacterString(c))
137                return *vm->smallStrings.singleCharacterStringRep(c);
138        }
139        if (!length)
140            return *StringImpl::empty();
141
142        return *AtomicString::add(s, length);
143    }
144
145    inline bool operator==(const Identifier& a, const Identifier& b)
146    {
147        return Identifier::equal(a, b);
148    }
149
150    inline bool operator!=(const Identifier& a, const Identifier& b)
151    {
152        return !Identifier::equal(a, b);
153    }
154
155    inline bool operator==(const Identifier& a, const LChar* b)
156    {
157        return Identifier::equal(a, b);
158    }
159
160    inline bool operator==(const Identifier& a, const char* b)
161    {
162        return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
163    }
164
165    inline bool operator!=(const Identifier& a, const LChar* b)
166    {
167        return !Identifier::equal(a, b);
168    }
169
170    inline bool operator!=(const Identifier& a, const char* b)
171    {
172        return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
173    }
174
175    inline bool Identifier::equal(const StringImpl* r, const LChar* s)
176    {
177        return WTF::equal(r, s);
178    }
179
180    inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length)
181    {
182        return WTF::equal(r, s, length);
183    }
184
185    inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
186    {
187        return WTF::equal(r, s, length);
188    }
189
190    struct IdentifierRepHash : PtrHash<RefPtr<StringImpl>> {
191        static unsigned hash(const RefPtr<StringImpl>& key) { return key->existingHash(); }
192        static unsigned hash(StringImpl* key) { return key->existingHash(); }
193    };
194
195    struct IdentifierMapIndexHashTraits : HashTraits<int> {
196        static int emptyValue() { return std::numeric_limits<int>::max(); }
197        static const bool emptyValueIsZero = false;
198    };
199
200    typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl>>, IdentifierMapIndexHashTraits> IdentifierMap;
201    typedef HashMap<StringImpl*, int, IdentifierRepHash, HashTraits<StringImpl*>, IdentifierMapIndexHashTraits> BorrowedIdentifierMap;
202
203} // namespace JSC
204
205namespace WTF {
206
207template <> struct VectorTraits<JSC::Identifier> : SimpleClassVectorTraits { };
208
209} // namespace WTF
210
211#endif // Identifier_h
212