#include "stdlib.h"
#include "assert.h"
#include "memory.h"
+//#define TRACE_ON
+#include "trace.hpp"
#include "util.hpp"
+CStringFactory* CStringFactory::m_instance = NULL;
+
/**
* Constructor.
*
+ * @param factory factory for cloning/destroying
* @param capacity the size of the list m_buffer
* @param blocksize the minimum count of entries to reserve
* @param maxBlocksize the blocksize is doubled during enlarging the buffer
* while blocksize is smaller than this maximum
* @param sorted <i>true</i>: the buffer is sorted
*/
-BaseArrayList::BaseArrayList(int capacity, int blocksize, int maxBlocksize,
- bool sorted) :
- m_capacity(capacity),
- m_blocksize(blocksize),
+BaseArrayList::BaseArrayList(ItemFactory& factory, int capacity, int blocksize,
+ int maxBlocksize, bool sorted) :
+ m_capacity(capacity <= 0 ? 16 : capacity),
+ m_blocksize(blocksize <= 0 ? 16 : blocksize),
m_maxBlocksize(maxBlocksize),
m_count(0),
- m_buffer(new void*[capacity]),
- m_sorted(sorted)
+ m_buffer((void**)malloc((m_capacity + 1) * sizeof m_buffer[0])),
+ m_sorted(sorted),
+ m_factory(factory)
{
- memset(m_buffer, 0, capacity * sizeof m_buffer[0] );
+ m_buffer[m_capacity] = (void**) MAGIC;
+ TRACE2("buffer: %llx capacity: %d\n", (long long int) m_buffer, m_capacity);
+ memset(m_buffer, 0, m_capacity * sizeof m_buffer[0] );
}
/**
m_blocksize(source.m_blocksize),
m_maxBlocksize(source.m_maxBlocksize),
m_count(source.m_count),
- m_buffer(new void*[source.m_capacity]),
- m_sorted(source.m_sorted)
+ m_buffer((void**) malloc((source.m_capacity + 1) * sizeof m_buffer[0])),
+ m_sorted(source.m_sorted),
+ m_factory(source.m_factory)
{
- // the derived class must call cloneBuffer().
- // not allowed here: virtual method cloneItem() is not initialized here
+ m_buffer[m_capacity] = (void**) MAGIC;
+ TRACE2("buffer (copy): %llx capacity: %d\n", (long long int) m_buffer, m_capacity);
+ ensuresSize(m_count = source.m_count);
+ for (int ix = 0; ix < m_count; ix++){
+ m_buffer[ix] = m_factory.cloneItem(source.m_buffer[ix]);
+ }
}
* Destructor.
*/
BaseArrayList::~BaseArrayList() {
- for (int ix = 0; ix < m_capacity; ix++){
- if (m_buffer[ix] != NULL){
- destroyItem(m_buffer[ix]);
- }
- }
- memset(m_buffer, 0, sizeof m_buffer[0] * m_capacity);
- delete[] m_buffer;
+ clear();
+ TRACE1("buffer del: %llx\n", (long long int) m_buffer);
+ assert((long long int) m_buffer[m_capacity] == (long long int) MAGIC);
+ free(m_buffer);
m_buffer = NULL;
}
BaseArrayList& BaseArrayList::operator= ( const BaseArrayList& source ) {
clear();
m_sorted = source.m_sorted;
- cloneBuffer(source);
+ ensuresSize(m_count = source.m_count);
+ for (int ix = 0; ix < m_count; ix++){
+ m_buffer[ix] = m_factory.cloneItem(source.m_buffer[ix]);
+ }
return *this;
}
int index;
binarySearch(item, index);
if (index >= m_count){
- m_buffer[m_count++] = cloneItem(item);
+ m_buffer[m_count++] = m_factory.cloneItem(item);
} else {
+ assert(m_count <= m_capacity && m_count >= 0);
// build a gap:
// [?, ?, ix, ?]: items to copy: 4 - 2 = count - ix
memmove(m_buffer + index + 1, m_buffer + index,
- sizeof m_buffer[0] * (m_count++ - index));
- m_buffer[index] = cloneItem(item);
+ sizeof(m_buffer[0]) * (m_count++ - index));
+ m_buffer[index] = m_factory.cloneItem(item);
}
} else {
if (index >= m_count)
- m_buffer[m_count++] = cloneItem(item);
+ m_buffer[m_count++] = m_factory.cloneItem(item);
else {
if (index < 0)
index = 0;
- memcpy(m_buffer + index, m_buffer + index + 1, sizeof m_buffer[0] * (++m_count - index));
- m_buffer[index] = cloneItem(item);
+ assert(m_count <= m_capacity && m_count >= 0);
+ memmove(m_buffer + index, m_buffer + index + 1,
+ sizeof m_buffer[0] * (++m_count - index));
+ m_buffer[index] = m_factory.cloneItem(item);
}
}
return *this;
}
-/**
- * Clones the buffer.
- *
- * This method must not be called from a copy constructor of BaseArrayList:
- * It uses the abstract methed cloneItem(), which is not initialized
- * in the base class.
- *
- * Call it in the copy constructor of the derived class.
- *
- * @param source the source
- */
-void BaseArrayList::cloneBuffer(const BaseArrayList& source){
- ensuresSize(m_count = source.m_count);
- for (int ix = 0; ix < m_count; ix++){
- m_buffer[ix] = cloneItem(reinterpret_cast<void*>(source.m_buffer[ix]));
- }
-}
-
/**
* Compares two items.
*
*/
BaseArrayList& BaseArrayList::ensuresSize(int capacity){
if (capacity > m_capacity){
+ assert((long long int) m_buffer[m_capacity] == (long long int) MAGIC);
if ((m_blocksize *= 2) > m_maxBlocksize)
m_blocksize = m_maxBlocksize;
if (capacity - m_capacity < m_blocksize)
capacity = m_capacity + m_blocksize;
- void** buffer = new void*[m_capacity = capacity];
- memcpy(buffer, m_buffer, sizeof m_buffer[0] * m_count);
- delete[] m_buffer;
+ void** buffer = (void**) malloc(((m_capacity = capacity) + 1) * sizeof (m_buffer[0]));
+ buffer[m_capacity] = (void**) MAGIC;
+ TRACE1("buffer (ensure): %llx\n", (long long int) buffer);
+ assert(m_count <= m_capacity && m_count >= 0);
+ memcpy(buffer, m_buffer, sizeof(m_buffer[0]) * m_count);
+ TRACE1("buffer del: %llx\n", (long long int) m_buffer);
+ free(m_buffer);
+
m_buffer = buffer;
}
return *this;
rc = -1;
} else {
rc = -1;
- for (int ix = 0; rc != 0 && ix < m_count; ix++){
+ for (int ix = 0; rc == -1 && ix < m_count; ix++){
if (compareItems(item, (const void*) m_buffer[ix]) == 0)
- rc = 0;
+ rc = ix;
}
}
return rc;
*/
BaseArrayList& BaseArrayList::removeAt(int index){
if (index >= 0 && index < m_count){
- destroyItem(m_buffer[index]);
- m_buffer[index] = NULL;
+ TRACEF(("removeAt(%d): %s factory: %llx\n", index, m_buffer[index], (long long int) &m_factory));
+ m_factory.destroyItem(m_buffer[index]);
+ TRACE1("removeAt(%d)\n", index);
if (index < --m_count)
// [?, ?, item, ?]: items to copy: 4 - 2 - 1 = count - ix - 1
- memcpy(m_buffer + index, m_buffer + index + 1, --m_count - index);
+ memmove(m_buffer + index, m_buffer + index + 1,
+ sizeof(m_buffer[0]) * (m_count - index));
+ else
+ m_buffer[index] = NULL;
+
}
return *this;
}
+/**
+ * Constructor.
+ *
+ * @param capacity number of elements at start
+ * @param blocksize the minimum of elements to reserve
+ * @param maxBlocksize the blocksize is doubled until this count
+ * @param sorted <i>true</i>: the list will be sorted
+ */
+CStringList::CStringList(int capacity, int blocksize, int maxBlocksize,
+ bool sorted):
+ ArrayList(reinterpret_cast<ItemFactory*>(CStringFactory::instance()),
+ capacity, blocksize, maxBlocksize, sorted) {
+}
/**
* Joins the list members to a concatenated string.
}
return buffer;
}
-
+/**
+ * Writes a the list for debug purposes.
+ *
+ * @trace title NULL: none<br>
+ * otherwise: the prefix to describe the list
+ */
void CStringList::dump(const char* title) const{
printf("=== %s: count: %d capacity: %d\n", title == NULL ? "" : title, count(), capacity());
const char* ptr;
#ifndef ARRAYLIST_H
#define ARRAYLIST_H
+#include "trace.hpp"
+#define MAGIC 0xdeadbeafaffedecaLL
+class ItemFactory {
+public:
+ virtual void* cloneItem(const void* source) = 0;
+ virtual void destroyItem(const void* item) = 0;
+};
class BaseArrayList
{
public:
- BaseArrayList(int capacity = 16, int blocksize = 16, int maxBlocksize = 1024*1024,
+ BaseArrayList(ItemFactory& factory, int capacity = 16, int blocksize = 16, int maxBlocksize = 1024*1024,
bool sorted = false);
BaseArrayList ( const BaseArrayList& other );
virtual ~BaseArrayList();
BaseArrayList& operator= ( const BaseArrayList& other );
-public:
- virtual void* cloneItem(const void* source) = 0;
public:
BaseArrayList& add(const void* item, int index = 0x7ffffff);
bool binarySearch(const void* item, int& index) const;
BaseArrayList& clear();
virtual int compareItems(const void* item1, const void* item2) const;
- virtual void destroyItem(const void* item){
- }
BaseArrayList& ensuresSize(int capacity);
int indexOf(const void* item) const;
BaseArrayList& remove(const void* item);
BaseArrayList& removeAt(int index);
-protected:
- void cloneBuffer(const BaseArrayList& source);
public:
inline void** getBuffer() const{
return m_buffer;
int m_count;
void** m_buffer;
bool m_sorted;
+ ItemFactory& m_factory;
};
template<class T> class ArrayList : protected BaseArrayList {
public:
- ArrayList(int capacity = 16, int blocksize = 16, int maxBlocksize = 1024*1024,
- bool sorted = false):
- BaseArrayList(capacity, blocksize, maxBlocksize, sorted) {
+ ArrayList(ItemFactory* factory, int capacity = 16, int blocksize = 16,
+ int maxBlocksize = 1024*1024, bool sorted = false):
+ BaseArrayList(*factory, capacity, blocksize, maxBlocksize, sorted) {
}
ArrayList ( const BaseArrayList& source ):
BaseArrayList(source){
}
- virtual ~ArrayList(){
- }
- ArrayList& operator= ( const ArrayList& source ){
- m_sorted = source.m_sorted;
- cloneBuffer(source);
- return *this;
- }
public:
inline ArrayList& add(const T* item, int index = 0x7ffffff){
BaseArrayList::add(reinterpret_cast<const void*>(item), index);
BaseArrayList::clear();
return *this;
}
-private:
- virtual void* cloneItem(const void* source){
- void* rc = reinterpret_cast<void*>(cloneItem(reinterpret_cast<const T*>(source)));
- return rc;
- }
-public:
- virtual T* cloneItem(const T* source) = 0;
-
private:
virtual int compareItems(const void* item1, const void* item2) const{
int rc = compareItems(reinterpret_cast<const T*> (item1),
inline int count() const {
return m_count;
}
-private:
- virtual void destroyItem(const void* item){
- destroyItem(reinterpret_cast<const T*>(item));
- }
-public:
- virtual void destroyItem(const T* item){
- delete (T*) item;
- }
inline ArrayList& ensuresSize(int capacity){
BaseArrayList::ensuresSize(capacity);
return *this;
class CStringList : public ArrayList<char> {
public:
CStringList(int capacity = 16, int blocksize = 16, int maxBlocksize = 1024*1024,
- bool sorted = false):
- ArrayList(capacity, blocksize, maxBlocksize, sorted) {
- }
+ bool sorted = false);
CStringList ( const CStringList& source ) :
ArrayList(source){
- cloneBuffer(source);
}
public:
- virtual char* cloneItem(const char* source){
- char* rc = strdup(source);
- return rc;
- }
virtual int compareItems(const char* item1, const char* item2) const{
int rc = strcmp(item1, item2);
return rc;
}
- virtual void destroyItem(const char* item){
- // reserved with strdup()
- free((void*) item);
- }
public:
DynBuffer& join(DynBuffer& buffer, const char* separator = NULL);
void dump(const char* title) const;
};
+
+class CStringFactory {
+ static CStringFactory* m_instance;
+public:
+ static CStringFactory* instance(){
+ if (m_instance == NULL)
+ m_instance = new CStringFactory();
+ return m_instance;
+ }
+public:
+ virtual void* cloneItem(const void* source) {
+ int length = strlen(reinterpret_cast<const char*>(source));
+ char* rc = (char*) malloc(length + 1 + 8);
+ memcpy(rc, source, length + 1);
+ *(long long int *) (rc + length + 1) = MAGIC;
+ //char* rc = strdup(source);
+ TRACEF(("strdup [%llx] -> [%llx]: %s\n", (long long int) source, (long long int) rc, (char*) rc));
+ return rc;
+ }
+ virtual void destroyItem(const void* item) {
+ TRACE2("free [%llx]: %s\n", (long long int) item, (char*) item);
+ // reserved with strdup()
+ int length = strlen(reinterpret_cast<const char*>(item));
+ if (*(long long int*) ((int8_t*) item + length + 1) != ((long long int) MAGIC))
+ printf("\n*********** destroyItem(): assert %llx\n**********\n",
+ * (long long int*) ((int8_t*)item + length + 1));
+ ::free((void*) item);
+ }
+};
#endif // ARRAYLIST_H
}
public:
virtual void run() {
+ testIndexOfUnsorted();
+ testIndexOfSorted();
testCopyUnsorted();
testCopySorted();
testDestroy();
testClear();
testCount();
testCompareItems();
- testDestroyItem();
testEnsuresSize();
testGet();
- testIndexOf();
testRemove();
testRemoveAt();
testSorted();
testSetSorted();
+ testDestroyItem();
}
void testCopyUnsorted() {
+ {
CStringList list1;
list1.add ( "Hi" );
checkF ( list2.sorted() );
list1.add ( " world" );
+ list2.dump("op=1");
list2 = list1;
+ list2.dump("op=2");
checkE ( 2, list2.count() );
checkE ( "Hi", list2.get ( 0 ) );
checkE ( " world", list2.get ( 1 ) );
+ }
}
void testCopySorted() {
}
void testDestroyItem() {
DynBuffer big;
- int size = 10*1024*1024;
+ int size = 100*1024*1024;
big.ensureSize ( size );
memset ( big.buffer(), 'x', size -1 );
big.setLength ( size - 1 );
- for ( int ix = 0; ix < 1024; ix++ ) {
+ printf("waiting for 128...\n");
+ for ( int ix = 0; ix < 128; ix++ ) {
+ if (ix % 10 == 0){
+ if (ix > 0)
+ fputc('\n', stdout);
+ printf("%4d ", ix);
+ } else {
+ putc('.', stdout);
+ fflush(stdout);
+ }
CStringList list1;
list1.add ( big.str() );
list1.add ( big.str() );
list.add ( "adam" );
list.add ( "charly" );
checkE ( 3, list.count() );
- checkE ( "joe", list.get ( 0 ) );
- checkE ( "adam", list.get ( 1 ) );
- checkE ( "charly", list.get ( 2 ) );
+ checkE ( "adam", list.get ( 0 ) );
+ checkE ( "charly", list.get ( 1 ) );
+ checkE ( "joe", list.get ( 2 ) );
}
- void testIndexOf() {
+ void testIndexOfUnsorted() {
int capacity = 16;
int blocksize = 16;
int maxBlocksize = 1024*1024;
bool sorted = true;
CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
DynBuffer buffer;
- for ( int ix = 0; ix < 1024; ix++ ) {
+ for ( int ix = 1; ix <= 1024; ix++ ) {
buffer.clear().appendInt ( 0x42ab7*ix );
list.add ( buffer.str() );
}
- for ( int ix = 0; ix < 1024; ix++ ) {
+ for ( int ix = 1; ix <= 1024; ix++ ) {
buffer.clear().appendInt ( 0x42ab7*ix );
- checkE ( ix, list.indexOf ( buffer.str() ) );
+ checkE ( ix - 1, list.indexOf ( buffer.str() ) );
+ }
+ }
+ void testIndexOfSorted() {
+ int capacity = 16;
+ int blocksize = 16;
+ int maxBlocksize = 1024*1024;
+ bool sorted = true;
+ CStringList list ( capacity, blocksize, maxBlocksize, sorted );
+ DynBuffer buffer;
+ for ( int ix = 1; ix <= 1024; ix++ ) {
+ buffer.clear().appendInt ( 0x1*ix, "%08x" );
+ list.add ( buffer.str() );
+ }
+ for ( int ix = 1; ix <= 1024; ix++ ) {
+ buffer.clear().appendInt ( 0x1*ix, "%08x" );
+ checkE ( ix - 1, list.indexOf ( buffer.str() ));
}
}
void testRemove() {
buffer.clear().appendInt ( ix );
list.add ( buffer.str() );
}
+ int count = 1024;
+ checkE(count, list.count());
for ( int ix = 1020; ix >= 3; ix-- ) {
list.removeAt ( ix );
+ if (--count != list.count())
+ checkE(count, list.count());
}
- checkE ( 8, list.count() );
- for ( int ix = 0; ix < 4; ix++ ) {
+ list.dump("reduced list:");
+ checkE ( count, list.count() );
+ for ( int ix = 0; ix < 3; ix++ ) {
buffer.clear().appendInt ( ix );
checkE ( buffer.str(), list.get ( ix ) );
}
- for ( int ix = 4; ix < list.count(); ix++ ) {
- buffer.clear().appendInt ( ix + 1020 );
+ for ( int ix = 3; ix < list.count(); ix++ ) {
+ buffer.clear().appendInt ( ix + 1020 - 3 + 1 );
checkE ( buffer.str(), list.get ( ix ) );
}
}
return buffer;
}
virtual void timerTask(){
- trace1("Counter::timerTask %d\n", threadId());
+ TRACE1("Counter::timerTask %d\n", threadId());
m_pool.lock();
++*m_counter;
m_pool.unlock();
* Connects the posix thread to the class instance.
*/
void* threadStarter(void *param){
- trace1("threadstarter(%llx)", (long long unsigned int) param);
+ TRACE1("threadstarter(%llx)", (long long unsigned int) param);
Thread* thread = reinterpret_cast<Thread*>(param);
thread->execute();
return param;
m_running(false)
{
pool->append(*this);
- trace1("Thread(%d)\n", m_threadId);
+ TRACE1("Thread(%d)\n", m_threadId);
}
/**
* Destructor.
*/
Thread::~Thread() {
- trace1("~Thread(%d)\n", m_threadId);
+ TRACE1("~Thread(%d)\n", m_threadId);
}
/**
* Executes the "run" of the thread and deactivates itself.
*/
void Thread::execute(){
- trace1("Thread::execute(%d)\n", m_threadId);
+ TRACE1("Thread::execute(%d)\n", m_threadId);
m_running = true;
run();
m_pool.remove(*this);
pthread_t pthread = m_pthread;
if (m_autoDelete){
- trace1("Thread::execute(%d) autodelete\n", m_threadId);
+ TRACE1("Thread::execute(%d) autodelete\n", m_threadId);
// delete this;
}
pthread_detach(pthread);
void Thread::start(){
pthread_attr_t attr;
pthread_attr_init(&attr);
- trace2("Thread::start(%d): %lx\n", m_threadId, m_pthread);
+ TRACE2("Thread::start(%d): %lx\n", m_threadId, m_pthread);
pthread_create(&m_pthread, &attr, &threadStarter, this);
}
/**
* and terminate if set.
*/
void Thread::terminate(){
- trace1("Thread::terminate(%d)\n", m_threadId);
+ TRACE1("Thread::terminate(%d)\n", m_threadId);
m_shouldStop = true;
}
/**
* Destructor.
*/
ThreadPool::~ThreadPool() {
- trace1("~ThreadPool: %d\n", m_count);
+ TRACE1("~ThreadPool: %d\n", m_count);
terminateAll();
int maxMillisec = m_maxExitTime * 1000 + 500;
while (m_count != 0 && maxMillisec > 0){
}
// Force the termination of the non terminated:
pthread_t pthread;
- trace1("~ThreadPool: force: %d\n", m_count);
+ TRACE1("~ThreadPool: force: %d\n", m_count);
while (m_count-- > 0){
lock();
Thread* thread = m_list[m_count];
} else {
m_list[m_count++] = &thread;
unlock();
- trace1("ThreadPool::append(): id: %d\n", thread.m_threadId);
+ TRACE1("ThreadPool::append(): id: %d\n", thread.m_threadId);
}
}
* otherwise: the exit code of the thread
*/
void* ThreadPool::join(int threadId){
- trace1("ThreadPool::join(%d):\n", threadId);
+ TRACE1("ThreadPool::join(%d):\n", threadId);
void* rc = NULL;
Thread* thread = NULL;
do {
if (thread != NULL)
Thread::microSleep(10*1000);
} while(thread != NULL);
- trace2("join: thread: %c %llx\n", thread != NULL ? 't' : 'f', (long long unsigned int) thread);
+ TRACE2("join: thread: %c %llx\n", thread != NULL ? 't' : 'f', (long long unsigned int) thread);
return rc;
}
*/
void ThreadPool::remove(Thread& thread){
// Destructor already called?
- trace1("ThreadPool::remove(%d)\n", thread.threadId());
+ TRACE1("ThreadPool::remove(%d)\n", thread.threadId());
lock();
for (int ix = 0; ix < m_count; ix++){
if (m_list[ix] == &thread){
break;
}
}
- trace2("ThreadPool::findBy(%d): %c\n", id, rc == NULL ? 'f' : 't');
+ TRACE2("ThreadPool::findBy(%d): %c\n", id, rc == NULL ? 'f' : 't');
return rc;
}
/**
* @param thread the thread to deactivate.
*/
void ThreadPool::terminateAll(){
- trace("terminateAll()\n");
+ TRACE("terminateAll()\n");
for (int ix = m_count - 1; ix >= 0; ix--){
m_list[ix]->terminate();
}
m_startDelay(delay),
m_unit(unit)
{
- trace2("Timer(%d, %d)\n", count, delay);
+ TRACE2("Timer(%d, %d)\n", count, delay);
}
Timer::~Timer() {
* The action called by <i>Thread</i>.
*/
void Timer::run(){
- trace1("Timer::run(%d)\n", threadId());
+ TRACE1("Timer::run(%d)\n", threadId());
if (! m_shouldStop && m_startDelay > 0){
sleep(m_startDelay);
}
while(! m_shouldStop && m_taskCount-- > 0){
- trace2("Timer::run(%d): %d\n", threadId(), m_taskCount);
+ TRACE2("Timer::run(%d): %d\n", threadId(), m_taskCount);
timerTask();
sleep(m_delay);
}
#define TRACE_HPP
#ifdef TRACE_ON
-#define trace(msg) printf(msg)
-#define trace1(format, arg1) printf(format, arg1)
-#define trace2(format, arg1, arg2) printf(format, arg1, arg2)
-#define tracef(arg) printf(arg)
+#define TRACE(msg) printf(msg)
+#define TRACE1(format, arg1) printf(format, arg1)
+#define TRACE2(format, arg1, arg2) printf(format, arg1, arg2)
+// usage TRACEF(("note: use a parenthesis pair inside the arguments: %d/%d/%d", 1, 2, 3))
+#define TRACEF(arg) printf arg
#else
-#define trace(msg)
-#define trace1(format, arg1)
-#define trace2(format, arg1, arg2)
-#define tracef(arg)
+#define TRACE(msg)
+#define TRACE1(format, arg1)
+#define TRACE2(format, arg1, arg2)
+#define TRACEF(arg)
#endif // TRACE_ON
#endif // TRACE_HPP
#include <stdint.h>
typedef unsigned char ubyte_t;
+template <class T> class Singleton{
+ static T* m_instance;
+public:
+ static T* instance(){
+ if (m_instance == NULL)
+ m_instance = new T();
+ return m_instance;
+ }
+};
+
#include "dynbuffer.hpp"
#include "arraylist.hpp"
#include "timeutils.hpp"