Back to index

lightning-sunbird  0.9+nobinonly
xpcmaps.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; 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  *   John Bandhauer <jband@netscape.com> (original author)
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /* Private maps (hashtables). */
00042 
00043 #include "xpcprivate.h"
00044 
00045 /***************************************************************************/
00046 // static shared...
00047 
00048 // Note this is returning the bit pattern of the first part of the nsID, not
00049 // the pointer to the nsID.
00050 
00051 static JSDHashNumber JS_DLL_CALLBACK
00052 HashIIDPtrKey(JSDHashTable *table, const void *key)
00053 {
00054     return *((JSHashNumber*)key);
00055 }
00056 
00057 static JSBool JS_DLL_CALLBACK
00058 MatchIIDPtrKey(JSDHashTable *table,
00059             const JSDHashEntryHdr *entry,
00060             const void *key)
00061 {
00062     return ((const nsID*)key)->
00063                 Equals(*((const nsID*)((JSDHashEntryStub*)entry)->key));
00064 }
00065 
00066 static JSDHashNumber JS_DLL_CALLBACK
00067 HashNativeKey(JSDHashTable *table, const void *key)
00068 {
00069     XPCNativeSetKey* Key = (XPCNativeSetKey*) key;
00070 
00071     JSDHashNumber h = 0;
00072 
00073     XPCNativeSet*       Set;
00074     XPCNativeInterface* Addition;
00075     PRUint16            Position;
00076 
00077     if(Key->IsAKey())
00078     {
00079         Set      = Key->GetBaseSet();
00080         Addition = Key->GetAddition();
00081         Position = Key->GetPosition();
00082     }
00083     else
00084     {
00085         Set      = (XPCNativeSet*) Key;
00086         Addition = nsnull;
00087         Position = 0;
00088     }
00089 
00090     if(!Set)
00091     {
00092         NS_ASSERTION(Addition, "bad key");
00093         // This would be an XOR like below. 
00094         // But "0 ^ x == x". So it does not matter.
00095         h = (JSHashNumber) NS_PTR_TO_INT32(Addition) >> 2;
00096     }
00097     else
00098     {
00099         XPCNativeInterface** Current = Set->GetInterfaceArray();
00100         PRUint16 count = Set->GetInterfaceCount();
00101         if(Addition)
00102         {
00103             count++;
00104             for(PRUint16 i = 0; i < count; i++)
00105             {
00106                 if(i == Position)
00107                     h ^= (JSHashNumber) NS_PTR_TO_INT32(Addition) >> 2;
00108                 else
00109                     h ^= (JSHashNumber) NS_PTR_TO_INT32(*(Current++)) >> 2;
00110             }
00111         }
00112         else
00113         {
00114             for(PRUint16 i = 0; i < count; i++)
00115                 h ^= (JSHashNumber) NS_PTR_TO_INT32(*(Current++)) >> 2;
00116         }
00117     }
00118 
00119     return h;
00120 }
00121 
00122 /***************************************************************************/
00123 // implement JSContext2XPCContextMap...
00124 
00125 // static
00126 JSContext2XPCContextMap*
00127 JSContext2XPCContextMap::newMap(int size)
00128 {
00129     JSContext2XPCContextMap* map = new JSContext2XPCContextMap(size);
00130     if(map && map->mTable)
00131         return map;
00132     delete map;
00133     return nsnull;
00134 }
00135 
00136 
00137 JSContext2XPCContextMap::JSContext2XPCContextMap(int size)
00138 {
00139     mTable = JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
00140                               sizeof(Entry), size);
00141 }
00142 
00143 JSContext2XPCContextMap::~JSContext2XPCContextMap()
00144 {
00145     if(mTable)
00146         JS_DHashTableDestroy(mTable);
00147 }
00148 
00149 /***************************************************************************/
00150 // implement JSObject2WrappedJSMap...
00151 
00152 // static
00153 JSObject2WrappedJSMap*
00154 JSObject2WrappedJSMap::newMap(int size)
00155 {
00156     JSObject2WrappedJSMap* map = new JSObject2WrappedJSMap(size);
00157     if(map && map->mTable)
00158         return map;
00159     delete map;
00160     return nsnull;
00161 }
00162 
00163 JSObject2WrappedJSMap::JSObject2WrappedJSMap(int size)
00164 {
00165     mTable = JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
00166                               sizeof(Entry), size);
00167 }
00168 
00169 JSObject2WrappedJSMap::~JSObject2WrappedJSMap()
00170 {
00171     if(mTable)
00172         JS_DHashTableDestroy(mTable);
00173 }
00174 
00175 /***************************************************************************/
00176 // implement Native2WrappedNativeMap...
00177 
00178 // static
00179 Native2WrappedNativeMap*
00180 Native2WrappedNativeMap::newMap(int size)
00181 {
00182     Native2WrappedNativeMap* map = new Native2WrappedNativeMap(size);
00183     if(map && map->mTable)
00184         return map;
00185     delete map;
00186     return nsnull;
00187 }
00188 
00189 Native2WrappedNativeMap::Native2WrappedNativeMap(int size)
00190 {
00191     mTable = JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
00192                               sizeof(Entry), size);
00193 }
00194 
00195 Native2WrappedNativeMap::~Native2WrappedNativeMap()
00196 {
00197     if(mTable)
00198         JS_DHashTableDestroy(mTable);
00199 }
00200 
00201 /***************************************************************************/
00202 // implement IID2WrappedJSClassMap...
00203 
00204 struct JSDHashTableOps IID2WrappedJSClassMap::Entry::sOps =
00205 {
00206     JS_DHashAllocTable,
00207     JS_DHashFreeTable,
00208     JS_DHashGetKeyStub,
00209     HashIIDPtrKey,
00210     MatchIIDPtrKey,
00211     JS_DHashMoveEntryStub,
00212     JS_DHashClearEntryStub,
00213     JS_DHashFinalizeStub
00214 };
00215 
00216 // static
00217 IID2WrappedJSClassMap*
00218 IID2WrappedJSClassMap::newMap(int size)
00219 {
00220     IID2WrappedJSClassMap* map = new IID2WrappedJSClassMap(size);
00221     if(map && map->mTable)
00222         return map;
00223     delete map;
00224     return nsnull;
00225 }
00226 
00227 IID2WrappedJSClassMap::IID2WrappedJSClassMap(int size)
00228 {
00229     mTable = JS_NewDHashTable(&Entry::sOps, nsnull, sizeof(Entry), size);
00230 }
00231 
00232 IID2WrappedJSClassMap::~IID2WrappedJSClassMap()
00233 {
00234     if(mTable)
00235         JS_DHashTableDestroy(mTable);
00236 }
00237 
00238 
00239 /***************************************************************************/
00240 // implement IID2NativeInterfaceMap...
00241 
00242 struct JSDHashTableOps IID2NativeInterfaceMap::Entry::sOps =
00243 {
00244     JS_DHashAllocTable,
00245     JS_DHashFreeTable,
00246     JS_DHashGetKeyStub,
00247     HashIIDPtrKey,
00248     MatchIIDPtrKey,
00249     JS_DHashMoveEntryStub,
00250     JS_DHashClearEntryStub,
00251     JS_DHashFinalizeStub
00252 };
00253 
00254 // static
00255 IID2NativeInterfaceMap*
00256 IID2NativeInterfaceMap::newMap(int size)
00257 {
00258     IID2NativeInterfaceMap* map = new IID2NativeInterfaceMap(size);
00259     if(map && map->mTable)
00260         return map;
00261     delete map;
00262     return nsnull;
00263 }
00264 
00265 IID2NativeInterfaceMap::IID2NativeInterfaceMap(int size)
00266 {
00267     mTable = JS_NewDHashTable(&Entry::sOps, nsnull, sizeof(Entry), size);
00268 }
00269 
00270 IID2NativeInterfaceMap::~IID2NativeInterfaceMap()
00271 {
00272     if(mTable)
00273         JS_DHashTableDestroy(mTable);
00274 }
00275 
00276 /***************************************************************************/
00277 // implement ClassInfo2NativeSetMap...
00278 
00279 // static
00280 ClassInfo2NativeSetMap*
00281 ClassInfo2NativeSetMap::newMap(int size)
00282 {
00283     ClassInfo2NativeSetMap* map = new ClassInfo2NativeSetMap(size);
00284     if(map && map->mTable)
00285         return map;
00286     delete map;
00287     return nsnull;
00288 }
00289 
00290 ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int size)
00291 {
00292     mTable = JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
00293                               sizeof(Entry), size);
00294 }
00295 
00296 ClassInfo2NativeSetMap::~ClassInfo2NativeSetMap()
00297 {
00298     if(mTable)
00299         JS_DHashTableDestroy(mTable);
00300 }
00301 
00302 /***************************************************************************/
00303 // implement ClassInfo2WrappedNativeProtoMap...
00304 
00305 // static
00306 ClassInfo2WrappedNativeProtoMap*
00307 ClassInfo2WrappedNativeProtoMap::newMap(int size)
00308 {
00309     ClassInfo2WrappedNativeProtoMap* map = new ClassInfo2WrappedNativeProtoMap(size);
00310     if(map && map->mTable)
00311         return map;
00312     delete map;
00313     return nsnull;
00314 }
00315 
00316 ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int size)
00317 {
00318     mTable = JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
00319                               sizeof(Entry), size);
00320 }
00321 
00322 ClassInfo2WrappedNativeProtoMap::~ClassInfo2WrappedNativeProtoMap()
00323 {
00324     if(mTable)
00325         JS_DHashTableDestroy(mTable);
00326 }
00327 
00328 /***************************************************************************/
00329 // implement NativeSetMap...
00330 
00331 JSBool JS_DLL_CALLBACK
00332 NativeSetMap::Entry::Match(JSDHashTable *table,
00333                            const JSDHashEntryHdr *entry,
00334                            const void *key)
00335 {
00336     XPCNativeSetKey* Key = (XPCNativeSetKey*) key;
00337 
00338     // See the comment in the XPCNativeSetKey declaration in xpcprivate.h.
00339     if(!Key->IsAKey())
00340     {
00341         XPCNativeSet* Set1 = (XPCNativeSet*) key;
00342         XPCNativeSet* Set2 = ((Entry*)entry)->key_value;
00343 
00344         if(Set1 == Set2)
00345             return JS_TRUE;
00346 
00347         PRUint16 count = Set1->GetInterfaceCount();
00348         if(count != Set2->GetInterfaceCount())
00349             return JS_FALSE;
00350 
00351         XPCNativeInterface** Current1 = Set1->GetInterfaceArray();
00352         XPCNativeInterface** Current2 = Set2->GetInterfaceArray();
00353         for(PRUint16 i = 0; i < count; i++)
00354         {
00355             if(*(Current1++) != *(Current2++))
00356                 return JS_FALSE;
00357         }
00358 
00359         return JS_TRUE;
00360     }
00361 
00362     XPCNativeSet*       SetInTable = ((Entry*)entry)->key_value;
00363     XPCNativeSet*       Set        = Key->GetBaseSet();
00364     XPCNativeInterface* Addition   = Key->GetAddition();
00365 
00366     if(!Set)
00367     {
00368         // This is a special case to deal with the invariant that says:
00369         // "All sets have exactly one nsISupports interface and it comes first."
00370         // See XPCNativeSet::NewInstance for details.
00371         //
00372         // Though we might have a key that represents only one interface, we
00373         // know that if that one interface were contructed into a set then
00374         // it would end up really being a set with two interfaces (except for
00375         // the case where the one interface happened to be nsISupports).
00376 
00377         return ((SetInTable->GetInterfaceCount() == 1 &&
00378                  SetInTable->GetInterfaceAt(0) == Addition) ||
00379                 (SetInTable->GetInterfaceCount() == 2 &&
00380                  SetInTable->GetInterfaceAt(1) == Addition));
00381     }
00382 
00383     if(!Addition && Set == SetInTable)
00384         return JS_TRUE;
00385 
00386     PRUint16 count = Set->GetInterfaceCount() + (Addition ? 1 : 0);
00387     if(count != SetInTable->GetInterfaceCount())
00388         return JS_FALSE;
00389 
00390     PRUint16 Position = Key->GetPosition();
00391     XPCNativeInterface** CurrentInTable = SetInTable->GetInterfaceArray();
00392     XPCNativeInterface** Current = Set->GetInterfaceArray();
00393     for(PRUint16 i = 0; i < count; i++)
00394     {
00395         if(Addition && i == Position)
00396         {
00397             if(Addition != *(CurrentInTable++))
00398                 return JS_FALSE;
00399         }
00400         else
00401         {
00402             if(*(Current++) != *(CurrentInTable++))
00403                 return JS_FALSE;
00404         }
00405     }
00406 
00407     return JS_TRUE;
00408 }
00409 
00410 struct JSDHashTableOps NativeSetMap::Entry::sOps =
00411 {
00412     JS_DHashAllocTable,
00413     JS_DHashFreeTable,
00414     JS_DHashGetKeyStub,
00415     HashNativeKey,
00416     Match,
00417     JS_DHashMoveEntryStub,
00418     JS_DHashClearEntryStub,
00419     JS_DHashFinalizeStub
00420 };
00421 
00422 // static
00423 NativeSetMap*
00424 NativeSetMap::newMap(int size)
00425 {
00426     NativeSetMap* map = new NativeSetMap(size);
00427     if(map && map->mTable)
00428         return map;
00429     delete map;
00430     return nsnull;
00431 }
00432 
00433 NativeSetMap::NativeSetMap(int size)
00434 {
00435     mTable = JS_NewDHashTable(&Entry::sOps, nsnull, sizeof(Entry), size);
00436 }
00437 
00438 NativeSetMap::~NativeSetMap()
00439 {
00440     if(mTable)
00441         JS_DHashTableDestroy(mTable);
00442 }
00443 
00444 /***************************************************************************/
00445 // implement IID2ThisTranslatorMap...
00446 
00447 const void* JS_DLL_CALLBACK
00448 IID2ThisTranslatorMap::Entry::GetKey(JSDHashTable *table, JSDHashEntryHdr *entry)
00449 {
00450     return &((Entry*)entry)->key;
00451 }
00452 
00453 JSBool JS_DLL_CALLBACK
00454 IID2ThisTranslatorMap::Entry::Match(JSDHashTable *table,
00455                                     const JSDHashEntryHdr *entry,
00456                                     const void *key)
00457 {
00458     return ((const nsID*)key)->Equals(((Entry*)entry)->key);
00459 }
00460 
00461 void JS_DLL_CALLBACK
00462 IID2ThisTranslatorMap::Entry::Clear(JSDHashTable *table, JSDHashEntryHdr *entry)
00463 {
00464     NS_IF_RELEASE(((Entry*)entry)->value);
00465     memset(entry, 0, table->entrySize);
00466 }
00467 
00468 struct JSDHashTableOps IID2ThisTranslatorMap::Entry::sOps =
00469 {
00470     JS_DHashAllocTable,
00471     JS_DHashFreeTable,
00472     GetKey,
00473     HashIIDPtrKey,
00474     Match,
00475     JS_DHashMoveEntryStub,
00476     Clear,
00477     JS_DHashFinalizeStub
00478 };
00479 
00480 // static
00481 IID2ThisTranslatorMap*
00482 IID2ThisTranslatorMap::newMap(int size)
00483 {
00484     IID2ThisTranslatorMap* map = new IID2ThisTranslatorMap(size);
00485     if(map && map->mTable)
00486         return map;
00487     delete map;
00488     return nsnull;
00489 }
00490 
00491 IID2ThisTranslatorMap::IID2ThisTranslatorMap(int size)
00492 {
00493     mTable = JS_NewDHashTable(&Entry::sOps, nsnull, sizeof(Entry), size);
00494 }
00495 
00496 IID2ThisTranslatorMap::~IID2ThisTranslatorMap()
00497 {
00498     if(mTable)
00499         JS_DHashTableDestroy(mTable);
00500 }
00501 
00502 /***************************************************************************/
00503 
00504 JSDHashNumber JS_DLL_CALLBACK
00505 XPCNativeScriptableSharedMap::Entry::Hash(JSDHashTable *table, const void *key)
00506 {
00507     JSDHashNumber h;
00508     const unsigned char *s;
00509 
00510     XPCNativeScriptableShared* obj =
00511         (XPCNativeScriptableShared*) key;
00512 
00513     // hash together the flags and the classname string
00514 
00515     h = (JSDHashNumber) obj->GetFlags();
00516     for (s = (const unsigned char*) obj->GetJSClass()->name; *s != '\0'; s++)
00517         h = (h >> (JS_DHASH_BITS - 4)) ^ (h << 4) ^ *s;
00518     return h;
00519 }
00520 
00521 JSBool JS_DLL_CALLBACK
00522 XPCNativeScriptableSharedMap::Entry::Match(JSDHashTable *table,
00523                                          const JSDHashEntryHdr *entry,
00524                                          const void *key)
00525 {
00526     XPCNativeScriptableShared* obj1 =
00527         ((XPCNativeScriptableSharedMap::Entry*) entry)->key;
00528 
00529     XPCNativeScriptableShared* obj2 =
00530         (XPCNativeScriptableShared*) key;
00531 
00532     // match the flags and the classname string
00533 
00534     if(obj1->GetFlags() != obj2->GetFlags())
00535         return JS_FALSE;
00536 
00537     const char* name1 = obj1->GetJSClass()->name;
00538     const char* name2 = obj2->GetJSClass()->name;
00539 
00540     if(!name1 || !name2)
00541         return name1 == name2;
00542 
00543     return 0 == strcmp(name1, name2);
00544 }
00545 
00546 struct JSDHashTableOps XPCNativeScriptableSharedMap::Entry::sOps =
00547 {
00548     JS_DHashAllocTable,
00549     JS_DHashFreeTable,
00550     JS_DHashGetKeyStub,
00551     Hash,
00552     Match,
00553     JS_DHashMoveEntryStub,
00554     JS_DHashClearEntryStub,
00555     JS_DHashFinalizeStub
00556 };
00557 
00558 // static
00559 XPCNativeScriptableSharedMap*
00560 XPCNativeScriptableSharedMap::newMap(int size)
00561 {
00562     XPCNativeScriptableSharedMap* map =
00563         new XPCNativeScriptableSharedMap(size);
00564     if(map && map->mTable)
00565         return map;
00566     delete map;
00567     return nsnull;
00568 }
00569 
00570 XPCNativeScriptableSharedMap::XPCNativeScriptableSharedMap(int size)
00571 {
00572     mTable = JS_NewDHashTable(&Entry::sOps, nsnull, sizeof(Entry), size);
00573 }
00574 
00575 XPCNativeScriptableSharedMap::~XPCNativeScriptableSharedMap()
00576 {
00577     if(mTable)
00578         JS_DHashTableDestroy(mTable);
00579 }
00580 
00581 JSBool
00582 XPCNativeScriptableSharedMap::GetNewOrUsed(JSUint32 flags,
00583                                            char* name,
00584                                            JSBool isGlobal,
00585                                            XPCNativeScriptableInfo* si)
00586 {
00587     NS_PRECONDITION(name,"bad param");
00588     NS_PRECONDITION(si,"bad param");
00589 
00590     XPCNativeScriptableShared key(flags, name);
00591 
00592     Entry* entry = (Entry*)
00593         JS_DHashTableOperate(mTable, &key, JS_DHASH_ADD);
00594     if(!entry)
00595         return JS_FALSE;
00596 
00597     XPCNativeScriptableShared* shared = entry->key;
00598 
00599     if(!shared)
00600     {
00601         entry->key = shared =
00602             new XPCNativeScriptableShared(flags, key.TransferNameOwnership());
00603         if(!shared)
00604             return JS_FALSE;
00605         shared->PopulateJSClass(isGlobal);
00606     }
00607     si->SetScriptableShared(shared);
00608     return JS_TRUE;
00609 }
00610 
00611 /***************************************************************************/
00612 // implement XPCWrappedNativeProtoMap...
00613 
00614 // static
00615 XPCWrappedNativeProtoMap*
00616 XPCWrappedNativeProtoMap::newMap(int size)
00617 {
00618     XPCWrappedNativeProtoMap* map = new XPCWrappedNativeProtoMap(size);
00619     if(map && map->mTable)
00620         return map;
00621     delete map;
00622     return nsnull;
00623 }
00624 
00625 XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap(int size)
00626 {
00627     mTable = JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
00628                               sizeof(JSDHashEntryStub), size);
00629 }
00630 
00631 XPCWrappedNativeProtoMap::~XPCWrappedNativeProtoMap()
00632 {
00633     if(mTable)
00634         JS_DHashTableDestroy(mTable);
00635 }
00636 
00637 /***************************************************************************/
00638 // implement XPCNativeWrapperMap...
00639 
00640 // static
00641 XPCNativeWrapperMap*
00642 XPCNativeWrapperMap::newMap(int size)
00643 {
00644     XPCNativeWrapperMap* map = new XPCNativeWrapperMap(size);
00645     if(map && map->mTable)
00646         return map;
00647     delete map;
00648     return nsnull;
00649 }
00650 
00651 XPCNativeWrapperMap::XPCNativeWrapperMap(int size)
00652 {
00653     mTable = JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
00654                               sizeof(JSDHashEntryStub), size);
00655 }
00656 
00657 XPCNativeWrapperMap::~XPCNativeWrapperMap()
00658 {
00659     if(mTable)
00660         JS_DHashTableDestroy(mTable);
00661 }
00662 
00663 /***************************************************************************/