blob: 9613d87517f7677a07fd254669769c10529dba5c [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#ifndef STRING_KEYVALUE_STORE_H_INCLUDED
#define STRING_KEYVALUE_STORE_H_INCLUDED
#ifndef OSCL_BASE_H_INCLUDED
#include "oscl_base.h"
#endif
#ifndef OSCL_MEM_H_INCLUDED
#include "oscl_mem.h"
#endif
#ifndef OSCL_MEM_MEMPOOL_H_INCLUDED
#include "oscl_mem_mempool.h"
#endif
#ifndef OSCL_STR_PTR_LEN_H_INCLUDED
#include "oscl_str_ptr_len.h"
#endif
#ifndef OSCL_VECTOR_H_INCLUDED
#include "oscl_vector.h"
#endif
#define KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS 1000
#define KEYVALUESTORE_MAX_SIZE 4000 // same as the RTSP parcom, but this size shouldn't include entity body size, which the composer library has no control
#define KEYVALUESTORE_VECTOR_RESERVE_VALUE 10 // for iStrCSumPtrLenWrapperVector.reserve()
// This StrCSumPtrLen wrapper wraps StrCSumPtrLen with the following new features.
// (1) changed checksum calculation algorithm to make checksum as an identifier to differentiate different StrCSumPtrLen object.
// This will be used in quick string comparison/search for field key of HTTP header.
// Note that in StrCSumPtrLen, the checksum is calulated as the sum of the ASCII codes of all string charaters (lowercase).
// And this is not quite efficient. The modified version is contrained within 500 (see the following getChecksum()), with tiny
// performance loss.
// (2) support simplified link list. This is mainly used for multiple same header field cases (i.e. same field key, but multiple field
// values).
struct StrCSumPtrLenWrapper
{
public:
// constructor
StrCSumPtrLenWrapper() : iNext(NULL)
{
;
}
// copy constructor
StrCSumPtrLenWrapper(const StrCSumPtrLen &x) : iStr(x), iNext(NULL)
{
;
}
StrCSumPtrLenWrapper(const char *x) : iStr(x), iNext(NULL)
{
;
}
StrCSumPtrLenWrapper(const char *x, const uint32 len) : iStr(x, len), iNext(NULL)
{
;
}
// destructor
~StrCSumPtrLenWrapper()
{
clear();
}
// use checksum (with some changes) as an identifier, will be used to differentiate different StrCSumPtrLen objects.
uint32 getChecksum()
{
// algorithm: checksum = (checksum % 1000) / 2
return (uint32)((uint32)iStr.getCheckSum() % KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS) / 2;
}
// add to linked list
void push_back(StrCSumPtrLenWrapper *aStrLinkTo)
{
StrCSumPtrLenWrapper **pWrapper = &iNext;
while (*pWrapper) pWrapper = &((*pWrapper)->iNext);
*pWrapper = aStrLinkTo;
}
// get next element
StrCSumPtrLenWrapper *getNext()
{
return iNext;
}
// clear
void clear()
{
iStr.setPtrLen("", 0);
iNext = NULL;
}
// empty
bool empty()
{
return (iNext == NULL && iStr.length() == 0);
}
// wrap some functions of StrCSumPtrLen
const char* c_str() const
{
return iStr.c_str();
}
uint32 length() const
{
return (uint32)iStr.length();
}
uint32 size() const
{
return (uint32)iStr.size();
}
bool isCIEquivalentTo(const StrCSumPtrLen& rhs) const
{
return (iStr.isCIEquivalentTo(rhs) > 0);
}
bool isCIEquivalentTo(const char*s, const uint32 len) const
{
StrCSumPtrLen str(s, len);
return (iStr.isCIEquivalentTo(str) > 0);
}
void setPtrLen(const char* newPtr, uint32 newLen)
{
iStr.setPtrLen(newPtr, newLen);
iNext = NULL;
}
void setPtrLen(const StrPtrLen &aString)
{
iStr.setPtrLen(aString.c_str(), aString.length());
iNext = NULL;
}
// operator =
StrCSumPtrLenWrapper& operator=(const StrCSumPtrLen& rhs)
{
iStr = rhs;
iNext = NULL;
return *this;
}
StrCSumPtrLenWrapper& operator=(const StrPtrLen& rhs)
{
iStr = rhs;
iNext = NULL;
return *this;
}
StrCSumPtrLenWrapper& operator=(const StrCSumPtrLenWrapper& rhs)
{
iStr = rhs.iStr;
iNext = rhs.iNext;
return *this;
}
private:
StrCSumPtrLen iStr;
StrCSumPtrLenWrapper *iNext;
};
// class declaration
class OsclMemPoolVariableChunkAllocator;
// class for encapsulating string based key-value pair handlings
// The major feature for this class is hash-table based key search. To handle hash table conllision, linear search
// table is used. Basically a whole hash table is divided into two parts, the first part is for real hash table,
// the second part is for collision.
class StringKeyValueStore
{
public:
// add a key-value pair, key-value will be made a copy inside the store
// return code is one of following StringKeyValueStoreReturnCodes
int32 addKeyValuePair(const StrCSumPtrLen &aNewKey, const StrPtrLen &aNewValue, const bool aNeedReplaceOldValue = false);
int32 addKeyValuePair(const StrCSumPtrLen &aNewKey, const char *aNewValue, const bool aNeedReplaceOldValue = false);
// This overloaded function is for this case, when the key and value are parsed from the data stream, to avoid memory copy,
// we locate the segment in the data stream for the key and value, which has no NULL terminatior.
int32 addKeyValuePair(const char *aNewKey, const uint32 aKeyLength, const char *aNewValue, const uint32 aValueLength,
const bool aNeedReplaceOldValue = false);
// get number of key-value pairs, which could be different from the number of keys,
// when there might be a key with multiple values
uint32 getNumberOfKeyValuePairs()
{
return iTotalNumberOfKeyValuePairs;
}
uint32 getNumberOfKeys()
{
return iFieldKeyTableIndexVector.size();
}
uint32 getTotalKeyValueLength()
{
return iTotalKeyValueLength;
}
// aListSize=0 means retrieves whatever the library has
// return the actual list size
uint32 getCurrentKeyList(StrPtrLen *&aFieldKeyList, const uint32 aListSize = 0);
bool getValueByKey(const StrCSumPtrLen &aKey, StrPtrLen &aValue, const uint32 index = 0);
// for one key multiple value cases.
// return value: 0 => no value for the given key, 1 or more => number of values for the given key
uint32 getNumberOfValuesByKey(const StrCSumPtrLen &aKey);
// search
bool isKeyValueAvailable(const StrCSumPtrLen &aKey);
// remove
bool removeKeyValuePair(const StrCSumPtrLen &aKey);
// clear
void clear();
// copy
bool copy(StringKeyValueStore& aStore);
// query store infomation
uint32 getCurrentMemoryUsage();
uint32 getStoreSize();
uint32 getAvailableSize();
// constructor
StringKeyValueStore() : iVariableSizeMemPool(NULL)
{
;
}
// destructor
~StringKeyValueStore();
// factory method
static StringKeyValueStore* create(const uint32 aStoreSize = KEYVALUESTORE_MAX_SIZE);
enum StringKeyValueStoreReturnCodes
{
StringKeyValueStore_Success = 0,
StringKeyValueStore_Failure = -1,
StringKeyValueStore_NoMemory = -2
};
private:
uint32 calculateChecksum(const char *aBuffer, uint32 aBufferLength);
bool construct(const uint32 aStoreSize);
// for conflict handling
// To handle hash table collisions, the hash table is divided into two parts, one part is for first hit elements, and
// all the conflict elements is collected into another part. The reason for not choosing link list approach is, usually
// conllision possibilities are very low, so no need to keep link list for every table element. (Note that if the collision
// possibilities go high, hash function should be updated to keep this collision possibility low) Another reason is, don't
// want to change the current structure too much.
// aFindKey=true, the purpose of getting table index is for element search or removal;
// aFindKey=false, the purpose is for adding a new element
// return value: table index, for operation failure, return -1
int32 getHashTableIndex(const StrCSumPtrLen &aKey, const bool aFindKey = true);
// linear seach in linear search area of hash table for the given key
// return table index for linear search area, -1 means the input key is not found
int32 query(const StrCSumPtrLen &aKey);
// supporting function for addKeyValuePair() and removeKeyValuePair()
// return code is one of StringKeyValueStoreReturnCodes
int32 addKeyToStore(const StrCSumPtrLen &aNewKey, int32 tableIndex);
// centralize memory related operations within these two fucntions
bool storeNewKeyValueItem(const char *aItem, const int32 aItemLength, char *&aNewLocation);
void releaseOldKeyValueItem(const char *aItem, const int32 aItemLength);
private:
uint32 iTotalNumberOfKeyValuePairs;
uint32 iTotalKeyValueLength;
// field key@value tables (field key table is a hash table per se)
StrCSumPtrLenWrapper iFieldKeys[KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS];
StrPtrLen iFieldVals[KEYVALUESTORE_HASH_TABLE_SIZE_FOR_KEYS];
// use variable-size memory pool to replace fixed-size memory storage
// OsclMemPoolResizableAllocator is not used because of overhead.
// That variable-size memory pool has fixed 28-byte header for each allocated memory segment. This
// overhead is too much in the current user scenario, storing field key and value. Especially for
// field key, it is usually less than 20 bytes. So that allocator is two expensive.
OsclMemPoolVariableChunkAllocator* iVariableSizeMemPool;
// storage for multiple field values with the same field key
Oscl_Vector<StrCSumPtrLenWrapper, OsclMemAllocator> iStrCSumPtrLenWrapperVector;
// save the parsed field key index of the field key table
// The reason for this, usually less than a dozen of header fields are set for a message, comparing the
// relatively big hash table, saving the table indices will save lots of search operations.
Oscl_Vector<uint32, OsclMemAllocator> iFieldKeyTableIndexVector;
uint32 iNumConflicts;
};
#endif // STRING_KEYVALUE_STORE_H_INCLUDED