Bug 460771 - Play/pause control confused after video ends. r=gavin
[wine-gecko.git] / xpcom / ds / nsAtomTable.cpp
blob472d250101b2da861e1b8f659c35b57c3c70e344
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:cindent:ts=2:et:sw=2:
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsAtomTable.h"
40 #include "nsStaticAtom.h"
41 #include "nsString.h"
42 #include "nsReadableUtils.h"
43 #include "nsUTF8Utils.h"
44 #include "nsCRT.h"
45 #include "pldhash.h"
46 #include "prenv.h"
47 #include "nsThreadUtils.h"
49 #define PL_ARENA_CONST_ALIGN_MASK 3
50 #include "plarena.h"
52 class nsStaticAtomWrapper;
54 /**
55 * The shared hash table for atom lookups.
57 * XXX This should be manipulated in a threadsafe way or we should make
58 * sure it's only manipulated from the main thread. Probably the latter
59 * is better, since the former would hurt performance.
61 * If |gAtomTable.ops| is 0, then the table is uninitialized.
63 static PLDHashTable gAtomTable;
65 // this is where we keep the nsStaticAtomWrapper objects
67 static PLArenaPool* gStaticAtomArena = 0;
69 class nsStaticAtomWrapper : public nsIAtom
71 public:
72 nsStaticAtomWrapper(const nsStaticAtom* aAtom, PRUint32 aLength) :
73 mStaticAtom(aAtom), mLength(aLength)
75 MOZ_COUNT_CTOR(nsStaticAtomWrapper);
77 ~nsStaticAtomWrapper() { // no subclasses -> not virtual
78 // this is arena allocated and won't be called except in debug
79 // builds. If this function ever does anything non-debug, be sure
80 // to get rid of the ifdefs in AtomTableClearEntry!
81 MOZ_COUNT_DTOR(nsStaticAtomWrapper);
84 NS_IMETHOD QueryInterface(REFNSIID aIID,
85 void** aInstancePtr);
86 NS_IMETHOD_(nsrefcnt) AddRef(void);
87 NS_IMETHOD_(nsrefcnt) Release(void);
89 NS_DECL_NSIATOM
91 const nsStaticAtom* GetStaticAtom() const {
92 return mStaticAtom;
95 PRUint32 getLength() const {
96 return mLength;
99 private:
100 const nsStaticAtom* mStaticAtom;
102 // The length of the string in the static atom. The static atom
103 // (nsStaticAtom) doesn't hold a length, so we keep it here in the
104 // wrapper instead.
105 PRUint32 mLength;
108 // The |key| pointer in the various PLDHashTable callbacks we use is an
109 // AtomTableClearEntry*. These pointers can come from two places: either a
110 // (probably stack-allocated) string key being passed to PL_DHashTableOperate,
111 // or an actual entry in the atom table. PLDHashTable reseves the keyHash
112 // values 0 and 1 for internal use, which means that the *PLDHashTable code*
113 // will never pass an entry whose keyhash is 0 or 1 to our hooks. That means we
114 // can use those values to tell whether an AtomTableEntry is a string key
115 // created by a PLDHashTable code caller or an actual live AtomTableEntry used
116 // by our PLDHashTable.
118 // Evil? Yes, but kinda neat too :-)
120 // An AtomTableEntry is a UTF-8 string key if keyHash is 0, in that
121 // case mBits points to a UTF-8 encoded char *. If keyHash is 1 the
122 // AtomTableEntry is a UTF-16 encoded string key and mBits points to a
123 // UTF-16 encoded PRUnichar *.
125 // If keyHash is any other value (> 1), the AtomTableEntry is an
126 // actual live entry in the table, and then mBits & ~0x1 in the
127 // AtomTableEntry points to an AtomImpl or a nsStaticAtomWrapper,
128 // indicated by the first bit of PtrBits.
129 // XXX This whole mess could be vastly simplified now that pldhash
130 // no longer has a getKey callback.
131 typedef PRUword PtrBits;
133 struct AtomTableEntry : public PLDHashEntryHdr {
134 // If keyHash > 1, mBits & 0x1 means (mBits & ~0x1) points to an
135 // nsStaticAtomWrapper else it points to an nsAtomImpl
136 PtrBits mBits;
137 PRUint32 mLength;
139 inline AtomTableEntry(const char *aString, PRUint32 aLength)
140 : mBits(PtrBits(aString)), mLength(aLength)
142 keyHash = 0;
145 inline AtomTableEntry(const PRUnichar *aString, PRUint32 aLength)
146 : mBits(PtrBits(aString)), mLength(aLength)
148 keyHash = 1;
151 inline PRBool IsStaticAtom() const {
152 NS_ASSERTION(keyHash > 1,
153 "IsStaticAtom() called on non-atom AtomTableEntry!");
154 return (mBits & 0x1) != 0;
157 inline PRBool IsUTF8String() const {
158 return keyHash == 0;
161 inline PRBool IsUTF16String() const {
162 return keyHash == 1;
165 inline void SetAtomImpl(AtomImpl* aAtom) {
166 NS_ASSERTION(keyHash > 1,
167 "SetAtomImpl() called on non-atom AtomTableEntry!");
168 NS_ASSERTION(aAtom, "Setting null atom");
169 mBits = PtrBits(aAtom);
170 mLength = aAtom->mLength;
173 inline void SetStaticAtomWrapper(nsStaticAtomWrapper* aAtom) {
174 NS_ASSERTION(keyHash > 1,
175 "SetStaticAtomWrapper() called on non-atom AtomTableEntry!");
176 NS_ASSERTION(aAtom, "Setting null atom");
177 NS_ASSERTION((PtrBits(aAtom) & ~0x1) == PtrBits(aAtom),
178 "Pointers must align or this is broken");
180 mBits = PtrBits(aAtom) | 0x1;
181 mLength = aAtom->getLength();
184 inline void ClearAtom() {
185 mBits = nsnull;
188 inline PRBool HasValue() const {
189 NS_ASSERTION(keyHash > 1,
190 "HasValue() called on non-atom AtomTableEntry!");
191 return (mBits & ~0x1) != 0;
194 // these accessors assume that you already know the type
195 inline AtomImpl *GetAtomImpl() const {
196 NS_ASSERTION(keyHash > 1,
197 "GetAtomImpl() called on non-atom AtomTableEntry!");
198 NS_ASSERTION(!IsStaticAtom(), "This is a static atom, not an AtomImpl");
199 return (AtomImpl*) (mBits & ~0x1);
202 inline nsStaticAtomWrapper *GetStaticAtomWrapper() const {
203 NS_ASSERTION(keyHash > 1,
204 "GetStaticAtomWrapper() called on non-atom AtomTableEntry!");
205 NS_ASSERTION(IsStaticAtom(), "This is an AtomImpl, not a static atom");
206 return (nsStaticAtomWrapper*) (mBits & ~0x1);
209 inline const nsStaticAtom* GetStaticAtom() const {
210 NS_ASSERTION(keyHash > 1,
211 "GetStaticAtom() called on non-atom AtomTableEntry!");
212 return GetStaticAtomWrapper()->GetStaticAtom();
215 // type-agnostic accessors
217 // get the string buffer
218 inline const char* getAtomString() const {
219 NS_ASSERTION(keyHash > 1,
220 "getAtomString() called on non-atom AtomTableEntry!");
222 return IsStaticAtom() ? GetStaticAtom()->mString : GetAtomImpl()->mString;
225 // get the string buffer
226 inline const char* getUTF8String() const {
227 NS_ASSERTION(keyHash == 0,
228 "getUTF8String() called on non-UTF8 AtomTableEntry!");
230 return (char *)mBits;
233 // get the string buffer
234 inline const PRUnichar* getUTF16String() const {
235 NS_ASSERTION(keyHash == 1,
236 "getUTF16String() called on non-UTF16 AtomTableEntry!");
238 return (PRUnichar *)mBits;
241 // get the string length
242 inline PRUint32 getLength() const {
243 return mLength;
246 // get an addreffed nsIAtom - not using already_AddRef'ed atom
247 // because the callers are not (and should not be) using nsCOMPtr
248 inline nsIAtom* GetAtom() const {
249 NS_ASSERTION(keyHash > 1,
250 "GetAtom() called on non-atom AtomTableEntry!");
252 nsIAtom* result;
254 if (IsStaticAtom())
255 result = GetStaticAtomWrapper();
256 else {
257 result = GetAtomImpl();
258 NS_ADDREF(result);
261 return result;
265 static PLDHashNumber
266 AtomTableGetHash(PLDHashTable *table, const void *key)
268 const AtomTableEntry *e = static_cast<const AtomTableEntry*>(key);
270 if (e->IsUTF16String()) {
271 return nsCRT::HashCodeAsUTF8(e->getUTF16String(), e->getLength());;
274 NS_ASSERTION(e->IsUTF8String(),
275 "AtomTableGetHash() called on non-string-key AtomTableEntry!");
277 return nsCRT::HashCode(e->getUTF8String(), e->getLength());
280 static PRBool
281 AtomTableMatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
282 const void *key)
284 const AtomTableEntry *he = static_cast<const AtomTableEntry*>(entry);
285 const AtomTableEntry *strKey = static_cast<const AtomTableEntry*>(key);
287 const char *atomString = he->getAtomString();
289 if (strKey->IsUTF16String()) {
290 return
291 CompareUTF8toUTF16(nsDependentCSubstring(atomString, atomString + he->getLength()),
292 nsDependentSubstring(strKey->getUTF16String(),
293 strKey->getUTF16String() + strKey->getLength())) == 0;
296 PRUint32 length = he->getLength();
297 if (length != strKey->getLength()) {
298 return PR_FALSE;
301 const char *str;
303 if (strKey->IsUTF8String()) {
304 str = strKey->getUTF8String();
305 } else {
306 str = strKey->getAtomString();
309 return memcmp(atomString, str, length * sizeof(char)) == 0;
312 static void
313 AtomTableClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
315 AtomTableEntry *he = static_cast<AtomTableEntry*>(entry);
317 if (!he->IsStaticAtom()) {
318 AtomImpl *atom = he->GetAtomImpl();
319 // Normal |AtomImpl| atoms are deleted when their refcount hits 0, and
320 // they then remove themselves from the table. In other words, they
321 // are owned by the callers who own references to them.
322 // |PermanentAtomImpl| permanent atoms ignore their refcount and are
323 // deleted when they are removed from the table at table destruction.
324 // In other words, they are owned by the atom table.
325 if (atom->IsPermanent()) {
326 he->keyHash = 0;
328 delete static_cast<PermanentAtomImpl*>(atom);
331 else {
332 he->GetStaticAtomWrapper()->~nsStaticAtomWrapper();
335 he->ClearAtom();
338 static PRBool
339 AtomTableInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
340 const void *key)
342 AtomTableEntry *he = static_cast<AtomTableEntry*>(entry);
343 const AtomTableEntry *strKey = static_cast<const AtomTableEntry*>(key);
345 he->mLength = strKey->getLength();
347 return PR_TRUE;
351 static const PLDHashTableOps AtomTableOps = {
352 PL_DHashAllocTable,
353 PL_DHashFreeTable,
354 AtomTableGetHash,
355 AtomTableMatchKey,
356 PL_DHashMoveEntryStub,
357 AtomTableClearEntry,
358 PL_DHashFinalizeStub,
359 AtomTableInitEntry
363 #ifdef DEBUG
365 static PLDHashOperator
366 DumpAtomLeaks(PLDHashTable *table, PLDHashEntryHdr *he,
367 PRUint32 index, void *arg)
369 AtomTableEntry *entry = static_cast<AtomTableEntry*>(he);
371 if (entry->IsStaticAtom())
372 return PL_DHASH_NEXT;
374 AtomImpl* atom = entry->GetAtomImpl();
375 if (!atom->IsPermanent()) {
376 ++*static_cast<PRUint32*>(arg);
377 const char *str;
378 atom->GetUTF8String(&str);
379 fputs(str, stdout);
380 fputs("\n", stdout);
382 return PL_DHASH_NEXT;
385 #endif
387 static inline
388 void PromoteToPermanent(AtomImpl* aAtom)
390 #ifdef NS_BUILD_REFCNT_LOGGING
392 nsrefcnt refcount = aAtom->GetRefCount();
393 do {
394 NS_LOG_RELEASE(aAtom, --refcount, "AtomImpl");
395 } while (refcount);
397 #endif
398 aAtom = new (aAtom) PermanentAtomImpl();
401 void
402 NS_PurgeAtomTable()
404 if (gAtomTable.ops) {
405 #ifdef DEBUG
406 if (PR_GetEnv("MOZ_DUMP_ATOM_LEAKS")) {
407 PRUint32 leaked = 0;
408 printf("*** %d atoms still exist (including permanent):\n",
409 gAtomTable.entryCount);
410 PL_DHashTableEnumerate(&gAtomTable, DumpAtomLeaks, &leaked);
411 printf("*** %u non-permanent atoms leaked\n", leaked);
413 #endif
414 PL_DHashTableFinish(&gAtomTable);
415 gAtomTable.entryCount = 0;
416 gAtomTable.ops = nsnull;
418 if (gStaticAtomArena) {
419 PL_FinishArenaPool(gStaticAtomArena);
420 delete gStaticAtomArena;
421 gStaticAtomArena = nsnull;
426 AtomImpl::AtomImpl()
430 AtomImpl::~AtomImpl()
432 NS_PRECONDITION(gAtomTable.ops, "uninitialized atom hashtable");
433 // Permanent atoms are removed from the hashtable at shutdown, and we
434 // don't want to remove them twice. See comment above in
435 // |AtomTableClearEntry|.
436 if (!IsPermanentInDestructor()) {
437 AtomTableEntry key(mString, mLength);
438 PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_REMOVE);
439 if (gAtomTable.entryCount == 0) {
440 PL_DHashTableFinish(&gAtomTable);
441 NS_ASSERTION(gAtomTable.entryCount == 0,
442 "PL_DHashTableFinish changed the entry count");
447 NS_IMPL_ISUPPORTS1(AtomImpl, nsIAtom)
449 PermanentAtomImpl::PermanentAtomImpl()
450 : AtomImpl()
454 PermanentAtomImpl::~PermanentAtomImpl()
456 // So we can tell if we were permanent while running the base class dtor.
457 mRefCnt = REFCNT_PERMANENT_SENTINEL;
460 NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::AddRef()
462 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
463 return 2;
466 NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::Release()
468 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
469 return 1;
472 /* virtual */ PRBool
473 AtomImpl::IsPermanent()
475 return PR_FALSE;
478 /* virtual */ PRBool
479 PermanentAtomImpl::IsPermanent()
481 return PR_TRUE;
484 void* AtomImpl::operator new ( size_t size, const nsACString& aString ) CPP_THROW_NEW
487 Note: since the |size| will initially also include the |PRUnichar| member
488 |mString|, our size calculation will give us one character too many.
489 We use that extra character for a zero-terminator.
491 Note: this construction is not guaranteed to be possible by the C++
492 compiler. A more reliable scheme is used by |nsShared[C]String|s, see
493 http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsSharedString.h#174
495 size += aString.Length() * sizeof(char);
496 AtomImpl* ii = static_cast<AtomImpl*>(::operator new(size));
497 NS_ENSURE_TRUE(ii, nsnull);
499 char* toBegin = &ii->mString[0];
500 nsACString::const_iterator fromBegin, fromEnd;
501 *copy_string(aString.BeginReading(fromBegin), aString.EndReading(fromEnd), toBegin) = '\0';
502 ii->mLength = aString.Length();
503 return ii;
506 void* PermanentAtomImpl::operator new ( size_t size, AtomImpl* aAtom ) CPP_THROW_NEW {
507 NS_ASSERTION(!aAtom->IsPermanent(),
508 "converting atom that's already permanent");
510 // Just let the constructor overwrite the vtable pointer.
511 return aAtom;
514 NS_IMETHODIMP
515 AtomImpl::ToString(nsAString& aBuf)
517 CopyUTF8toUTF16(nsDependentCString(mString, mLength), aBuf);
518 return NS_OK;
521 NS_IMETHODIMP
522 AtomImpl::ToUTF8String(nsACString& aBuf)
524 aBuf.Assign(mString, mLength);
525 return NS_OK;
528 NS_IMETHODIMP
529 AtomImpl::GetUTF8String(const char **aResult)
531 NS_PRECONDITION(aResult, "null out param");
532 *aResult = mString;
533 return NS_OK;
536 NS_IMETHODIMP
537 AtomImpl::EqualsUTF8(const nsACString& aString, PRBool* aResult)
539 *aResult = aString.Equals(nsDependentCString(mString, mLength));
540 return NS_OK;
543 NS_IMETHODIMP
544 AtomImpl::Equals(const nsAString& aString, PRBool* aResult)
546 *aResult = CompareUTF8toUTF16(nsDependentCString(mString, mLength),
547 aString) == 0;
548 return NS_OK;
551 //----------------------------------------------------------------------
553 // wrapper class for the nsStaticAtom struct
555 NS_IMETHODIMP_(nsrefcnt)
556 nsStaticAtomWrapper::AddRef()
558 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
559 return 2;
562 NS_IMETHODIMP_(nsrefcnt)
563 nsStaticAtomWrapper::Release()
565 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
566 return 1;
569 NS_IMPL_QUERY_INTERFACE1(nsStaticAtomWrapper, nsIAtom)
571 NS_IMETHODIMP
572 nsStaticAtomWrapper::GetUTF8String(const char** aResult)
574 *aResult = mStaticAtom->mString;
575 return NS_OK;
578 NS_IMETHODIMP
579 nsStaticAtomWrapper::ToString(nsAString& aBuf)
581 // static should always be always ASCII, to allow tools like gperf
582 // to generate the tables, and to avoid unnecessary conversion
583 NS_ASSERTION(nsCRT::IsAscii(mStaticAtom->mString),
584 "Data loss - atom should be ASCII");
585 CopyASCIItoUTF16(nsDependentCString(mStaticAtom->mString, mLength), aBuf);
586 return NS_OK;
589 NS_IMETHODIMP
590 nsStaticAtomWrapper::ToUTF8String(nsACString& aBuf)
592 aBuf.Assign(mStaticAtom->mString);
593 return NS_OK;
596 NS_IMETHODIMP
597 nsStaticAtomWrapper::EqualsUTF8(const nsACString& aString, PRBool* aResult)
599 *aResult = aString.Equals(nsDependentCString(mStaticAtom->mString, mLength));
600 return NS_OK;
603 NS_IMETHODIMP
604 nsStaticAtomWrapper::Equals(const nsAString& aString, PRBool* aResult)
606 *aResult = CompareUTF8toUTF16(nsDependentCString(mStaticAtom->mString,
607 mLength),
608 aString) == 0;
609 return NS_OK;
611 //----------------------------------------------------------------------
613 static nsStaticAtomWrapper*
614 WrapStaticAtom(const nsStaticAtom* aAtom, PRUint32 aLength)
616 if (!gStaticAtomArena) {
617 gStaticAtomArena = new PLArenaPool;
618 if (!gStaticAtomArena)
619 return nsnull;
621 PL_INIT_ARENA_POOL(gStaticAtomArena, "nsStaticAtomArena", 4096);
624 void* mem;
625 PL_ARENA_ALLOCATE(mem, gStaticAtomArena, sizeof(nsStaticAtomWrapper));
627 nsStaticAtomWrapper* wrapper =
628 new (mem) nsStaticAtomWrapper(aAtom, aLength);
630 return wrapper;
633 #define ATOM_HASHTABLE_INITIAL_SIZE 4096
635 static inline AtomTableEntry*
636 GetAtomHashEntry(const char* aString, PRUint32 aLength)
638 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
639 if (!gAtomTable.ops &&
640 !PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0,
641 sizeof(AtomTableEntry), ATOM_HASHTABLE_INITIAL_SIZE)) {
642 gAtomTable.ops = nsnull;
643 return nsnull;
646 AtomTableEntry key(aString, aLength);
647 return static_cast<AtomTableEntry*>
648 (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
651 static inline AtomTableEntry*
652 GetAtomHashEntry(const PRUnichar* aString, PRUint32 aLength)
654 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
655 if (!gAtomTable.ops &&
656 !PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0,
657 sizeof(AtomTableEntry), ATOM_HASHTABLE_INITIAL_SIZE)) {
658 gAtomTable.ops = nsnull;
659 return nsnull;
662 AtomTableEntry key(aString, aLength);
663 return static_cast<AtomTableEntry*>
664 (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
667 NS_COM nsresult
668 NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, PRUint32 aAtomCount)
670 // this does two things:
671 // 1) wraps each static atom in a wrapper, if necessary
672 // 2) initializes the address pointed to by each mBits slot
674 for (PRUint32 i=0; i<aAtomCount; i++) {
675 NS_ASSERTION(nsCRT::IsAscii(aAtoms[i].mString),
676 "Static atoms must be ASCII!");
678 PRUint32 stringLen = strlen(aAtoms[i].mString);
680 AtomTableEntry *he =
681 GetAtomHashEntry(aAtoms[i].mString, stringLen);
683 if (he->HasValue() && aAtoms[i].mAtom) {
684 // there already is an atom with this name in the table.. but we
685 // still have to update mBits
686 if (!he->IsStaticAtom() && !he->GetAtomImpl()->IsPermanent()) {
687 // since we wanted to create a static atom but there is
688 // already one there, we convert it to a non-refcounting
689 // permanent atom
690 PromoteToPermanent(he->GetAtomImpl());
693 // and now, if the consumer wants to remember this value in a
694 // slot, we do so
695 if (aAtoms[i].mAtom)
696 *aAtoms[i].mAtom = he->GetAtom();
698 else {
699 nsStaticAtomWrapper* atom = WrapStaticAtom(&aAtoms[i], stringLen);
700 NS_ASSERTION(atom, "Failed to wrap static atom");
702 // but even if atom is null, no real difference in code..
703 he->SetStaticAtomWrapper(atom);
704 if (aAtoms[i].mAtom)
705 *aAtoms[i].mAtom = atom;
708 return NS_OK;
711 NS_COM nsIAtom*
712 NS_NewAtom(const char* aUTF8String)
714 return NS_NewAtom(nsDependentCString(aUTF8String));
717 NS_COM nsIAtom*
718 NS_NewAtom(const nsACString& aUTF8String)
720 AtomTableEntry *he = GetAtomHashEntry(aUTF8String.Data(),
721 aUTF8String.Length());
723 if (!he) {
724 return nsnull;
727 NS_ASSERTION(!he->IsUTF8String() && !he->IsUTF16String(),
728 "Atom hash entry is string? Should be atom!");
730 if (he->HasValue())
731 return he->GetAtom();
733 AtomImpl* atom = new (aUTF8String) AtomImpl();
734 he->SetAtomImpl(atom);
735 if (!atom) {
736 PL_DHashTableRawRemove(&gAtomTable, he);
737 return nsnull;
740 NS_ADDREF(atom);
741 return atom;
744 NS_COM nsIAtom*
745 NS_NewAtom(const PRUnichar* aUTF16String)
747 return NS_NewAtom(nsDependentString(aUTF16String));
750 NS_COM nsIAtom*
751 NS_NewAtom(const nsAString& aUTF16String)
753 AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(),
754 aUTF16String.Length());
756 if (he->HasValue())
757 return he->GetAtom();
759 // MSVC.NET doesn't like passing a temporary NS_ConvertUTF16toUTF8() to
760 // operator new, so declare one as a local instead.
761 NS_ConvertUTF16toUTF8 str(aUTF16String);
762 AtomImpl* atom = new (str) AtomImpl();
763 he->SetAtomImpl(atom);
764 if (!atom) {
765 PL_DHashTableRawRemove(&gAtomTable, he);
766 return nsnull;
769 NS_ADDREF(atom);
770 return atom;
773 NS_COM nsIAtom*
774 NS_NewPermanentAtom(const char* aUTF8String)
776 return NS_NewPermanentAtom(nsDependentCString(aUTF8String));
779 NS_COM nsIAtom*
780 NS_NewPermanentAtom(const nsACString& aUTF8String)
782 AtomTableEntry *he = GetAtomHashEntry(aUTF8String.Data(),
783 aUTF8String.Length());
785 if (he->HasValue() && he->IsStaticAtom())
786 return he->GetStaticAtomWrapper();
788 // either there is no atom and we'll create an AtomImpl,
789 // or there is an existing AtomImpl
790 AtomImpl* atom = he->GetAtomImpl();
792 if (atom) {
793 // ensure that it's permanent
794 if (!atom->IsPermanent()) {
795 PromoteToPermanent(atom);
797 } else {
798 // otherwise, make a new atom
799 atom = new (aUTF8String) PermanentAtomImpl();
800 he->SetAtomImpl(atom);
801 if ( !atom ) {
802 PL_DHashTableRawRemove(&gAtomTable, he);
803 return nsnull;
807 NS_ADDREF(atom);
808 return atom;
811 NS_COM nsIAtom*
812 NS_NewPermanentAtom(const nsAString& aUTF16String)
814 return NS_NewPermanentAtom(NS_ConvertUTF16toUTF8(aUTF16String));
817 NS_COM nsIAtom*
818 NS_NewPermanentAtom(const PRUnichar* aUTF16String)
820 return NS_NewPermanentAtom(NS_ConvertUTF16toUTF8(aUTF16String));
823 NS_COM nsrefcnt
824 NS_GetNumberOfAtoms(void)
826 return gAtomTable.entryCount;