kde-extraapps/kdevplatform/language/duchain/indexedstring.cpp
2015-07-26 14:23:17 +03:00

337 lines
10 KiB
C++

/***************************************************************************
Copyright 2008 David Nolden <david.nolden.kdevelop@art-master.de>
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "indexedstring.h"
#include "repositories/stringrepository.h"
#include <kurl.h>
#include "referencecounting.h"
namespace KDevelop {
namespace {
struct IndexedStringData {
unsigned short length;
unsigned int refCount;
unsigned int itemSize() const {
return sizeof(IndexedStringData) + length;
}
unsigned int hash() const {
IndexedString::RunningHash running;
const char* str = ((const char*)this) + sizeof(IndexedStringData);
for(int a = length-1; a >= 0; --a) {
running.append(*str);
++str;
}
return running.hash;
}
};
inline void increase(uint& val) {
++val;
}
inline void decrease(uint& val) {
--val;
}
struct IndexedStringRepositoryItemRequest {
//The text is supposed to be utf8 encoded
IndexedStringRepositoryItemRequest(const char* text, unsigned int hash, unsigned short length) : m_hash(hash), m_length(length), m_text(text) {
}
enum {
AverageSize = 10 //This should be the approximate average size of an Item
};
typedef unsigned int HashType;
//Should return the hash-value associated with this request(For example the hash of a string)
HashType hash() const {
return m_hash;
}
//Should return the size of an item created with createItem
uint itemSize() const {
return sizeof(IndexedStringData) + m_length;
}
//Should create an item where the information of the requested item is permanently stored. The pointer
//@param item equals an allocated range with the size of itemSize().
void createItem(IndexedStringData* item) const {
item->length = m_length;
item->refCount = 0;
++item;
memcpy(item, m_text, m_length);
}
static void destroy(IndexedStringData* item, KDevelop::AbstractItemRepository&) {
Q_UNUSED(item);
//Nothing to do here (The object is not intelligent)
}
static bool persistent(const IndexedStringData* item) {
return (bool)item->refCount;
}
//Should return whether the here requested item equals the given item
bool equals(const IndexedStringData* item) const {
return item->length == m_length && (memcmp(++item, m_text, m_length) == 0);
}
unsigned int m_hash;
unsigned short m_length;
const char* m_text;
};
typedef ItemRepository<IndexedStringData, IndexedStringRepositoryItemRequest, false, true> IndexedStringRepository;
///@param item must be valid(nonzero)
inline QString stringFromItem(const IndexedStringData* item) {
const unsigned short* textPos = (unsigned short*)(item+1);
return QString::fromUtf8((char*)textPos, item->length);
}
inline QByteArray arrayFromItem(const IndexedStringData* item) {
const unsigned short* textPos = (unsigned short*)(item+1);
return QByteArray((char*)textPos, item->length);
}
inline const char* c_strFromItem(const IndexedStringData* item) {
return (const char*)(item+1);
}
}
namespace {
RepositoryManager< IndexedStringRepository >& getGlobalIndexedStringRepository(){
static RepositoryManager< IndexedStringRepository > globalIndexedStringRepository("String Index");
return globalIndexedStringRepository;
}
}
IndexedString::IndexedString() : m_index(0) {
}
///@param str must be a utf8 encoded string, does not need to be 0-terminated.
///@param length must be its length in bytes.
IndexedString::IndexedString( const char* str, unsigned short length, unsigned int hash ) {
if(!length)
m_index = 0;
else if(length == 1)
m_index = 0xffff0000 | str[0];
else {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
m_index = getGlobalIndexedStringRepository()->index(IndexedStringRepositoryItemRequest(str, hash ? hash : hashString(str, length), length));
if(shouldDoDUChainReferenceCounting(this))
increase(getGlobalIndexedStringRepository()->dynamicItemFromIndexSimple(m_index)->refCount);
}
}
IndexedString::IndexedString( char c ) {
m_index = 0xffff0000 | c;
}
IndexedString::IndexedString( const KUrl& url ) {
QByteArray array(url.pathOrUrl().toUtf8());
const char* str = array.constData();
int size = array.size();
if(!size)
m_index = 0;
else if(size == 1)
m_index = 0xffff0000 | str[0];
else {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
m_index = getGlobalIndexedStringRepository()->index(IndexedStringRepositoryItemRequest(str, hashString(str, size), size));
if(shouldDoDUChainReferenceCounting(this))
increase(getGlobalIndexedStringRepository()->dynamicItemFromIndexSimple(m_index)->refCount);
}
}
IndexedString::IndexedString( const QString& string ) {
QByteArray array(string.toUtf8());
const char* str = array.constData();
int size = array.size();
if(!size)
m_index = 0;
else if(size == 1)
m_index = 0xffff0000 | str[0];
else {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
m_index = getGlobalIndexedStringRepository()->index(IndexedStringRepositoryItemRequest(str, hashString(str, size), size));
if(shouldDoDUChainReferenceCounting(this))
increase(getGlobalIndexedStringRepository()->dynamicItemFromIndexSimple(m_index)->refCount);
}
}
IndexedString::IndexedString( const char* str) {
unsigned int length = strlen(str);
if(!length)
m_index = 0;
else if(length == 1)
m_index = 0xffff0000 | str[0];
else {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
m_index = getGlobalIndexedStringRepository()->index(IndexedStringRepositoryItemRequest(str, hashString(str, length), length));
if(shouldDoDUChainReferenceCounting(this))
increase(getGlobalIndexedStringRepository()->dynamicItemFromIndexSimple(m_index)->refCount);
}
}
IndexedString::IndexedString( const QByteArray& str) {
unsigned int length = str.length();
if(!length)
m_index = 0;
else if(length == 1)
m_index = 0xffff0000 | str[0];
else {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
m_index = getGlobalIndexedStringRepository()->index(IndexedStringRepositoryItemRequest(str, hashString(str, length), length));
if(shouldDoDUChainReferenceCounting(this))
increase(getGlobalIndexedStringRepository()->dynamicItemFromIndexSimple(m_index)->refCount);
}
}
IndexedString::~IndexedString() {
if(m_index && (m_index & 0xffff0000) != 0xffff0000) {
if(shouldDoDUChainReferenceCounting(this)) {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
decrease(getGlobalIndexedStringRepository()->dynamicItemFromIndexSimple(m_index)->refCount);
}
}
}
IndexedString::IndexedString( const IndexedString& rhs ) : m_index(rhs.m_index) {
if(m_index && (m_index & 0xffff0000) != 0xffff0000) {
if(shouldDoDUChainReferenceCounting(this)) {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
increase(getGlobalIndexedStringRepository()->dynamicItemFromIndexSimple(m_index)->refCount);
}
}
}
IndexedString& IndexedString::operator=(const IndexedString& rhs) {
if(m_index == rhs.m_index)
return *this;
if(m_index && (m_index & 0xffff0000) != 0xffff0000) {
if(shouldDoDUChainReferenceCounting(this)) {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
decrease(getGlobalIndexedStringRepository()->dynamicItemFromIndexSimple(m_index)->refCount);
}
}
m_index = rhs.m_index;
if(m_index && (m_index & 0xffff0000) != 0xffff0000) {
if(shouldDoDUChainReferenceCounting(this)) {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
increase(getGlobalIndexedStringRepository()->dynamicItemFromIndexSimple(m_index)->refCount);
}
}
return *this;
}
KUrl IndexedString::toUrl() const {
KUrl url( str() );
return url;
}
QString IndexedString::str() const {
if(!m_index)
return QString();
else if((m_index & 0xffff0000) == 0xffff0000)
return QString(QChar((char)m_index & 0xff));
else
return stringFromItem(getGlobalIndexedStringRepository()->itemFromIndex(m_index));
}
int IndexedString::length() const {
return lengthFromIndex(m_index);
}
int IndexedString::lengthFromIndex(unsigned int index) {
if(!index)
return 0;
else if((index & 0xffff0000) == 0xffff0000)
return 1;
else
return getGlobalIndexedStringRepository()->itemFromIndex(index)->length;
}
const char* IndexedString::c_str() const
{
if(!m_index)
return 0;
else if((m_index & 0xffff0000) == 0xffff0000)
return ((char*)&m_index)+3; //The last byte contains the character
else
return c_strFromItem(getGlobalIndexedStringRepository()->itemFromIndex(m_index));
}
QByteArray IndexedString::byteArray() const {
if(!m_index)
return QByteArray();
else if((m_index & 0xffff0000) == 0xffff0000)
return QString(QChar((char)m_index & 0xff)).toUtf8();
else
return arrayFromItem(getGlobalIndexedStringRepository()->itemFromIndex(m_index));
}
unsigned int IndexedString::hashString(const char* str, unsigned short length) {
RunningHash running;
for(int a = length-1; a >= 0; --a) {
running.append(*str);
++str;
}
return running.hash;
}
uint IndexedString::indexForString( const char* str, short unsigned length, uint hash) {
if(!length)
return 0;
else if(length == 1)
return 0xffff0000 | str[0];
else {
QMutexLocker lock(getGlobalIndexedStringRepository()->mutex());
return getGlobalIndexedStringRepository()->index(IndexedStringRepositoryItemRequest(str, hash ? hash : hashString(str, length), length));
}
}
uint IndexedString::indexForString(const QString& str, uint hash) {
const QByteArray array(str.toUtf8());
return indexForString(array.constBegin(), array.size(), hash);
}
}
QDebug operator<<(QDebug s, const KDevelop::IndexedString& string)
{
s.nospace() << string.str();
return s.space();
}