michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "xpcom-config.h" michael@0: #include // for placement new michael@0: #include "nscore.h" michael@0: #include "nsCRT.h" michael@0: michael@0: #include "nsCommandParams.h" michael@0: #include "mozilla/HashFunctions.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: const PLDHashTableOps nsCommandParams::sHashOps = michael@0: { michael@0: PL_DHashAllocTable, michael@0: PL_DHashFreeTable, michael@0: HashKey, michael@0: HashMatchEntry, michael@0: HashMoveEntry, michael@0: HashClearEntry, michael@0: PL_DHashFinalizeStub michael@0: }; michael@0: michael@0: michael@0: NS_IMPL_ISUPPORTS(nsCommandParams, nsICommandParams) michael@0: michael@0: nsCommandParams::nsCommandParams() michael@0: : mCurEntry(0) michael@0: , mNumEntries(eNumEntriesUnknown) michael@0: { michael@0: // init the hash table later michael@0: } michael@0: michael@0: nsCommandParams::~nsCommandParams() michael@0: { michael@0: PL_DHashTableFinish(&mValuesHash); michael@0: } michael@0: michael@0: nsresult michael@0: nsCommandParams::Init() michael@0: { michael@0: PL_DHashTableInit(&mValuesHash, &sHashOps, (void *)this, sizeof(HashEntry), 4); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: #if 0 michael@0: #pragma mark - michael@0: #endif michael@0: michael@0: /* short getValueType (in string name); */ michael@0: NS_IMETHODIMP nsCommandParams::GetValueType(const char * name, int16_t *_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = eNoType; michael@0: HashEntry* foundEntry = GetNamedEntry(name); michael@0: if (foundEntry) michael@0: { michael@0: *_retval = foundEntry->mEntryType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* boolean getBooleanValue (in AString name); */ michael@0: NS_IMETHODIMP nsCommandParams::GetBooleanValue(const char * name, bool *_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = false; michael@0: michael@0: HashEntry* foundEntry = GetNamedEntry(name); michael@0: if (foundEntry && foundEntry->mEntryType == eBooleanType) michael@0: { michael@0: *_retval = foundEntry->mData.mBoolean; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* long getLongValue (in AString name); */ michael@0: NS_IMETHODIMP nsCommandParams::GetLongValue(const char * name, int32_t *_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = false; michael@0: michael@0: HashEntry* foundEntry = GetNamedEntry(name); michael@0: if (foundEntry && foundEntry->mEntryType == eLongType) michael@0: { michael@0: *_retval = foundEntry->mData.mLong; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* double getDoubleValue (in AString name); */ michael@0: NS_IMETHODIMP nsCommandParams::GetDoubleValue(const char * name, double *_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = 0.0; michael@0: michael@0: HashEntry* foundEntry = GetNamedEntry(name); michael@0: if (foundEntry && foundEntry->mEntryType == eDoubleType) michael@0: { michael@0: *_retval = foundEntry->mData.mDouble; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* AString getStringValue (in AString name); */ michael@0: NS_IMETHODIMP nsCommandParams::GetStringValue(const char *name, nsAString & _retval) michael@0: { michael@0: _retval.Truncate(); michael@0: HashEntry* foundEntry = GetNamedEntry(name); michael@0: if (foundEntry && foundEntry->mEntryType == eWStringType) michael@0: { michael@0: NS_ASSERTION(foundEntry->mData.mString, "Null string"); michael@0: _retval.Assign(*foundEntry->mData.mString); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* AString getStringValue (in AString name); */ michael@0: NS_IMETHODIMP nsCommandParams::GetCStringValue(const char * name, char **_retval) michael@0: { michael@0: HashEntry* foundEntry = GetNamedEntry(name); michael@0: if (foundEntry && foundEntry->mEntryType == eStringType) michael@0: { michael@0: NS_ASSERTION(foundEntry->mData.mCString, "Null string"); michael@0: *_retval = ToNewCString(*foundEntry->mData.mCString); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* nsISupports getISupportsValue (in AString name); */ michael@0: NS_IMETHODIMP nsCommandParams::GetISupportsValue(const char * name, nsISupports **_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = nullptr; michael@0: michael@0: HashEntry* foundEntry = GetNamedEntry(name); michael@0: if (foundEntry && foundEntry->mEntryType == eISupportsType) michael@0: { michael@0: NS_IF_ADDREF(*_retval = foundEntry->mISupports.get()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: #if 0 michael@0: #pragma mark - michael@0: #endif michael@0: michael@0: /* void setBooleanValue (in AString name, in boolean value); */ michael@0: NS_IMETHODIMP nsCommandParams::SetBooleanValue(const char * name, bool value) michael@0: { michael@0: HashEntry* foundEntry; michael@0: GetOrMakeEntry(name, eBooleanType, foundEntry); michael@0: if (!foundEntry) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: foundEntry->mData.mBoolean = value; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setLongValue (in AString name, in long value); */ michael@0: NS_IMETHODIMP nsCommandParams::SetLongValue(const char * name, int32_t value) michael@0: { michael@0: HashEntry* foundEntry; michael@0: GetOrMakeEntry(name, eLongType, foundEntry); michael@0: if (!foundEntry) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: foundEntry->mData.mLong = value; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setDoubleValue (in AString name, in double value); */ michael@0: NS_IMETHODIMP nsCommandParams::SetDoubleValue(const char * name, double value) michael@0: { michael@0: HashEntry* foundEntry; michael@0: GetOrMakeEntry(name, eDoubleType, foundEntry); michael@0: if (!foundEntry) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: foundEntry->mData.mDouble = value; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setStringValue (in AString name, in AString value); */ michael@0: NS_IMETHODIMP nsCommandParams::SetStringValue(const char * name, const nsAString & value) michael@0: { michael@0: HashEntry* foundEntry; michael@0: GetOrMakeEntry(name, eWStringType, foundEntry); michael@0: if (!foundEntry) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: foundEntry->mData.mString = new nsString(value); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setCStringValue (in string name, in string value); */ michael@0: NS_IMETHODIMP nsCommandParams::SetCStringValue(const char * name, const char * value) michael@0: { michael@0: HashEntry* foundEntry; michael@0: GetOrMakeEntry(name, eStringType, foundEntry); michael@0: if (!foundEntry) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: foundEntry->mData.mCString = new nsCString(value); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setISupportsValue (in AString name, in nsISupports value); */ michael@0: NS_IMETHODIMP nsCommandParams::SetISupportsValue(const char * name, nsISupports *value) michael@0: { michael@0: HashEntry* foundEntry; michael@0: GetOrMakeEntry(name, eISupportsType, foundEntry); michael@0: if (!foundEntry) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: foundEntry->mISupports = value; // addrefs michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void removeValue (in AString name); */ michael@0: NS_IMETHODIMP michael@0: nsCommandParams::RemoveValue(const char * name) michael@0: { michael@0: // PL_DHASH_REMOVE doesn't tell us if the entry was really removed, so we return michael@0: // NS_OK unconditionally. michael@0: (void)PL_DHashTableOperate(&mValuesHash, (void *)name, PL_DHASH_REMOVE); michael@0: michael@0: // inval the number of entries michael@0: mNumEntries = eNumEntriesUnknown; michael@0: return NS_OK; michael@0: } michael@0: michael@0: #if 0 michael@0: #pragma mark - michael@0: #endif michael@0: michael@0: nsCommandParams::HashEntry* michael@0: nsCommandParams::GetNamedEntry(const char * name) michael@0: { michael@0: HashEntry *foundEntry = (HashEntry *)PL_DHashTableOperate(&mValuesHash, (void *)name, PL_DHASH_LOOKUP); michael@0: michael@0: if (PL_DHASH_ENTRY_IS_BUSY(foundEntry)) michael@0: return foundEntry; michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: michael@0: nsCommandParams::HashEntry* michael@0: nsCommandParams::GetIndexedEntry(int32_t index) michael@0: { michael@0: HashEntry* entry = reinterpret_cast(mValuesHash.entryStore); michael@0: HashEntry* limit = entry + PL_DHASH_TABLE_SIZE(&mValuesHash); michael@0: uint32_t entryCount = 0; michael@0: michael@0: do michael@0: { michael@0: if (!PL_DHASH_ENTRY_IS_LIVE(entry)) michael@0: continue; michael@0: michael@0: if ((int32_t)entryCount == index) michael@0: return entry; michael@0: michael@0: entryCount ++; michael@0: } while (++entry < limit); michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: michael@0: uint32_t michael@0: nsCommandParams::GetNumEntries() michael@0: { michael@0: HashEntry* entry = reinterpret_cast(mValuesHash.entryStore); michael@0: HashEntry* limit = entry + PL_DHASH_TABLE_SIZE(&mValuesHash); michael@0: uint32_t entryCount = 0; michael@0: michael@0: do michael@0: { michael@0: if (PL_DHASH_ENTRY_IS_LIVE(entry)) michael@0: entryCount ++; michael@0: } while (++entry < limit); michael@0: michael@0: return entryCount; michael@0: } michael@0: michael@0: nsresult michael@0: nsCommandParams::GetOrMakeEntry(const char * name, uint8_t entryType, HashEntry*& outEntry) michael@0: { michael@0: michael@0: HashEntry *foundEntry = (HashEntry *)PL_DHashTableOperate(&mValuesHash, (void *)name, PL_DHASH_LOOKUP); michael@0: if (PL_DHASH_ENTRY_IS_BUSY(foundEntry)) // reuse existing entry michael@0: { michael@0: foundEntry->Reset(entryType); michael@0: foundEntry->mEntryName.Assign(name); michael@0: outEntry = foundEntry; michael@0: return NS_OK; michael@0: } michael@0: michael@0: foundEntry = (HashEntry *)PL_DHashTableOperate(&mValuesHash, (void *)name, PL_DHASH_ADD); michael@0: if (!foundEntry) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: // placement new that sucker. Our ctor does not clobber keyHash, which is important. michael@0: outEntry = new (foundEntry) HashEntry(entryType, name); michael@0: return NS_OK; michael@0: } michael@0: michael@0: #if 0 michael@0: #pragma mark - michael@0: #endif michael@0: michael@0: PLDHashNumber michael@0: nsCommandParams::HashKey(PLDHashTable *table, const void *key) michael@0: { michael@0: return HashString((const char *)key); michael@0: } michael@0: michael@0: bool michael@0: nsCommandParams::HashMatchEntry(PLDHashTable *table, michael@0: const PLDHashEntryHdr *entry, const void *key) michael@0: { michael@0: const char* keyString = (const char*)key; michael@0: const HashEntry* thisEntry = static_cast(entry); michael@0: michael@0: return thisEntry->mEntryName.Equals(keyString); michael@0: } michael@0: michael@0: void michael@0: nsCommandParams::HashMoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from, michael@0: PLDHashEntryHdr *to) michael@0: { michael@0: const HashEntry* fromEntry = static_cast(from); michael@0: HashEntry* toEntry = static_cast(to); michael@0: michael@0: *toEntry = *fromEntry; michael@0: // we leave from dirty, but that's OK michael@0: } michael@0: michael@0: void michael@0: nsCommandParams::HashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) michael@0: { michael@0: HashEntry* thisEntry = static_cast(entry); michael@0: thisEntry->~HashEntry(); // call dtor explicitly michael@0: memset(thisEntry, 0, sizeof(HashEntry)); // and clear out michael@0: } michael@0: michael@0: #if 0 michael@0: #pragma mark - michael@0: #endif michael@0: michael@0: /* boolean hasMoreElements (); */ michael@0: NS_IMETHODIMP michael@0: nsCommandParams::HasMoreElements(bool *_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: michael@0: if (mNumEntries == eNumEntriesUnknown) michael@0: mNumEntries = GetNumEntries(); michael@0: michael@0: *_retval = mCurEntry < mNumEntries; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void first (); */ michael@0: NS_IMETHODIMP michael@0: nsCommandParams::First() michael@0: { michael@0: mCurEntry = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* AString getNext (); */ michael@0: NS_IMETHODIMP michael@0: nsCommandParams::GetNext(char **_retval) michael@0: { michael@0: HashEntry* thisEntry = GetIndexedEntry(mCurEntry); michael@0: if (!thisEntry) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *_retval = ToNewCString(thisEntry->mEntryName); michael@0: mCurEntry++; michael@0: return NS_OK; michael@0: }