// hwintext.h
#pragma once
#ifndef __HWINTEXT_H__
#define __HWINTEXT_H__
#include "hwinobject.h"
#include "hwinstring.h"
#include "hwinexception.h"
#include "hwintypes.h"
namespace harlinn
{
namespace windows
{
namespace text
{
class StringBuilder
{
static const unsigned DataBlockTextSize = (2048 - sizeof(wchar_t*))/ sizeof(wchar_t);
struct DataBlock
{
DataBlock* next;
wchar_t text[DataBlockTextSize];
DataBlock()
: next(0)
{}
~DataBlock()
{
if(next)
{
delete next;
}
}
};
struct Data
{
long referenceCount;
size_t capacity;
size_t length;
DataBlock* start;
DataBlock* end;
DataBlock* current;
size_t currentUsed;
Data(size_t newCapacity)
: referenceCount(1),
capacity(0),
length(0),
start(0),
end(0),
current(0),
currentUsed(0)
{
SetCapacity(newCapacity);
}
~Data()
{
if(start)
{
delete start;
}
}
Data& Reset()
{
referenceCount = 1;
length = 0;
current = start;
currentUsed = 0;
return *this;
}
Data& AddDataBlock()
{
DataBlock* newBlock = new DataBlock();
if(newBlock)
{
if(end)
{
end->next = newBlock;
end = newBlock;
}
else
{
start = newBlock;
current = newBlock;
end = newBlock;
}
capacity += DataBlockTextSize;
}
else
{
throw OutOfMemoryException();
}
return *this;
}
size_t Capacity() const
{
return capacity;
}
Data& SetCapacity(size_t newCapacity)
{
while(capacity < newCapacity)
{
AddDataBlock();
}
return *this;
}
Data& Append(const wchar_t* text, size_t textLength)
{
size_t minRequiredCapacity = length+textLength;
if(minRequiredCapacity > capacity)
{
SetCapacity(minRequiredCapacity);
}
if(currentUsed < (DataBlockTextSize))
{
size_t copyLength = textLength;
if(copyLength > (DataBlockTextSize - currentUsed) )
{
copyLength = DataBlockTextSize - currentUsed;
}
wmemcpy( current->text + currentUsed, text, copyLength );
length += copyLength;
text += copyLength;
textLength -= copyLength;
currentUsed += copyLength;
}
while(textLength)
{
current = current->next;
size_t copyLength = textLength;
if(copyLength > DataBlockTextSize)
{
currentUsed = DataBlockTextSize;
copyLength = DataBlockTextSize;
}
else
{
currentUsed = copyLength;
}
wmemcpy( current->text, text, copyLength );
length += copyLength;
text += copyLength;
textLength -= copyLength;
}
return *this;
}
Data& Append(const wchar_t c)
{
size_t minRequiredCapacity = length+1;
if(minRequiredCapacity > capacity)
{
SetCapacity(minRequiredCapacity);
}
if(currentUsed >= DataBlockTextSize)
{
current = current->next;
currentUsed = 0;
}
current->text[currentUsed] = c;
length++;
currentUsed++;
return *this;
}
String ToString() const
{
String result;
if(length)
{
result.SetLength(length);
wchar_t* dest = result.c_str();
DataBlock* block = start;
while(block != current)
{
wmemcpy(dest,block->text,DataBlockTextSize);
block = block->next;
}
wmemcpy(dest,block->text,currentUsed);
}
return result;
}
long AddRef()
{
return InterlockedIncrement(&referenceCount);
}
long Release()
{
return InterlockedDecrement(&referenceCount);
}
};
class DataManager
{
static const unsigned cacheSize = 5;
CRITICAL_SECTION mutex;
Data* cache[cacheSize];
public:
HWIN_EXPORT DataManager();
HWIN_EXPORT ~DataManager();
HWIN_EXPORT Data* Allocate(size_t minCapacity);
HWIN_EXPORT void Free(Data* data);
};
HWIN_EXPORT static DataManager dataManager;
Data* data;
void Release()
{
if(data)
{
if(data->Release() == 0)
{
dataManager.Free(data);
}
}
}
public:
StringBuilder()
: data(0)
{}
StringBuilder(size_t minCapacity)
: data(dataManager.Allocate(minCapacity))
{}
StringBuilder(const StringBuilder& other)
: data(other.data)
{
if(data)
{
data->AddRef();
}
}
StringBuilder(StringBuilder&& other)
: data(other.data)
{
other.data = nullptr;
}
~StringBuilder()
{
Release();
}
StringBuilder& operator = (const StringBuilder& other)
{
if(data != other.data)
{
Release();
data = other.data;
if(data)
{
data->AddRef();
}
}
return *this;
}
StringBuilder& operator = (StringBuilder&& other)
{
if(this != &other)
{
Release();
data = other.data;
other.data = nullptr;
}
return *this;
}
StringBuilder& Append(const wchar_t* text, size_t textLength)
{
if(!data)
{
data = dataManager.Allocate(textLength);
}
data->Append(text,textLength);
return *this;
}
StringBuilder& Append(const String& s)
{
auto length = s.length();
if(length)
{
if(!data)
{
data = dataManager.Allocate(length);
}
data->Append(s.c_str(),length);
}
return *this;
}
StringBuilder& Append(const wchar_t c)
{
if(!data)
{
data = dataManager.Allocate(1);
}
data->Append(c);
return *this;
}
StringBuilder& operator += (const String& s)
{
return Append(s);
}
StringBuilder& operator += (const wchar_t c)
{
return Append(c);
}
String ToString() const
{
if(data)
{
return data->ToString();
}
return String();
}
};
class Endoding : public Object
{
unsigned codePage;
public:
typedef Object Base;
HWIN_EXPORT static std::shared_ptr<Endoding> ASCII;
HWIN_EXPORT static std::shared_ptr<Endoding> UTF8;
HWIN_EXPORT static std::shared_ptr<Endoding> UTF7;
HWIN_EXPORT static std::shared_ptr<Endoding> Latin1;
HWIN_EXPORT Endoding();
HWIN_EXPORT Endoding(unsigned theCodePage);
HWIN_EXPORT String GetString( const std::vector<Byte::ValueType>& bytes );
HWIN_EXPORT std::shared_ptr< std::vector<Byte::ValueType> > GetBytes( const String& theText );
};
};
};
};
#endif // __HWINTEXT_H__