Initial commit
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# ZUtil//Makefile
|
||||
# Makefile for ZUtil, requires GNU "make"
|
||||
|
||||
BINNAME := $(DIST)/libZUtil.a
|
||||
ifeq ($(TARGET),debug)
|
||||
BINNAME := $(subst .a,_d.a, $(BINNAME))
|
||||
endif
|
||||
|
||||
SRC := \
|
||||
ZAlloc.cpp \
|
||||
ZAllocWindow.cpp \
|
||||
ZBinaryFileReader.cpp \
|
||||
ZBinaryFileWriter.cpp \
|
||||
ZBinaryBufferReader.cpp \
|
||||
ZBinaryBufferWriter.cpp \
|
||||
ZConcurrency.cpp \
|
||||
ZEvent.cpp \
|
||||
ZIniReader.cpp \
|
||||
ZIniWriter.cpp \
|
||||
ZJSONReader.cpp \
|
||||
ZJSONWriter.cpp \
|
||||
ZKVTree.cpp \
|
||||
ZLog.cpp \
|
||||
ZMutex.cpp \
|
||||
ZName.cpp \
|
||||
ZRandomGenerator.cpp \
|
||||
ZReadWriteLock.cpp \
|
||||
ZRegistry.cpp \
|
||||
ZSemaphore.cpp \
|
||||
ZSimplexNoise.cpp \
|
||||
ZSimplexNoiseMap.cpp \
|
||||
ZTaskStream.cpp \
|
||||
ZThread.cpp \
|
||||
ZXMLReader.cpp \
|
||||
ZXMLWriter.cpp
|
||||
|
||||
|
||||
OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .cpp,.o,$(SRC)) )
|
||||
|
||||
$(shell mkdir -p obj/$(ARCH)/$(TARGET))
|
||||
|
||||
$(BINNAME): $(OBJ)
|
||||
$(AR) cru $@ $+
|
||||
$(RANLIB) $@
|
||||
|
||||
# CLEAN
|
||||
clean:
|
||||
@-rm -r -f obj $(DIST)/libZUtil*.a
|
||||
|
||||
|
||||
# *.cpp files to *.o files
|
||||
obj/$(ARCH)/$(TARGET)/%.o: %.cpp
|
||||
@echo CXX $@
|
||||
@$(CXX) $(CXXFLAGS) -c $*.cpp -o obj/$(ARCH)/$(TARGET)/$*.o
|
||||
@@ -0,0 +1,288 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h> /* memmove() */
|
||||
#include <iostream>
|
||||
|
||||
#include <SST/SST_Concurrency.h>
|
||||
|
||||
#include <ZUtil/ZAlloc.hpp>
|
||||
|
||||
SST_Mutex AllocLock = SST_Concurrency_CreateMutex();
|
||||
|
||||
#if ZALLOC_CHECK_ALLOC
|
||||
|
||||
static ZAllocInfo* AllocList = NULL;
|
||||
|
||||
int ZAllocInfo::CurrentAllocCount = 0;
|
||||
int ZAllocInfo::CurrentCheckpoint = 0;
|
||||
|
||||
void ZAllocAddTrack(uintptr_t _address, size_t _size, const char *_file, int _line, int _checkpoint)
|
||||
{
|
||||
ZAllocInfo *info = (ZAllocInfo*)malloc(sizeof(ZAllocInfo));
|
||||
size_t len = strlen(_file);
|
||||
|
||||
info->Address = _address;
|
||||
info->Size = _size;
|
||||
|
||||
if(len > sizeof(info->File)-1)
|
||||
len = sizeof(info->File)-1;
|
||||
|
||||
memcpy(info->File, _file, len);
|
||||
info->File[len] = '\0';
|
||||
|
||||
info->Line = _line;
|
||||
info->Checkpoint = _checkpoint;
|
||||
|
||||
info->Next = NULL;
|
||||
|
||||
//Mutex may be NULL if doing pre-main() init
|
||||
if (AllocLock)
|
||||
SST_Concurrency_LockMutex(AllocLock);
|
||||
|
||||
info->Next = AllocList;
|
||||
AllocList = info;
|
||||
|
||||
#if ZALLOC_EXTRA_SPAMMY
|
||||
std::cerr << "Inc Alloc Count " << ZAllocInfo::CurrentAllocCount << " -> " << (ZAllocInfo::CurrentAllocCount+1) << std::endl;
|
||||
#endif
|
||||
|
||||
ZAllocInfo::CurrentAllocCount++;
|
||||
|
||||
//Mutex may be NULL if doing pre-main() init
|
||||
if (AllocLock)
|
||||
SST_Concurrency_UnlockMutex(AllocLock);
|
||||
}
|
||||
|
||||
void ZAllocRemoveTrack(uintptr_t _address)
|
||||
{
|
||||
//Mutex may be NULL if doing pre-main() init
|
||||
if (AllocLock)
|
||||
SST_Concurrency_LockMutex(AllocLock);
|
||||
|
||||
ZAllocInfo *prev = NULL;
|
||||
ZAllocInfo *cur = AllocList;
|
||||
|
||||
while (cur != NULL)
|
||||
{
|
||||
if (cur->Address == _address)
|
||||
{
|
||||
if (prev == NULL) //i.e. removing head
|
||||
AllocList = cur->Next;
|
||||
else
|
||||
prev->Next = cur->Next; //Remove "this" from the chain. link parent's next pointer to this one's next pointer so nobody has a reference to "this".
|
||||
|
||||
free(cur);
|
||||
|
||||
#if ZALLOC_EXTRA_SPAMMY
|
||||
std::cerr << "Dec Alloc Count " << ZAllocInfo::CurrentAllocCount << " -> " << (ZAllocInfo::CurrentAllocCount-1) << std::endl;
|
||||
#endif
|
||||
|
||||
ZAllocInfo::CurrentAllocCount--;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
prev = cur;
|
||||
cur = cur->Next;
|
||||
}
|
||||
|
||||
//Mutex may be NULL if doing pre-main() init
|
||||
if (AllocLock)
|
||||
SST_Concurrency_UnlockMutex(AllocLock);
|
||||
}
|
||||
|
||||
void ZAllocDumpUnfreed(ZMemState *_state)
|
||||
{
|
||||
SST_Concurrency_LockMutex(AllocLock);
|
||||
|
||||
size_t totalSize = 0;
|
||||
int checkpoint = _state == NULL ? 0 : _state->Checkpoint;
|
||||
|
||||
std::cerr << "--- ZAlloc Unfreed Memory Dump ---" << std::endl << std::endl;
|
||||
std::cerr << ZAllocInfo::CurrentAllocCount << " Current Unfreed Allocations:" << std::endl;
|
||||
|
||||
ZAllocInfo *cur = AllocList;
|
||||
|
||||
while (cur != NULL)
|
||||
{
|
||||
if (cur->Checkpoint >= checkpoint)
|
||||
{
|
||||
std::cerr << cur->File << "\n\tLINE: " << cur->Line << "\n\tADDRESS " << (void*)cur->Address << " (" << cur->Size << " bytes) unfreed!" << std::endl;
|
||||
totalSize += cur->Size;
|
||||
}
|
||||
|
||||
cur = cur->Next;
|
||||
}
|
||||
|
||||
std::cerr << "-----------------------------------------------------------\n";
|
||||
std::cerr << "Total Unfreed: " << totalSize << " bytes" << std::endl << std::endl;
|
||||
|
||||
std::cerr << "--- End Unfreed Memory Dump ---" << std::endl;
|
||||
|
||||
SST_Concurrency_UnlockMutex(AllocLock);
|
||||
}
|
||||
|
||||
//Debug Operator New
|
||||
void * operator new(size_t _size, const char *_file, int _line, int _checkpoint)
|
||||
throw()
|
||||
{
|
||||
void *ptr = (void*)malloc(_size);
|
||||
|
||||
ZAllocAddTrack((uintptr_t)ptr, _size, _file, _line, _checkpoint);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void * operator new[](size_t _size, const char* _file, int _line, int _checkpoint)
|
||||
throw()
|
||||
{
|
||||
void *ptr = (void*)malloc(_size);
|
||||
|
||||
ZAllocAddTrack((uintptr_t)ptr, _size, _file, _line, _checkpoint);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
//Debug Delete
|
||||
void operator delete(void *_ptr, const char* _file, int _line, int _checkpoint)
|
||||
{
|
||||
(void)_file;
|
||||
(void)_line;
|
||||
(void)_checkpoint;
|
||||
|
||||
ZAllocRemoveTrack((uintptr_t)_ptr);
|
||||
|
||||
free(_ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *_ptr, const char* _file, int _line, int _checkpoint)
|
||||
{
|
||||
(void)_file;
|
||||
(void)_line;
|
||||
(void)_checkpoint;
|
||||
|
||||
ZAllocRemoveTrack((uintptr_t)_ptr);
|
||||
|
||||
free(_ptr);
|
||||
}
|
||||
#ifndef __sun /* TODO: some error with Solaris Studio C++ compiler. */
|
||||
void operator delete(void *_ptr)
|
||||
{
|
||||
ZAllocRemoveTrack((uintptr_t)_ptr);
|
||||
|
||||
free(_ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *_ptr)
|
||||
{
|
||||
ZAllocRemoveTrack((uintptr_t)_ptr);
|
||||
|
||||
free(_ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////
|
||||
/* Static New Functions and Fields */
|
||||
/////////////////////////////////////
|
||||
|
||||
//This contains all our statically allocated pointers
|
||||
void **StaticAllocArray = NULL;
|
||||
|
||||
//This is how many we can hold
|
||||
int StaticAllocCapacity = 0;
|
||||
|
||||
//This is how many we've got
|
||||
int StaticAllocSize = 0;
|
||||
|
||||
//This iterates and deletes
|
||||
void ZAllocDeleteStatic(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
//Mutex may be NULL if doing pre-main() init
|
||||
if (AllocLock)
|
||||
SST_Concurrency_LockMutex(AllocLock);
|
||||
|
||||
//Iterate, delete, then delete our static alloc array
|
||||
for (i = 0; i < StaticAllocSize; i++)
|
||||
free(StaticAllocArray[i]);
|
||||
|
||||
free(StaticAllocArray);
|
||||
|
||||
StaticAllocArray = NULL;
|
||||
StaticAllocCapacity = 0;
|
||||
StaticAllocSize = 0;
|
||||
|
||||
//Mutex may be NULL if doing pre-main() init
|
||||
if (AllocLock)
|
||||
SST_Concurrency_UnlockMutex(AllocLock);
|
||||
}
|
||||
|
||||
void ZAllocAddStaticPtr(void *_ptr)
|
||||
{
|
||||
//Mutex may be NULL if doing pre-main() init
|
||||
if (AllocLock)
|
||||
SST_Concurrency_LockMutex(AllocLock);
|
||||
|
||||
//If we need to, register with atexit to call ZAllocDeleteStatic
|
||||
if (StaticAllocArray == NULL)
|
||||
atexit(ZAllocDeleteStatic);
|
||||
|
||||
//Check to see if StaticAllocArray is full
|
||||
if (StaticAllocSize >= StaticAllocCapacity )
|
||||
{
|
||||
//Allocate new one
|
||||
size_t newCapacity = StaticAllocCapacity == 0 ? 128 : StaticAllocCapacity * 2;
|
||||
void *temp = malloc(newCapacity * sizeof(void*));
|
||||
|
||||
//Make sure we don't need to crash hard here
|
||||
if (temp == NULL)
|
||||
{
|
||||
std::cerr << "ZAlloc failed to allocate static tracking array!" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//Copy the old data in
|
||||
memmove(temp, StaticAllocArray, StaticAllocSize * sizeof(void*));
|
||||
|
||||
//Free the old pointer
|
||||
free(StaticAllocArray);
|
||||
|
||||
//Reset our pointer
|
||||
StaticAllocArray = (void**)temp;
|
||||
}
|
||||
|
||||
//Add new void*
|
||||
StaticAllocArray[StaticAllocSize] = _ptr;
|
||||
|
||||
//Increment size
|
||||
StaticAllocSize++;
|
||||
|
||||
//Mutex may be NULL if doing pre-main() init
|
||||
if (AllocLock)
|
||||
SST_Concurrency_UnlockMutex(AllocLock);
|
||||
}
|
||||
|
||||
//Static operator new
|
||||
void * operator new(size_t _size, znew_static_t _staticAlloc)
|
||||
{
|
||||
URFP(_staticAlloc);
|
||||
|
||||
void *ptr = (void*)malloc(_size);
|
||||
|
||||
ZAllocAddStaticPtr(ptr);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void * operator new[](size_t _size, znew_static_t _staticAlloc)
|
||||
{
|
||||
URFP(_staticAlloc);
|
||||
|
||||
void *ptr = (void*)malloc(_size);
|
||||
|
||||
ZAllocAddStaticPtr(ptr);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
#include <ZUtil/ZAllocWindow.hpp>
|
||||
#include <ZUtil/ZAssert.hpp>
|
||||
|
||||
#include <SST/SST_OS.h>
|
||||
|
||||
#define ALLOC_BITS (0xF00D) // Used to flag a section of memory as 'allocated'
|
||||
#define DEALLOC_BITS (0xDEAD) // Used to flag a section of memory as 'deallocated'
|
||||
#define LOOP_BITS (0xCAB0) // Used to flag that the next allocated section is back at the beginning of the buffer
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZAllocWindow::ZAllocWindow()
|
||||
: Buffer(NULL), Begin(NULL), End(NULL),
|
||||
BufferSize(0), bOwnsBuffer(true),
|
||||
NumAllocs(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZAllocWindow::ZAllocWindow( size_t _buffersize )
|
||||
: Buffer(NULL), Begin(NULL), End(NULL),
|
||||
BufferSize(_buffersize), bOwnsBuffer(true),
|
||||
NumAllocs(0)
|
||||
{
|
||||
Resize(_buffersize);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZAllocWindow::~ZAllocWindow()
|
||||
{
|
||||
if (bOwnsBuffer)
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void* ZAllocWindow::Allocate( size_t _size )
|
||||
{
|
||||
// boundary is the location in memory that we cannot write past
|
||||
uintptr_t boundary;
|
||||
|
||||
// determine where our boundary is
|
||||
uintptr_t pool_begin = (uintptr_t)Buffer;
|
||||
uintptr_t pool_end = pool_begin + BufferSize;
|
||||
uintptr_t ptr_begin = (uintptr_t)Begin;
|
||||
uintptr_t ptr_end = (uintptr_t)End;
|
||||
|
||||
boundary = (ptr_begin > ptr_end ? ptr_begin :
|
||||
ptr_begin < ptr_end ? pool_end :
|
||||
( NumAllocs > 0 ? ptr_end :
|
||||
pool_end ) );
|
||||
|
||||
// align segment to word boundary
|
||||
uintptr_t seg_begin = (uintptr_t)End;
|
||||
uintptr_t seg_end = (uintptr_t)SST_OS_AlignPtr((void*)(seg_begin + 2*sizeof(uint32_t) + _size), sizeof(void*));
|
||||
|
||||
// check segment against boundary
|
||||
if (seg_end > boundary) {
|
||||
|
||||
// if the segment has not just run up against the pool end, we are done
|
||||
if (boundary != pool_end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// signal a loop (if less than 'end') and check again
|
||||
if (seg_begin < pool_end) {
|
||||
uint32_t* ptr_32 = (uint32_t*)seg_begin;
|
||||
ptr_32[0] = (uint32_t)LOOP_BITS;
|
||||
}
|
||||
|
||||
boundary = ptr_begin;
|
||||
|
||||
seg_begin = pool_begin;
|
||||
seg_end = (uintptr_t)SST_OS_AlignPtr((void*)(seg_begin + 2 * sizeof(uint32_t) + _size), sizeof(void*));
|
||||
}
|
||||
|
||||
// check segment against boundary again
|
||||
if (seg_end <= boundary) {
|
||||
NumAllocs++;
|
||||
|
||||
// set size as first element in block
|
||||
uint32_t* ptr_32 = (uint32_t*)seg_begin;
|
||||
ptr_32[0] = (uint32_t)ALLOC_BITS;
|
||||
ptr_32[1] = (uint32_t)(seg_end - seg_begin);
|
||||
|
||||
// set new End pointer to ptr_end
|
||||
End = (void*)seg_end;
|
||||
|
||||
// if End == BufferEnd, End == 0
|
||||
if (End == (void*)((uintptr_t)Buffer + (uintptr_t)BufferSize))
|
||||
End = Buffer;
|
||||
|
||||
// return the address of the first non-reserved element of the segment
|
||||
return &ptr_32[2];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZAllocWindow::Deallocate( void* _data )
|
||||
{
|
||||
// check size before data
|
||||
uint32_t* ptr_32 = (uint32_t*)((uintptr_t)_data - (2*sizeof(uint32_t)));
|
||||
uint32_t flag = ptr_32[0];
|
||||
uint32_t size = ptr_32[1];
|
||||
|
||||
// quick sanity check
|
||||
ZASSERT(flag == ALLOC_BITS, "ZAllocWindow passed invalid pointer to deallocate!");
|
||||
ZASSERT(size < BufferSize, "ZAllocWindow passed corrupted pointer to deallocate!");
|
||||
|
||||
// mark size slot as 'freed'
|
||||
ptr_32[0] = (uint32_t)DEALLOC_BITS;
|
||||
NumAllocs--;
|
||||
|
||||
// see if this was the oldest allocated block, and start rolling up
|
||||
if (ptr_32 == Begin) {
|
||||
while (WHILE_TRUE) {
|
||||
ptr_32 = (uint32_t*)Begin;
|
||||
|
||||
// if begin is at or past end, loop to the beginning
|
||||
if ((uintptr_t)ptr_32 >= ((uintptr_t)Begin + BufferSize)) {
|
||||
Begin = Buffer;
|
||||
continue;
|
||||
}
|
||||
|
||||
// determine flag (size if needed)
|
||||
flag = ptr_32[0];
|
||||
|
||||
// if this is a loop flag, start again at the beginning
|
||||
if (flag == LOOP_BITS) {
|
||||
Begin = Buffer;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if this is a dealloc flag, dealloc the segment, increment Begin
|
||||
if (flag == DEALLOC_BITS) {
|
||||
size = ptr_32[1];
|
||||
|
||||
uintptr_t seg_start = (uintptr_t)ptr_32;
|
||||
uintptr_t seg_end = seg_start + size;
|
||||
|
||||
Begin = (void*)seg_end;
|
||||
|
||||
#ifdef _DEBUG
|
||||
ptr_32[1] = DEALLOC_BITS;
|
||||
#endif
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZAllocWindow::Reset()
|
||||
{
|
||||
NumAllocs = 0;
|
||||
Begin = Buffer;
|
||||
End = Buffer;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZAllocWindow::Resize( size_t _newsize )
|
||||
{
|
||||
// don't resize if we have allocations or don't own the buffer
|
||||
if (NumAllocs > 0 || !bOwnsBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check newsize is zero to free everything
|
||||
if (_newsize == 0) {
|
||||
if (Buffer != NULL) {
|
||||
free(Buffer);
|
||||
Buffer = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// free current buffer if not NULL
|
||||
if (Buffer != NULL) {
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
// allocate new buffer and return success / failure
|
||||
Buffer = malloc(_newsize);
|
||||
Begin = Buffer;
|
||||
End = Buffer;
|
||||
BufferSize = _newsize;
|
||||
|
||||
return Buffer != NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZAllocWindow::SetBuffer( void* _buffer, size_t _buffersize )
|
||||
{
|
||||
// don't accept buffer if we have allocations
|
||||
if (NumAllocs > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if the new buffer is null, just reallocate to buffersize
|
||||
if (_buffer == NULL) {
|
||||
bOwnsBuffer = true;
|
||||
return Resize(_buffersize);
|
||||
}
|
||||
|
||||
// Get rid of the current buffer if we need to
|
||||
if (Buffer != NULL) {
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
// lose ownership and set parameters, return success
|
||||
bOwnsBuffer = false;
|
||||
Buffer = _buffer;
|
||||
Begin = Buffer;
|
||||
End = Buffer;
|
||||
BufferSize = _buffersize;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
ZBinaryBufferReader.cpp
|
||||
Author: Chris Ertel <crertel@762studios.com>, Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 3/6/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Reads a binary stream from memory.
|
||||
|
||||
License:
|
||||
|
||||
TODO
|
||||
|
||||
*/
|
||||
|
||||
#include <ZUtil/ZBinaryBufferReader.hpp>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint8_t ZBinaryBufferReader::ReadU8()
|
||||
{
|
||||
uint8_t retval = (uint8_t)Data[Offset];
|
||||
|
||||
++Offset;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint16_t ZBinaryBufferReader::ReadU16()
|
||||
{
|
||||
uint16_t value;
|
||||
memcpy(&value, GetPosition(), sizeof(uint16_t));
|
||||
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
value = SST_OS_ByteSwap16(value);
|
||||
|
||||
Offset += sizeof(uint16_t);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint32_t ZBinaryBufferReader::ReadU32()
|
||||
{
|
||||
uint32_t value;
|
||||
memcpy(&value, GetPosition(), sizeof(uint32_t));
|
||||
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
value = SST_OS_ByteSwap32(value);
|
||||
|
||||
Offset += sizeof(uint32_t);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint64_t ZBinaryBufferReader::ReadU64()
|
||||
{
|
||||
uint64_t value;
|
||||
memcpy(&value, GetPosition(), sizeof(uint64_t));
|
||||
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
value = SST_OS_ByteSwap64(value);
|
||||
|
||||
Offset += sizeof(uint64_t);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferReader::ReadU8Array(uint8_t* ptr, size_t count)
|
||||
{
|
||||
memcpy(ptr, GetPosition(), count);
|
||||
Offset += count;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferReader::ReadU16Array(uint16_t* ptr, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
{
|
||||
memcpy(ptr, GetPosition(), sizeof(uint16_t) * count);
|
||||
Offset += sizeof(uint16_t) * count;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
ptr[i] = ReadU16();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferReader::ReadU32Array(uint32_t* ptr, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
{
|
||||
memcpy(ptr, GetPosition(), sizeof(uint32_t) * count);
|
||||
Offset += sizeof(uint32_t) * count;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
ptr[i] = ReadU32();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferReader::ReadU64Array(uint64_t* ptr, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
{
|
||||
memcpy(ptr, GetPosition(), sizeof(uint64_t) * count);
|
||||
Offset += sizeof(uint64_t) * count;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
ptr[i] = ReadU64();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void* ZBinaryBufferReader::ReadPointer()
|
||||
{
|
||||
uintptr_t value;
|
||||
memcpy(&value, GetPosition(), sizeof(uintptr_t));
|
||||
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
{
|
||||
switch(sizeof(uintptr_t))
|
||||
{
|
||||
case sizeof(uint16_t): value = (uintptr_t)SST_OS_ByteSwap16((uint16_t)value); break;
|
||||
case sizeof(uint32_t): value = (uintptr_t)SST_OS_ByteSwap32((uint32_t)value); break;
|
||||
case sizeof(uint64_t): value = (uintptr_t)SST_OS_ByteSwap64((uint64_t)value); break;
|
||||
}
|
||||
}
|
||||
|
||||
Offset += sizeof(uintptr_t);
|
||||
return (void*)value;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
ZBinaryBufferWriter.cpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/05/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Writes a binary stream to memory
|
||||
|
||||
License:
|
||||
|
||||
TODO
|
||||
|
||||
*/
|
||||
|
||||
#include <ZUtil/ZBinaryBufferWriter.hpp>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferWriter::WriteU8(uint8_t v)
|
||||
{
|
||||
Data[Offset] = v;
|
||||
++Offset;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferWriter::WriteU16(uint16_t v)
|
||||
{
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
v = SST_OS_ByteSwap16(v);
|
||||
|
||||
memcpy(Data+Offset, &v, sizeof(uint16_t));
|
||||
|
||||
Offset += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferWriter::WriteU32(uint32_t v)
|
||||
{
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
v = SST_OS_ByteSwap32(v);
|
||||
|
||||
memcpy(Data+Offset, &v, sizeof(uint32_t));
|
||||
|
||||
Offset += sizeof(uint32_t);
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferWriter::WriteU64(uint64_t v)
|
||||
{
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
v = SST_OS_ByteSwap64(v);
|
||||
|
||||
memcpy(Data+Offset, &v, sizeof(uint64_t));
|
||||
|
||||
Offset += sizeof(uint64_t);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferWriter::WriteU8Array(const uint8_t* v, size_t count)
|
||||
{
|
||||
memcpy(Data+Offset, v, count);
|
||||
|
||||
Offset += sizeof(uint8_t) * count;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferWriter::WriteU16Array(const uint16_t* v, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
memcpy(Data+Offset, v, count*sizeof(uint16_t));
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
{
|
||||
uint16_t value = SST_OS_ByteSwap16(v[i]);
|
||||
memcpy(Data+Offset+i*sizeof(uint16_t), &value, sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
Offset += sizeof(uint16_t) * count;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferWriter::WriteU32Array(const uint32_t* v, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
memcpy(Data+Offset, v, count*sizeof(uint32_t));
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
{
|
||||
uint32_t value = SST_OS_ByteSwap32(v[i]);
|
||||
memcpy(Data+Offset+i*sizeof(uint32_t), &value, sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
Offset += sizeof(uint32_t) * count;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferWriter::WriteU64Array(const uint64_t* v, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
memcpy(Data+Offset, v, count*sizeof(uint16_t));
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
{
|
||||
uint64_t value = SST_OS_ByteSwap64(v[i]);
|
||||
memcpy(Data+Offset+i*sizeof(uint64_t), &value, sizeof(uint64_t));
|
||||
}
|
||||
}
|
||||
|
||||
Offset += sizeof(uint64_t) * count;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryBufferWriter::WritePointer(void* pointer)
|
||||
{
|
||||
uintptr_t ptrValue = (uintptr_t)pointer;
|
||||
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
memcpy(Data+Offset, &ptrValue, sizeof(uintptr_t));
|
||||
else
|
||||
{
|
||||
switch(sizeof(uintptr_t))
|
||||
{
|
||||
case sizeof(uint16_t): WriteU16((uint16_t)ptrValue); break;
|
||||
case sizeof(uint32_t): WriteU32((uint32_t)ptrValue); break;
|
||||
case sizeof(uint64_t): WriteU64((uint64_t)ptrValue); break;
|
||||
}
|
||||
}
|
||||
|
||||
Offset += sizeof(uintptr_t);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
ZBinaryFileReader.cpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 3/6/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Reads a binary stream from a SST_File handle. NOTE: On 32-bit platforms, only files up to 4GB are supported.
|
||||
|
||||
License:
|
||||
|
||||
TODO
|
||||
|
||||
*/
|
||||
|
||||
#include <ZUtil/ZBinaryFileReader.hpp>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZBinaryFileReader::ZBinaryFileReader(SST_File handle, SST_ByteOrder bo)
|
||||
: ZBinaryReader(bo), fp(handle)
|
||||
{
|
||||
uint64_t size64;
|
||||
uint64_t offset64;
|
||||
|
||||
SST_OS_GetFilePointer(fp, &offset64);
|
||||
size64 = SST_OS_GetFileSize(fp);
|
||||
|
||||
//Downcast (potentially) to size_t
|
||||
Size = (size_t)size64;
|
||||
Offset = (size_t)offset64;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint8_t ZBinaryFileReader::ReadU8()
|
||||
{
|
||||
uint8_t retval;
|
||||
|
||||
SST_OS_ReadFile(fp, &retval, sizeof(uint8_t));
|
||||
|
||||
++Offset;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint16_t ZBinaryFileReader::ReadU16()
|
||||
{
|
||||
uint16_t value;
|
||||
|
||||
SST_OS_ReadFile(fp, &value, sizeof(uint16_t));
|
||||
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
value = SST_OS_ByteSwap16(value);
|
||||
|
||||
Offset += sizeof(uint16_t);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint32_t ZBinaryFileReader::ReadU32()
|
||||
{
|
||||
uint32_t value;
|
||||
SST_OS_ReadFile(fp, &value, sizeof(uint32_t));
|
||||
|
||||
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
value = SST_OS_ByteSwap32(value);
|
||||
|
||||
Offset += sizeof(uint32_t);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint64_t ZBinaryFileReader::ReadU64()
|
||||
{
|
||||
uint64_t value;
|
||||
SST_OS_ReadFile(fp, &value, sizeof(uint64_t));
|
||||
|
||||
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
value = SST_OS_ByteSwap64(value);
|
||||
|
||||
Offset += sizeof(uint64_t);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileReader::ReadU8Array(uint8_t* ptr, size_t count)
|
||||
{
|
||||
SST_OS_ReadFile(fp, ptr, count);
|
||||
|
||||
Offset += count;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileReader::ReadU16Array(uint16_t* ptr, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
{
|
||||
SST_OS_ReadFile(fp, ptr, sizeof(uint16_t) * count);
|
||||
Offset += sizeof(uint16_t) * count;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
ptr[i] = ReadU16();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileReader::ReadU32Array(uint32_t* ptr, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
{
|
||||
SST_OS_ReadFile(fp, ptr, sizeof(uint32_t) * count);
|
||||
Offset += sizeof(uint32_t) * count;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
ptr[i] = ReadU32();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileReader::ReadU64Array(uint64_t* ptr, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
{
|
||||
SST_OS_ReadFile(fp, ptr, sizeof(uint64_t) * count);
|
||||
Offset += sizeof(uint64_t) * count;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
ptr[i] = ReadU64();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileReader::SeekTo(size_t offset)
|
||||
{
|
||||
SST_OS_SeekFile(fp, (int64_t)offset, SST_SEEK_START);
|
||||
Offset = offset;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
ZBinaryFileWriter.cpp
|
||||
Author: Chris Ertel <crertel@762studios.com>, Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 3/11/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Writes a binary stream from a SST_File handle. NOTE: On 32-bit platforms, only files up to 4GB are supported.
|
||||
|
||||
License:
|
||||
|
||||
TODO
|
||||
|
||||
*/
|
||||
|
||||
#include <ZUtil/ZBinaryFileWriter.hpp>
|
||||
|
||||
/*
|
||||
TODO: This implementation makes use of SST_File, which is a thin wrapper over system calls. Because of this,
|
||||
small writes can reduce performance. A 4KB buffer (or better, one that is a multiple of inode size) would
|
||||
help reduce the overhead.
|
||||
*/
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZBinaryFileWriter::ZBinaryFileWriter(SST_File handle, SST_ByteOrder bo) :
|
||||
ZBinaryWriter(bo), fp(handle)
|
||||
{
|
||||
uint64_t offset64;
|
||||
|
||||
SST_OS_GetFilePointer(fp, &offset64);
|
||||
|
||||
Offset = (size_t)offset64;
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileWriter::WriteU8(uint8_t v)
|
||||
{
|
||||
SST_OS_WriteFile(fp, &v, sizeof(uint8_t));
|
||||
|
||||
++Offset;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileWriter::WriteU16(uint16_t v)
|
||||
{
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
v = SST_OS_ByteSwap16(v);
|
||||
|
||||
SST_OS_WriteFile(fp, &v, sizeof(uint16_t));
|
||||
|
||||
Offset += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileWriter::WriteU32(uint32_t v)
|
||||
{
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
v = SST_OS_ByteSwap32(v);
|
||||
|
||||
SST_OS_WriteFile(fp, &v, sizeof(uint32_t));
|
||||
|
||||
Offset += sizeof(uint32_t);
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileWriter::WriteU64(uint64_t v)
|
||||
{
|
||||
if(GetStreamByteOrder() != SST_BYTEORDER_HOST)
|
||||
v = SST_OS_ByteSwap64(v);
|
||||
|
||||
SST_OS_WriteFile(fp, &v, sizeof(uint64_t));
|
||||
|
||||
Offset += sizeof(uint64_t);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileWriter::WriteU8Array(const uint8_t* v, size_t count)
|
||||
{
|
||||
SST_OS_WriteFile(fp, v, count);
|
||||
|
||||
Offset += sizeof(uint8_t) * count;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileWriter::WriteU16Array(const uint16_t* v, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
SST_OS_WriteFile(fp, v, count * sizeof(uint16_t));
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
{
|
||||
uint16_t value = SST_OS_ByteSwap16(v[i]);
|
||||
SST_OS_WriteFile(fp, &value, sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
Offset += sizeof(uint16_t) * count;
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileWriter::WriteU32Array(const uint32_t* v, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
SST_OS_WriteFile(fp, v, count * sizeof(uint32_t));
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
{
|
||||
uint32_t value = SST_OS_ByteSwap32(v[i]);
|
||||
SST_OS_WriteFile(fp, &value, sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
Offset += sizeof(uint32_t) * count;
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileWriter::WriteU64Array(const uint64_t* v, size_t count)
|
||||
{
|
||||
if(GetStreamByteOrder() == SST_BYTEORDER_HOST)
|
||||
SST_OS_WriteFile(fp, v, count * sizeof(uint64_t));
|
||||
else
|
||||
{
|
||||
for(size_t i=0; i<count; i++)
|
||||
{
|
||||
uint64_t value = SST_OS_ByteSwap64(v[i]);
|
||||
SST_OS_WriteFile(fp, &value, sizeof(uint64_t));
|
||||
}
|
||||
}
|
||||
|
||||
Offset += sizeof(uint64_t) * count;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZBinaryFileWriter::SeekTo(size_t offset)
|
||||
{
|
||||
uint64_t offset64 = (uint64_t)offset; //Because size_t can be 32 bits, casting to int64_t can sign extend (bad), cast to uint64_t first so it is zero-extended.
|
||||
SST_OS_SeekFile(fp, (int64_t)offset64, SST_SEEK_START);
|
||||
|
||||
Offset = offset;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <ZUtil/ZConcurrency.hpp>
|
||||
#include <SST/SST_Concurrency.h>
|
||||
|
||||
ZThreadContext ZConcurrency::CreateThread(int(*_func)(void*), void *_arg)
|
||||
{
|
||||
ZThreadContext context;
|
||||
|
||||
context.Thread = SST_Concurrency_CreateThread(_func, _arg);
|
||||
|
||||
//TODO - this doesn't install the running thread id, just this current thread id
|
||||
//bleargh
|
||||
//context.ThreadId = SST_Concurrency_GetThreadId();
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void ZConcurrency::DestroyThread(ZThreadContext& _context)
|
||||
{
|
||||
SST_Concurrency_DestroyThread(_context.Thread);
|
||||
|
||||
_context.Thread = NULL;
|
||||
_context.ThreadId = 0;
|
||||
_context.ThreadExitStatus = 0;
|
||||
}
|
||||
|
||||
void ZConcurrency::SleepThread(uint32_t _ms)
|
||||
{
|
||||
SST_Concurrency_SleepThread(_ms);
|
||||
}
|
||||
|
||||
uint32_t ZConcurrency::GetThreadId()
|
||||
{
|
||||
return SST_Concurrency_GetThreadId();
|
||||
}
|
||||
|
||||
uint64_t ZConcurrency::GetTicks()
|
||||
{
|
||||
return SST_Concurrency_GetTicks();
|
||||
}
|
||||
|
||||
bool ZConcurrency::WaitThread(ZThreadContext& _context)
|
||||
{
|
||||
return SST_Concurrency_WaitThread(_context.Thread, &_context.ThreadExitStatus) != 0;
|
||||
}
|
||||
|
||||
void ZConcurrency::YieldThread()
|
||||
{
|
||||
SST_Concurrency_YieldThread();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#include <ZUtil/ZEvent.hpp>
|
||||
#include <ZUtil/ZAssert.hpp>
|
||||
#include <SST/SST_Concurrency.h> //Need this for SST_WAIT_INFINITE
|
||||
|
||||
ZEvent::ZEvent()
|
||||
: Event(SST_Concurrency_CreateEvent())
|
||||
{
|
||||
ZASSERT_RUNTIME(Event != NULL, "ZEvent failed to allocate event from libsst-concurrency!");
|
||||
}
|
||||
|
||||
ZEvent::~ZEvent()
|
||||
{
|
||||
SST_Concurrency_DestroyEvent(Event);
|
||||
}
|
||||
|
||||
void ZEvent::Notify()
|
||||
{
|
||||
SST_Concurrency_SignalEvent(Event);
|
||||
}
|
||||
|
||||
void ZEvent::Reset()
|
||||
{
|
||||
SST_Concurrency_ResetEvent(Event);
|
||||
}
|
||||
|
||||
bool ZEvent::Wait()
|
||||
{
|
||||
return SST_Concurrency_WaitEvent(Event, SST_WAIT_INFINITE) != 0;
|
||||
}
|
||||
|
||||
bool ZEvent::Wait( uint32_t _ms )
|
||||
{
|
||||
return SST_Concurrency_WaitEvent(Event, _ms) != 0;
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
#include <ZUtil/ZIniReader.hpp>
|
||||
|
||||
#include <ZSTL/ZBasicStringAlgo.hpp>
|
||||
|
||||
bool ZIniReader::Read(const char* data, size_t length)
|
||||
{
|
||||
/*
|
||||
Algorithm:
|
||||
1) Read a line, ignore blank lines and comment lines
|
||||
2) If line is KVP
|
||||
2.1) No section? -> Error
|
||||
2.2) Section exists? -> Parse KVP
|
||||
2.2.1) Takes form of K = V? -> Add KVP
|
||||
2.2.2) Doesn't? -> Error
|
||||
3) Else if section
|
||||
3.1) If already seen section -> Error
|
||||
3.2) Create section hashtable, insert it
|
||||
4) Next line
|
||||
*/
|
||||
|
||||
ClearData();
|
||||
ErrorMessage.Clear();
|
||||
|
||||
ZHashMap<ZString, ZString>* currentSection = NULL;
|
||||
|
||||
size_t i = 0; //Current index into file data
|
||||
size_t lineStart = 0; //Start of line
|
||||
size_t lineLength;
|
||||
uint32_t lineNumber = 1;
|
||||
|
||||
//Parse loop
|
||||
while(i < length)
|
||||
{
|
||||
char c = data[i];
|
||||
i++;
|
||||
|
||||
//Treat final character as EOL too
|
||||
if(i < length)
|
||||
{
|
||||
//Split on \n or \r
|
||||
if(c != 0x0A && c != 0x0D)
|
||||
continue;
|
||||
else //Found EOL character
|
||||
{
|
||||
//Line length does NOT include EOL character
|
||||
lineLength = i - 1 - lineStart;
|
||||
}
|
||||
}
|
||||
else //Final line, don't remove extra character
|
||||
lineLength = i - lineStart;
|
||||
|
||||
//Line must be non-blank
|
||||
if(lineLength > 0 && data[lineStart] != '\n')
|
||||
{
|
||||
//Get pointer to start of line
|
||||
const char* line = &data[lineStart];
|
||||
|
||||
//Ignore comments
|
||||
if(line[0] != ';' && line [0] != '#')
|
||||
{
|
||||
//Section name
|
||||
if(line[0] == '[')
|
||||
{
|
||||
size_t j=1; //Start after '['
|
||||
//Read until closing '] or EOL
|
||||
while(j<lineLength && line[j] != ']')
|
||||
{
|
||||
if(!isalnum(line[j]) && line[j] != '_' && line[j] != ' ')
|
||||
{
|
||||
SetError("Header must contain alphanumeric, space, or _ only", lineNumber);
|
||||
return false;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
//Reached end of line but no terminator
|
||||
if(j == lineLength)
|
||||
{
|
||||
SetError("Missing closing \']\'", lineNumber);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Copy section name to ZString
|
||||
ZString sectionName(line+1, j-1);
|
||||
|
||||
//Check for existence
|
||||
if(StringSectionMap.ContainsKey(sectionName))
|
||||
{
|
||||
SetError("Section already exists", lineNumber);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Construct new table
|
||||
ZHashMap<ZString, ZString>* table = new(std::nothrow) ZHashMap<ZString, ZString>();
|
||||
if(table != NULL)
|
||||
{
|
||||
//Add mapping
|
||||
StringSectionMap.Put(sectionName, table);
|
||||
Sections.PushBack(table);
|
||||
SectionNames.PushBack(sectionName);
|
||||
|
||||
//Save this as the current section
|
||||
currentSection = table;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetError("Out of memory", lineNumber);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(!isspace(line[0])) //Not a space, not comment, not section -> KVP
|
||||
{
|
||||
//Did we find a section first?
|
||||
if(currentSection != NULL)
|
||||
{
|
||||
size_t j=0; //length of key
|
||||
|
||||
//Scan until space, equals sign, or EOL
|
||||
while(j<lineLength && line[j] != '=' && !isspace(line[j]))
|
||||
{
|
||||
if(!isalnum(line[j]) && line[j] != '_')
|
||||
{
|
||||
SetError("Key must contain alphanumeric or '_' only", lineNumber);
|
||||
return false;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
//Didn't find either a space or '='
|
||||
if(j == lineLength)
|
||||
{
|
||||
SetError("Missing '=' after key name", lineNumber);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Copy key to ZString
|
||||
ZString key(line, j);
|
||||
|
||||
if(line[j] != '=')
|
||||
{
|
||||
//Skip remaining whitespace
|
||||
while(j<lineLength && isspace(line[j]))
|
||||
j++;
|
||||
|
||||
if(j == lineLength || line[j] != '=')
|
||||
{
|
||||
SetError("Missing '=' after key name", lineNumber);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Now we definitely point to a '=' character. Ensure there is data after it
|
||||
if(j+1 == lineLength)
|
||||
{
|
||||
SetError("Expected value after '='", lineNumber);
|
||||
return false;
|
||||
}
|
||||
j++;
|
||||
|
||||
//Skip any whitespace after '='
|
||||
while(j<lineLength && isspace(line[j]))
|
||||
j++;
|
||||
|
||||
//Special case: if we hit EOL, then we have an empty value
|
||||
if(j == lineLength)
|
||||
{
|
||||
currentSection->Put(key, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
ZString val(&line[j], lineLength-j);
|
||||
currentSection->Put(key, val);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetError("Values must be in a section", lineNumber);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
SetError("Invalid line. Must be a section, comment, or value", lineNumber);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} //if(non-blank line)
|
||||
|
||||
//Check for \r \n pattern
|
||||
if(c == '\r') //we expect a \n, but verify
|
||||
{
|
||||
if(i < length && data[i] == '\n')
|
||||
i++;
|
||||
}
|
||||
|
||||
//Start on next line
|
||||
lineStart = i;
|
||||
lineNumber++;
|
||||
}
|
||||
|
||||
return !Sections.Empty();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
const ZHashMap<ZString, ZString>* ZIniReader::GetSection(const ZString& sectionName)
|
||||
{
|
||||
ZHashMap<ZString, ZHashMap<ZString, ZString>* >::Iterator it = StringSectionMap.Find(sectionName);
|
||||
|
||||
if(it.HasCurrent())
|
||||
return it.GetValue();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZIniReader::SetError(const char* message, uint32_t line)
|
||||
{
|
||||
ZStringAlgo::BuildPrintf(ErrorMessage, "Line %u: %s", line, message);
|
||||
|
||||
//Clear all data
|
||||
ClearData();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZIniReader::ClearData()
|
||||
{
|
||||
for(size_t i = 0; i < Sections.Size(); i++)
|
||||
delete Sections[i];
|
||||
|
||||
Sections.Clear();
|
||||
SectionNames.Clear();
|
||||
StringSectionMap.Clear();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZIniReader::GetKVTree(ZKVTree& _kvtree)
|
||||
{
|
||||
for(size_t i = 0; i < Sections.Size(); i++)
|
||||
{
|
||||
ZHashMap<ZString, ZString>* hmap = Sections[i];
|
||||
ZHashMap<ZString, ZString>::Iterator it = hmap->Begin();
|
||||
|
||||
for(; it != hmap->End(); ++it)
|
||||
{
|
||||
ZString key = SectionNames[i]+"."+it.GetKey();
|
||||
ZString& value = it.GetValue();
|
||||
|
||||
_kvtree.Put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#include <ZUtil/ZIniWriter.hpp>
|
||||
|
||||
#include <ZSTL/ZString.hpp>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
const ZString& ZIniWriter::GetErrorString()
|
||||
{
|
||||
return ErrorMessage;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZIniWriter::Write( const ZKVTree& _kvtree, ZString& _output )
|
||||
{
|
||||
ErrorMessage.Clear();
|
||||
|
||||
ZKVTree::Iterator itr = _kvtree.Begin();
|
||||
|
||||
if (itr == _kvtree.End())
|
||||
{
|
||||
ErrorMessage = "ZIniWriter: KV Tree has no data!";
|
||||
return false;
|
||||
}
|
||||
|
||||
//Each node name at this level is a section
|
||||
for (size_t i = 0; i < itr.GetSiblingCount(); i++)
|
||||
{
|
||||
//Append the name in [Section] form
|
||||
_output.PushBack('[');
|
||||
|
||||
ZStringAlgo::Append(_output, itr.GetName());
|
||||
|
||||
_output.PushBack(']');
|
||||
|
||||
ZStringAlgo::Append(_output, LINE_TERMINATOR);
|
||||
|
||||
//Iterate the kids (the kids!)
|
||||
if (itr.CheckChild())
|
||||
{
|
||||
itr.Child();
|
||||
|
||||
//Each node at this level is a key/value pair
|
||||
for (size_t j = 0; j < itr.GetSiblingCount(); j++)
|
||||
{
|
||||
//Append the kid in key=value form
|
||||
ZStringAlgo::Append(_output, itr.GetName());
|
||||
|
||||
_output.PushBack('=');
|
||||
|
||||
ZStringAlgo::Append(_output, itr.GetValue());
|
||||
ZStringAlgo::Append(_output, LINE_TERMINATOR);
|
||||
|
||||
if (itr.CheckNextSibling())
|
||||
itr.NextSibling();
|
||||
}
|
||||
|
||||
itr.Parent();
|
||||
}
|
||||
|
||||
ZStringAlgo::Append(_output, LINE_TERMINATOR);
|
||||
|
||||
if (itr.CheckNextSibling())
|
||||
itr.NextSibling();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <ZUtil/ZJSONReader.hpp>
|
||||
|
||||
#include <ZSTL/ZString.hpp>
|
||||
#include <ZSTL/ZBasicStringAlgo.hpp>
|
||||
#include <jansson.h>
|
||||
|
||||
/* iterate over the values, adding to the KVTree as needed */
|
||||
static void recurse_and_populate ( json_t* _object, void* _itr, ZKVTree& _storage, ZString _currPath )
|
||||
{
|
||||
/* for each key-value pair in the object...*/
|
||||
while (_itr != NULL)
|
||||
{
|
||||
json_t* val = json_object_iter_value(_itr);
|
||||
|
||||
if ( json_is_array ( val ) )
|
||||
{
|
||||
|
||||
/*
|
||||
TODO:
|
||||
What happens if we have an array of arrays? An array of objects?
|
||||
*/
|
||||
size_t arraySize = json_array_size(val);
|
||||
for (size_t i = 0; i < arraySize; i++)
|
||||
{
|
||||
ZBasicStringAlgo::BuildPrintf(_currPath,"%s.%s[%d]", _currPath.Data(), json_object_iter_key(_itr), i );
|
||||
json_t* data = json_array_get(val, i);
|
||||
_storage.Put( _currPath, json_string_value(data) );
|
||||
}
|
||||
}
|
||||
else if ( json_is_object( val ) == false)
|
||||
{
|
||||
/* store the pair if it just a value...*/
|
||||
ZBasicStringAlgo::BuildPrintf(_currPath,"%s.%s", _currPath.Data(), json_object_iter_key(_itr) );
|
||||
json_t* data= json_object_iter_value( _itr );
|
||||
_storage.Put( _currPath, json_string_value(data) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/*...or parse it if it isn't */
|
||||
_currPath = ZString( json_object_iter_key(_itr)) + ".";
|
||||
recurse_and_populate( _object, _itr, _storage, _currPath );
|
||||
}
|
||||
|
||||
_itr = json_object_iter_next( _object, _itr );
|
||||
}
|
||||
}
|
||||
|
||||
ZJSONReader::ZJSONReader(const ZString& _jsonData)
|
||||
: ErrorMessage(), JSONData(_jsonData), Registry(new (std::nothrow) ZKVTree())
|
||||
{
|
||||
json_t* rootNode;
|
||||
|
||||
if (Registry == NULL)
|
||||
{
|
||||
ErrorMessage = "ZJSONReader: unable to create registry!";
|
||||
return;
|
||||
}
|
||||
|
||||
/* have Jansson parse the string out and make an object */
|
||||
json_error_t error;
|
||||
rootNode = json_loads( _jsonData.Data(), 0, &error);
|
||||
if (rootNode == NULL)
|
||||
{
|
||||
ZBasicStringAlgo::BuildPrintf(ErrorMessage, "ZJSONReader: %s on line %d", error.text, error.line);
|
||||
return;
|
||||
}
|
||||
|
||||
/* now, we parse it out */
|
||||
void* itr = json_object_iter(rootNode);
|
||||
recurse_and_populate( rootNode, itr, *Registry, "");
|
||||
}
|
||||
|
||||
const ZString& ZJSONReader::GetErrorString()
|
||||
{
|
||||
return this->ErrorMessage;
|
||||
}
|
||||
|
||||
ZPtr<ZKVTree> ZJSONReader::GetKVTree()
|
||||
{
|
||||
return this->Registry;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <ZUtil/ZJSONWriter.hpp>
|
||||
|
||||
#include <ZSTL/ZString.hpp>
|
||||
#include <jansson.h>
|
||||
|
||||
ZJSONWriter::ZJSONWriter(ZPtr<ZKVTree> _registry)
|
||||
: ErrorMessage("No error."), Registry(_registry), NoError("No error.")
|
||||
{
|
||||
}
|
||||
|
||||
const ZString& ZJSONWriter::GetErrorString()
|
||||
{
|
||||
return this->ErrorMessage;
|
||||
}
|
||||
|
||||
bool ZJSONWriter::Write(ZString& _output)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,547 @@
|
||||
#include <ZUtil/ZKVTree.hpp>
|
||||
#include <ZUtil/ZLog.hpp>
|
||||
|
||||
#include <ZSTL/ZBasicStringAlgo.hpp>
|
||||
#include <ZSTL/ZArrayAlgo.hpp>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZKVTree::NodeCheckIn(Node* _node)
|
||||
{
|
||||
for (size_t i = 0; i < _node->Children.Size(); i++)
|
||||
NodeCheckIn(_node->Children[i]);
|
||||
|
||||
_node->Children.Clear();
|
||||
|
||||
NodeAllocator.Deallocate(_node);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::ZKVTree()
|
||||
: RootNode()
|
||||
{
|
||||
RootNode.ParentNode = NULL;
|
||||
RootNode.Index = 0;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::ZKVTree( const ZKVTree& _other )
|
||||
: RootNode()
|
||||
{
|
||||
RootNode.ParentNode = NULL;
|
||||
RootNode.Index = 0;
|
||||
|
||||
for (ZKVTree::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) {
|
||||
Put(itr, itr.GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::~ZKVTree()
|
||||
{
|
||||
for (size_t i = 0; i < RootNode.Children.Size(); i++)
|
||||
NodeCheckIn(RootNode.Children[i]);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree& ZKVTree::operator = ( const ZKVTree& _other )
|
||||
{
|
||||
Clear();
|
||||
|
||||
for (ZKVTree::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) {
|
||||
Put(itr.GetPath(), itr.GetValue());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
// This will convert to a full path, with subscripts everywhere and path separators. EXAMPLES:
|
||||
//
|
||||
// A.B[2].C.d -> A[0].B[2].C[0].d[0]
|
||||
// A.B[0][1] -> A[0].B[0].[1]
|
||||
//
|
||||
static bool ConvertPath(const ZString& _path, ZString& _out)
|
||||
{
|
||||
const ZString zeroSubscript("[0]");
|
||||
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
size_t k = 0;
|
||||
|
||||
//We are going to loop, looking for path separator and making sure we have subscripts and proper path separators
|
||||
while (i != ZSTL::InvalidPos) {
|
||||
// find the next path separator or the first occurrence of a nested array access
|
||||
j = ZStringAlgo::FindFirst(_path, ZKVTREE_PATH_SEPARATOR, i, _path.Length());
|
||||
k = ZStringAlgo::FindSub(_path, i, _path.Length(), "][", 0, 2);
|
||||
|
||||
// if a nested array access occurs
|
||||
if (k < j) {
|
||||
// append the first part of it, a path separators, and then process from there
|
||||
ZStringAlgo::Append(_out, _path, i, k + 1);
|
||||
|
||||
_out.PushBack(ZKVTREE_PATH_SEPARATOR);
|
||||
|
||||
i = k + 1;
|
||||
} else if (i == j) {
|
||||
// this means we are dealing with a node without a name (potentially first node)
|
||||
if (_out.Empty() || _out.Back() != ']')
|
||||
ZStringAlgo::Append(_out, zeroSubscript);
|
||||
|
||||
_out.PushBack(ZKVTREE_PATH_SEPARATOR);
|
||||
|
||||
i = j + 1;
|
||||
} else if (j != ZSTL::InvalidPos) {
|
||||
// found a substring between two path separators
|
||||
ZStringAlgo::Append(_out, _path, i, j);
|
||||
|
||||
if (_out.Back() != ']')
|
||||
ZStringAlgo::Append(_out, zeroSubscript);
|
||||
|
||||
_out.PushBack(ZKVTREE_PATH_SEPARATOR);
|
||||
|
||||
i = j + 1;
|
||||
} else {
|
||||
// we have reached the end
|
||||
ZStringAlgo::Append(_out, _path, i, _path.Length());
|
||||
|
||||
if (_out.Empty() || _out.Back() != ']')
|
||||
ZStringAlgo::Append(_out, zeroSubscript);
|
||||
|
||||
i = ZSTL::InvalidPos;
|
||||
}
|
||||
}
|
||||
|
||||
// this method may be expanded later for path verification via regex or some such
|
||||
return true;
|
||||
}
|
||||
|
||||
//This will insert a child node at the given index and increment the indices on the other child values
|
||||
static void InsertNode( ZKVTree::Node* _parent, ZKVTree::Node* _child, size_t _index )
|
||||
{
|
||||
_parent->Children.Insert(_index, _child);
|
||||
|
||||
for (size_t i = _index + 1; i < _parent->Children.Size(); i++)
|
||||
_parent->Children.Data()[i]->Index++;
|
||||
}
|
||||
|
||||
//This will erase a child node at the given index and decrement the indices on the other child values
|
||||
static ZKVTree::Node* EraseChildNode( ZKVTree::Node* _parent, size_t _index )
|
||||
{
|
||||
for (size_t i = _index + 1; i < _parent->Children.Size(); i++)
|
||||
_parent->Children.Data()[i]->Index--;
|
||||
|
||||
return _parent->Children.Erase(_index);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
// gets the value from a completed path (returned from ConvertFullPath)
|
||||
ZKVTree::Node* ZKVTree::GetFromPath(const ZString& _path) const
|
||||
{
|
||||
size_t i, j, k;
|
||||
size_t subscript;
|
||||
|
||||
const Node* node = &RootNode;
|
||||
|
||||
// path[i...j] is our path window (current value we are looking for)
|
||||
// path[subscript].nextpath
|
||||
// ^ ^ ^
|
||||
// i j k
|
||||
// or
|
||||
// path.nextpath
|
||||
// ^ ^
|
||||
// i j,k
|
||||
i = 0;
|
||||
j = 0;
|
||||
k = 0;
|
||||
|
||||
//While we still have a node to look in
|
||||
while (node != NULL)
|
||||
{
|
||||
//See if we have reached the end
|
||||
if (i >= _path.Length())
|
||||
break;
|
||||
|
||||
subscript = 0;
|
||||
|
||||
j = ZStringAlgo::FindFirst(_path, ZKVTREE_PATH_SEPARATOR, i, _path.Length());
|
||||
|
||||
//If we can't find a path separator, go to the end
|
||||
if (j == ZSTL::InvalidPos)
|
||||
j = _path.Length();
|
||||
|
||||
//See if we have found the node
|
||||
if (i >= j)
|
||||
break;
|
||||
|
||||
k = j;
|
||||
|
||||
//Determine if it has a subscript
|
||||
if (_path[j - 1] == ']')
|
||||
{
|
||||
j = ZStringAlgo::FindLast(_path, '[', i, j);
|
||||
|
||||
//Make sure this is bounded correct
|
||||
if (j == ZSTL::InvalidPos || j < i)
|
||||
{
|
||||
node = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
subscript = (size_t)ZStringAlgo::NumericInt(_path, j + 1, k - 1);
|
||||
}
|
||||
|
||||
node = node->GetChildByName(_path, i, j, subscript);
|
||||
|
||||
//Move up our path 'window'
|
||||
i = k + 1;
|
||||
}
|
||||
|
||||
return const_cast<ZKVTree::Node*>(node);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::Node* ZKVTree::CreatePath(const ZString& _path)
|
||||
{
|
||||
size_t i, j, k;
|
||||
size_t subscript;
|
||||
|
||||
Node* node = &RootNode;
|
||||
|
||||
// path[i...j] is our path window (current value we are looking for)
|
||||
// path[subscript].nextpath
|
||||
// ^ ^ ^
|
||||
// i j k
|
||||
// or
|
||||
// path.nextpath
|
||||
// ^ ^
|
||||
// i j,k
|
||||
i = 0;
|
||||
j = 0;
|
||||
k = 0;
|
||||
|
||||
// while we still have a node to look in
|
||||
while (node != NULL) {
|
||||
// see if we have reached the end
|
||||
if (i >= _path.Length()) {
|
||||
break;
|
||||
}
|
||||
|
||||
subscript = 0;
|
||||
|
||||
j = ZStringAlgo::FindFirst(_path, ZKVTREE_PATH_SEPARATOR, i, _path.Length());
|
||||
|
||||
//If we can't find a path separator, go to the end
|
||||
if (j == ZSTL::InvalidPos) {
|
||||
j = _path.Length();
|
||||
}
|
||||
|
||||
//See if we are done creating
|
||||
if (i == j) {
|
||||
break;
|
||||
}
|
||||
|
||||
k = j;
|
||||
|
||||
// determine if it has a subscript
|
||||
if (_path[j - 1] == ']') {
|
||||
j = ZStringAlgo::FindLast(_path, '[', i, j);
|
||||
|
||||
// make sure this is bounded correct (if not, bail out)
|
||||
if (j == ZSTL::InvalidPos || j < i) {
|
||||
node = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
subscript = (size_t)ZStringAlgo::NumericInt(_path, j + 1, k - 1);
|
||||
}
|
||||
|
||||
Node* childNode = node->GetChildByName(_path, i, j, subscript);
|
||||
|
||||
// create this node if it doesn't exist
|
||||
if (childNode == NULL) {
|
||||
// get the child count by name at the parent node
|
||||
size_t count = node->GetChildCountByName(_path, i, j);
|
||||
|
||||
// see if the subscript at the end is the 'next' value (if not, bail out)
|
||||
if (count != subscript) {
|
||||
node = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
// get a new node, set the parent node, name, index (leave out the value)
|
||||
childNode = NodeAllocator.Allocate();
|
||||
|
||||
childNode->ParentNode = node;
|
||||
childNode->Name.Resize(j - i);
|
||||
ZStringAlgo::Copy(childNode->Name, 0, childNode->Name.Length(), _path, i, j);
|
||||
|
||||
if (count > 0) {
|
||||
childNode->Index = node->GetLastIndexByName(_path, i, j) + 1;
|
||||
|
||||
// increment the index on the rest of the nodes
|
||||
for (size_t i = childNode->Index; i < node->Children.Size(); i++)
|
||||
node->Children[i]->Index++;
|
||||
|
||||
node->Children.Insert(childNode->Index, childNode);
|
||||
} else {
|
||||
childNode->Index = node->Children.Size();
|
||||
node->Children.PushBack(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
// set our new node
|
||||
node = childNode;
|
||||
|
||||
// move up our 'path window'
|
||||
i = k + 1;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::Iterator ZKVTree::Add( const ZString& _name, const ZString& _value )
|
||||
{
|
||||
return Add(End(), _name, _value);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::Iterator ZKVTree::Add( const ZString& _parent, const ZString& _name, const ZString& _value )
|
||||
{
|
||||
ZString path;
|
||||
|
||||
if (!ConvertPath(_parent, path))
|
||||
return End();
|
||||
|
||||
Node* node = CreatePath(path);
|
||||
|
||||
return Add(Iterator(node, this), _name, _value);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::Iterator ZKVTree::Add( const Iterator& _itr, const ZString& _name, const ZString& _value )
|
||||
{
|
||||
ZKVTree::Node* parentNode = NULL;
|
||||
ZKVTree::Node* childNode = NULL;
|
||||
|
||||
if (_itr.CurrentNode == NULL) {
|
||||
return End();
|
||||
}
|
||||
|
||||
if (_itr.KVTree == this) {
|
||||
parentNode = _itr.CurrentNode;
|
||||
|
||||
// allocate a child node and set values
|
||||
childNode = NodeAllocator.Allocate();
|
||||
childNode->ParentNode = parentNode;
|
||||
childNode->Name = _name;
|
||||
childNode->Value = _value;
|
||||
|
||||
// determine if any other children of the same name exist (grouped on insert)
|
||||
size_t count = parentNode->GetChildCountByName(_name, 0, _name.Length());
|
||||
|
||||
if (count > 0) {
|
||||
childNode->Index = parentNode->GetLastIndexByName(_name, 0, _name.Length()) + 1;
|
||||
} else {
|
||||
childNode->Index = parentNode->Children.Size();
|
||||
}
|
||||
|
||||
InsertNode(parentNode, childNode, childNode->Index);
|
||||
|
||||
return Iterator(childNode, this);
|
||||
} else {
|
||||
// if this is from another tree, just add at the path
|
||||
return Add(_itr.GetPath(), _name, _value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZKVTree::Clear()
|
||||
{
|
||||
for (size_t i = 0; i < RootNode.Children.Size(); i++) {
|
||||
NodeCheckIn(RootNode.Children.Data()[i]);
|
||||
}
|
||||
|
||||
RootNode.Children.Clear();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZKVTree::Erase( const ZString& _path )
|
||||
{
|
||||
Erase(Find(_path));
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZKVTree::Erase( const Iterator& _itr )
|
||||
{
|
||||
ZASSERT_RUNTIME(_itr.CurrentNode != NULL, "ZKVTree: Unable to erase value from provided iterator!");
|
||||
ZASSERT_RUNTIME(_itr.CurrentNode != &RootNode, "ZKVTree: Unable to erase root node!");
|
||||
|
||||
if (_itr.KVTree == this) {
|
||||
NodeCheckIn(EraseChildNode(_itr.CurrentNode->ParentNode, _itr.CurrentNode->Index));
|
||||
} else {
|
||||
Erase(_itr.GetPath());
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::Iterator ZKVTree::Find( const ZString& _path ) const
|
||||
{
|
||||
ZString path;
|
||||
|
||||
if (!ConvertPath(_path, path)) {
|
||||
return End();
|
||||
}
|
||||
|
||||
Node* node = GetFromPath(path);
|
||||
|
||||
if (node == NULL) {
|
||||
return End();
|
||||
}
|
||||
|
||||
return ZKVTree::Iterator(node, const_cast<ZKVTree*>(this));
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::Iterator ZKVTree::Find( const Iterator& _itr, const ZString& _path ) const
|
||||
{
|
||||
ZString path;
|
||||
|
||||
if (!ConvertPath(_path, path)) {
|
||||
return End();
|
||||
}
|
||||
|
||||
Node* node = GetFromPath(_itr.GetPath() + ZKVTREE_PATH_SEPARATOR + path);
|
||||
|
||||
if (node == NULL) {
|
||||
return End();
|
||||
}
|
||||
|
||||
return ZKVTree::Iterator(node, const_cast<ZKVTree*>(this));
|
||||
|
||||
}
|
||||
/*************************************************************************/
|
||||
|
||||
const ZString& ZKVTree::Get( const ZString& _path ) const
|
||||
{
|
||||
ZKVTree::Iterator itr = Find(_path);
|
||||
|
||||
ZASSERT_RUNTIME(itr != End(), "ZKVTree: No value mapped to path!");
|
||||
|
||||
return itr.GetValue();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
const ZString& ZKVTree::Get( const Iterator& _itr, const ZString& _path )
|
||||
{
|
||||
ZKVTree::Iterator itr = Find(_itr, _path);
|
||||
|
||||
ZASSERT_RUNTIME(itr != End(), "ZKVTree: No value mapped to path!");
|
||||
|
||||
return itr.GetValue();
|
||||
}
|
||||
/*************************************************************************/
|
||||
|
||||
void ZKVTree::Merge( const ZKVTree& _other, bool _overwrite )
|
||||
{
|
||||
for (ZKVTree::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) {
|
||||
if (_overwrite) {
|
||||
Put(itr.GetPath(), itr.GetValue());
|
||||
} else {
|
||||
ZKVTree::Iterator found = Find(itr.GetPath());
|
||||
if (found == End()) {
|
||||
Put(itr.GetPath(), itr.GetValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::Iterator ZKVTree::Put( const ZString& _path, const ZString& _value )
|
||||
{
|
||||
ZString path;
|
||||
|
||||
if (!ConvertPath(_path, path))
|
||||
return End();
|
||||
|
||||
// create the node at the path given (will return the existing node if there)
|
||||
Node* node = CreatePath(path);
|
||||
|
||||
// if we were able to successfully create the node, set its value
|
||||
if (node != NULL) {
|
||||
node->Value = _value;
|
||||
return Iterator(node, this);
|
||||
} else return End();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::Iterator ZKVTree::Put(const Iterator& _itr, const ZString& _value)
|
||||
{
|
||||
// ensure this iterator belongs to us
|
||||
if (_itr.KVTree == this) {
|
||||
// it does, just set the value
|
||||
_itr.CurrentNode->Value = _value;
|
||||
return _itr;
|
||||
} else {
|
||||
// it does not, just create a new value using the path variant
|
||||
return Put(_itr.GetPath(), _value);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZKVTree::Iterator ZKVTree::Begin() const
|
||||
{
|
||||
if (RootNode.Children.Empty()) {
|
||||
return End();
|
||||
} else return ZKVTree::Iterator(const_cast<Node*>(RootNode.Children.Front()), const_cast<ZKVTree*>(this));
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
const ZKVTree::Iterator ZKVTree::End() const
|
||||
{
|
||||
return ZKVTree::Iterator(const_cast<Node*>(&RootNode), const_cast<ZKVTree*>(this));
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static bool isInvalidKeyNameChar(const char _char)
|
||||
{
|
||||
return ( isspace(_char) != 0) ||
|
||||
( iscntrl(_char) != 0) ||
|
||||
( _char == ZKVTREE_PATH_SEPARATOR ) ||
|
||||
( _char == '[' ) ||
|
||||
( _char == ']' );
|
||||
}
|
||||
|
||||
bool ZKVTree::IsValidKeyName( const ZString& _name ) const
|
||||
{
|
||||
for (size_t i = 0; i < _name.Length(); i++) {
|
||||
if (isInvalidKeyNameChar( _name.Data()[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
+306
@@ -0,0 +1,306 @@
|
||||
#include <ZUtil/ZLog.hpp>
|
||||
#include <ZUtil/ZAlloc.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdarg.h>
|
||||
#include <algorithm>
|
||||
|
||||
////////////////////////////////////
|
||||
/* Static Variable Initialization */
|
||||
////////////////////////////////////
|
||||
|
||||
ZMutex ZLog::LogLock;
|
||||
|
||||
bool ZLog::bIsInitialized = false;
|
||||
|
||||
ZArray< ZPair<std::ofstream*, bool> > ZLog::LogFiles;
|
||||
|
||||
ZArray< ZPtr<ZLogDelegate> > ZLog::Delegates;
|
||||
|
||||
ZString ZLog::LogFileRoot;
|
||||
|
||||
uint64_t* ZLog::UserTick = NULL;
|
||||
uint64_t* ZLog::UserUpdate = NULL;
|
||||
|
||||
uint64_t ZLog::TickEstimate = 0;
|
||||
uint64_t ZLog::UpdateFrameEstimate = 0;
|
||||
|
||||
///////////////////////////
|
||||
/* Local Helper Function */
|
||||
///////////////////////////
|
||||
|
||||
void writeHeader(std::ofstream& logfile, const char* filename)
|
||||
{
|
||||
|
||||
logfile << filename << " : ZUtil version " << ZUTIL_VERSION_STRING << " default log file\n\n";
|
||||
|
||||
#if ZLOG_LEVEL >= ZLOG_LEVEL_INFO
|
||||
logfile << "+------------+------------+\n";
|
||||
logfile << "| Time (sec) | Update No. |\n";
|
||||
logfile << "+------------+------------+\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
void writeFooter(std::ofstream& logfile)
|
||||
{
|
||||
#if ZLOG_LEVEL >= ZLOG_LEVEL_INFO
|
||||
logfile << "+------------+------------+\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
int logAssertHandler(const char* _msg, void *_arg)
|
||||
{
|
||||
URFP(_arg);
|
||||
|
||||
//Log it!
|
||||
SystemLogError("Assertion Failed: \n");
|
||||
SystemLogError(_msg);
|
||||
|
||||
//Let the error propagate
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
/* Static Function Declaration */
|
||||
/////////////////////////////////
|
||||
|
||||
void ZLog::Init(const ZString& _logFileRoot, const ZString& _defaultLogFile, uint64_t* _ticks /*= NULL*/, uint64_t* _update /*= NULL*/)
|
||||
{
|
||||
std::ofstream *logfile;
|
||||
|
||||
//Save our root path
|
||||
ZLog::LogFileRoot = _logFileRoot;
|
||||
|
||||
//Create a default log file
|
||||
ZString logFilePath = ZLog::LogFileRoot + _defaultLogFile;
|
||||
|
||||
logfile = znew_notrack std::ofstream();
|
||||
logfile->open(logFilePath.Data(), std::ios::out);
|
||||
|
||||
while (logfile->fail()) {
|
||||
logFilePath += "_";
|
||||
logfile->open(logFilePath.Data(), std::ios::out);
|
||||
}
|
||||
|
||||
//Write the header
|
||||
writeHeader(*logfile, _defaultLogFile.Data());
|
||||
|
||||
//Add the default log file to the set
|
||||
ZLog::LogFiles.Reserve(16);
|
||||
ZLog::LogFiles.Clear();
|
||||
ZLog::LogFiles.PushBack(ZPair<std::ofstream*, bool>(logfile, true));
|
||||
|
||||
//Set our SST_Assert handlers
|
||||
SST_OS_SetDebugAssertHandler(logAssertHandler, NULL);
|
||||
SST_OS_SetRuntimeAssertHandler(logAssertHandler, NULL);
|
||||
|
||||
ZLog::UserTick = _ticks;
|
||||
ZLog::UserUpdate = _update;
|
||||
|
||||
//We're ready to rock and roll
|
||||
ZLog::bIsInitialized = true;
|
||||
}
|
||||
|
||||
void ZLog::Shutdown()
|
||||
{
|
||||
ZArray< ZPair<std::ofstream*, bool> >::Iterator itr;
|
||||
|
||||
//Iterate and close out
|
||||
for (itr = ZLog::LogFiles.Begin(); itr != ZLog::LogFiles.End(); itr++)
|
||||
{
|
||||
writeFooter(*((*itr).First));
|
||||
|
||||
(*itr).First->close();
|
||||
(*itr).Second = false;
|
||||
|
||||
zdelete (*itr).First;
|
||||
}
|
||||
|
||||
//Flush standard outputs
|
||||
std::cout.flush();
|
||||
std::cerr.flush();
|
||||
|
||||
//Clear our set of log files
|
||||
ZLog::LogFiles.Clear();
|
||||
}
|
||||
|
||||
void ZLog::AddLoggingDelegate(ZPtr<ZLogDelegate> _delegate)
|
||||
{
|
||||
ZLog::LogLock.Acquire();
|
||||
|
||||
ZLog::Delegates.PushBack(_delegate);
|
||||
|
||||
ZLog::LogLock.Release();
|
||||
}
|
||||
|
||||
ZLogFile ZLog::CreateLogFile(const ZString& _fileName)
|
||||
{
|
||||
ZLogFile handle;
|
||||
std::ofstream *file;
|
||||
|
||||
//See if we can early out
|
||||
if (!ZLog::bIsInitialized)
|
||||
{
|
||||
std::cerr << "Attempted to create log file (Before call to Init) : " << _fileName.Data() << std::endl;
|
||||
return (ZLogFile)0;
|
||||
}
|
||||
|
||||
ZString logFilePath = ZLog::LogFileRoot + _fileName;
|
||||
|
||||
//Synchronized Section
|
||||
{
|
||||
//Scoped lock
|
||||
ZLock scopedLock(ZLog::LogLock);
|
||||
|
||||
file = znew_notrack std::ofstream();
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to create log file %s!\n", _fileName.Data());
|
||||
return (ZLogFile)0;
|
||||
}
|
||||
|
||||
file->open(logFilePath.Data(), std::ios::out);
|
||||
|
||||
if (!file->is_open())
|
||||
{
|
||||
//Nope nope nope
|
||||
fprintf(stderr, "Failed to open log file %s!\n", _fileName.Data());
|
||||
zdelete file;
|
||||
return (ZLogFile)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Write the header
|
||||
writeHeader(*file, _fileName.Data());
|
||||
|
||||
//This will give us the index where it will be going
|
||||
handle = ZLog::LogFiles.Size();
|
||||
|
||||
//Add to the set of streams already activated
|
||||
ZLog::LogFiles.PushBack(ZPair<std::ofstream*, bool>(file, true));
|
||||
}
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void ZLog::Resume( ZLogFile _logFile )
|
||||
{
|
||||
//Scoped Lock
|
||||
ZLock scopedLock(ZLog::LogLock);
|
||||
|
||||
ZASSERT_RUNTIME((size_t)_logFile < LogFiles.Size(), "Cannot resume logging to file: file does not exist!");
|
||||
|
||||
ZLog::LogFiles[_logFile].Second = true;
|
||||
}
|
||||
|
||||
void ZLog::Suspend( ZLogFile _logFile )
|
||||
{
|
||||
//Scoped Lock
|
||||
ZLock scopedLock(ZLog::LogLock);
|
||||
|
||||
ZASSERT_RUNTIME((size_t)_logFile < LogFiles.Size(), "Cannot resume logging to file: file does not exist!");
|
||||
|
||||
ZLog::LogFiles[_logFile].Second = false;
|
||||
}
|
||||
|
||||
void ZLog::Printf(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char *_function, const char *_str, ...)
|
||||
{
|
||||
URFP(_function);
|
||||
|
||||
va_list args;
|
||||
|
||||
//Check for easy out
|
||||
if (!ZLog::bIsInitialized)
|
||||
return;
|
||||
|
||||
//Make sure we're null terminated
|
||||
char string[32768];
|
||||
MemSetChar(string, 0, 32768);
|
||||
|
||||
va_start(args, _str);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
vsnprintf_s(string, sizeof(string)-1, sizeof(string)-1, _str, args);
|
||||
#else
|
||||
vsnprintf(string, sizeof(string)-1, _str, args);
|
||||
#endif
|
||||
|
||||
//Write using our existing write function
|
||||
ZLog::WriteLine(_type, _file, _ticks, _updateFrame, string);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void ZLog::WriteLine(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char *_str)
|
||||
{
|
||||
#if ZLOG_LEVEL >= ZLOG_LEVEL_INFO
|
||||
char time[32];
|
||||
char update[32];
|
||||
#endif
|
||||
|
||||
//See if we can early out (should warn)
|
||||
if (!ZLog::bIsInitialized)
|
||||
{
|
||||
std::cerr << "Logging Output (Before call to Init): " << _str << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//Synchronized Section
|
||||
{
|
||||
//Scoped Lock
|
||||
ZLock scopedLock(ZLog::LogLock);
|
||||
|
||||
ZASSERT_RUNTIME((size_t)_file < LogFiles.Size(), "Cannot log to file: file not created!");
|
||||
|
||||
//Get the file and find out if activated
|
||||
std::ofstream *logfile = ZLog::LogFiles[_file].First;
|
||||
bool enabled = ZLog::LogFiles[_file].Second;
|
||||
|
||||
//If we are not currently enabled, we are no longer needed
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
//Get our best guesses
|
||||
if (ZLog::UserTick != NULL) {
|
||||
ZLog::TickEstimate = *ZLog::UserTick;
|
||||
} else if (_ticks > ZLog::TickEstimate) {
|
||||
ZLog::TickEstimate = _ticks;
|
||||
}
|
||||
|
||||
if (ZLog::UserUpdate != NULL) {
|
||||
ZLog::UpdateFrameEstimate = *ZLog::UserUpdate;
|
||||
} else if (_updateFrame > ZLog::UpdateFrameEstimate) {
|
||||
ZLog::UpdateFrameEstimate = _updateFrame;
|
||||
}
|
||||
|
||||
ZASSERT_UTIL(logfile != NULL, "ZLog Error: logfile is NULL!");
|
||||
|
||||
#if ZLOG_LEVEL >= ZLOG_LEVEL_INFO
|
||||
|
||||
//If we are at detailed (or higher) log level, then log the extra details, then the string
|
||||
if (_ticks == 0 && _updateFrame == 0 && ZLog::UserTick == NULL && ZLog::UserUpdate == NULL) {
|
||||
sprintf(time, "?%11.3f", ((float)ZLog::TickEstimate) / 1000.0f);
|
||||
sprintf(update, "?%11lu", ZLog::UpdateFrameEstimate);
|
||||
} else {
|
||||
sprintf(time, "%12.3f", ((float)ZLog::TickEstimate) / 1000.0f);
|
||||
sprintf(update, "%12lu", ZLog::UpdateFrameEstimate);
|
||||
}
|
||||
|
||||
std::cout << _str << std::endl;
|
||||
*logfile << "|" << time << "|" << update << "| " << /*ZConcurrency::GetThreadName() << ": " << */_str << std::endl;
|
||||
|
||||
#else
|
||||
|
||||
std::cout << _str << std::endl;
|
||||
*logfile << _str << std::endl;
|
||||
|
||||
#endif //ZLOG_LEVEL >= ZLOG_LEVEL_DETAILED
|
||||
|
||||
//Let the delegates know what happened
|
||||
for (ZArray< ZPtr<ZLogDelegate> >::Iterator i = ZLog::Delegates.Begin(); i != ZLog::Delegates.End(); i++)
|
||||
(*i)->Execute(_type, _file, _str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <ZUtil/ZMutex.hpp>
|
||||
#include <ZUtil/ZAssert.hpp>
|
||||
|
||||
//////////////////////////
|
||||
/* ZLock Implementation */
|
||||
//////////////////////////
|
||||
|
||||
ZMutex::ZMutex()
|
||||
: Mutex(SST_Concurrency_CreateMutex())
|
||||
{
|
||||
ZASSERT_RUNTIME(Mutex != NULL, "ZMutex failed to allocate mutex from libsst-concurrency!");
|
||||
}
|
||||
|
||||
ZMutex::~ZMutex()
|
||||
{
|
||||
SST_Concurrency_DestroyMutex(Mutex);
|
||||
}
|
||||
|
||||
void ZMutex::Acquire()
|
||||
{
|
||||
SST_Concurrency_LockMutex(Mutex);
|
||||
}
|
||||
|
||||
void ZMutex::Release()
|
||||
{
|
||||
SST_Concurrency_UnlockMutex(Mutex);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
/* ZScopedLock Implementation */
|
||||
////////////////////////////////
|
||||
|
||||
ZLock::ZLock( ZMutex& _mutex )
|
||||
: Mutex(_mutex)
|
||||
{
|
||||
Mutex.Acquire();
|
||||
}
|
||||
|
||||
ZLock::~ZLock()
|
||||
{
|
||||
Mutex.Release();
|
||||
}
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
#include <ZUtil/ZName.hpp>
|
||||
#include <ZUtil/ZAssert.hpp>
|
||||
#include <ZUtil/ZAlloc.hpp>
|
||||
|
||||
#include <SST/SST_Hash.h>
|
||||
|
||||
ZName::ZName()
|
||||
: Length(0), Hash(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName::ZName( const char *_string )
|
||||
: Length(0), Hash(0)
|
||||
{
|
||||
Length = _string != NULL ? strlen(_string) : 0;
|
||||
|
||||
if (Length > ZNAME_MAX_LENGTH)
|
||||
{
|
||||
ZASSERT_RUNTIME_FAIL("ZName: Constructed from string with > ZNAME_MAX_LEN characters!");
|
||||
Length = ZNAME_MAX_LENGTH;
|
||||
}
|
||||
|
||||
MemCopyChar(String, _string, Length);
|
||||
MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1);
|
||||
|
||||
Hash = SST_Crypto_HashJCR2(String, Length);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName::ZName( const ZString& _string )
|
||||
{
|
||||
Length = _string.Length();
|
||||
|
||||
if (Length > ZNAME_MAX_LENGTH)
|
||||
{
|
||||
ZASSERT_RUNTIME_FAIL("ZName: Constructed from string with > ZNAME_MAX_LEN characters!");
|
||||
Length = ZNAME_MAX_LENGTH;
|
||||
}
|
||||
|
||||
MemCopyChar(String, _string.Data(), Length);
|
||||
MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1);
|
||||
|
||||
Hash = SST_Crypto_HashJCR2(String, Length);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName::ZName( const ZName& _other )
|
||||
: Length(0), Hash(0)
|
||||
{
|
||||
MemCopyChar(String, _other.String, ZNAME_MAX_LENGTH);
|
||||
|
||||
Length = _other.Length;
|
||||
Hash = _other.Hash;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName::ZName( uint64_t _hash )
|
||||
: Length(0), Hash(_hash)
|
||||
{
|
||||
const char* precompStr = "<precomputed>";
|
||||
|
||||
MemCopyChar(String, precompStr, sizeof(precompStr));
|
||||
|
||||
Length = sizeof(precompStr) - 1;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName::~ZName()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName& ZName::operator = ( const ZName& _other )
|
||||
{
|
||||
MemCopyChar(String, _other.String, ZNAME_MAX_LENGTH);
|
||||
|
||||
Length = _other.Length;
|
||||
Hash = _other.Hash;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName& ZName::operator = ( const ZString& _string )
|
||||
{
|
||||
Length = _string.Length();
|
||||
|
||||
if (Length > ZNAME_MAX_LENGTH)
|
||||
{
|
||||
ZASSERT_RUNTIME_FAIL("ZName: Assigned from string with > ZNAME_MAX_LEN characters!");
|
||||
Length = ZNAME_MAX_LENGTH;
|
||||
}
|
||||
|
||||
MemCopyChar(String, _string.Data(), Length);
|
||||
MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1);
|
||||
|
||||
Hash = SST_Crypto_HashJCR2(String, Length);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName& ZName::operator = (const char* _string )
|
||||
{
|
||||
Length = _string != NULL ? strlen(_string) : 0;
|
||||
|
||||
if (Length > ZNAME_MAX_LENGTH)
|
||||
{
|
||||
ZASSERT_RUNTIME_FAIL("ZName: Assigned from string with > ZNAME_MAX_LEN characters!");
|
||||
Length = ZNAME_MAX_LENGTH;
|
||||
}
|
||||
|
||||
MemCopyChar(String, _string, Length);
|
||||
MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1);
|
||||
|
||||
Hash = SST_Crypto_HashJCR2(String, Length);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZName::operator == ( const ZName& _other ) const
|
||||
{
|
||||
#if ZSTL_CHECK_NAME
|
||||
|
||||
bool ret = (Hash == _other.Hash);
|
||||
|
||||
if (ret == true)
|
||||
{
|
||||
int strcmpRet = strcmp(String, _other.String);
|
||||
|
||||
ZASSERT_RUNTIME(strcmpRet == 0, "ZName: Hash reported same, but failed strcmp!\n");
|
||||
|
||||
return (strcmpRet == 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
#else
|
||||
|
||||
return Hash == _other.Hash;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZName::operator == ( const ZHashValue hash ) const
|
||||
{
|
||||
return Hash == hash;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZName::operator==( const ZString& _other ) const
|
||||
{
|
||||
return Hash == ZName(_other);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZName::operator != ( const ZName& _other ) const
|
||||
{
|
||||
return !((*this) == _other);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName::operator ZHashValue() const
|
||||
{
|
||||
return (ZHashValue)Hash;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZName::operator ZString() const
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZString ZName::ToString() const
|
||||
{
|
||||
return ZString(String);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
const char* ZName::Data() const
|
||||
{
|
||||
return String;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
@@ -0,0 +1,213 @@
|
||||
#include <ZUtil/ZRandomGenerator.hpp>
|
||||
|
||||
#include <ZUtil/ZAssert.hpp>
|
||||
|
||||
#include <math.h> /* sine and other functions */
|
||||
#include <time.h> /* time function */
|
||||
|
||||
//Helper Function that returns a float distributed normally between a float min and max using random numbers r1, r2
|
||||
float getGaussianHelper(float _min, float _max, float _r1, float _r2)
|
||||
{
|
||||
float deltamid, delta;
|
||||
|
||||
deltamid = (float)(((_max - _min) / 2) * sin(_r1 * 3.14159f)); /* absolute delta from middle value */
|
||||
delta = _max - _min - (2 * deltamid); /* calculate the actual delta */
|
||||
|
||||
return (_min + deltamid + (_r2 * delta));
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZRandomGenerator::ZRandomGenerator()
|
||||
: Type(SST_PRNG_SMALLPRNG), Seed((uint32_t)time(0)), Sequence(0), RNG(NULL)
|
||||
{
|
||||
RNG = SST_Random_CreatePRNGFromSeed(Type, Seed);
|
||||
|
||||
ZASSERT_RUNTIME(RNG != NULL, "ZRandomGenerator: Failure to initialize SST_PRNG instance!");
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZRandomGenerator::ZRandomGenerator(SST_PRNG_TYPE _type, uint32_t _seed, uint64_t _sequence )
|
||||
: Type(_type), Seed(_seed), Sequence(_sequence), RNG(SST_Random_CreatePRNGFromSeed(_type, _seed))
|
||||
{
|
||||
ZASSERT_RUNTIME(RNG != NULL, "ZRandomGenerator: Failure to initialize SST_PRNG instance!");
|
||||
|
||||
//Generate and discard a number of times equal to Sequence
|
||||
for (uint64_t i = 0; i < Sequence; i++)
|
||||
SST_Random_GetPRNGInt(RNG, 0, 1);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZRandomGenerator::~ZRandomGenerator()
|
||||
{
|
||||
if (RNG != NULL)
|
||||
SST_Random_DestroyPRNG(RNG);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
float ZRandomGenerator::GetFloat()
|
||||
{
|
||||
++Sequence;
|
||||
|
||||
return SST_Random_GetPRNGFloat(RNG, 0, 1);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZRandomGenerator::GetFloatArray( float *_array, size_t _count )
|
||||
{
|
||||
Sequence += _count;
|
||||
|
||||
return SST_Random_GetPRNGFloatArray(RNG, _array, _count, 0, 1);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
float ZRandomGenerator::GetFloatInRange( float _min, float _max )
|
||||
{
|
||||
++Sequence;
|
||||
|
||||
return SST_Random_GetPRNGFloat(RNG, _min, _max);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZRandomGenerator::GetFloatArrayInRange( float *_array, size_t _count, float _min, float _max )
|
||||
{
|
||||
Sequence += _count;
|
||||
|
||||
return SST_Random_GetPRNGFloatArray(RNG, _array, _count, _min, _max);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
float ZRandomGenerator::GetGaussianFloat( float _min, float _max )
|
||||
{
|
||||
float r1, r2;
|
||||
|
||||
r1 = GetFloat();
|
||||
r2 = GetFloat();
|
||||
|
||||
return getGaussianHelper(_min, _max, r1, r2);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZRandomGenerator::GetGaussianFloatArray( float *_array, size_t _count, float _min, float _max )
|
||||
{
|
||||
size_t i;
|
||||
float r1, r2;
|
||||
|
||||
for (i = 0; i < _count; ++i)
|
||||
{
|
||||
r1 = GetFloat();
|
||||
r2 = GetFloat();
|
||||
|
||||
_array[i] = getGaussianHelper(_min, _max, r1, r2);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
int ZRandomGenerator::GetGaussianInt( int _min, int _max )
|
||||
{
|
||||
return (int)GetGaussianFloat((float)_min + 0.5f, (float)_max + 0.5f);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZRandomGenerator::GetGaussianIntArray( int *_array, size_t _count, int _min, int _max )
|
||||
{
|
||||
size_t i;
|
||||
float r1, r2;
|
||||
|
||||
for (i = 0; i < _count; ++i)
|
||||
{
|
||||
r1 = GetFloat();
|
||||
r2 = GetFloat();
|
||||
|
||||
_array[i] = (int)getGaussianHelper((float)_min + 0.5f, (float)_max + 0.5f, r1, r2);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
int ZRandomGenerator::GetInt()
|
||||
{
|
||||
++Sequence;
|
||||
|
||||
return SST_Random_GetPRNGInt(RNG, STDINT_MIN, STDINT_MAX);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZRandomGenerator::GetIntArray( int *_array, size_t _count )
|
||||
{
|
||||
Sequence += _count;
|
||||
|
||||
return SST_Random_GetPRNGIntArray(RNG, _array, _count, STDINT_MIN, STDINT_MAX);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
int ZRandomGenerator::GetIntInRange( int _min, int _max )
|
||||
{
|
||||
++Sequence;
|
||||
|
||||
return SST_Random_GetPRNGInt(RNG, _min, _max);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZRandomGenerator::GetIntArrayInRange( int *_array, size_t _count, int _min, int _max )
|
||||
{
|
||||
Sequence += _count;
|
||||
|
||||
return SST_Random_GetPRNGIntArray(RNG, _array, _count, _min, _max);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint32_t ZRandomGenerator::GetSeed()
|
||||
{
|
||||
return Seed;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint64_t ZRandomGenerator::GetSequence()
|
||||
{
|
||||
return Sequence;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZRandomGenerator::SetSequence( uint64_t _seq )
|
||||
{
|
||||
//If less than, new instance
|
||||
if (_seq < Sequence)
|
||||
SetSeed(Seed);
|
||||
|
||||
while (Sequence < _seq)
|
||||
{
|
||||
SST_Random_GetPRNGInt(RNG, 0, 1);
|
||||
++Sequence;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZRandomGenerator::SetSeed( uint32_t _seed )
|
||||
{
|
||||
if (RNG != NULL) SST_Random_DestroyPRNG(RNG);
|
||||
|
||||
Seed = _seed;
|
||||
Sequence = 0;
|
||||
|
||||
RNG = SST_Random_CreatePRNGFromSeed(Type, Seed);
|
||||
|
||||
ZASSERT_RUNTIME(RNG != NULL, "ZRandomGenerator: Failure to initialize SST_PRNG_Instance!");
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <ZUtil/ZReadWriteLock.hpp>
|
||||
#include <ZUtil/ZAssert.hpp>
|
||||
|
||||
ZReadWriteLock::ZReadWriteLock()
|
||||
: Lock(SST_Concurrency_CreateReadWriteLock())
|
||||
{
|
||||
ZASSERT_RUNTIME(Lock != NULL, "ZReadWriteLock failed to allocate lock from libsst-concurrency!");
|
||||
}
|
||||
|
||||
ZReadWriteLock::~ZReadWriteLock()
|
||||
{
|
||||
SST_Concurrency_DestroyReadWriteLock(Lock);
|
||||
}
|
||||
|
||||
bool ZReadWriteLock::LockForReading( uint32_t ticks ) const
|
||||
{
|
||||
return SST_Concurrency_LockForReading(Lock, ticks) != 0;
|
||||
}
|
||||
|
||||
bool ZReadWriteLock::LockForWriting( uint32_t ticks )
|
||||
{
|
||||
return SST_Concurrency_LockForWriting(Lock, ticks) != 0;
|
||||
}
|
||||
|
||||
void ZReadWriteLock::EndReading( ) const
|
||||
{
|
||||
SST_Concurrency_EndReading(Lock);
|
||||
}
|
||||
|
||||
void ZReadWriteLock::EndWriting( )
|
||||
{
|
||||
SST_Concurrency_EndWriting(Lock);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#include <ZUtil/ZRegistry.hpp>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZRegistry::ZRegistry()
|
||||
: Lock(), Tree()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZRegistry::ZRegistry( const ZKVTree& _tree )
|
||||
: Lock(), Tree(_tree)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZRegistry::~ZRegistry()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZRegistry::Erase( const ZString& _key )
|
||||
{
|
||||
Lock.LockForWriting(SST_WAIT_INFINITE);
|
||||
|
||||
ZKVTree::Iterator itr = Tree.Find(_key);
|
||||
|
||||
if (itr != Tree.End()) {
|
||||
Tree.Erase(itr);
|
||||
}
|
||||
|
||||
Lock.EndWriting();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
const ZRegistry::Value ZRegistry::Get( const ZString& _key ) const
|
||||
{
|
||||
Lock.LockForReading(SST_WAIT_INFINITE);
|
||||
|
||||
ZKVTree::Iterator itr = Tree.Find(_key);
|
||||
|
||||
if (itr != Tree.End()) {
|
||||
ZRegistry::Value val(itr.GetValue(), true);
|
||||
Lock.EndReading();
|
||||
return val;
|
||||
}
|
||||
|
||||
Lock.EndReading();
|
||||
return ZRegistry::Value("", false);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZRegistry::Put( const ZString& _key, const ZString& _value )
|
||||
{
|
||||
size_t i = _key.Length();
|
||||
|
||||
//ZRegistry does not support sibling nodes with the same name
|
||||
if (ZStringAlgo::FindFirstOf(_key, "[]") != ZSTL::InvalidPos)
|
||||
return false;
|
||||
|
||||
Lock.LockForWriting(SST_WAIT_INFINITE);
|
||||
|
||||
/*
|
||||
NOTE: This algorithm is not currently needed with the way ZKVTree works, but
|
||||
that may change - placing value-less nodes in KV tree may be incorrect. If that
|
||||
changes, this should work.
|
||||
|
||||
Algorithm:
|
||||
|
||||
attempt to place full key
|
||||
if it succeeds, return true
|
||||
else
|
||||
while (valid path)
|
||||
attempt key - child (i.e., A.B.C.d -> A.B.C, A.B.C -> A.B, A.B -> A, A -> '')
|
||||
if success, attempt full key
|
||||
else repeat
|
||||
*/
|
||||
while (i > 0) {
|
||||
Tree.Put(ZString(_key, 0, i), _value);
|
||||
|
||||
if (i == _key.Length()) {
|
||||
break;
|
||||
} else {
|
||||
i = _key.Length();
|
||||
}
|
||||
|
||||
i = ZStringAlgo::FindLast(_key, ZKVTREE_PATH_SEPARATOR, 0, i);
|
||||
|
||||
if (i == ZSTL::InvalidPos)
|
||||
break;
|
||||
}
|
||||
|
||||
Lock.EndWriting();
|
||||
|
||||
return i > 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <ZUtil/ZSemaphore.hpp>
|
||||
#include <ZUtil/ZAssert.hpp>
|
||||
#include <SST/SST_Concurrency.h> //For SST_WAIT_INFINITE
|
||||
|
||||
ZSemaphore::ZSemaphore(int _initialCount)
|
||||
: Semaphore(SST_Concurrency_CreateSemaphore(_initialCount))
|
||||
{
|
||||
ZASSERT_RUNTIME(Semaphore != NULL, "ZSemaphore failed to allocate semaphore from libsst-concurrency!");
|
||||
}
|
||||
|
||||
ZSemaphore::~ZSemaphore()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ZSemaphore::Post()
|
||||
{
|
||||
SST_Concurrency_PostSemaphore(Semaphore, 1);
|
||||
}
|
||||
|
||||
void ZSemaphore::Post( uint32_t _count )
|
||||
{
|
||||
SST_Concurrency_PostSemaphore(Semaphore, _count);
|
||||
}
|
||||
|
||||
bool ZSemaphore::Wait()
|
||||
{
|
||||
return SST_Concurrency_WaitSemaphore(Semaphore, SST_WAIT_INFINITE) != 0;
|
||||
}
|
||||
|
||||
bool ZSemaphore::Wait( uint32_t _ms )
|
||||
{
|
||||
return SST_Concurrency_WaitSemaphore(Semaphore, _ms) != 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <ZUtil/ZUtil.hpp>
|
||||
#include <ZUtil/ZSimplexNoise.hpp>
|
||||
#include <SST/SST_SimplexNoise.h>
|
||||
|
||||
ZSimplexNoise::ZSimplexNoise()
|
||||
{
|
||||
this->simplexGenerator = SST_Random_CreateSimplexNoise();
|
||||
}
|
||||
|
||||
void ZSimplexNoise::reseed(const int _seed)
|
||||
{
|
||||
SST_Random_ReseedSimplexNoise(this->simplexGenerator, _seed);
|
||||
}
|
||||
|
||||
float ZSimplexNoise::noise1(const float _x)
|
||||
{
|
||||
return SST_Random_MapSimplexNoise1D(this->simplexGenerator, _x);
|
||||
}
|
||||
|
||||
// 2D simplex noise
|
||||
float ZSimplexNoise::noise2(const float _x, const float _y)
|
||||
{
|
||||
return SST_Random_MapSimplexNoise2D(this->simplexGenerator, _x, _y);
|
||||
}
|
||||
|
||||
// 3D simplex noise
|
||||
float ZSimplexNoise::noise3(const float _x, const float _y, const float _z)
|
||||
{
|
||||
return SST_Random_MapSimplexNoise3D(this->simplexGenerator, _x, _y, _z);
|
||||
}
|
||||
|
||||
// 4D simplex noise
|
||||
float ZSimplexNoise::noise4(const float _x, const float _y, const float _z, const float _w)
|
||||
{
|
||||
return SST_Random_MapSimplexNoise4D(this->simplexGenerator, _x, _y, _z, _w);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
ZSimplexNoiseMap.cpp
|
||||
Author : Chris Ertel
|
||||
|
||||
Purpose : Implementation of 2D, 3D, and 4D simplex noise maps.
|
||||
|
||||
Changelog
|
||||
2/20/11 - Creation (crertel)
|
||||
*/
|
||||
|
||||
#include <ZUtil/ZSimplexNoise.hpp>
|
||||
#include <ZUtil/ZSimplexNoiseMap.hpp>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
bool ZSimplexNoiseMap2D::Generate(int _seed)
|
||||
{
|
||||
int buffsize;
|
||||
int currOctave;
|
||||
float b_coeff;
|
||||
float a_coeff;
|
||||
float u,v;
|
||||
int xstride;
|
||||
|
||||
noiseGen.reseed(_seed);
|
||||
|
||||
/* allocate buffer */
|
||||
if (this->values != NULL)
|
||||
{
|
||||
delete [] this->values;
|
||||
this->values = NULL;
|
||||
}
|
||||
|
||||
buffsize = this->numberSamplesInX * this->numberSamplesInY;
|
||||
this->values = znew float[buffsize];
|
||||
if (this->values == NULL)
|
||||
return false;
|
||||
|
||||
memset(this->values, 0, buffsize * sizeof(float));
|
||||
|
||||
/* fill in the noise */
|
||||
/* for good reference, consult http://local.wasp.uwa.edu.au/~pbourke/texture_colour/perlin/ */
|
||||
for (currOctave = 0; currOctave < this->numberofoctaves; currOctave++)
|
||||
{
|
||||
b_coeff = pow(this->lacunarity, currOctave);
|
||||
a_coeff = pow(this->persistence, currOctave);
|
||||
|
||||
for (int i = 0; i < this->numberSamplesInX; i++)
|
||||
{
|
||||
u = ((float) i)/((float) this->numberSamplesInX);
|
||||
xstride = i * this->numberSamplesInY;
|
||||
for (int j = 0; j < this->numberSamplesInY; j++)
|
||||
{
|
||||
v = ((float) j)/((float) this->numberSamplesInY);
|
||||
this->values[ xstride + j ] += ((float) this->noiseGen.noise2(b_coeff * u, b_coeff * v))/a_coeff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZSimplexNoiseMap2D::Cleanup()
|
||||
{
|
||||
delete [] this->values;
|
||||
this->values = NULL;
|
||||
}
|
||||
|
||||
float ZSimplexNoiseMap2D::getValue(int _x, int _y)
|
||||
{
|
||||
float ret;
|
||||
int xstride = _x * this->numberSamplesInY;
|
||||
ret = this->values[ xstride + _y];
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ZSimplexNoiseMap3D::Generate(int _seed)
|
||||
{
|
||||
int buffsize;
|
||||
int currOctave;
|
||||
float b_coeff;
|
||||
float a_coeff;
|
||||
float u,v,w;
|
||||
int xstride, ystride;
|
||||
|
||||
noiseGen.reseed(_seed);
|
||||
|
||||
/* allocate buffer */
|
||||
if (this->values != NULL)
|
||||
{
|
||||
delete [] this->values;
|
||||
this->values = NULL;
|
||||
}
|
||||
|
||||
buffsize = this->numberSamplesInX * this->numberSamplesInY * this->numberSamplesInZ;
|
||||
this->values = znew float[buffsize];
|
||||
if (this->values == NULL)
|
||||
return false;
|
||||
|
||||
memset(this->values, 0, buffsize * sizeof(float));
|
||||
|
||||
/* fill in the noise */
|
||||
for (currOctave = 0; currOctave < this->numberofoctaves; currOctave++)
|
||||
{
|
||||
b_coeff = pow(this->lacunarity, currOctave);
|
||||
a_coeff = pow(this->persistence, currOctave);
|
||||
|
||||
for (int i = 0; i < this->numberSamplesInX; i++)
|
||||
{
|
||||
u = ((float) i)/((float) this->numberSamplesInX);
|
||||
xstride = i * this->numberSamplesInY * this->numberSamplesInZ;
|
||||
|
||||
for (int j = 0; j < this->numberSamplesInY; j++)
|
||||
{
|
||||
v = ((float) j)/((float) this->numberSamplesInY);
|
||||
|
||||
ystride = j * this->numberSamplesInZ ;
|
||||
for (int k = 0; k < this->numberSamplesInZ; k++)
|
||||
{
|
||||
w = ((float) k)/((float) this->numberSamplesInZ);
|
||||
this->values[xstride+ystride+k] += ((float) this->noiseGen.noise3(b_coeff * u, b_coeff * v, b_coeff * w))/a_coeff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZSimplexNoiseMap3D::Cleanup()
|
||||
{
|
||||
delete [] this->values;
|
||||
this->values = NULL;
|
||||
}
|
||||
|
||||
float ZSimplexNoiseMap3D::getValue(int _x, int _y, int _z)
|
||||
{
|
||||
float ret;
|
||||
int xstride = _x * this->numberSamplesInY * this->numberSamplesInZ;
|
||||
int ystride = _y * this->numberSamplesInZ;
|
||||
ret = this->values[ xstride + ystride + _z];
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ZSimplexNoiseMap4D::Generate(int _seed)
|
||||
{
|
||||
int buffsize;
|
||||
int currOctave;
|
||||
float b_coeff;
|
||||
float a_coeff;
|
||||
float u,v,w,r;
|
||||
int xstride, ystride, zstride;
|
||||
|
||||
noiseGen.reseed(_seed);
|
||||
|
||||
/* allocate buffer */
|
||||
if (this->values != NULL)
|
||||
{
|
||||
delete [] this->values;
|
||||
this->values = NULL;
|
||||
}
|
||||
|
||||
buffsize = this->numberSamplesInX * this->numberSamplesInY * this->numberSamplesInZ * this->numberSamplesInW;
|
||||
this->values = znew float[buffsize];
|
||||
if (this->values == NULL)
|
||||
return false;
|
||||
|
||||
/* fill in the noise */
|
||||
for (currOctave = 0; currOctave < this->numberofoctaves; currOctave++)
|
||||
{
|
||||
b_coeff = pow(this->lacunarity, currOctave);
|
||||
a_coeff = pow(this->persistence, currOctave);
|
||||
|
||||
for (int i = 0; i < this->numberSamplesInX; i++)
|
||||
{
|
||||
u = ((float) i)/((float) this->numberSamplesInX);
|
||||
xstride = i * this->numberSamplesInY * this->numberSamplesInZ * this->numberSamplesInW;
|
||||
|
||||
for (int j = 0; j < this->numberSamplesInY; j++)
|
||||
{
|
||||
v = ((float) j)/((float) this->numberSamplesInY);
|
||||
ystride = j * this->numberSamplesInZ * this->numberSamplesInW;
|
||||
|
||||
for (int k = 0; k < this->numberSamplesInZ; k++)
|
||||
{
|
||||
w = ((float) k)/((float) this->numberSamplesInZ);
|
||||
zstride = k * this->numberSamplesInW;
|
||||
|
||||
for (int l = 0; l < this->numberSamplesInW; l++)
|
||||
{
|
||||
r = ((float) l)/((float) this->numberSamplesInW);
|
||||
this->values[xstride+ystride+zstride+l] += ((float) this->noiseGen.noise4(b_coeff * u, b_coeff * v, b_coeff * w, b_coeff*r))/a_coeff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZSimplexNoiseMap4D::Cleanup()
|
||||
{
|
||||
delete [] this->values;
|
||||
this->values = NULL;
|
||||
}
|
||||
|
||||
float ZSimplexNoiseMap4D::getValue(int _x, int _y, int _z, int _w)
|
||||
{
|
||||
float ret;
|
||||
int xstride = _x * this->numberSamplesInY * this->numberSamplesInZ * this->numberSamplesInW;
|
||||
int ystride = _y * this->numberSamplesInZ * this->numberSamplesInW;
|
||||
int zstride = _z * this->numberSamplesInW;
|
||||
ret = this->values[ xstride + ystride + zstride + _w];
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
#include <ZUtil/ZTaskStream.hpp>
|
||||
|
||||
#include <ZUtil/ZAlloc.hpp>
|
||||
|
||||
/////////////////
|
||||
/* ZTaskThread */
|
||||
/////////////////
|
||||
|
||||
ZThreadReturn ZTaskThread::run( uint64_t _dt )
|
||||
{
|
||||
URFP(_dt);
|
||||
|
||||
ZPtr<ZTask> task;
|
||||
|
||||
//Check if a task is available. If it isn't set our status as waiting, then do an full wait
|
||||
if(!TaskSema.Wait(0)) {
|
||||
this->ThrStatus = ZTTS_WAITING;
|
||||
TaskSema.Wait();
|
||||
}
|
||||
|
||||
//At this point, we've decremented the semaphore. There should be a task waiting
|
||||
TaskLock.Acquire();
|
||||
|
||||
//No tasks -> a) Logic error b) time to exit. Gracefully handle this
|
||||
if(Tasks.Size() == 0) {
|
||||
TaskLock.Release();
|
||||
return ZTR_TERMINATE;
|
||||
}
|
||||
|
||||
//Ok, we're executing tasks
|
||||
ThrStatus = ZTTS_EXECUTING;
|
||||
|
||||
task = Tasks.PopBack();
|
||||
|
||||
//Save the priority of the task that is executing
|
||||
CurrentTaskPriority = task->Priority;
|
||||
|
||||
TaskLock.Release();
|
||||
|
||||
//If the task has not been canceled
|
||||
if (!task->bCancelTask) {
|
||||
//Execute it and check task return status
|
||||
if (task->Execute(task->TaskArgument) == ZTRS_FAILURE)
|
||||
task->OnTaskFailed(task->TaskArgument);
|
||||
} else {
|
||||
//Reset the cancel flag
|
||||
task->bCancelTask = false;
|
||||
}
|
||||
|
||||
return ZTR_LOOP;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
ZTaskThread::ZTaskThread( ZTaskStream *_stream, ZTaskThreadId _id )
|
||||
: TaskLock(), TaskSema(0), Stream(_stream), Id(_id), ThrStatus(ZTTS_UNINITIALIZED)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
ZTaskThread::~ZTaskThread()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ZTaskThread::PushTask( ZPtr<ZTask> _task )
|
||||
{
|
||||
//Add a task while the mutex is locked
|
||||
TaskLock.Acquire();
|
||||
|
||||
Tasks.PushBack(_task);
|
||||
|
||||
TaskLock.Release();
|
||||
|
||||
//1 new task available.
|
||||
TaskSema.Post();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/////////////////
|
||||
/* ZTaskStream */
|
||||
/////////////////
|
||||
|
||||
ZTaskStream::ZTaskStream()
|
||||
: TaskStreamLock(), TaskStreamSema(0),
|
||||
FrameCompletedEvent(), PausedEvent(),
|
||||
Tasks(ZTS_DEFAULT_BUFFER_SIZE), bPaused(false), bShouldHalt(false)
|
||||
{
|
||||
//Initially unpaused
|
||||
PausedEvent.Notify();
|
||||
|
||||
SetTaskThreadCount(1);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
ZTaskStream::~ZTaskStream()
|
||||
{
|
||||
SetTaskThreadCount(0);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ZTaskStream::PushTask( ZPtr<ZTask> _task )
|
||||
{
|
||||
TaskStreamLock.Acquire();
|
||||
|
||||
Tasks.PushBack(_task);
|
||||
|
||||
TaskStreamLock.Release();
|
||||
|
||||
TaskStreamSema.Post(); // 1 new task to schedule
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ZTaskStream::PushTask( ZTask* _task )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ZTaskStream::PushTasks( ZArray< ZPtr<ZTask> >& _tasks )
|
||||
{
|
||||
size_t count = _tasks.Size();
|
||||
|
||||
TaskStreamLock.Acquire();
|
||||
|
||||
ZArrayAlgo::Append(Tasks, _tasks);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Tasks.PushBack( _tasks[i]);
|
||||
TaskStreamSema.Post(); // 1 new task to schedule
|
||||
}
|
||||
|
||||
TaskStreamLock.Release();
|
||||
}
|
||||
|
||||
void ZTaskStream::PushTasks( ZTask* _tasks, size_t _count )
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ZTaskStream::ExecuteTasks(int _frameTime)
|
||||
{
|
||||
ZPtr<ZTask> curTask;
|
||||
ZArray< ZPtr<ZTask> > tmp;
|
||||
ZArray< ZPtr<ZTask> > delayed;
|
||||
|
||||
//Wait for the paused event to be signaled.
|
||||
//When it isn't, this code blocks.
|
||||
PausedEvent.Wait();
|
||||
|
||||
uint64_t timeStart = ZConcurrency::GetTicks();
|
||||
uint64_t timeEnd = timeStart + _frameTime;
|
||||
uint64_t timeNow = timeStart;
|
||||
|
||||
//Schedule tasks until timer elapsed
|
||||
for (;;) {
|
||||
//If we need to halt, do so
|
||||
if (bShouldHalt) {
|
||||
bShouldHalt = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if we've run out of time
|
||||
timeNow = ZConcurrency::GetTicks();
|
||||
|
||||
if (timeEnd < timeNow) {
|
||||
break;
|
||||
}
|
||||
|
||||
//Empty task queue into a temporary array so we minimize time held with lock
|
||||
TaskStreamLock.Acquire();
|
||||
|
||||
while(TaskStreamSema.Wait(0)) {
|
||||
tmp.PushBack(Tasks.PopBack());
|
||||
}
|
||||
|
||||
TaskStreamLock.Release();
|
||||
|
||||
//Check each task
|
||||
while (tmp.Size() > 0) {
|
||||
//Start assigning tasks to threads
|
||||
curTask = tmp.PopBack();
|
||||
|
||||
//If our task can be delayed
|
||||
if (curTask->Priority > 0) {
|
||||
size_t newPriority;
|
||||
uint64_t tickDelta = ZConcurrency::GetTicks() - timeStart;
|
||||
if (tickDelta > curTask->Priority) {
|
||||
newPriority = 0;
|
||||
} else {
|
||||
newPriority = curTask->Priority - (size_t)tickDelta;
|
||||
}
|
||||
|
||||
curTask->Priority = newPriority;
|
||||
|
||||
delayed.PushBack(curTask); //delay the current task until after priority zero tasks are executed
|
||||
} else {
|
||||
//Assign to be executed immediately
|
||||
TaskThreads[AssignTask(curTask.Pointer())]->PushTask(curTask);
|
||||
}
|
||||
}
|
||||
|
||||
//Check what priority tasks are executing
|
||||
bool execP0 = false; //Priority 0 tasks are executing
|
||||
bool execPN = false; //Priority N > 0 tasks are executing
|
||||
|
||||
for (ZArray<ZTaskThread*>::Iterator itr = TaskThreads.Begin(); itr != TaskThreads.End(); itr++) {
|
||||
ZTaskThread* thr = *itr;
|
||||
|
||||
if(thr->ThrStatus != ZTTS_WAITING) {
|
||||
if(thr->CurrentTaskPriority == 0) {
|
||||
execP0 = true;
|
||||
} else {
|
||||
execPN = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//No priority 0 tasks executing -> schedule lower priority stuff now
|
||||
if (!execP0) {
|
||||
//At least one delayed task to assign?
|
||||
if(delayed.Size() != 0) {
|
||||
//Schedule a delayed task now
|
||||
ZPtr<ZTask> task = delayed.PopBack();
|
||||
TaskThreads[AssignTask(task.Pointer())]->PushTask(task);
|
||||
execPN = true;
|
||||
}
|
||||
}
|
||||
|
||||
//No priority N tasks executing -> wait for something to do
|
||||
if(!execPN) {
|
||||
//Check if we've run out of time
|
||||
timeNow = ZConcurrency::GetTicks();
|
||||
|
||||
if (timeEnd < timeNow) {
|
||||
break;
|
||||
}
|
||||
|
||||
//Compute remaining time, and wait for up to that amount or
|
||||
//the scheduler wait period, whichever is less.
|
||||
uint64_t timeLeft = timeEnd - timeNow;
|
||||
|
||||
bool newTasks = TaskStreamSema.Wait((uint32_t)timeLeft);
|
||||
|
||||
if (newTasks) {
|
||||
//Calling WaitSemaphore() actually decreased the count but since we won't
|
||||
//duplicate code here, we'll just re-increment it because next loop
|
||||
//iteration will do another WaitSemaphore() that won't block.
|
||||
TaskStreamSema.Post();
|
||||
} else {
|
||||
//Timeout -> Time to exit
|
||||
break;
|
||||
}
|
||||
}
|
||||
} //main scheduling loop
|
||||
|
||||
// return delayed tasks to the task stream
|
||||
PushTasks(delayed);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
size_t ZTaskStream::GetTaskThreadCount()
|
||||
{
|
||||
return TaskThreads.Size();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ZTaskStream::HaltFrame()
|
||||
{
|
||||
bShouldHalt = true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ZTaskStream::PauseFrame( bool _pause )
|
||||
{
|
||||
if (_pause)
|
||||
{
|
||||
this->bPaused = true;
|
||||
PausedEvent.Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->bPaused = false;
|
||||
PausedEvent.Notify();
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ZTaskStream::SetTaskThreadCount( size_t _count )
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
TaskStreamLock.Acquire();
|
||||
|
||||
//If there are n task threads and the user wants n + k threads, there is no point in killing all n
|
||||
//threads just to create n + k more all over again. Similarly, if the user has n threads but wants
|
||||
//n - k (> 0), then only k threads need to be shut down.
|
||||
if (_count > TaskThreads.Size())
|
||||
{
|
||||
//In with the new
|
||||
for (i = TaskThreads.Size(); i < _count; ++i)
|
||||
{
|
||||
ZTaskThread* thr = znew ZTaskThread(this, i);
|
||||
TaskThreads.PushBack(thr);
|
||||
thr->StartThread();
|
||||
while(!thr->ThreadInitialized())
|
||||
thr->WaitInitialized();
|
||||
}
|
||||
|
||||
}
|
||||
else if (_count < TaskThreads.Size())
|
||||
{
|
||||
//KILLAMANJARO!
|
||||
size_t killCount = TaskThreads.Size() - _count;
|
||||
|
||||
//Out with the old
|
||||
for (i = TaskThreads.Size() - 1, j = 0; j < killCount; --i, ++j)
|
||||
KillTaskThread(i);
|
||||
}
|
||||
|
||||
TaskStreamLock.Release();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
ZTaskThreadId ZTaskStream::AssignTask( ZTask *_task )
|
||||
{
|
||||
URFP(_task);
|
||||
|
||||
static int next = 0;
|
||||
|
||||
int taskThread = next++ % TaskThreads.Size();
|
||||
|
||||
return TaskThreads[taskThread]->Id;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ZTaskStream::KillTaskThread( size_t _idx )
|
||||
{
|
||||
//Post a task that does not exist, task thread will shut down
|
||||
TaskThreads[_idx]->TaskSema.Post();
|
||||
TaskThreads[_idx]->ShutdownThread();
|
||||
zdelete TaskThreads[_idx];
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
#include <ZUtil/ZThread.hpp>
|
||||
#include <ZUtil/ZLog.hpp>
|
||||
#include <ZSTL/ZString.hpp>
|
||||
|
||||
#ifdef _MSC_VER //begin Microsoft Visual C++ specific code
|
||||
#include <windows.h>
|
||||
#undef CreateMutex
|
||||
#undef CreateEvent
|
||||
const DWORD MS_VC_EXCEPTION=0x406D1388;
|
||||
|
||||
#pragma pack(push,8)
|
||||
typedef struct tagTHREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
} THREADNAME_INFO;
|
||||
#pragma pack(pop)
|
||||
|
||||
//This disgusting little hack sets the thread's name in the MSVC debugger
|
||||
void NativeSetThreadName(const char* threadName)
|
||||
{
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = threadName;
|
||||
info.dwThreadID = (DWORD)~0;
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#define NativeSetThreadName(name)
|
||||
#endif //end Microsoft Visual C++ specific code
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZThread::ZThread(ZString _threadName)
|
||||
:
|
||||
ThreadName(_threadName),
|
||||
bShouldShutdown(false), bShouldPause(false),
|
||||
ThreadContext(),
|
||||
ThreadLock(),
|
||||
InitEvent(),
|
||||
PreviousTickCount(0), CurrentTickCount(0),
|
||||
bIsRunning(false), bIsInitialized(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZThread::~ZThread()
|
||||
{
|
||||
ShutdownThread();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
int ZThread::InitThread(void *_runnable)
|
||||
{
|
||||
ZThread *thr = ((ZThread*)_runnable);
|
||||
|
||||
NativeSetThreadName(thr->GetThreadName().Data());
|
||||
|
||||
//TODO - hack for now, need to fix CreateThread
|
||||
thr->ThreadContext.ThreadId = ZConcurrency::GetThreadId();
|
||||
|
||||
thr->initThread();
|
||||
|
||||
thr->bIsInitialized = true;
|
||||
|
||||
thr->InitEvent.Notify();
|
||||
|
||||
thr->Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::Run()
|
||||
{
|
||||
uint64_t dt;
|
||||
|
||||
bIsRunning = true;
|
||||
|
||||
while (!bShouldShutdown)
|
||||
{
|
||||
while (bShouldPause)
|
||||
ZConcurrency::YieldThread();
|
||||
|
||||
ExecuteThreadRequests();
|
||||
|
||||
PreviousTickCount = CurrentTickCount;
|
||||
CurrentTickCount = ZConcurrency::GetTicks();
|
||||
dt = CurrentTickCount - PreviousTickCount;
|
||||
|
||||
switch (run(dt))
|
||||
{
|
||||
case ZTR_LOOP: continue;
|
||||
case ZTR_PAUSE: bShouldPause = true; break;
|
||||
case ZTR_TERMINATE: bShouldShutdown = true; break;
|
||||
default: bShouldShutdown = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
ExecuteThreadRequests();
|
||||
|
||||
shutdownThread();
|
||||
|
||||
bIsInitialized = false;
|
||||
bIsRunning = false;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::AddThreadRequest(ZPtr<ZThreadRequest> _request, bool _wait)
|
||||
{
|
||||
|
||||
//If this is thread adding a request to itself, don't deadlock
|
||||
if(IsCallerTheThread()) {
|
||||
_request->Execute(this);
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadLock.Acquire();
|
||||
{
|
||||
ZTRCallbacks.PushBack(_request);
|
||||
}
|
||||
ThreadLock.Release();
|
||||
|
||||
if (_wait)
|
||||
_request->Wait();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::AddCallbackRequest(ZThreadCallbackFunc function, void* arg, bool async)
|
||||
{
|
||||
ZThreadCallbackRequest req;
|
||||
|
||||
//If this is the thread adding a callback to itself, don't deadlock
|
||||
if(IsCallerTheThread()) {
|
||||
function(this, arg);
|
||||
return;
|
||||
}
|
||||
|
||||
req.arg = arg;
|
||||
req.callback = function;
|
||||
req.doneEvent = (async ? NULL : SST_Concurrency_CreateEvent());
|
||||
|
||||
ThreadLock.Acquire();
|
||||
{
|
||||
Callbacks.PushBack(req);
|
||||
}
|
||||
ThreadLock.Release();
|
||||
|
||||
//Non-async -> wait for done
|
||||
if(!async) {
|
||||
SST_Concurrency_WaitEvent(req.doneEvent, SST_WAIT_INFINITE);
|
||||
SST_Concurrency_DestroyEvent(req.doneEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::ExecuteThreadRequests()
|
||||
{
|
||||
ZList< ZPtr<ZThreadRequest> > persistentRequests;
|
||||
|
||||
ThreadLock.Acquire();
|
||||
|
||||
while (!ZTRCallbacks.Empty())
|
||||
{
|
||||
//Don't execute if we are told to stop
|
||||
if (ZTRCallbacks.Front()->Stop)
|
||||
{
|
||||
ZTRCallbacks.Front()->Persist = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ZTRCallbacks.Front()->CompletedEvent.Reset();
|
||||
|
||||
ZTRCallbacks.Front()->Execute(this);
|
||||
|
||||
ZTRCallbacks.Front()->CompletedEvent.Notify();
|
||||
}
|
||||
|
||||
//If we are to persist, do so
|
||||
if (ZTRCallbacks.Front()->Persist)
|
||||
persistentRequests.PushBack(ZTRCallbacks.PopFront());
|
||||
else
|
||||
ZTRCallbacks.PopFront();
|
||||
}
|
||||
|
||||
while(!Callbacks.Empty()) {
|
||||
ZThreadCallbackRequest& req = Callbacks.Front();
|
||||
|
||||
req.callback(this, req.arg);
|
||||
if(req.doneEvent) {
|
||||
SST_Concurrency_SignalEvent(req.doneEvent);
|
||||
}
|
||||
|
||||
Callbacks.PopFront();
|
||||
}
|
||||
|
||||
|
||||
//Swap back in persistent requests
|
||||
ZTRCallbacks.Swap(persistentRequests);
|
||||
|
||||
ThreadLock.Release();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZThread::StartThread()
|
||||
{
|
||||
bShouldShutdown = false;
|
||||
bShouldPause = false;
|
||||
|
||||
ThreadContext = ZConcurrency::CreateThread(ZThread::InitThread, this);
|
||||
|
||||
if (!ThreadContext.IsValid())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::ShutdownThread()
|
||||
{
|
||||
bShouldShutdown = true;
|
||||
|
||||
if (ThreadContext.IsValid())
|
||||
{
|
||||
ZConcurrency::WaitThread(ThreadContext);
|
||||
ZConcurrency::DestroyThread(ThreadContext);
|
||||
ThreadContext.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::PauseThread()
|
||||
{
|
||||
bShouldPause = true;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::RestartThread()
|
||||
{
|
||||
bShouldPause = false;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZThread::ThreadRunning()
|
||||
{
|
||||
return bIsRunning;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZThread::ThreadInitialized()
|
||||
{
|
||||
return bIsInitialized;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint32_t ZThread::GetThreadId()
|
||||
{
|
||||
return ThreadContext.ThreadId;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZString ZThread::GetThreadName()
|
||||
{
|
||||
ZString name;
|
||||
|
||||
ThreadLock.Acquire();
|
||||
|
||||
name = ThreadName;
|
||||
|
||||
ThreadLock.Release();
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::WaitInitialized()
|
||||
{
|
||||
InitEvent.Wait();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::WaitShutdown()
|
||||
{
|
||||
if (ThreadContext.IsValid())
|
||||
ZConcurrency::WaitThread(ThreadContext);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
bool ZThread::IsCallerTheThread()
|
||||
{
|
||||
uint32_t callerThreadID = SST_Concurrency_GetThreadId();
|
||||
|
||||
return (callerThreadID == this->GetThreadId());
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{49E96A5C-AC79-412B-BBBA-4653795D5EDC}</ProjectGuid>
|
||||
<RootNamespace>Util</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>$(SolutionDir)Bin\x86\</OutDir>
|
||||
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
<TargetName>$(ProjectName)-debug</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(SolutionDir)Bin\x64\</OutDir>
|
||||
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
<TargetName>$(ProjectName)-debug</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>$(SolutionDir)Bin\x86\</OutDir>
|
||||
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(SolutionDir)Bin\x64\</OutDir>
|
||||
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_DEBUG ZASSERT_ENABLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<DisableLanguageExtensions>false</DisableLanguageExtensions>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError>false</TreatWarningAsError>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_DEBUG ZASSERT_ENABLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<DisableLanguageExtensions>false</DisableLanguageExtensions>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError>false</TreatWarningAsError>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_RELEASE; _CRT_SECURE_NO_WARNINGS=1; SST_ASSERT_NODEBUG=1; ZSTL_DISABLE_RUNTIME_CHECKS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)$(ProjectName).lib</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_RELEASE; _CRT_SECURE_NO_WARNINGS=1; SST_ASSERT_NODEBUG=1; ZSTL_DISABLE_RUNTIME_CHECKS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ZAllocWindow.cpp" />
|
||||
<ClCompile Include="ZBinaryBufferReader.cpp" />
|
||||
<ClCompile Include="ZBinaryBufferWriter.cpp" />
|
||||
<ClCompile Include="ZBinaryFileReader.cpp" />
|
||||
<ClCompile Include="ZBinaryFileWriter.cpp" />
|
||||
<ClCompile Include="ZJSONReader.cpp" />
|
||||
<ClCompile Include="ZJSONWriter.cpp" />
|
||||
<ClCompile Include="ZRegistry.cpp" />
|
||||
<ClCompile Include="ZLog.cpp" />
|
||||
<ClCompile Include="ZXMLReader.cpp" />
|
||||
<ClCompile Include="ZXMLWriter.cpp" />
|
||||
<ClCompile Include="ZConcurrency.cpp" />
|
||||
<ClCompile Include="ZEvent.cpp" />
|
||||
<ClCompile Include="ZMutex.cpp" />
|
||||
<ClCompile Include="ZReadWriteLock.cpp" />
|
||||
<ClCompile Include="ZSemaphore.cpp" />
|
||||
<ClCompile Include="ZTaskStream.cpp" />
|
||||
<ClCompile Include="ZThread.cpp" />
|
||||
<ClCompile Include="ZKVTree.cpp" />
|
||||
<ClCompile Include="ZAlloc.cpp" />
|
||||
<ClCompile Include="ZName.cpp" />
|
||||
<ClCompile Include="ZIniReader.cpp" />
|
||||
<ClCompile Include="ZIniWriter.cpp" />
|
||||
<ClCompile Include="ZRandomGenerator.cpp" />
|
||||
<ClCompile Include="ZSimplexNoise.cpp" />
|
||||
<ClCompile Include="ZSimplexNoiseMap.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Include\ZUtil\ZAssert.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZAllocWindow.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryBufferReader.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryBufferWriter.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryFileReader.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryFileWriter.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryReader.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryWriter.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZJSONReader.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZJSONWriter.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZRegistry.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZUtil.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZUtilBuild.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZLog.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZXMLReader.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZXMLWriter.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZConcurrency.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZEvent.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZMutex.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZReadWriteLock.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZSemaphore.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZTaskStream.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZThread.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZKVTree.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZAlloc.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZReferenceCounter.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZSlabAllocator.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZSmartPointer.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZWeakPointer.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZBitmap.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZIniReader.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZIniWriter.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZNoise.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZNoiseMap.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZRandomGenerator.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZSimplexNoise.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZSimplexNoiseMap.hpp" />
|
||||
<ClInclude Include="..\Include\ZUtil\ZName.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\libsst-atomic\libsst-atomic.vcxproj">
|
||||
<Project>{43ed481f-c4a3-40ed-81a3-46c43dc4eb1e}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\libsst-concurrency\libsst-concurrency.vcxproj">
|
||||
<Project>{7af55ff8-2f78-42ec-8a05-7fa1ae514814}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\libsst-crypto\libsst-crypto.vcxproj">
|
||||
<Project>{e5172b73-ab9a-4702-998f-84c841b30c02}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\libsst-os\libsst-os.vcxproj">
|
||||
<Project>{4bac6d63-c2e8-43f7-87ea-ef953cbfddd3}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\libsst-random\libsst-random.vcxproj">
|
||||
<Project>{8aa34f81-4045-4613-88b7-6ff58d7e0a7a}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,278 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\IO">
|
||||
<UniqueIdentifier>{0c1f31dc-02e7-4854-b43b-f34122d54aef}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Concurrency">
|
||||
<UniqueIdentifier>{fad6c8b5-e651-439c-bb10-da7549c3489a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Memory">
|
||||
<UniqueIdentifier>{fdf92c2b-f4b3-4897-b3cb-fce4bfa6ab2c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Parsing">
|
||||
<UniqueIdentifier>{46ffdb11-088a-42e1-b6e4-d48521f8bbe8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Name">
|
||||
<UniqueIdentifier>{56d072e1-ad9b-4f1e-ba27-69ac3e6aa033}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Random">
|
||||
<UniqueIdentifier>{1310d55f-38d1-4da8-a565-2d7f9d40a4f1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\IO">
|
||||
<UniqueIdentifier>{c778d68f-0696-43bd-834c-a83f3e4e7926}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Concurrency">
|
||||
<UniqueIdentifier>{99043719-ca05-4069-b7b4-c3a572f562bf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Memory">
|
||||
<UniqueIdentifier>{4b31f2cf-ae99-47a6-a73f-70917c38affb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Images">
|
||||
<UniqueIdentifier>{5792b217-d26d-4330-89f3-03afdec0dbf9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Parsing">
|
||||
<UniqueIdentifier>{c17952c6-c398-4dd0-8cf6-b101e689d7ab}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Random">
|
||||
<UniqueIdentifier>{15ff240d-bda5-4b0e-890d-5c0c3504f1e3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Name">
|
||||
<UniqueIdentifier>{dd5284dc-acb7-43c6-985f-978b37eaa30d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Data Structures">
|
||||
<UniqueIdentifier>{5ba7ebcc-9121-466d-a20b-48433acc9793}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Data Structures">
|
||||
<UniqueIdentifier>{ea8e988f-3565-46fb-bff7-a2a1b71be4be}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Parsing\Binary">
|
||||
<UniqueIdentifier>{dc488f2c-c725-4010-a94a-3b2f16316e18}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Parsing\Ini">
|
||||
<UniqueIdentifier>{8dddf8b2-5d9e-44d7-ae81-80e24681e795}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Parsing\XML">
|
||||
<UniqueIdentifier>{45c76189-9994-4ae5-a18f-2f741f9f5054}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Parsing\Binary">
|
||||
<UniqueIdentifier>{bc955f80-4159-4f9d-9baa-b30619e94f40}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Parsing\Ini">
|
||||
<UniqueIdentifier>{e7c88882-2e0b-49a8-beb5-7bcf6ba6f9d1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Parsing\XML">
|
||||
<UniqueIdentifier>{e27c228e-1536-49ce-b79b-a2b25e224594}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Parsing\JSON">
|
||||
<UniqueIdentifier>{8e4d71c0-00fb-4508-9498-d73ec0762ea7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Parsing\JSON">
|
||||
<UniqueIdentifier>{ace79183-f13f-4f5f-905f-2d5c7b80391d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ZLog.cpp">
|
||||
<Filter>Source Files\IO</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZXMLReader.cpp">
|
||||
<Filter>Source Files\Parsing\XML</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZXMLWriter.cpp">
|
||||
<Filter>Source Files\Parsing\XML</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZConcurrency.cpp">
|
||||
<Filter>Source Files\Concurrency</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZEvent.cpp">
|
||||
<Filter>Source Files\Concurrency</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZMutex.cpp">
|
||||
<Filter>Source Files\Concurrency</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZReadWriteLock.cpp">
|
||||
<Filter>Source Files\Concurrency</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZSemaphore.cpp">
|
||||
<Filter>Source Files\Concurrency</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZTaskStream.cpp">
|
||||
<Filter>Source Files\Concurrency</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZThread.cpp">
|
||||
<Filter>Source Files\Concurrency</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZAlloc.cpp">
|
||||
<Filter>Source Files\Memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZName.cpp">
|
||||
<Filter>Source Files\Name</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZIniReader.cpp">
|
||||
<Filter>Source Files\Parsing\Ini</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZIniWriter.cpp">
|
||||
<Filter>Source Files\Parsing\Ini</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZRandomGenerator.cpp">
|
||||
<Filter>Source Files\Random</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZSimplexNoise.cpp">
|
||||
<Filter>Source Files\Random</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZSimplexNoiseMap.cpp">
|
||||
<Filter>Source Files\Random</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZKVTree.cpp">
|
||||
<Filter>Source Files\Data Structures</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZRegistry.cpp">
|
||||
<Filter>Source Files\Data Structures</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZBinaryBufferReader.cpp">
|
||||
<Filter>Source Files\Parsing\Binary</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZBinaryFileReader.cpp">
|
||||
<Filter>Source Files\Parsing\Binary</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZAllocWindow.cpp">
|
||||
<Filter>Source Files\Memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZBinaryFileWriter.cpp">
|
||||
<Filter>Source Files\Parsing\Binary</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZJSONWriter.cpp">
|
||||
<Filter>Source Files\Parsing\JSON</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZJSONReader.cpp">
|
||||
<Filter>Source Files\Parsing\JSON</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZBinaryBufferWriter.cpp">
|
||||
<Filter>Source Files\Parsing\Binary</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Include\ZUtil\ZAssert.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZUtil.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZUtilBuild.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZLog.hpp">
|
||||
<Filter>Header Files\IO</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZXMLReader.hpp">
|
||||
<Filter>Header Files\Parsing\XML</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZXMLWriter.hpp">
|
||||
<Filter>Header Files\Parsing\XML</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZConcurrency.hpp">
|
||||
<Filter>Header Files\Concurrency</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZEvent.hpp">
|
||||
<Filter>Header Files\Concurrency</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZMutex.hpp">
|
||||
<Filter>Header Files\Concurrency</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZReadWriteLock.hpp">
|
||||
<Filter>Header Files\Concurrency</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZSemaphore.hpp">
|
||||
<Filter>Header Files\Concurrency</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZTaskStream.hpp">
|
||||
<Filter>Header Files\Concurrency</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZThread.hpp">
|
||||
<Filter>Header Files\Concurrency</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZAlloc.hpp">
|
||||
<Filter>Header Files\Memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZReferenceCounter.hpp">
|
||||
<Filter>Header Files\Memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZSlabAllocator.hpp">
|
||||
<Filter>Header Files\Memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZSmartPointer.hpp">
|
||||
<Filter>Header Files\Memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZWeakPointer.hpp">
|
||||
<Filter>Header Files\Memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZBitmap.hpp">
|
||||
<Filter>Header Files\Images</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZIniReader.hpp">
|
||||
<Filter>Header Files\Parsing\Ini</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZIniWriter.hpp">
|
||||
<Filter>Header Files\Parsing\Ini</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZNoise.hpp">
|
||||
<Filter>Header Files\Random</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZNoiseMap.hpp">
|
||||
<Filter>Header Files\Random</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZRandomGenerator.hpp">
|
||||
<Filter>Header Files\Random</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZSimplexNoise.hpp">
|
||||
<Filter>Header Files\Random</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZSimplexNoiseMap.hpp">
|
||||
<Filter>Header Files\Random</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZName.hpp">
|
||||
<Filter>Header Files\Name</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZKVTree.hpp">
|
||||
<Filter>Header Files\Data Structures</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZRegistry.hpp">
|
||||
<Filter>Header Files\Data Structures</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryBufferReader.hpp">
|
||||
<Filter>Header Files\Parsing\Binary</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryFileReader.hpp">
|
||||
<Filter>Header Files\Parsing\Binary</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryReader.hpp">
|
||||
<Filter>Header Files\Parsing\Binary</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZAllocWindow.hpp">
|
||||
<Filter>Header Files\Memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryWriter.hpp">
|
||||
<Filter>Header Files\Parsing\Binary</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryFileWriter.hpp">
|
||||
<Filter>Header Files\Parsing\Binary</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZJSONReader.hpp">
|
||||
<Filter>Header Files\Parsing\JSON</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZJSONWriter.hpp">
|
||||
<Filter>Header Files\Parsing\JSON</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Include\ZUtil\ZBinaryBufferWriter.hpp">
|
||||
<Filter>Header Files\Parsing\Binary</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <ZUtil/ZXMLReader.hpp>
|
||||
|
||||
//We don't want rapidxml throwing exceptions at us, let the parse handler do it
|
||||
#ifndef RAPIDXML_NO_EXCEPTIONS
|
||||
#define RAPIDXML_NO_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
#include <rapidxml/rapidxml.hpp>
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
void parse_error_handler(const char *what, void *where, void *arg)
|
||||
{
|
||||
URFP(where); //For now
|
||||
|
||||
ZString& errorMsg = *((ZString*)arg);
|
||||
|
||||
errorMsg = "ZXMLReader (rapidxml): ";
|
||||
ZStringAlgo::Append(errorMsg, what);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZXMLReader::Read(const char* data, size_t length)
|
||||
{
|
||||
Tree.Clear();
|
||||
|
||||
ZString name; // current node name
|
||||
ZString value; // current node value
|
||||
|
||||
// make a copy of xml data so we can use rapidxml in destructive mode
|
||||
ZString xmlData(data, length);
|
||||
rapidxml::xml_document<> doc(&ErrorMessage); // character type is 'char'
|
||||
|
||||
// 0 is default flags (error message will be set by handler)
|
||||
if (!doc.parse<rapidxml::parse_no_data_nodes>(xmlData.Data())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// iterate the nodes and set data in the tree
|
||||
rapidxml::xml_node<> *node = doc.first_node();
|
||||
ZKVTree::Iterator itr = Tree.Begin();
|
||||
|
||||
while (node != NULL) {
|
||||
name = node->name();
|
||||
value = node->value();
|
||||
|
||||
// xml often contains a lot of control characters within the 'body'
|
||||
ZStringAlgo::Trim(value);
|
||||
|
||||
// add this node under the root node
|
||||
ZKVTree::Iterator node_itr = Tree.Add(itr, name, value);
|
||||
|
||||
// iterate the attributes and set data in the kvtree
|
||||
for (rapidxml::xml_attribute<> *attr = node->first_attribute(); attr != NULL; attr = attr->next_attribute()) {
|
||||
ZString attr_name = attr->name();
|
||||
ZString attr_value = attr->value();
|
||||
|
||||
// add this node under the newly created node
|
||||
Tree.Add(node_itr, attr_name, attr_value);
|
||||
}
|
||||
|
||||
// iterate to next node (check child first, then sibling, then go up to parent)
|
||||
if (node->first_node() != NULL) {
|
||||
node = node->first_node();
|
||||
itr = node_itr;
|
||||
} else if (node->next_sibling() != NULL) {
|
||||
node = node->next_sibling();
|
||||
} else {
|
||||
|
||||
// go to next element (up and out)
|
||||
while (node->parent() != NULL) {
|
||||
node = node->parent();
|
||||
|
||||
if (node->type() != rapidxml::node_document) {
|
||||
itr = itr.Parent();
|
||||
} else break;
|
||||
|
||||
if (node->next_sibling() != NULL) {
|
||||
node = node->next_sibling();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if we end up NULL or back at the 'document' node by going to parent, then we are done.
|
||||
if (node == NULL || node->parent() == NULL || node->type() == rapidxml::node_document) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
const ZString& ZXMLReader::GetErrorString()
|
||||
{
|
||||
return ErrorMessage;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZXMLReader::GetKVTree(ZKVTree& _kvtree)
|
||||
{
|
||||
_kvtree = Tree;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#include <ZUtil/ZXMLWriter.hpp>
|
||||
|
||||
#define APPEND_NEWLINE \
|
||||
if (_useNewlines) { \
|
||||
ZStringAlgo::Append(_output, LINE_TERMINATOR); \
|
||||
} \
|
||||
|
||||
const ZString& ZXMLWriter::GetErrorString()
|
||||
{
|
||||
return ErrorMessage;
|
||||
}
|
||||
|
||||
bool ZXMLWriter::writeAttributes(ZString& _output, const ZKVTree::Iterator& _itr)
|
||||
{
|
||||
bool found_sub = false; // indicates we have sub-elements
|
||||
|
||||
for (size_t i = 0; i < _itr.GetChildCount(); i++) {
|
||||
|
||||
const ZKVTree::Iterator itr = _itr.ChildItr(i);
|
||||
|
||||
if (itr.GetChildCount() > 0) { // attributes have no children
|
||||
found_sub = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const ZString& name = itr.GetName(); // attrib name
|
||||
const ZString& val = itr.GetValue(); // attrib value
|
||||
|
||||
_output.PushBack(' '); // start with a space
|
||||
ZStringAlgo::Append(_output, name); // append attribute name
|
||||
_output.PushBack('='); // equals
|
||||
_output.PushBack('\"'); // escaped quote
|
||||
ZStringAlgo::Append(_output, val); // attribute value
|
||||
_output.PushBack('\"'); // escaped quote
|
||||
}
|
||||
|
||||
return found_sub;
|
||||
}
|
||||
|
||||
bool ZXMLWriter::writeElements(ZString& _output, bool _useNewlines, const ZKVTree::Iterator& _itr)
|
||||
{
|
||||
if (_itr.GetChildCount() == 0) { // indicates an attribute
|
||||
return true;
|
||||
}
|
||||
|
||||
const ZString& name = _itr.GetName(); // element name
|
||||
const ZString& val = _itr.GetValue(); // element value
|
||||
|
||||
_output.PushBack('<'); // open tag
|
||||
ZStringAlgo::Append(_output, name); // element name
|
||||
|
||||
bool found_sub = writeAttributes(_output, _itr); // write all attributes
|
||||
|
||||
if (val.Empty() && !found_sub) { // close the tag, no body, no sub-elements
|
||||
_output.PushBack('/');
|
||||
_output.PushBack('>');
|
||||
|
||||
APPEND_NEWLINE;
|
||||
|
||||
} else { // keep tag open for sub-elements and body
|
||||
_output.PushBack('>');
|
||||
|
||||
APPEND_NEWLINE;
|
||||
|
||||
// write all sub-elements (this does nothing on an attribute)
|
||||
for (size_t i = 0; i < _itr.GetChildCount(); i++) {
|
||||
writeElements(_output, _useNewlines, _itr.ChildItr(i));
|
||||
}
|
||||
|
||||
if (!val.Empty()) {
|
||||
ZStringAlgo::Append(_output, val); // write element body
|
||||
APPEND_NEWLINE;
|
||||
}
|
||||
|
||||
_output.PushBack('<'); // closing tag begin
|
||||
_output.PushBack('/');
|
||||
ZStringAlgo::Append(_output, name);
|
||||
_output.PushBack('>'); // closing tag end
|
||||
|
||||
APPEND_NEWLINE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZXMLWriter::Write( const ZKVTree& _input, ZString& _output, bool _useNewlines )
|
||||
{
|
||||
ZKVTree::Iterator itr = _input.Begin();
|
||||
|
||||
if (itr == _input.End()) {
|
||||
ErrorMessage = "ZXMLWriter: key value tree has no data!";
|
||||
return false;
|
||||
}
|
||||
|
||||
return writeElements(_output, _useNewlines, itr);
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user