File indexing completed on 2024-05-12 15:43:22

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 2003 Apple Computer, Inc
0004  *
0005  *  This library is free software; you can redistribute it and/or
0006  *  modify it under the terms of the GNU Library General Public
0007  *  License as published by the Free Software Foundation; either
0008  *  version 2 of the License, or (at your option) any later version.
0009  *
0010  *  This library is distributed in the hope that it will be useful,
0011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  *  Library General Public License for more details.
0014  *
0015  *  You should have received a copy of the GNU Library General Public License
0016  *  along with this library; see the file COPYING.LIB.  If not, write to
0017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  *  Boston, MA 02110-1301, USA.
0019  *
0020  */
0021 
0022 #include "identifier.h"
0023 
0024 #include <wtf/FastMalloc.h>
0025 #include <wtf/HashSet.h>
0026 #include <string.h> // for strlen
0027 #include <new> // for placement new
0028 
0029 namespace KJS
0030 {
0031 
0032 typedef HashSet<UString::Rep *> IdentifierTable;
0033 static IdentifierTable *table;
0034 
0035 static inline IdentifierTable &identifierTable()
0036 {
0037     if (!table) {
0038         table = new IdentifierTable;
0039     }
0040     return *table;
0041 }
0042 
0043 bool Identifier::equal(const UString::Rep *r, const char *s)
0044 {
0045     int length = r->len;
0046     const UChar *d = r->data();
0047     for (int i = 0; i != length; ++i)
0048         if (d[i].uc != (unsigned char)s[i]) {
0049             return false;
0050         }
0051     return s[length] == 0;
0052 }
0053 
0054 bool Identifier::equal(const UString::Rep *r, const UChar *s, int length)
0055 {
0056     if (r->len != length) {
0057         return false;
0058     }
0059     const UChar *d = r->data();
0060     for (int i = 0; i != length; ++i)
0061         if (d[i].uc != s[i].uc) {
0062             return false;
0063         }
0064     return true;
0065 }
0066 
0067 struct CStringTranslator {
0068     static unsigned hash(const char *c)
0069     {
0070         return UString::Rep::computeHash(c);
0071     }
0072 
0073     static bool equal(UString::Rep *r, const char *s)
0074     {
0075         return Identifier::equal(r, s);
0076     }
0077 
0078     static void translate(UString::Rep *&location, const char *c, unsigned hash)
0079     {
0080         size_t length = strlen(c);
0081         UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * length));
0082         for (size_t i = 0; i != length; i++) {
0083             d[i] = c[i];
0084         }
0085 
0086         UString::Rep *r = UString::Rep::create(d, static_cast<int>(length)).releaseRef();
0087         r->isIdentifier = 1;
0088         r->rc = 0;
0089         r->_hash = hash;
0090 
0091         location = r;
0092     }
0093 };
0094 
0095 PassRefPtr<UString::Rep> Identifier::add(const char *c)
0096 {
0097     if (!c) {
0098         UString::Rep::null.hash();
0099         return &UString::Rep::null;
0100     }
0101 
0102     if (!c[0]) {
0103         UString::Rep::empty.hash();
0104         return &UString::Rep::empty;
0105     }
0106 
0107     return *identifierTable().add<const char *, CStringTranslator>(c).first;
0108 }
0109 
0110 struct UCharBuffer {
0111     const UChar *s;
0112     unsigned int length;
0113 };
0114 
0115 struct UCharBufferTranslator {
0116     static unsigned hash(const UCharBuffer &buf)
0117     {
0118         return UString::Rep::computeHash(buf.s, buf.length);
0119     }
0120 
0121     static bool equal(UString::Rep *str, const UCharBuffer &buf)
0122     {
0123         return Identifier::equal(str, buf.s, buf.length);
0124     }
0125 
0126     static void translate(UString::Rep  *&location, const UCharBuffer &buf, unsigned hash)
0127     {
0128         UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * buf.length));
0129         for (unsigned i = 0; i != buf.length; i++) {
0130             d[i] = buf.s[i];
0131         }
0132 
0133         UString::Rep *r = UString::Rep::create(d, buf.length).releaseRef();
0134         r->isIdentifier = 1;
0135         r->rc = 0;
0136         r->_hash = hash;
0137 
0138         location = r;
0139     }
0140 };
0141 
0142 PassRefPtr<UString::Rep> Identifier::add(const UChar *s, int length)
0143 {
0144     if (!length) {
0145         UString::Rep::empty.hash();
0146         return &UString::Rep::empty;
0147     }
0148 
0149     UCharBuffer buf = {s, static_cast<unsigned int>(length)};
0150     return *identifierTable().add<UCharBuffer, UCharBufferTranslator>(buf).first;
0151 }
0152 
0153 PassRefPtr<UString::Rep> Identifier::addSlowCase(UString::Rep *r)
0154 {
0155     assert(!r->isIdentifier);
0156 
0157     if (r->len == 0) {
0158         UString::Rep::empty.hash();
0159         return &UString::Rep::empty;
0160     }
0161 
0162     UString::Rep *result = *identifierTable().add(r).first;
0163     if (result == r) {
0164         r->isIdentifier = true;
0165     }
0166     return result;
0167 }
0168 
0169 void Identifier::remove(UString::Rep *r)
0170 {
0171     identifierTable().remove(r);
0172 }
0173 
0174 } // namespace KJS