Back to index

lightning-sunbird  0.9+nobinonly
nsStaticNameTable.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code, released
00017  * March 31, 1998.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 /* Class to manage lookup of static names in a table. */
00041 
00042 #include "nsCRT.h"
00043 
00044 #include "nscore.h"
00045 #include "nsString.h"
00046 #include "nsReadableUtils.h"
00047 
00048 #define PL_ARENA_CONST_ALIGN_MASK 3
00049 #include "nsStaticNameTable.h"
00050 
00051 struct NameTableEntry : public PLDHashEntryHdr
00052 {
00053     // no ownership here!
00054     const char *mKey;
00055     PRInt32 mIndex;
00056 };
00057 
00058 PR_STATIC_CALLBACK(PRBool)
00059 matchNameKeysCaseInsensitive(PLDHashTable*, const PLDHashEntryHdr* aHdr,
00060                              const void* key)
00061 {
00062     const NameTableEntry* entry =
00063         NS_STATIC_CAST(const NameTableEntry *, aHdr);
00064     const char *keyValue = NS_STATIC_CAST(const char*, key);
00065 
00066     return (nsCRT::strcasecmp(entry->mKey, keyValue)==0);
00067 }
00068 
00069 /*
00070  * caseInsensitiveHashKey is just like PL_DHashStringKey except it
00071  * uses (*s & ~0x20) instead of simply *s.  This means that "aFOO" and
00072  * "afoo" and "aFoo" will all hash to the same thing.  It also means
00073  * that some strings that aren't case-insensensitively equal will hash
00074  * to the same value, but it's just a hash function so it doesn't
00075  * matter.
00076  */
00077 PR_STATIC_CALLBACK(PLDHashNumber)
00078 caseInsensitiveStringHashKey(PLDHashTable *table, const void *key)
00079 {
00080     PLDHashNumber h = 0;
00081     for (const unsigned char* s =
00082            NS_STATIC_CAST(const unsigned char*, key);
00083          *s != '\0';
00084          s++)
00085         h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ (*s & ~0x20);
00086     return h;
00087 }
00088 
00089 static const struct PLDHashTableOps nametable_CaseInsensitiveHashTableOps = {
00090     PL_DHashAllocTable,
00091     PL_DHashFreeTable,
00092     PL_DHashGetKeyStub,
00093     caseInsensitiveStringHashKey,
00094     matchNameKeysCaseInsensitive,
00095     PL_DHashMoveEntryStub,
00096     PL_DHashClearEntryStub,
00097     PL_DHashFinalizeStub,
00098     nsnull,
00099 };
00100 
00101 nsStaticCaseInsensitiveNameTable::nsStaticCaseInsensitiveNameTable()
00102   : mNameArray(nsnull), mNullStr("")
00103 {
00104     MOZ_COUNT_CTOR(nsStaticCaseInsensitiveNameTable);
00105     mNameTable.ops = nsnull;
00106 }
00107 
00108 nsStaticCaseInsensitiveNameTable::~nsStaticCaseInsensitiveNameTable()
00109 {
00110     if (mNameArray) {
00111         // manually call the destructor on placement-new'ed objects
00112         for (PRUint32 index = 0; index < mNameTable.entryCount; index++) {
00113             mNameArray[index].~nsDependentCString();
00114         }
00115         nsMemory::Free((void*)mNameArray);
00116     }
00117     if (mNameTable.ops)
00118         PL_DHashTableFinish(&mNameTable);
00119     MOZ_COUNT_DTOR(nsStaticCaseInsensitiveNameTable);
00120 }
00121 
00122 PRBool 
00123 nsStaticCaseInsensitiveNameTable::Init(const char* const aNames[], PRInt32 Count)
00124 {
00125     NS_ASSERTION(!mNameArray, "double Init");
00126     NS_ASSERTION(!mNameTable.ops, "double Init");
00127     NS_ASSERTION(aNames, "null name table");
00128     NS_ASSERTION(Count, "0 count");
00129 
00130     mNameArray = (nsDependentCString*)
00131                    nsMemory::Alloc(Count * sizeof(nsDependentCString));
00132     if (!mNameArray)
00133         return PR_FALSE;
00134 
00135     if (!PL_DHashTableInit(&mNameTable,
00136                            &nametable_CaseInsensitiveHashTableOps,
00137                            nsnull, sizeof(NameTableEntry), Count)) {
00138         mNameTable.ops = nsnull;
00139         return PR_FALSE;
00140     }
00141 
00142     for (PRInt32 index = 0; index < Count; ++index) {
00143         const char* raw = aNames[index];
00144 #ifdef DEBUG
00145         {
00146             // verify invariants of contents
00147             nsCAutoString temp1(raw);
00148             nsDependentCString temp2(raw);
00149             ToLowerCase(temp1);
00150             NS_ASSERTION(temp1.Equals(temp2), "upper case char in table");
00151             NS_ASSERTION(nsCRT::IsAscii(raw),
00152                          "non-ascii string in table -- "
00153                          "case-insensitive matching won't work right");
00154         }
00155 #endif
00156         // use placement-new to initialize the string object
00157         new (&mNameArray[index]) nsDependentCString(raw);
00158 
00159         NameTableEntry *entry =
00160           NS_STATIC_CAST(NameTableEntry*,
00161                          PL_DHashTableOperate(&mNameTable, raw, PL_DHASH_ADD));
00162 
00163         if (!entry) continue;
00164 
00165         NS_ASSERTION(entry->mKey == 0, "Entry already exists!");
00166 
00167         entry->mKey = raw;      // not owned!
00168         entry->mIndex = index;
00169     }
00170     return PR_TRUE;
00171 }
00172 
00173 inline PRInt32
00174 LookupFlatKeyword(const nsAFlatCString& aKeyword,
00175                   PLDHashTable& aTable)
00176 {
00177     NameTableEntry *entry =
00178       NS_STATIC_CAST(NameTableEntry*,
00179                      PL_DHashTableOperate(&aTable, aKeyword.get(), PL_DHASH_LOOKUP));
00180 
00181     if (PL_DHASH_ENTRY_IS_FREE(entry))
00182         return nsStaticCaseInsensitiveNameTable::NOT_FOUND;
00183 
00184     return entry->mIndex;
00185 }
00186 
00187 PRInt32
00188 nsStaticCaseInsensitiveNameTable::Lookup(const nsACString& aName)
00189 {
00190     NS_ASSERTION(mNameArray, "not inited");
00191     NS_ASSERTION(mNameTable.ops, "not inited");
00192 
00193     return LookupFlatKeyword(PromiseFlatCString(aName), mNameTable);
00194 }
00195 
00196 PRInt32
00197 nsStaticCaseInsensitiveNameTable::Lookup(const nsAString& aName)
00198 {
00199     NS_ASSERTION(mNameArray, "not inited");
00200     NS_ASSERTION(mNameTable.ops, "not inited");
00201 
00202     nsCAutoString cstring;
00203     cstring.AssignWithConversion(aName);
00204     return LookupFlatKeyword(cstring, mNameTable);
00205 }
00206 
00207 const nsAFlatCString& 
00208 nsStaticCaseInsensitiveNameTable::GetStringValue(PRInt32 index)
00209 {
00210     NS_ASSERTION(mNameArray, "not inited");
00211     NS_ASSERTION(mNameTable.ops, "not inited");
00212 
00213     if ((NOT_FOUND < index) && ((PRUint32)index < mNameTable.entryCount)) {
00214         return mNameArray[index];
00215     }
00216     return mNullStr;
00217 }