mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-25 19:32:54 +00:00
337 lines
10 KiB
C++
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();
|
|
}
|