CC = g++
+#CC = clang
CFLAGS = "-Wall"
LDFLAGS = -lm -lpthread
CL = g++
+#CL = clang
OBJ = cuarraylist.o cutimeutils.o cutimer.o cudynbuffer.o \
arraylist.o dynbuffer.o logger.o timeutils.o unittest.o test.o thread.o \
* The latest sources: https://github.com/republib
*
*/
+//#define TRACE_ON 1
#include "stdlib.h"
#include "assert.h"
#include "memory.h"
-//#define TRACE_ON
#include "trace.hpp"
#include "util.hpp"
return *this;
}
+/**
+ * Sorts a part of the array.
+ *
+ * @param count the number of elements to sort
+ */
+void BaseArrayList::sort(){
+ heapify();
+
+ // The following loop maintains the invariants that a[0:end] is a heap and every element
+ // beyond end is greater than everything before it (so a[end:count] is in sorted order))
+ int end = m_count - 1;
+ while (end > 0) {
+ // (a[0] is the root and largest value. The swap moves it in front of the sorted elements.)
+ swapItems(end, 0);
+ // the heap size is reduced by one
+ --end;
+ // the swap ruined the heap property, so restore it:
+ shiftDown(0, end);
+ }
+}
+void BaseArrayList::heapify(){
+ // start is assigned the index in 'a' of the last parent node)
+ // the last element in a 0-based array is at index count-1; find the parent of that element)
+ int start = iParent(m_count-1);
+
+ while (start >= 0){
+ // shift down the node at index 'start' to the proper place such that all nodes below
+ // the start index are in heap order:
+ shiftDown(start, m_count - 1);
+ // go to the next parent node:
+ --start;
+ }
+ // after shifting down the root all nodes/elements are in heap order)
+}
+void BaseArrayList::shiftDown(int start, int end){
+ int root = start;
+
+ // while the root has at least one child:
+ while (iLeftChild(root) <= end){
+ // Left child of root)
+ int child = iLeftChild(root);
+ // (Keeps track of child to swap with:
+ int swap = root;
+
+ if (m_factory.compareItems(m_buffer[swap], m_buffer[child]) < 0)
+ swap = child;
+
+ // If there is a right child and that child is greater:
+ if (child+1 <= end
+ && m_factory.compareItems(m_buffer[swap], m_buffer[child + 1]) < 0)
+ swap = child + 1;
+ if (swap == root){
+ // The root holds the largest element. Since we assume the heaps rooted at the
+ // children are valid, this means that we are done:
+ break;
+ } else {
+ swapItems(root, swap);
+ // repeat to continue shifting down the child now:
+ root = swap;
+ }
+ }
+}
+
/**
* Removes a the item with a given index from the list.
*
*/
BaseArrayList& BaseArrayList::removeAt(int index){
if (index >= 0 && index < m_count){
- TRACEF(("removeAt(%d): %s factory: %llx\n", index, m_buffer[index], (long long int) &m_factory));
+ TRACEF(("removeAt(%d): %s factory: %llx\n", index,
+ (char*) m_buffer[index], (long long int) &m_factory));
m_factory.destroyItem(m_buffer[index]);
TRACE1("removeAt(%d)\n", index);
if (index < --m_count)
for (int ii = 0; ii < m_count; ii++)
printf("%2d: %s\n", ii, (ptr = get(ii)) == NULL ? "<null>" : ptr);
}
+
+void* CStringFactory::cloneItem(const void* source) {
+ char* rc = strdup(reinterpret_cast<const char*>(source));
+ TRACEF(("strdup [%llx] -> [%llx]: %s\n", (long long int) source, (long long int) rc, (char*) rc));
+ return rc;
+}
+void CStringFactory::destroyItem(const void* item) {
+ TRACE2("free [%llx]: %s\n", (long long int) item, (char*) item);
+ // reserved with strdup()
+ ::free((void*) item);
+}
+int CStringFactory::compareItems(const void* item1, const void* item2) const{
+ int rc = strcmp(reinterpret_cast<const char*>(item1),
+ reinterpret_cast<const char*>(item2));
+ return rc;
+}
class ItemFactory {
public:
virtual void* cloneItem(const void* source) = 0;
- virtual int compareItems(const void* item1, const void* item2) const;
+ virtual int compareItems(const void* item1, const void* item2) const = 0;
virtual void destroyItem(const void* item) = 0;
};
class BaseArrayList
BaseArrayList& clear();
BaseArrayList& ensuresSize(int capacity);
int indexOf(const void* item) const;
- BaseArrayList& remove(const void* item);
- BaseArrayList& removeAt(int index);
-public:
inline void** getBuffer() const{
return m_buffer;
}
+ BaseArrayList& remove(const void* item);
+ BaseArrayList& removeAt(int index);
+ void sort();
+protected:
+ void heapify();
+ void shiftDown(int start, int end);
+ inline void swapItems(int index1, int index2){
+ void* tmp = m_buffer[index1];
+ m_buffer[index1] = m_buffer[index2];
+ m_buffer[index2] = tmp;
+ }
+ inline int iParent(int index){
+ return (index-1) / 2;
+ }
+ inline int iLeftChild(int index){
+ return 2*index + 1;
+ }
+ inline int iRightChild(int index){
+ return 2*index + 2;
+ }
protected:
int m_capacity;
int m_blocksize;
BaseArrayList::clear();
return *this;
}
-private:
- virtual int compareItems(const void* item1, const void* item2) const{
- int rc = compareItems(reinterpret_cast<const T*> (item1),
- reinterpret_cast<const T *> (item2));
- return rc;
- return rc;
- }
public:
inline int count() const {
return m_count;
BaseArrayList::removeAt(index);
return *this;
}
+ inline void sort(){
+ BaseArrayList::sort();
+ }
inline int sorted() const{
return m_sorted;
}
inline void setSorted(bool sorted){
m_sorted = sorted;
+ if (m_sorted)
+ sort();
}
};
class CStringFactory {
static CStringFactory* m_instance;
+private:
+ CStringFactory(){
+ }
public:
static CStringFactory* instance(){
if (m_instance == NULL)
- m_instance = new CStringFactory();
+ m_instance = new CStringFactory;
return m_instance;
}
public:
- virtual void* cloneItem(const void* source) {
- char* rc = strdup(reinterpret_cast<const char*>(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()
- ::free((void*) item);
- }
-public:
- virtual int compareItems(const void* item1, const void* item2) const{
- int rc = strcmp(reinterpret_cast<const char*>(item1),
- reinterpret_cast<const char*>(item2));
- return rc;
- }
+ virtual void* cloneItem(const void* source);
+ virtual int compareItems(const void* item1, const void* item2) const;
+ virtual void destroyItem(const void* item);
};
#endif // ARRAYLIST_H
}
public:
virtual void run() {
+ testSort();
testIndexOfUnsorted();
testIndexOfSorted();
testCopyUnsorted();
testSetSorted();
testDestroyItem();
}
+ void checkSorted(int count, CStringList& list){
+ DynBuffer buffer;
+ for ( int ii = 0; ii < count; ii++ ) {
+ buffer.clear().appendInt ( ii, "%08x" );
+ checkE ( buffer.str(), list.get ( ii ) );
+ }
+ }
+ void fillReverse(int count, CStringList& list){
+ DynBuffer buffer;
+ for ( int ii = 0; ii < count; ii++ ) {
+ buffer.clear().appendInt ( count - ii - 1, "%08x");
+ list.add ( buffer.str() );
+ }
+ }
+ void testSort(){
+ CStringList list1 ( 16, 16, 256, true );
+ DynBuffer buffer;
+ for ( int ii = 0; ii < m_permutationSize; ii++ ) {
+ buffer.clear().appendInt ( m_permutation[ii], "%08x" );
+ list1.add ( buffer.str() );
+ }
+ list1.sort();
+ checkSorted(m_permutationSize, list1);
+
+ for (int ii = 1; ii < 128; ii++){
+ list1.clear();
+ fillReverse(ii, list1);
+ list1.sort();
+ checkSorted(ii, list1);
+ }
+ }
void testCopyUnsorted() {
{
CStringList list1;
checkE ( "joe", list.get ( 2 ) );
}
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 = 1; ix <= 1024; ix++ ) {
- buffer.clear().appendInt ( 0x42ab7*ix );
- list.add ( buffer.str() );
- }
- for ( int ix = 1; ix <= 1024; ix++ ) {
- buffer.clear().appendInt ( 0x42ab7*ix );
- checkE ( ix - 1, list.indexOf ( buffer.str() ) );
- }
+ {
+ int capacity = 16;
+ int blocksize = 16;
+ int maxBlocksize = 1024*1024;
+ bool sorted = true;
+ CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+ DynBuffer buffer;
+ int count = 1;
+ for ( int ix = 1; ix <= count; ix++ ) {
+ buffer.clear().appendInt ( 0x42ab7*ix );
+ list.add ( buffer.str() );
+ }
+ for ( int ix = 1; ix <= count; ix++ ) {
+ buffer.clear().appendInt ( 0x42ab7*ix );
+ checkE ( ix - 1, list.indexOf ( buffer.str() ) );
+ }
+ count++;
+ }
}
void testIndexOfSorted() {
int capacity = 16;
DynBuffer buf4(4, 8);
buf4.append("1234");
checkE(4, buf4.length());
- checkE(4, buf4.size());
+ checkE(4, buf4.capacity());
buf4.append("5");
checkE(5, buf4.length());
checkE("12345", buf4);
- checkE(4+8, buf4.size());
- checkT(buf.length() <= buf.size());
+ checkE(4+2*8, buf4.capacity());
+ checkT(buf.length() <= buf.capacity());
buf = "abc";
checkE("abc", buf);
checkE(3, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf = DynBuffer("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
checkE("ABCDEFGHIJKLMNOPQRSTUVWXYZ", buf);
checkE(26, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
}
void testAppend(){
DynBuffer buf("1", 1, 1);
checkE(1, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.append("2x", 1);
checkE("12", buf);
checkE(2, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
DynBuffer buf2("xy");
buf.append(buf2);
checkE("12xy", buf);
checkE(4, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.clear();
checkE(0, buf.length());
buf.append("a");
checkE("a", buf);
checkE(1, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.append("zzz", 2);
checkE("azz", buf);
checkE(3, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
}
void testAppendFormatted(){
DynBuffer buf(2, 4);
buf.appendFormatted("%03d%c%s", 7, 'x', "Z.").appendFormatted("%.2s", "+++++");
checkE("007xZ.++", buf);
checkE(8, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.clear();
buf.appendFormatted("%x", 15);
checkE("f", buf);
checkE(1, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.appendFormatted("%c", '!');
checkE("f!", buf);
checkE(2, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
}
void testAppendInt(){
DynBuffer buf(2,2);
buf.appendInt(123);
checkE("123", buf);
checkE(3, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.appendInt(64, "%4x");
checkE("123 40", buf);
checkE(3 + 4, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.clear();
buf.appendInt(2);
checkE("2", buf);
checkE(1, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.appendInt(8, "%02d");
checkE("208", buf);
checkE(3, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
}
void testAppendLittleEndian(){
DynBuffer buf(2,2);
buf.appendAsLE(0x31323334, 4);
checkE("4321", buf);
checkE(4, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.appendAsLE(0x414243, 3);
checkE("4321CBA", buf);
checkE(7, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.clear();
buf.appendAsLE(0x6162, 2);
checkE("ba", buf);
checkE(2, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.appendAsLE(0x21);
checkE("ba!", buf);
checkE(3, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
}
void testAt(){
DynBuffer buf("abcd");
void testBufferClearLength(){
DynBuffer buf(2, 2);
- checkE(2, buf.size());
+ checkE(2, buf.capacity());
checkE(0, buf.length());
const char* longString = "123456789 123456789 123456789";
int len = strlen(longString);
buf.setLength(len);
checkE(longString, buf);
checkE(29, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
buf.clear();
checkE("", buf);
checkE(0, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
}
void testEnsureSize(){
DynBuffer buf(2, 2);
- checkE(2, buf.size());
+ checkE(2, buf.capacity());
checkE(0, buf.length());
// blocksize is 2:
buf.ensureSize(3);
- checkE(4, buf.size());
+ checkE(6, buf.capacity());
checkE(0, buf.length());
// reserve more than blocksize:
buf.ensureSize(7);
- checkE(7, buf.size());
+ checkE(14, buf.capacity());
checkE(0, buf.length());
}
void testSet(){
DynBuffer buf("123");
checkE("123", buf);
checkE(3, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
// a shorter string:
buf.set("ab");
checkE("ab", buf);
checkE(2, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
// a longer string:
buf.set("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
checkE("ABCDEFGHIJKLMNOPQRSTUVWXYZ", buf);
checkE(26, buf.length());
- checkT(buf.length() <= buf.size());
+ checkT(buf.length() <= buf.capacity());
}
void testSetBlocksize(){
DynBuffer buf(2, 4);
- checkE(2, buf.size());
+ checkE(2, buf.capacity());
checkE(0, buf.length());
checkE(4, buf.blocksize());
buf.setBlocksize(23);
- checkE(2, buf.size());
+ checkE(2, buf.capacity());
checkE(0, buf.length());
checkE(23, buf.blocksize());
}
DynBuffer buf("12345");
buf.setBlocksize(2);
checkE("12345", buf);
- checkE(5, buf.size());
+ checkE(5, buf.capacity());
checkE(5, buf.length());
// make it shorter:
buf.setLength(8);
checkT(buf.startsWith("1234"));
checkE(8, buf.length());
- checkE(8, buf.size());
+ checkE(9, buf.capacity());
}
// testSize() not implemented
void testStartsWith(){
}
}
void testValueOfLE(){
- // int valueOfLE(int size, int index = 0, int defaultValue = -1);
+ // int valueOfLE(int capacity, int index = 0, int defaultValue = -1);
DynBuffer buf("abc");
buf.appendAsLE(0x01020304, 4).append("xyz");
checkE(0x04, buf.valueOfLE(1, 3));
void testMemory(){
clock_t start = clock();
int count = 1000*1000;
- int size = 10*1024*1024;
+ int capacity = 10*1024*1024;
for (int ix = 0; ix < 1000; ix++){
- DynBuffer big(size);
- big.setLength(size + 10);
+ DynBuffer big(capacity);
+ big.setLength(capacity + 10);
}
double duration = (clock() - start) / CLOCKS_PER_SEC;
- printf("allocation of %d blocks with %d MiByte: %.3f sec\n", count, size / 1024 / 1024, duration);
+ printf("allocation of %d blocks with %d MiByte: %.3f sec\n", count, capacity / 1024 / 1024, duration);
}
};
double dummy = 0.0;
uint64_t startReal = TimeUtils::nanosecSinceEpoche();
uint64_t startCpu = TimeUtils::nanosecSinceBoot();
- int count;
+ int count = 0;
uint64_t current;
while(startReal + MRD > (current = TimeUtils::nanosecSinceEpoche())){
dummy = dummy * 12.45 + 1.12345 * sin(dummy) + tan(dummy*7);
/**
* Constructor.
*
- * @param bufferSize initial size of the buffer
+ * @param capacity initial size of the buffer
* @param blocksize minimal increment of size when reallocation is needed<br>
* 0: use <i>bufferSize</i> as block size
*/
-DynBuffer::DynBuffer(size_t bufferSize, size_t blocksize) :
- m_size(bufferSize == 0 ? 16 : bufferSize),
+DynBuffer::DynBuffer(size_t capacity, size_t blocksize, size_t m_maxBlocksize) :
+ m_capacity(capacity == 0 ? 16 : capacity),
m_length(0),
- m_blocksize(blocksize == 0 ? m_size : blocksize),
- m_buffer(new char[m_size + 1]){
+ m_blocksize(blocksize == 0 ? m_capacity : blocksize),
+ m_maxBlocksize(m_maxBlocksize),
+ m_buffer(new char[m_capacity + 1]){
m_buffer[0] = '\0';
}
/**
* @param value initial value
* @param length 0: <i>strlen(value)</i> will be taken<br>
* otherwise: the length of value
- * @param size the initial buffer size<br>
+ * @param capacity the initial buffer size<br>
* 0: size depends on <i>length</i>
*/
-DynBuffer::DynBuffer(const char* value, size_t length, size_t size) :
- m_size(0),
+DynBuffer::DynBuffer(const char* value, size_t length, size_t capacity) :
+ m_capacity(0),
m_length(length == 0 ? strlen(value) : length),
- m_blocksize(256),
+ m_blocksize(8),
+ m_maxBlocksize(1024*1024),
m_buffer(NULL){
- m_size = size == 0 ? m_length : size < m_length ? m_length : size;
- m_buffer = new char[m_size + 1];
+ m_capacity = capacity == 0 ? m_length : capacity < m_length ? m_length : capacity;
+ m_buffer = new char[m_capacity + 1];
memcpy(m_buffer, value, m_length);
m_buffer[m_length] = '\0';
}
}
m_buffer = NULL;
m_length = 0;
- m_size = 0;
+ m_capacity = 0;
}
/**
* Copy constructor.
* @param source the source to copy
*/
DynBuffer::DynBuffer(const DynBuffer& source) :
- m_size(source.m_length < 16 ? 16 : source.m_length),
+ m_capacity(source.m_length < 16 ? 16 : source.m_length),
m_length(source.m_length),
m_blocksize(256),
- m_buffer(new char[m_size + 1])
+ m_buffer(new char[m_capacity + 1])
{
// copy including the trailing '\0':
memcpy(m_buffer, source.m_buffer, m_length + 1);
DynBuffer& DynBuffer::operator =(const DynBuffer& source){
if (source.m_length == 0){
clear();
- } else if (m_size >= source.m_length){
+ } else if (m_capacity >= source.m_length){
// copy with '\0':
memcpy(m_buffer, source.m_buffer, (m_length = source.m_length) + 1);
} else {
delete[] m_buffer;
- m_buffer = new char[(m_size = m_length = source.m_length) + 1];
+ m_buffer = new char[(m_capacity = m_length = source.m_length) + 1];
// copy with '\0':
memcpy(m_buffer, source.m_buffer, m_length + 1);
}
* @return <i>*this</i> (for chaining)
*/
DynBuffer& DynBuffer::ensureSize(size_t size){
- if (size > m_size){
- m_size = m_size + m_blocksize;
- if (size > m_size)
- m_size = size;
- char* newBuffer = new char[m_size + 1];
+ if (size > m_capacity){
+ if ( (m_blocksize *= 2) > m_maxBlocksize)
+ m_blocksize = m_maxBlocksize;
+ m_capacity = m_capacity + m_blocksize;
+ if (size > m_capacity)
+ m_capacity = size;
+ char* newBuffer = new char[m_capacity + 1];
// copy with '\0':
memcpy(newBuffer, m_buffer, m_length + 1);
delete[] m_buffer;
*/
class DynBuffer {
public:
- DynBuffer(size_t bufferSize = 16, size_t blocksize = 0);
+ DynBuffer(size_t capacity = 16, size_t blocksize = 0,
+ size_t m_maxBlocksize = 1024*1024);
DynBuffer(const char* value, size_t length = 0, size_t size = 0);
~DynBuffer();
DynBuffer(const DynBuffer& source);
* @return the instance (for chaining)
*/
inline DynBuffer& append(char cc){
- if (m_length >= m_size - 1)
+ if (m_length >= m_capacity - 1)
ensureSize(m_length + 1);
m_buffer[m_length ++] = cc;
return *this;
* @return <i>*this</i> (for chaining)
*/
inline DynBuffer& setLength(int length){
- if (length > (int) m_size)
+ if (length > (int) m_capacity)
ensureSize(length);
m_buffer[m_length = length] = '\0';
return *this;
*
* @return the current size
*/
- inline size_t size() const{
- return m_size;
+ inline size_t capacity() const{
+ return m_capacity;
}
/**
* Tests whether the buffer starts with a given string.
int valueOfLE(int size, int index = 0, int defaultValue = -1);
private:
/// size of the buffer (without the trailing '\0')
- size_t m_size;
+ size_t m_capacity;
/// length without the trailing '\0'
size_t m_length;
/// the minimal increment when reallocation is done
size_t m_blocksize;
/// Holds the buffer contents
+ size_t m_maxBlocksize;
+ // the blocksize will be doubled until this size
char* m_buffer;
};
extern void testTimerUtils();
extern void testArrayList();
+ testDynBuffer();
testArrayList();
testTimer();
testTimerUtils();
- testDynBuffer();
return 0;
}
* Implements a base class of a posix thread.
*/
class Thread {
- friend ThreadPool;
+ friend class ThreadPool;
public:
Thread(Announcer* logger, bool autoDelete = true, ThreadPool* pool = NULL);
virtual ~Thread();