Initial commit

This commit is contained in:
2026-04-03 00:22:39 -05:00
commit eca1e8c458
945 changed files with 218160 additions and 0 deletions

161
Include/ZUtil/ZAlloc.hpp Normal file
View File

@@ -0,0 +1,161 @@
/*
ZAlloc.hpp (created 9/12/10)
Author : James Russell
Purpose :
Memory allocation library and memory allocation tracker for ZEngine. If ZALLOC_EXTRA_SPAMMY is defined,
then allocations will log a message to stderr when allocation occurs indicating how much.
License:
TODO
*/
#pragma once
#ifndef _ZALLOC_H
#define _ZALLOC_H
#include <ZUtil/ZUtilBuild.hpp>
#include <new>
//The compiler really should be smart enough to include size_t in the global
//namespace by default. But, on some Linux configurations, it will drop
//it in std. Explicitly including this doesn't hurt anything.
#include <stddef.h>
#if ZALLOC_CHECK_ALLOC
//Memory Checkpoint Struct
struct ZMemState
{
int Checkpoint; //Checkpoint Number
};
//Allocation Info Struct
struct ZAllocInfo
{
static int CurrentAllocCount; //Current number of unfreed allocations
static int CurrentCheckpoint; //Static current checkpoint tracker
ZAllocInfo* Next; //Next Info Node
uintptr_t Address; //Address assigned
size_t Size; //Size of the allocation
int Line; //Line Number
int Checkpoint; //Checkpoint Integer
char File[128]; //File String
};
//Adds a tracking node for an allocation
extern void ZAllocAddTrack(uintptr_t _address, size_t _size, const char *_file, int _line, int _checkpoint);
//Removes a tracking node for an allocation
extern void ZAllocRemoveTrack(uintptr_t _address);
//Dumps unfreed memory string containing a list of memory leaks
extern void ZAllocDumpUnfreed(ZMemState *_state);
//Debug Placement Operator New
extern void* operator new(size_t _size, const char *_file, int _line, int _checkpoint) throw();
extern void* operator new[](size_t _size, const char *_file, int _line, int _checkpoint) throw();
//Debug Placement Delete
extern void operator delete(void *_ptr, const char* _file, int _line, int _checkpoint);
extern void operator delete[](void *_ptr, const char* _file, int _line, int _checkpoint);
//Our arguments to znew
#define ZNEW_ARGS (__FILE__, __LINE__, ZAllocInfo::CurrentCheckpoint)
//Macros for declaring a memory 'checkpoint' and
//dumping memory leaks to stderr
#define ZALLOC_MEM_CHECKPOINT(stateP) stateP->Checkpoint = AtomicAddReturn((volatile int*)&ZAllocInfo::CurrentCheckpoint, 1)
#define ZALLOC_MEM_DUMP_LEAKS(stateP) ZAllocDumpUnfreed(stateP)
#else //!ZALLOC_CHECK_ALLOC
#define ZNEW_ARGS (std::nothrow)
#define ZALLOC_MEM_CHECKPOINT(stateP)
#define ZALLOC_MEM_DUMP_LEAKS(stateP)
#endif //ZALLOC_CHECK_ALLOC
/* Some definitions we need for znew_static */
//This is used to indicate a static allocation (basically a type flag)
struct znew_static_t { };
//Our actual static allocation overrides
extern void* operator new(size_t _size, znew_static_t _staticAlloc);
extern void* operator new[](size_t _size, znew_static_t _staticAlloc);
/* Some Memory Management Macros */
//znew loves you!
#define znew new ZNEW_ARGS //Allocate with params
#define znew_notrack new (std::nothrow) //Allocate without tracking
#define znew_static new (znew_static_t()) //Allocate, but register for delete onexit
#define zdelete delete //Delete
#define zalloc(_type, _size) ZAlloc::Alloc<_type>(_size) //Allocates an array (block of memory) using the ZAlloc allocation library
#define zfree(_data) ZAlloc::Free(_data) //Frees an array (block of memory) using the ZAlloc allocation library
#define MemCopy(_type, _dest, _src, _count) memcpy(_dest, _src, _count * sizeof(_type))
#define MemCopyFloat(_dest, _src, _count) memcpy(_dest, _src, _count * sizeof(float))
#define MemCopyInt(_dest, _src, _count) memcpy(_dest, _src, _count * sizeof(int))
#define MemCopyChar(_dest, _src, _count) memcpy(_dest, _src, _count * sizeof(char))
#define MemMove(_type, _dest, _src, _count) memmove(_dest, _src, _count * sizeof(_type))
#define MemMoveFloat(_dest, _src, _count) memmove(_dest, _src, _count * sizeof(float))
#define MemMoveInt(_dest, _src, _count) memmove(_dest, _src, _count * sizeof(int))
#define MemMoveChar(_dest, _src, _count) memmove(_dest, _src, _count * sizeof(char))
#define MemSet(_type, _dest, _val, _count) memset(_dest, _val, _count * sizeof(_type))
#define MemSetFloat(_dest, _val, _count) memset(_dest, _val, _count * sizeof(float))
#define MemSetInt(_dest, _val, _count) memset(_dest, _val, _count * sizeof(int))
#define MemSetChar(_dest, _val, _count) memset(_dest, _val, _count * sizeof(char))
class ZAlloc
{
public:
/*
static public Alloc
Allocation function. Gives back an allocated array of at least _size in length.
@param _size - the size of the block of type T
@return (T*) - an array of T of at least _size in length
*/
template <class T>
static T* Alloc(size_t _size);
/*
public static Free
Free function.
@param _data - an array allocated through the use of Alloc
@return (void)
*/
template <class T>
static void Free(T *_data);
};
template <class T>
T* ZAlloc::Alloc(size_t _size)
{
return new (std::nothrow) T[_size];
}
template <class T>
void ZAlloc::Free(T *_data)
{
delete [] _data;
}
#endif

View File

@@ -0,0 +1,205 @@
/*
ZAllocWindow.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 3/7/2013
Purpose:
Buffer used to maintain a sliding window of allocations in a buffer. Primary
use case is sliding packet windows, but could also be used for other forms
of data.
Able to allocate raw memory blocks or perform in-place construction using
default constructors. Destructor calls can be omitted or performed.
License:
TODO
*/
#pragma once
#ifndef _ZALLOCWINDOW_HPP
#define _ZALLOCWINDOW_HPP
#include <new> // for placement new
#include <ZUtil/ZUtilBuild.hpp>
/*
Allocation window class. Operating on a contiguous array of backing memory,
this will allocate chunks of that memory, increasing the window until the
entire block would be used.
When deallocations are performed, no memory is actually freed from the buffer
unless the earliest allocation is deallocated, which will shrink the window.
As an example, consider the following:
buffer.Allocate(A);
buffer.Allocate(B);
buffer.Allocate(C);
buffer.Allocate(D);
A large enough buffer would return four pointers and would have the following
layout (a = allocated flag, d = deallocated flag, f = free memory):
+-----------------------------------+
| a | A | a | B | a | C | a | D | f |
+-----------------------------------+
^ ^
buffer begin buffer end
buffer.Deallocate(B);
+-----------------------------------+
| a | A | d | B | a | C | a | D | f |
+-----------------------------------+
^ ^
buffer begin buffer end
buffer.Deallocate(A);
+-----------------------------------+
| f | f | f | f | a | C | a | D | f |
+-----------------------------------+
^ ^
buffer begin buffer end
Notice that when B was deallocated, no space was actually made available
in the buffer until A was deallocated. If a further attempt had been made
to allocate data, it would have returned NULL, indicating that the allocation
window was full. The only way to free data at that point would have been to
deallocate the earliest allocation (A, in this case).
The allocation window will automatically handle wrapping around when the end
of the buffer is reached.
*/
class ZAllocWindow
{
public:
// c'tor
ZAllocWindow();
// parameterized c'tor
ZAllocWindow(size_t _buffersize);
// d'tor
~ZAllocWindow();
/*
void* ZAllocWindow::Allocate
Allocates a contiguous block of memory from the buffer. If this
would wrap around such that the previously allocated data (that has
not been deallocated) would be overwritten, then it returns NULL.
An additional 8 bytes are used per allocation from the buffer for
allocation metadata.
This will always return a word aligned pointer.
The template version will default construct an object of type T.
@param _size - number of bytes to allocate
@return (void*) - the allocated block of memory (NULL if not possible)
*/
void* Allocate(size_t _size);
template <typename T> T* Allocate()
{ T* obj = (T*)Allocate(sizeof(T)); return (obj != NULL ? new (obj) T() : NULL); }
/*
void ZAllocWindow::Deallocate
Deallocates a previously allocated block of memory from the binary buffer. Since
allocation is done in a sliding window, this only moves frees up memory if this
is the oldest currently allocated block of data. Any other data that is deallocated
will be marked as freed to be made available when the oldest allocated block is freed.
The template version will call the destructor for the object.
@param _data - the data to be deallocated
@param _obj - the object to deallocate (destructor is called)
@return (void)
*/
void Deallocate(void* _data);
template <typename T> void Deallocate(T* _obj)
{ _obj->~T(); Deallocate((void*)_obj); }
/*
size_t ZAllocWindow::GetAllocCount
Gets the current number of allocations out on this allocation window.
@return (size_t) - the number of allocations
*/
size_t GetAllocCount() const
{ return NumAllocs; }
/*
void ZAllocWindow::Reset
Completely resets the allocation window, completely invalidating all
existing allocations.
@return (void)
*/
void Reset();
/*
bool ZAllocWindow::Resize
Attempts to resize the buffer. This will fail if data is currently allocated in
the buffer.
The template version will set the buffer to enough room for N objects of type T.
@param _newsize - the new desired size of the buffer
@param _count - the number of objects of type T to resize the buffer for
@return (bool) - true if able to resize, false otherwise
*/
bool Resize(size_t _newsize);
template <typename T> bool Resize(size_t _count)
{ return Resize((sizeof(T) + 8) * _count); }
/*
void ZAllocWindow::SetBuffer
Sets the backing buffer for this binary buffer. This will fail if data is currently
allocated in the buffer. If NULL, will release ownership of any previous set buffer
and allocate a new one equal to the current size.
Does not assume ownership of the buffer - will not delete it upon destruction of this
buffer.
@param _buffer - the buffer to use as backing
@param _buffersize - the size of the buffer being set
@return (bool) - true if able to use, false otherwise
*/
bool SetBuffer(void* _buffer, size_t _buffersize);
/*
size_t ZAllocWindow::Size
Returns the current size of the buffer.
@return (size_t) - size (in bytes) of the buffer
*/
size_t Size() const
{ return BufferSize; }
private:
DISABLE_COPY_AND_ASSIGN(ZAllocWindow);
void* Buffer; // The allocated buffer
void* Begin; // The (moving) front pointer of the buffer
void* End; // The (moving) back pointer of the buffer
size_t BufferSize; // The current allocated size of the buffer
bool bOwnsBuffer; // Flag indicating we own the buffer (and should free when done)
size_t NumAllocs; // The number of allocations we've done
};
#endif

53
Include/ZUtil/ZAssert.hpp Normal file
View File

@@ -0,0 +1,53 @@
/*
ZAssert.hpp
Author : Chris Ertel
Purpose : Asserts for debugging and error checking purposes.
Changelog
8/16/2010 - creation (crertel)
12/4/2011 - Updated to use libsst-os asserts (jcrussell)
*/
#pragma once
#ifndef _ZASSERT_H
#define _ZASSERT_H
#include <SST/SST_Assert.h>
/*****************/
/* Assert Macros */
/*****************/
//ZASSERT_RUNTIME macro, which will raise an error with debug output if the condition is not true after logging the message
#define ZASSERT_RUNTIME(_condition, _message) SST_OS_RuntimeAssert(_condition, _message)
//ZASSERT_RUNTIME_FAIL macro, which will raise an error with debug output
#define ZASSERT_RUNTIME_FAIL(_message) SST_OS_RuntimeError(_message)
#if ZASSERT_ENABLE
//ZASSERT macro, which will trigger a breakpoint if the condition is not met
#define ZASSERT(_condition, _message) SST_OS_DebugAssert(_condition, _message)
//ZASSERT_FAIL macro, which triggers a breakpoint
#define ZASSERT_FAIL(_message) SST_OS_DebugError(_message)
#else /* ZASSERT is disabled */
#define ZASSERT(_condition, _message)
#define ZASSERT_FAIL(_message)
#endif //ZASSERT_ENABLE
#if ZASSERT_UTIL_ENABLE
//ZASSERT_UTIL macro, which will trigger a breakpoint if the condition is not met
//ZASSERT_UTIL is meant to be used within the ZUtil project for internal assertion debugging
//ZASSERT should be used when the error condition can be caused by user actions
#define ZASSERT_UTIL(_condition, _message) SST_OS_DebugAssert(_condition, _message)
#else /* ZASSERT_UTIL is disabled */
#define ZASSERT_UTIL(_condition, _message) ((void)0)
#endif //ZASSERT_UTIL_ENABLE
#endif

View File

@@ -0,0 +1,87 @@
/*
ZBinaryBufferReader.hpp
Author: Chris Ertel <crertel@762studios.com>, Patrick Baggett <ptbaggett@762studios.com>
Created: 3/6/2013
Purpose:
Reads a binary stream from memory.
License:
TODO
*/
#pragma once
#ifndef _ZBINARYBUFFERREADER_HPP
#define _ZBINARYBUFFERREADER_HPP
#include <stddef.h>
#include <pstdint.h>
#include <ZUtil/ZBinaryReader.hpp>
class ZBinaryBufferReader : public ZBinaryReader
{
private:
const char* Data;
size_t Size;
size_t Offset;
//This is typed to char* so pointer arithmetic can occur
const char* GetPosition() const { return &Data[Offset]; }
public:
ZBinaryBufferReader(const void* _data, size_t _size, SST_ByteOrder bo)
: ZBinaryReader(bo), Data( (const char*) _data), Size(_size), Offset(0)
{
}
//Subclass implementation
uint8_t ReadU8();
//Subclass implementation
uint16_t ReadU16();
//Subclass implementation
uint32_t ReadU32();
//Subclass implementation
uint64_t ReadU64();
//Subclass implementation
void ReadU8Array(uint8_t* ptr, size_t count);
//Subclass implementation
void ReadU16Array(uint16_t* ptr, size_t count);
//Subclass implementation
void ReadU32Array(uint32_t* ptr, size_t count);
//Subclass implementation
void ReadU64Array(uint64_t* ptr, size_t count);
//Subclass implementation
size_t GetLength() const { return Size; }
//Subclass implementation
size_t GetOffset() const { return Offset; }
//Subclass implementation
void SeekTo(size_t offset) { Offset = offset; }
//New to ZBinaryBufferReader. Returns the current address that would be read by the next ReadXxx() call.
//Since 'const void*' is the constructor type, this returns 'const void*' as well. See [private] GetPosition().
const void* GetBufferReadAddress() const { return (const void*)GetPosition(); }
//New to ZBinaryBufferReader. Returns the original buffer address
const void* GetBufferBaseAddress() const { return (const void*)Data; }
//New to ZBinaryBufferReader. Reads a pointer
void* ReadPointer();
};
#endif

View File

@@ -0,0 +1,78 @@
/*
ZBinaryBufferWriter.hpp
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 6/05/2013
Purpose:
Writes a binary stream to memory
License:
TODO
*/
#pragma once
#ifndef _ZBINARYBUFFERWRITER_HPP
#define _ZBINARYBUFFERWRITER_HPP
#include <ZUtil/ZBinaryWriter.hpp>
class ZBinaryBufferWriter : public ZBinaryWriter
{
public:
ZBinaryBufferWriter(void* data, size_t _size, SST_ByteOrder bo) :
ZBinaryWriter(bo), Data((uint8_t*)data), Size(_size), Offset(0)
{
}
//Subclass implementation
void WriteU8(uint8_t v);
//Subclass implementation
void WriteU16(uint16_t v);
//Subclass implementation
void WriteU32(uint32_t v);
//Subclass implementation
void WriteU64(uint64_t v);
//Subclass implementation
void WriteU8Array(const uint8_t* v, size_t count);
//Subclass implementation
void WriteU16Array(const uint16_t* v, size_t count);
//Subclass implementation
void WriteU32Array(const uint32_t* v, size_t count);
//Subclass implementation
void WriteU64Array(const uint64_t* v, size_t count);
//Subclass implementation
size_t GetOffset() const { return Offset; }
//Subclass implementation
void SeekTo(size_t offset) { Offset = offset; }
//Specific to ZBinaryBufferWriter, returns next write address
const void* GetBufferWriteAddress() const { return &Data[Offset]; }
//Specific to ZBinaryBufferWriter, returns base address
void* GetBufferBaseAddress() const { return Data; }
//Specific to ZBinaryBufferWriter, writes a pointer
void WritePointer(void* pointer);
private:
uint8_t* Data;
size_t Size; //TODO: no safe ops ?
size_t Offset;
};
#endif

View File

@@ -0,0 +1,72 @@
/*
ZBinaryFileReader.hpp
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
*/
#pragma once
#ifndef _ZBINARYFILEREADER_HPP
#define _ZBINARYFILEREADER_HPP
#include <SST/SST_File.h>
#include <ZUtil/ZBinaryReader.hpp>
class ZBinaryFileReader : public ZBinaryReader
{
private:
SST_File fp;
size_t Size;
size_t Offset;
public:
ZBinaryFileReader(SST_File handle, SST_ByteOrder bo);
//Subclass implementation
uint8_t ReadU8();
//Subclass implementation
uint16_t ReadU16();
//Subclass implementation
uint32_t ReadU32();
//Subclass implementation
uint64_t ReadU64();
//Subclass implementation
void ReadU8Array(uint8_t* ptr, size_t count);
//Subclass implementation
void ReadU16Array(uint16_t* ptr, size_t count);
//Subclass implementation
void ReadU32Array(uint32_t* ptr, size_t count);
//Subclass implementation
void ReadU64Array(uint64_t* ptr, size_t count);
//Subclass implementation
size_t GetLength() const { return Size; }
//Subclass implementation
size_t GetOffset() const { return Offset; }
//Subclass implementation
void SeekTo(size_t offset);
//Unique to ZBinaryFileReader
SST_File GetFileHandle() { return fp; }
};
#endif

View File

@@ -0,0 +1,68 @@
/*
ZBinaryFileWriter.hpp
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
*/
#pragma once
#ifndef _ZBINARYFILEWRITER_HPP
#define _ZBINARYFILEWRITER_HPP
#include <SST/SST_File.h>
#include <ZUtil/ZBinaryWriter.hpp>
class ZBinaryFileWriter : public ZBinaryWriter
{
public:
ZBinaryFileWriter(SST_File handle, SST_ByteOrder bo);
//Subclass implementation
void WriteU8(uint8_t v);
//Subclass implementation
void WriteU16(uint16_t v);
//Subclass implementation
void WriteU32(uint32_t v);
//Subclass implementation
void WriteU64(uint64_t v);
//Subclass implementation
void WriteU8Array(const uint8_t* v, size_t count);
//Subclass implementation
void WriteU16Array(const uint16_t* v, size_t count);
//Subclass implementation
void WriteU32Array(const uint32_t* v, size_t count);
//Subclass implementation
void WriteU64Array(const uint64_t* v, size_t count);
//Subclass implementation
size_t GetOffset() const { return Offset; }
//Subclass implementation
void SeekTo(size_t offset);
//Unique to ZBinaryFileWriter
SST_File GetFileHandle() { return fp; }
private:
SST_File fp;
size_t Offset;
};
#endif

View File

@@ -0,0 +1,749 @@
/*
ZBinaryReader.hpp
Author: Patrick Baggett <ptbaggett@762studios.com
Created: 3/6/2013
Purpose:
Binary stream reader interface
License:
TODO
*/
#pragma once
#ifndef _ZBINARYREADER_HPP
#define _ZBINARYREADER_HPP
#include <pstdint.h>
#include <SST/SST_Endian.h>
class ZBinaryReader
{
public:
ZBinaryReader(SST_ByteOrder streamOrder) :
streamByteOrder(streamOrder)
{
}
//SINGLE ELEMENT READ
/*
virtual public ZBinaryReader::ReadU8
Reads a single unsigned 8-bit value from the stream.
No validation is performed.
@return (uint8_t) - value read from the stream
*/
virtual uint8_t ReadU8() = 0;
/*
virtual public ZBinaryReader::ReadU16
Reads a single unsigned 16-bit value from the stream.
No validation is performed.
@return (uint16_t) - value read from the stream
*/
virtual uint16_t ReadU16() = 0;
/*
virtual public ZBinaryReader::ReadU32
Reads a single unsigned 32-bit value from the stream.
No validation is performed.
@return (uint32_t) - value read from the stream
*/
virtual uint32_t ReadU32() = 0;
/*
virtual public ZBinaryReader::ReadU64
Reads a single unsigned 64-bit value from the stream.
No validation is performed.
@return (uint64_t) - value read from the stream
*/
virtual uint64_t ReadU64() = 0;
/*
public ZBinaryReader::ReadF32
Reads a single 32-bit floating point value from the stream.
No validation is performed.
@return (float) - value read from the stream
*/
float ReadF32() { return cast_i2f(ReadU32()); }
/*
public ZBinaryReader::ReadF64
Reads a single 64-bit floating point value from the stream.
No validation is performed.
@return (double) - value read from the stream
*/
double ReadF64() { return cast_i2d(ReadU64()); }
//=====================================================================
//ARRAY READ
//=====================================================================
/*
virtual public ZBinaryReader::ReadU8Array
Reads an array of 8-bit unsigned values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
virtual void ReadU8Array(uint8_t* ptr, size_t count) = 0;
/*
virtual public ZBinaryReader::ReadU16Array
Reads an array of 16-bit unsigned values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
virtual void ReadU16Array(uint16_t* ptr, size_t count) = 0;
/*
virtual public ZBinaryReader::ReadU32Array
Reads an array of 32-bit unsigned values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
virtual void ReadU32Array(uint32_t* ptr, size_t count) = 0;
/*
virtual public ZBinaryReader::ReadU64Array
Reads an array of 64-bit unsigned values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
virtual void ReadU64Array(uint64_t* ptr, size_t count) = 0;
/*
public ZBinaryReader::ReadF32Array
Reads an array of 32-bit floating point values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
void ReadF32Array(float* ptr, size_t count) { ReadU32Array((uint32_t*)ptr, count); }
/*
public ZBinaryReader::ReadF64Array
Reads an array of 64-bit floating point values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
void ReadF64Array(double* ptr, size_t count) { ReadU64Array((uint64_t*)ptr, count); }
//=====================================================================
//STREAM SEEKING / POSITIONING
//=====================================================================
/*
virtual public ZBinaryReader::GetLength
Gets the total length of the stream in bytes.
@return (size_t) - The total length of the stream
*/
virtual size_t GetLength() const = 0;
/*
virtual public ZBinaryReader::GetOffset
Gets the current (zero-based) offset into the stream from which the next read will
be performed.
@return (size_t) - The offset.
*/
virtual size_t GetOffset() const = 0;
/*
public ZBinaryReader::SeekForward
Advances the offset into the stream by the given number of bytes.
No validation is performed.
@param amount - The amount of seek forward by.
@return (void)
*/
void SeekForward(size_t amount) { SeekTo(GetOffset() + amount); }
/*
public ZBinaryReader::SeekBackward
Rewinds the offset into the stream by the given number of bytes.
No validation is performed.
@param amount - The amount of seek backward by.
@return (void)
*/
void SeekBackward(size_t amount) { SeekTo(GetOffset() - amount); }
/*
virtual public ZBinaryReader::SeekTo
Directly sets the offset into the stream from which reads will occur.
No validation is performed.
@param offset - The new offset
@return (void)
*/
virtual void SeekTo(size_t offset) = 0;
/*
public ZBinaryReader::Rewind
Sets the offset to the start of the stream
@param offset - The new offset
@return (void)
*/
void Rewind() { SeekTo(0); }
/*
public ZBinaryReader::CanRead
Checks if the given number of bytes can be read
@param bytes - The number of bytes that wish to be read
@return (void)
*/
bool CanRead(size_t bytes) const { return (GetLength() - GetOffset() >= bytes); }
//=====================================================================
//SAFE SEEK FUNCTIONS
//=====================================================================
/*
public ZBinaryReader::SafeSeekForward
Attempts to advance the offset into the stream by the given number of bytes. If
this would produce an out-of-bounds result, then false is returned and the offset
is not adjusted, otherwise, the offset is adjusted and true is returned.
@param amount - The amount to seek forward by
@return (bool) - True if the seek operation succeeded, false if the value was invalid
*/
bool SafeSeekForward(size_t amount)
{
bool ok = (GetLength() - GetOffset() > amount); //i.e. length > offset + amount
if(ok)
SeekTo(GetOffset() + amount);
return ok;
}
/*
public ZBinaryReader::SafeSeekBackward
Attempts to rewind the offset into the stream by the given number of bytes. If
this would produce an out-of-bounds result, then false is returned and the offset
is not adjusted, otherwise, the offset is adjusted and true is returned.
@param amount - The amount to seek backward by
@return (bool) - True if the seek operation succeeded, false if the value was invalid
*/
bool SafeSeekBackward(size_t amount)
{
bool ok = (GetOffset() >= amount); //i.e. offset - amount >= 0
if(ok)
SeekTo(GetOffset() - amount);
return ok;
}
/*
public ZBinaryReader::SafeSeekTo
Attempts to set the offset into the stream directly. If the new offset is
out-of-bounds, then false is returned and the offset is not adjusted,
otherwise, the offset is adjusted and true is returned.
@return (bool) - True if the seek operation succeeded, false if the value was invalid
*/
bool SafeSeekTo(size_t offset)
{
bool ok = (offset < GetLength());
if(ok) SeekTo(offset);
return ok;
}
//=====================================================================
//SAFE READ FUNCTIONS
//=====================================================================
/*
public ZBinaryReader::SafeReadU8
Attempt to reads a single unsigned 8-bit value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadU8(uint8_t* ptr)
{
bool ok = CanRead(sizeof(uint8_t));
if(ok) *ptr = ReadU8();
return ok;
}
/*
public ZBinaryReader::SafeReadU16
Attempt to reads a single unsigned 16-bit value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadU16(uint16_t* ptr)
{
bool ok = CanRead(sizeof(uint16_t));
if(ok) *ptr = ReadU16();
return ok;
}
/*
public ZBinaryReader::SafeReadU32
Attempt to reads a single unsigned 32-bit value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadU32(uint32_t* ptr)
{
bool ok = CanRead(sizeof(uint32_t));
if(ok) *ptr = ReadU32();
return ok;
}
/*
public ZBinaryReader::SafeReadU64
Attempt to reads a single unsigned 64-bit value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadU64(uint64_t* ptr)
{
bool ok = CanRead(sizeof(uint64_t));
if(ok) *ptr = ReadU64();
return ok;
}
/*
public ZBinaryReader::SafeReadF32
Attempt to reads a single 32-bit floating point value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadF32(float* ptr)
{
bool ok = CanRead(sizeof(float));
if(ok) *ptr = ReadF32();
return ok;
}
/*
public ZBinaryReader::SafeReadF64
Attempt to reads a single 64-bit floating point value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadF64(double* ptr)
{
bool ok = CanRead(sizeof(double));
if(ok) *ptr = ReadF64();
return ok;
}
/*
public ZBinaryReader::SafeReadU8Array
Attempt to reads an array of unsigned 8-bit values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadU8Array(uint8_t* ptr, size_t count)
{
bool ok = CanRead(count);
if(ok) ReadU8Array(ptr, count);
return ok;
}
/*
public ZBinaryReader::SafeReadU16Array
Attempt to reads an array of unsigned 16-bit values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadU16Array(uint16_t* ptr, size_t count)
{
bool ok = (SIZE_MAX / count > sizeof(uint16_t)); //i.e. SIZE_MAX > count * size
ok = ok && CanRead(count * sizeof(uint16_t));
if(ok) ReadU16Array(ptr, count);
return ok;
}
/*
public ZBinaryReader::SafeReadU32Array
Attempt to reads an array of unsigned 32-bit values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadU32Array(uint32_t* ptr, size_t count)
{
bool ok = (SIZE_MAX / count > sizeof(uint32_t)); //i.e. SIZE_MAX > count * size
ok = ok && CanRead(count * sizeof(uint32_t));
if(ok) ReadU32Array(ptr, count);
return ok;
}
/*
public ZBinaryReader::SafeReadU64Array
Attempt to reads an array of unsigned 64-bit values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadU64Array(uint64_t* ptr, size_t count)
{
bool ok = (SIZE_MAX / count > sizeof(uint64_t)); //i.e. SIZE_MAX > count * size
ok = ok && CanRead(count * sizeof(uint64_t));
if(ok) ReadU64Array(ptr, count);
return ok;
}
/*
public ZBinaryReader::SafeReadF32Array
Attempt to reads an array of 32-bit floating point values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadF32Array(float* ptr, size_t count) { return SafeReadU32Array((uint32_t*)ptr, count); }
/*
public ZBinaryReader::SafeReadF64Array
Attempt to reads an array of 64-bit floating point values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadF64Array(double* ptr, size_t count) { return SafeReadU64Array((uint64_t*)ptr, count); }
//=====================================================================
//TYPED ALIASES
//=====================================================================
/*
public ZBinaryReader::ReadI8
Reads a single signed 8-bit value from the stream.
No validation is performed.
@return (int8_t) - value read from the stream
*/
int8_t ReadI8() { return (int8_t)ReadU8(); }
/*
public ZBinaryReader::ReadI16
Reads a single signed 16-bit value from the stream.
No validation is performed.
@return (int16_t) - value read from the stream
*/
int16_t ReadI16() { return (int16_t)ReadU16(); }
/*
public ZBinaryReader::ReadI32
Reads a single signed 32-bit value from the stream.
No validation is performed.
@return (int32_t) - value read from the stream
*/
int32_t ReadI32() { return (int32_t)ReadU32(); }
/*
public ZBinaryReader::ReadI64
Reads a single signed 64-bit value from the stream.
No validation is performed.
@return (int64_t) - value read from the stream
*/
int64_t ReadI64() { return (int64_t)ReadU64(); }
/*
public ZBinaryReader::ReadI8Array
Reads an array of 8-bit signed values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
void ReadI8Array(int8_t* ptr, size_t count) { return ReadU8Array((uint8_t*)ptr, count); }
/*
public ZBinaryReader::ReadI16Array
Reads an array of 16-bit signed values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
void ReadI16Array(int16_t* ptr, size_t count) { return ReadU16Array((uint16_t*)ptr, count); }
/*
public ZBinaryReader::ReadI32Array
Reads an array of 32-bit signed values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
void ReadI32Array(int32_t* ptr, size_t count) { return ReadU32Array((uint32_t*)ptr, count); }
/*
public ZBinaryReader::ReadI64Array
Reads an array of 64-bit signed values from the stream.
No validation is performed.
@param ptr - The base of the array
@param count - Number of elements to read
@return (void)
*/
void ReadI64Array(int64_t* ptr, size_t count) { return ReadU64Array((uint64_t*)ptr, count); }
/*
public ZBinaryReader::SafeReadI8
Attempt to reads a single signed 8-bit value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadI8(int8_t* ptr) { return SafeReadU8((uint8_t*)ptr); }
/*
public ZBinaryReader::SafeReadI16
Attempt to reads a single signed 16-bit value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadI16(int16_t* ptr) { return SafeReadU16((uint16_t*)ptr); }
/*
public ZBinaryReader::SafeReadI32
Attempt to reads a single signed 32-bit value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadI32(int32_t* ptr) { return SafeReadU32((uint32_t*)ptr); }
/*
public ZBinaryReader::SafeReadI64
Attempt to reads a single signed 64-bit value from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the value is read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the read value at
@return (bool) - If the value was successfully read
*/
bool SafeReadI64(int64_t* ptr) { return SafeReadU64((uint64_t*)ptr); }
/*
public ZBinaryReader::SafeReadI8Array
Attempt to reads an array of signed 8-bit values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadI8Array(int8_t* ptr, size_t count) { return SafeReadU8Array((uint8_t*)ptr, count); }
/*
public ZBinaryReader::SafeReadI16Array
Attempt to reads an array of signed 16-bit values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadI16Array(int16_t* ptr, size_t count) { return SafeReadU16Array((uint16_t*)ptr, count); }
/*
public ZBinaryReader::SafeReadI32Array
Attempt to reads an array of signed 32-bit values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadI32Array(int32_t* ptr, size_t count) { return SafeReadU32Array((uint32_t*)ptr, count); }
/*
public ZBinaryReader::SafeReadI64Array
Attempt to reads an array of signed 64-bit values from the stream. If this would
result in reading out of bounds, false is returned and *ptr is unmodified, otherwise
the values are read and stored at *ptr and true is returned.
No validation is performed.
@param ptr - The address to store the values
@param count - The number of values to read
@return (bool) - If the array was successfully read
*/
bool SafeReadI64Array(int64_t* ptr, size_t count) { return SafeReadU64Array((uint64_t*)ptr, count); }
//=====================================================================
//GETTERS / SETTERS
//=====================================================================
/*
public ZBinaryReader::GetStreamByteOrder
Gets the byte order in which the stream (source data) is read as.
@return (SST_ByteOrder) - The byte order
*/
SST_ByteOrder GetStreamByteOrder() const { return streamByteOrder; }
/*
public ZBinaryReader::SetStreamByteOrder
Sets the byte order in which the stream (source data) is read as.
@param newOrder - The new byte order
@return (void)
*/
void SetStreamByteOrder(SST_ByteOrder newOrder) { streamByteOrder = newOrder; }
private:
SST_ByteOrder streamByteOrder; //The current byte order the stream is being read in.
};
#endif

View File

@@ -0,0 +1,279 @@
/*
ZBinaryWriter.hpp
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 3/11/2013
Purpose:
Binary stream writer interface
License:
TODO
*/
#pragma once
#ifndef _ZBINARYWRITER_HPP
#define _ZBINARYWRITER_HPP
#include <SST/SST_Endian.h>
#include <pstdint.h>
class ZBinaryWriter
{
public:
ZBinaryWriter(SST_ByteOrder streamOrder) :
streamByteOrder(streamOrder)
{
}
//=====================================================================
//SINGLE ELEMENT WRITE
//=====================================================================
virtual void WriteU8(uint8_t v) = 0;
virtual void WriteU16(uint16_t v) = 0;
virtual void WriteU32(uint32_t v) = 0;
virtual void WriteU64(uint64_t v) = 0;
void WriteF32(float v) { WriteU32(cast_f2i(v)); }
void WriteF64(double v) { WriteU64(cast_d2i(v)); }
//=====================================================================
//ARRAY WRITE
//=====================================================================
/*
virtual public ZBinaryWriter::WriteU8Array
Writes an array of 8-bit unsigned values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
virtual void WriteU8Array(const uint8_t* v, size_t count) = 0;
/*
virtual public ZBinaryWriter::WriteU16Array
Writes an array of 16-bit unsigned values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
virtual void WriteU16Array(const uint16_t* v, size_t count) = 0;
/*
virtual public ZBinaryWriter::WriteU32Array
Writes an array of 32-bit unsigned values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
virtual void WriteU32Array(const uint32_t* v, size_t count) = 0;
/*
virtual public ZBinaryWriter::WriteU64Array
Writes an array of 64-bit unsigned values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
virtual void WriteU64Array(const uint64_t* v, size_t count) = 0;
/*
public ZBinaryWriter::WriteF32Array
Writes an array of 32-bit floating point values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
void WriteF32Array(const float* v, size_t count) { WriteU32Array((uint32_t*)v, count); }
/*
public ZBinaryWriter::WriteF64Array
Writes an array of 64-bit floating point values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
void WriteF64Array(const double* v, size_t count) { WriteU64Array((uint64_t*)v, count); }
//=====================================================================
//STREAM SEEKING / POSITIONING
//=====================================================================
/*
virtual public ZBinaryReader::GetOffset
Gets the current (zero-based) offset into the stream from which the next read will
be performed.
@return (size_t) - The offset.
*/
virtual size_t GetOffset() const = 0;
/*
public ZBinaryReader::SeekForward
Advances the offset into the stream by the given number of bytes.
No validation is performed.
@param amount - The amount of seek forward by.
@return (void)
*/
void SeekForward(size_t amount) { SeekTo(GetOffset() + amount); }
/*
public ZBinaryReader::SeekBackward
Rewinds the offset into the stream by the given number of bytes.
No validation is performed.
@param amount - The amount of seek backward by.
@return (void)
*/
void SeekBackward(size_t amount) { SeekTo(GetOffset() - amount); }
/*
virtual public ZBinaryReader::SeekTo
Directly sets the offset into the stream from which reads will occur.
No validation is performed.
@param offset - The new offset
@return (void)
*/
virtual void SeekTo(size_t offset) = 0;
/*
public ZBinaryReader::Rewind
Sets the offset to the start of the stream
@param offset - The new offset
@return (void)
*/
void Rewind() { SeekTo(0); }
//=====================================================================
//TYPED ALIASES
//=====================================================================
/*
public ZBinaryWriter::WriteI8
Writes a single signed 8-bit value to the stream.
@param v - value read to write to the stream
*/
void WriteI8(int8_t v) { return WriteU8((uint8_t)v); }
/*
public ZBinaryWriter::WriteI16
Writes a single signed 16-bit value to the stream.
@param v - value read to write to the stream
*/
void WriteI16(int16_t v) { return WriteU16((uint16_t)v); }
/*
public ZBinaryWriter::WriteI32
Writes a single signed 32-bit value to the stream.
@param v - value read to write to the stream
*/
void WriteI32(int32_t v) { return WriteU32((uint32_t)v); }
/*
public ZBinaryWriter::WriteI64
Writes a single signed 64-bit value to the stream.
@param v - value read to write to the stream
*/
void WriteI64(int64_t v) { return WriteU64((uint64_t)v); }
/*
public ZBinaryWriter::WriteI8Array
Writes an array of 8-bit signed values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
void WriteI8Array(const int8_t* v, size_t count) { return WriteU8Array((const uint8_t*)v, count); }
/*
public ZBinaryWriter::WriteI16Array
Writes an array of 16-bit signed values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
void WriteI16Array(const int16_t* v, size_t count) { return WriteU16Array((const uint16_t*)v, count); }
/*
public ZBinaryWriter::WriteI32Array
Writes an array of 32-bit signed values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
void WriteI32Array(const int32_t* v, size_t count) { return WriteU32Array((const uint32_t*)v, count); }
/*
public ZBinaryWriter::WriteI64Array
Writes an array of 64-bit signed values to the stream.
@param v - The base of the array
@param count - Number of elements to write
@return (void)
*/
void WriteI64Array(const int64_t* v, size_t count) { return WriteU64Array((const uint64_t*)v, count); }
//=====================================================================
//GETTERS / SETTERS
//=====================================================================
/*
public ZBinaryReader::GetStreamByteOrder
Gets the byte order in which the stream (source data) is read as.
@return (SST_ByteOrder) - The byte order
*/
SST_ByteOrder GetStreamByteOrder() const { return streamByteOrder; }
/*
public ZBinaryReader::SetStreamByteOrder
Sets the byte order in which the stream (source data) is read as.
@param newOrder - The new byte order
@return (void)
*/
void SetStreamByteOrder(SST_ByteOrder newOrder) { streamByteOrder = newOrder; }
private:
SST_ByteOrder streamByteOrder; //The current byte order the stream is being read in.
};
#endif

253
Include/ZUtil/ZBitmap.hpp Normal file
View File

@@ -0,0 +1,253 @@
/*
ZBitmap.hpp
Author: Chris Ertel <crertel@762studios.com>,
James Russell <jcrussell@762studios.com>
Created: 12/09/2010
Purpose:
Bitmap metadata class. This is designed as a metadata package for the data, and
does not assume ownership of the data. By passing around a ZBitmap instead of a raw
pointer to byte data we always have metadata about the byte data on hand.
License:
TODO
*/
#pragma once
#ifndef _ZBITMAP_H
#define _ZBITMAP_H
#include <ZUtil/ZUtilBuild.hpp>
//This is the format of the bitmap, which describes color layout and bits per channel
enum ZBitmapFormat
{
ZBF_UNKNOWN, //Unknown Format (usually uninitialized)
ZBF_R8, //8-bit Red Channel
ZBF_R8I, //8-bit Signed Red Channel
ZBF_R16, //16-bit Red Channel
ZBF_R16I, //16-bit Signed Red Channel
ZBF_R32, //32-bit Red Channel
ZBF_R32I, //32-bit Signed Red Channel
ZBF_R32F, //32-bit Floating Point Red Channel
ZBF_RG8, //8-bit Red, Green Channel
ZBF_RG8I, //8-bit Signed Red, Green Channel
ZBF_RG16, //16-bit Red, Green Channel
ZBF_RG16I, //16-bit Signed Red, Green Channel
ZBF_RG32, //32-bit Red, Green Channel
ZBF_RG32I, //32-bit Signed Red, Green Channel
ZBF_RG32F, //32-bit Floating Point Red, Green Channel
ZBF_RGB8, //8-bit Red, Green, Blue Channel
ZBF_RGB8I, //8-bit Signed Red, Green, Blue Channel
ZBF_RGB16, //16-bit Red, Green, Blue Channel
ZBF_RGB16I, //16-bit Signed Red, Green, Blue Channel
ZBF_RGB32, //32-bit Red, Green, Blue Channel
ZBF_RGB32I, //32-bit Signed Red, Green, Blue Channel
ZBF_RGB32F, //32-bit Floating Point Red, Green, Blue Channel
ZBF_RGBA8, //8-bit Red, Green, Blue, Alpha Channel
ZBF_RGBA8I, //8-bit Signed Red, Green, Blue, Alpha Channel
ZBF_RGBA16, //16-bit Red, Green, Blue, Alpha Channel
ZBF_RGBA16I, //16-bit Signed Red, Green, Blue, Alpha Channel
ZBF_RGBA32, //32-bit Red, Green, Blue, Alpha Channel
ZBF_RGBA32I, //32-bit Signed Red, Green, Blue, Alpha Channel
ZBF_RGBA32F, //32-bit Floating Point Red, Green, Blue, Alpha Channel
ZBF_BGR8, //8-bit Blue, Green, Red Channel
ZBF_BGR8I, //8-bit Signed Blue, Green, Red Channel
ZBF_BGR16, //16-bit Blue, Green, Red Channel
ZBF_BGR16I, //16-bit Signed Blue, Green, Red Channel
ZBF_BGR32, //32-bit Blue, Green, Red Channel
ZBF_BGR32I, //32-bit Signed Blue, Green, Red Channel
ZBF_BGR32F, //32-bit Floating Point Blue, Green, Red Channel
ZBF_BGRA8, //8-bit Blue, Green, Red, Alpha Channel
ZBF_BGRA8I, //8-bit Signed Blue, Green, Red, Alpha Channel
ZBF_BGRA16, //16-bit Blue, Green, Red, Alpha Channel
ZBF_BGRA16I, //16-bit Signed Blue, Green, Red, Alpha Channel
ZBF_BGRA32, //32-bit Blue, Green, Red, Alpha Channel
ZBF_BGRA32I, //32-bit Signed Blue, Green, Red, Alpha Channel
ZBF_BGRA32F, //32-bit Floating Point Blue, Green, Red, Alpha Channel
ZBF_DEPTH32, //32-bit Unsigned Depth
ZBCM_SIZE
};
/*
Bitmap data class.
*/
class ZBitmap
{
protected:
ZBitmapFormat Format; //Format of the bitmap
uint32_t Width; //Width of the bitmap
uint32_t Height; //Height of the bitmap
uint32_t Depth; //Depth of the bitmap
void* Data; //Pointer to the bitmap data (can be NULL)
public:
/*
Default Constructor
*/
ZBitmap()
: Format(ZBF_UNKNOWN),
Width(1),
Height(1),
Depth(1),
Data(NULL)
{ }
/*
Constructor.
@param _format - the bitmap format
@param _width - the width (pixels)
@param _height - the height (pixels)
*/
ZBitmap(ZBitmapFormat _format, uint32_t _width, uint32_t _height)
: Format(_format),
Width(_width),
Height(_height),
Depth(1),
Data(NULL)
{ }
/*
Constructor.
@param _format - the bitmap format
@param _width - the width (pixels)
@param _height - the height (pixels)
@param _depth - the depth (pixels)
*/
ZBitmap(ZBitmapFormat _format, uint32_t _width, uint32_t _height, uint32_t _depth)
: Format(_format),
Width(_width),
Height(_height),
Depth(_depth),
Data(NULL)
{ }
/*
Constructor.
@param _format - the bitmap format
@param _width - the width (pixels)
@param _height - the height (pixels)
@param _depth - the depth (pixels)
@param _data - the bitmap data
*/
ZBitmap(ZBitmapFormat _format, uint32_t _width, uint32_t _height, uint32_t _depth, void* _data)
: Format(_format),
Width(_width),
Height(_height),
Depth(_depth),
Data(_data)
{ }
//Determines (based off Format) the Bits Per Pixel of this bitmap
size_t GetBPP() const
{
switch(Format)
{
case ZBF_R8: return 8;
case ZBF_R8I: return 8;
case ZBF_R16: return 16;
case ZBF_R16I: return 16;
case ZBF_R32: return 32;
case ZBF_R32I: return 32;
case ZBF_R32F: return 32;
case ZBF_RG8: return 16;
case ZBF_RG8I: return 16;
case ZBF_RG16: return 32;
case ZBF_RG16I: return 32;
case ZBF_RG32: return 64;
case ZBF_RG32I: return 64;
case ZBF_RG32F: return 64;
case ZBF_RGB8: return 24;
case ZBF_RGB8I: return 24;
case ZBF_RGB16: return 48;
case ZBF_RGB16I: return 48;
case ZBF_RGB32: return 96;
case ZBF_RGB32I: return 96;
case ZBF_RGB32F: return 96;
case ZBF_RGBA8: return 32;
case ZBF_RGBA8I: return 32;
case ZBF_RGBA16: return 64;
case ZBF_RGBA16I: return 64;
case ZBF_RGBA32: return 128;
case ZBF_RGBA32I: return 128;
case ZBF_RGBA32F: return 128;
case ZBF_BGR8: return 24;
case ZBF_BGR8I: return 24;
case ZBF_BGR16: return 48;
case ZBF_BGR16I: return 48;
case ZBF_BGR32: return 96;
case ZBF_BGR32I: return 96;
case ZBF_BGR32F: return 96;
case ZBF_BGRA8: return 32;
case ZBF_BGRA8I: return 32;
case ZBF_BGRA16: return 64;
case ZBF_BGRA16I: return 64;
case ZBF_BGRA32: return 128;
case ZBF_BGRA32I: return 128;
case ZBF_BGRA32F: return 128;
default: return 0;
}
}
//Determines (based off of Width, Height, and Depth) the dimension of this bitmap (1, 2, or 3, 0 if inconsistent values)
size_t GetDimension() const
{
if (Width > 1 && Height > 1 && Depth > 1)
return 3;
else if (Width > 1 && Height > 1 && Depth <= 1)
return 2;
else if (Width > 1 && Height <= 1 && Depth <= 1)
return 1;
return 0;
}
//Computes and returns the size of the bitmap (in bytes)
size_t GetSize() const
{
return (Width * Depth * Height * GetBPP()) / 8;
}
//Getter and Settter for 'Format'
inline ZBitmapFormat GetFormat() const { return this->Format; }
inline void SetFormat(ZBitmapFormat _format) { this->Format = _format; }
//Getter and Setter for 'Width', in pixels
inline uint32_t GetWidth() const { return this->Width; }
inline void SetWidth(uint32_t _width) { this->Width = _width; }
//Getter and Setter for 'Height', in pixels
inline uint32_t GetHeight() const { return this->Height; }
inline void SetHeight(uint32_t _height) { this->Height = _height; }
//Getter and Setter for 'Depth', in pixels
inline uint32_t GetDepth() const { return this->Depth; }
inline void SetDepth(uint32_t _depth) { this->Depth = _depth; }
//Getter and Setter for 'Data'
inline void* GetData() const { return this->Data; }
inline void SetData(void* _data) { this->Data = _data; }
};
#endif

View File

@@ -0,0 +1,137 @@
/*
ZConcurrency.hpp
Author : James Russell, Patrick Baggett
Purpose : Provides a number of primitives for building concurrent programs. Each supported
platform has a separate implementation.
Changelog
1/24/11 - Creation (jcrussell)
3/17/11 - Major change to support events, mutexes, thread local storage, and semaphores. (ptbaggett)
*/
#pragma once
#ifndef _ZCONCURRENCY_HPP
#define _ZCONCURRENCY_HPP
#include <ZUtil/ZUtilBuild.hpp>
#include <ZUtil/ZSemaphore.hpp>
#include <ZUtil/ZMutex.hpp>
#include <ZUtil/ZEvent.hpp>
#include <ZUtil/ZReadWriteLock.hpp>
//Used to indicate an indefinite wait
#define ZWAIT_INFINITE (~((uint32_t)0))
//Typedef for a thread handle
typedef void* ZThreadHandle;
/*
ZEngine thread data, used as a context for threads. The fields here should not be accessed directly.
*/
struct ZThreadContext
{
//The handle to this thread
ZThreadHandle Thread;
//The id given to this thread. Unique, but may be reused after thread is destroyed
uint32_t ThreadId;
//The return status this thread exited with (invalid unless Thread == NULL)
int ThreadExitStatus;
//Default Constructor
ZThreadContext() { Invalidate(); }
//Returns if it's valid
bool IsValid() const { return Thread != NULL; }
//Marks a thread context as invalid
void Invalidate() { Thread = NULL; ThreadId = 0; ThreadExitStatus = 0; }
};
/*
Namespace used for static access to low-level thread functionality.
*/
namespace ZConcurrency
{
/*
ZThreadContext CreateThread()
Creates a thread instance that will begin running the provided function.
The thread context should be cleaned up with DestroyThread() after the
thread exits (use WaitThread() to ensure it is exited).
@param _func - function that the thread will execute. Should be of return type
int and take a void* as an argument.
@param _arg - the argument that is passed to the function.
@return (ZThreadContext) - thread context, used as a handle to the thread
*/
ZThreadContext CreateThread(int(*_func)(void*), void *_arg);
/*
void DestroyThread()
Frees memory associated with a thread context. This should only be called
after the thread is known to be dead (e.g. using WaitThread()). As implied
by the last comment, this does not kill the OS thread if it was already
running.
@param _context - Thread context to be cleaned up
@return (void)
*/
void DestroyThread(ZThreadContext& _context);
/*
void SleepThread()
Causes the calling thread to sleep for a minimum of the specified time (in ms).
@param _ms - the specified time to sleep (in ms)
@return (void)
*/
void SleepThread(uint32_t _ms);
/*
int GetThreadId()
Gets the thread ID of the calling thread.
@return (uint32_t) - int that is the thread id of the calling thread
*/
uint32_t GetThreadId();
/*
unsigned int GetTicks()
Gets the tick count since the last call to GetTicks.
@return (uint64_t) - the count (in ms) since program start.
*/
uint64_t GetTicks();
/*
int WaitThread()
Waits for a thread to terminate. This is the only way to ensure thread resources are
returned. The termination code from the thread is stored in the thread context.
@param _context - the handle returned from CreateThread (the termination code is stored here)
@return (bool) - true if the thread terminated, false otherwise
*/
bool WaitThread(ZThreadContext& _context);
/*
void YieldThread()
Causes the calling thread to yield execution to another thread.
@return (void)
*/
void YieldThread();
}
#endif

86
Include/ZUtil/ZEvent.hpp Normal file
View File

@@ -0,0 +1,86 @@
/*
ZEvent.hpp
Author: James Russell <jcrussell@762studios.com>
Purpose: RAII wrapper for SST_Event from libsst-concurrency.
Changelog
2011/11/27 - creation (jcrussell)
*/
#pragma once
#ifndef _ZEVENT_H
#define _ZEVENT_H
#include <ZUtil/ZUtilBuild.hpp>
#include <SST/SST_Event.h>
/*
Event class. Used to manage allocation and deallocation of events.
Cannot be copied or assigned, which prevents it from being used in stl-like containers.
*/
class ZEvent
{
private:
DISABLE_COPY_AND_ASSIGN(ZEvent);
//libsst Event
SST_Event Event;
public:
/*
Constructor. Creates an event from libsst-concurrency.
*/
ZEvent();
/*
Destructor. Frees our event from libsst-concurrency.
*/
~ZEvent();
/*
public ZSignal::Notify
Signals event, waking up all waiting threads. Until this event is reset, waiting threads will return.
@return (void)
@context (all)
*/
void Notify();
/*
public ZSignal::Reset
Signals reset, which causes threads that call Wait to block until signaled.
@return (void)
@context (all)
*/
void Reset();
/*
public ZSignal::Wait
Waits on a signal. Blocks until Signal is called.
@return (bool) - true if the event was signaled, false if returned before a signal (such as event not reset)
@context (all)
*/
bool Wait();
/*
public ZSignal::Wait
Waits on a signal for an amount of time.
@param _ms - the amount of time (in ms) to wait.
@return (bool) - true if the event was signaled, false if returned before a signal (event not reset our out of time).
@context (all)
*/
bool Wait(uint32_t _ms);
};
#endif

View File

@@ -0,0 +1,184 @@
/*
ZIniReader.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 4/27/2012
Purpose:
Parses INI file format in memory.
(File Begin)
# This is a commented line
; This is too
[SectionA]
Key1=Value1
Key2 =Value2
Key3= Value3
Key4 = Value4
[SectionB]
Key1 = Value1
...
(File End)
Comments must be on their own line. Sections must be unique to a file. Keys can be repeated,
but the final value seen is the value recorded.
ZIniReader class does no I/O - it merely parses in-memory representations.
The data structures it provides a read-only, but you can get a mutable copy of its data as
a ZRegistry object. The data above would be loaded into a registry with the following layout:
Root
|
+-> SectionA
| |
| +-> Key1 (Value1)
| +-> Key2 (Value2)
| +-> Key3 (Value3)
| +-> Key4 (Value4)
|
+-> SectionB
|
+-> Key1 (Value1)
License:
TODO
*/
#ifndef _ZINIREADER_HPP
#define _ZINIREADER_HPP
#include <ZUtil/ZKVTree.hpp>
/*
IniReader class.
*/
class ZIniReader
{
public:
/*
Default constructor.
*/
ZIniReader()
: ErrorMessage() { }
/*
Destructor.
*/
~ZIniReader()
{ ClearData(); }
/*
public ZIniReader::Read
Reads an INI file stored as a ZString.
@param _iniData - string holding the data of an ini file, which will be parsed
@return (bool) - True if successful, false if failure. Use GetErrorString() to get the message
*/
bool Read(const ZString& _iniData)
{ return Read(_iniData.Data(), _iniData.Length()); }
/*
public ZIniReader::Read
Reads an INI file stored as memory block
@param data - Pointer to INI data
@param length - Length of INI data
@return (bool) - true if successful, false if failure (use GetErrorString() to get the message)
*/
bool Read(const char* data, size_t length);
/*
public ZIniReader::GetErrorString
Gets the error message generated while loading the data if loading failed. If loading
the data was successful, this returns an empty string.
@return (const ZString&) - error message string
*/
const ZString& GetErrorString()
{ return ErrorMessage; }
/*
public ZIniReader::GetSection
Looks up a section by name and returns a pointer to the ZHashMap object. If the
section does not exist, NULL is returned. The hashmap contains a list of key-value pairs
found for that section
@param sectionName - The name of the section
@return (const ZHashMap<ZString, ZString>*) - The section, or NULL if it does not exist
*/
const ZHashMap<ZString, ZString>* GetSection(const ZString& sectionName);
/*
public ZIniReader::GetSection
Looks up a section by ordinal and returns a pointer to the ZHashMap object. Sections
are given in order of appearance in the file. The hashmap contains a list of key-value pairs
found for that section.
@param index - The index of the section, between 0 and GetSectionCount() - 1
@return (const ZHashMap<ZString, ZString>*) - The section
*/
const ZHashMap<ZString, ZString>* GetSection(size_t index)
{ return Sections[index]; }
/*
public ZIniReader::GetSectionCount
Gets the number of sections parsed. If Read() returned true, this will be at least one.
@return (size_t) - The number of sections parsed.
*/
size_t GetSectionCount()
{ return Sections.Size(); }
/*
public ZIniReader::GetSectionName
Gets the name for a section by ordinal. Sections names are given in order of appearance
in the file.
@param index - The index of the section, between 0 and GetSectionCount()-1
@return (const ZString&) - The section name
*/
const ZString& GetSectionName(size_t index)
{ return SectionNames[index]; }
/*
public ZIniReader::GetKVTree
Populates a ZKVTree using the read values. If loading the data has failed,
no data is entered.
To get values in the kv-tree, use the path string 'Section.Key'.
@param _kvtree - the kv-tree to contain the parsed ini values
@return (void)
*/
void GetKVTree(ZKVTree& _kvtree);
private:
DISABLE_COPY_AND_ASSIGN(ZIniReader);
ZString ErrorMessage; // Error Message (if an error has happened)
ZHashMap<ZString, ZHashMap<ZString, ZString>*> StringSectionMap; // String -> Hashmap table
ZArray<ZHashMap<ZString, ZString>*> Sections; // Linear order in which sections were found
ZArray<ZString> SectionNames; // Name of sections parsed
void SetError(const char* message, uint32_t line); // Sets the error message
void ClearData(); // Clears previously read section data
};
#endif

View File

@@ -0,0 +1,69 @@
/*
ZIniWriter.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 5/6/2012
Purpose:
The 'inverse' of ZIniReader, this will take a kvtree of values (like the one given by
ZIniReader) and write to an output string in the .ini format specified in ZIniReader.hpp.
License:
TODO
*/
#pragma once
#ifndef _ZINIWRITER_HPP
#define _ZINIWRITER_HPP
#include <ZUtil/ZKVTree.hpp>
#include <ZUtil/ZSmartPointer.hpp>
/*
IniWriter class.
*/
class ZIniWriter
{
public:
/*
Default Constructor.
*/
ZIniWriter() { }
/*
Destructor.
*/
~ZIniWriter() { }
/*
public ZIniWriter::GetErrorString
Gets the error message generated while writing the data if writing failed. If writing
the data was successful, this returns an empty string.
@return (const ZString&)
*/
const ZString& GetErrorString();
/*
public ZIniWriter::Write
Writes the data from the provided kvtree into the provided output string in the 'ini' format.
@param _input - the tree to read values from
@param _output - the string to write the data into (the data is appended)
@return (bool) - true if successful, false otherwise
*/
bool Write(const ZKVTree& _input, ZString& _output);
private:
DISABLE_COPY_AND_ASSIGN(ZIniWriter);
//Error message (if an error has happened)
ZString ErrorMessage;
};
#endif

View File

@@ -0,0 +1,69 @@
/*
ZJSONReader.hpp
Author: Chris Ertel <crertel@762studios.com>
Created: 3/26/2013
Purpose:
JSON reading support, to convert JSON strings into ZKVTrees.
License:
TODO
*/
#pragma once
#ifndef _ZJSONREADER_H
#define _ZJSONREADER_H
#include <ZUtil/ZKVTree.hpp>
#include <ZUtil/ZSmartPointer.hpp>
/*
ZJSONReader class, which converts JSON data into a ZKVTree that can be used to access / iterate
the data.
*/
class ZJSONReader
{
private:
DISABLE_COPY_AND_ASSIGN(ZJSONReader);
//Error Message (if an error has happened)
ZString ErrorMessage;
const ZString JSONData;
//Registry of data
ZPtr<ZKVTree> Registry;
public:
/*
Parameterized Constructor.
@param _jsonData - string containing JSON data to parse
*/
ZJSONReader(const ZString& _jsonData);
/*
public ZJSONReader::GetErrorString
Gets the error message generated while loading the data if loading failed. If loading
the data was successful, this returns an empty string.
@return (const ZString&) - error message string
*/
const ZString& GetErrorString();
/*
public ZJSONReader::GetKVTree
Gets the registry that was constructed from the parsed JSON data. If the loading failed,
the pointer returned is NULL.
TODO - describe the format
@return (ZPtr<ZRegistry>) - registry containing the parsed JSON data
*/
ZPtr<ZKVTree> GetKVTree();
};
#endif

View File

@@ -0,0 +1,64 @@
/*
ZJSONWriter.hpp
Author: Chris Ertel <crertel@762studios.com>
Created: 3/26/2013
Purpose:
JSON writing support, to convert ZKVTrees into JSON strings.
License:
TODO
*/
#pragma once
#ifndef _ZJSONWRITER_H
#define _ZJSONWRITER_H
#include <ZUtil/ZSmartPointer.hpp>
#include <ZUtil/ZKVTree.hpp>
class ZJSONWriter
{
private:
DISABLE_COPY_AND_ASSIGN(ZJSONWriter);
//Error message (if an error has happened)
ZString ErrorMessage;
//The registry we will be getting values from
ZPtr<ZKVTree> Registry;
const ZString NoError;
public:
/*
Parameterized Constructor.
@param _registry - the registry to generate XML data from
*/
ZJSONWriter(ZPtr<ZKVTree> _registry);
/*
public ZJSONWriter::GetErrorString
Gets the error message generated while writing the data if writing failed. If writing
the data was successful, this returns an empty string.
@return (const ZString&) - a string describing an error that occurred
*/
const ZString& GetErrorString();
/*
public ZJSONWriter::Write
Writes the data from the registry into the provided output string in XML format.
@param _output - the string to write the data into (the data is appended)
@return (bool) - true if successful, false otherwise
*/
bool Write(ZString& _output);
};
#endif

821
Include/ZUtil/ZKVTree.hpp Normal file
View File

@@ -0,0 +1,821 @@
/*
ZKVTree.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 3/22/2012
Purpose:
ZKVTree defines a KV-Tree that uses strings as both keys and values. The model
supported is hierarchical with no nesting limit, and individual nodes can be addressed
directly or the tree can be iterated. This makes ZKVTree's typical use case as an
in memory representation of hierarchical text formats such as XML and JSON, and can
be used for simpler formats such as INI. When the layout and keys are known
(such as with most INI files), lookup via path string is the easiest route. When the layout
is not known (such as with an XML file with variable numbers of children and attributes),
then iteration is the preferred method of getting access to the data.
Multiple nodes of the same name existing at the same level in the tree is supported.
When a path is given that does not contain the number, then it is assumed to be
referencing the first sibling node at that location (index 0).
Unnamed tree nodes are supported, with the key used to access those being omitted from the
path string but the subscript being required.
If the tree has the following layout, with the values at each node contained
in parenthesis:
Root
|
+-> A (0)
| |
| +-> B (8)
| | |
| | +-> c (16)
| | +-> c (32)
| | +-> (100)
| | +-> (200)
| |
| +-> B (8)
| | |
| | +-> c (64)
| | +-> d (128)
| | +-> (10)
| | +-> (20)
| |
| +-> b (5)
| +-> b (10)
| +-> c (15)
| +-> d (20)
|
+-> B (8)
| |
| +-> c (50)
| +-> d (100)
|
+-> a (1)
+-> a (2)
+-> a (3)
+-> b (4)
Then valid path strings include (but are not limited to):
A.B - would get the value of node 'B[0]' (8) with parent node 'A[0]'
A.B.c - would get the value of node 'c[0]' (16) with parent node 'A[0].B[0]'
A.B.c[1] - would get the value of node 'c[1]' (32) with parent node 'A[0].B[0]'
A.B[1].c - would get the value of node 'c[0]' (64) with parent node 'A[0].B[1]'
A.B[1].c[1] - would get the value of node 'c[1]' (128) with parent node 'A[0].B[1]'
A.b[1] - would get the value of node 'b[1]' (10) with parent node 'A[0]'
B.c - would get the value of node 'c[0]' (50) with parent node 'B[0]'
a - would get the value of node 'a[0]' (1) with root parent node ''
a[2] - would get the value of node 'a[2]' (3) with root parent node ''
If this KVTree were to be iterated using ZKVTree::Iterator::Next(), a depth first
traversal of the structure would take place, giving us the following order:
A
A.B[0]
A.B[0].c[0]
A.B[0].c[1]
A.B[0].[0]
A.B[0].[1]
A.B[1].c
A.B[1].d
A.B[1].[0]
A.B[1].[1]
A.b[0]
A.b[1]
A.c
A.d
B
B.c
B.d
a[0]
a[1]
a[2]
A special syntax for accessing unnamed children is supported, which enables nested array behavior
for values:
A.B[0][0] - would get the value of (unnamed) node '[0]' (100) with parent node 'A.B[0]'
A.B[1][0] - would get the value of (unnamed) node '[0]' (10) with parent node 'A.B[0]'
A.B[1][1] - would get the value of (unnamed) node '[1]' (20) with parent node 'A.B[1]'
Note that these are syntactic sugar for:
A.B[0].[0] (could also be expressed as A.B[0]. or A.B. due to the implicit [0])
A.B[1].[0] (could also be expressed as A.B[1]. due to the implicit [0])
A.B[1].[1]
License:
TODO
*/
#ifndef _ZREGISTRY_H
#define _ZREGISTRY_H
#include <SST/SST_Hash.h>
#include <ZSTL/ZHashMap.hpp>
#include <ZSTL/ZString.hpp>
#include <ZSTL/ZBasicStringAlgo.hpp>
#include <ZUtil/ZConcurrency.hpp>
#include <ZUtil/ZSlabAllocator.hpp>
#include <stdarg.h>
//Valid path separator for ZKVTree
#ifndef ZKVTREE_PATH_SEPARATOR
#define ZKVTREE_PATH_SEPARATOR '.'
#endif
//Default number of nodes preallocated
#ifndef ZKVTREE_NODE_COUNT
#define ZKVTREE_NODE_COUNT (128)
#endif
//Invalid characters for a path ([] valid on subscript only)
#define ZKVTREE_INVALID_PATH_CHARS "%[]"
/*
ZKVTree class.
*/
class ZKVTree
{
public:
//KVTree node structure
struct Node
{
ZString Name; //Name of the node
ZString Value; //Value held by this node
Node* ParentNode; //Pointer to our parent node
size_t Index; //Index of this node in the parent's children array
ZArray< Node* > Children; //Children of this node
//Determines if this is the root node
bool IsRootNode() const {
if (ParentNode == NULL) {
return true;
} else return false;
}
//Finds the node with the given name in the child array
Node* GetChildByName(const ZString& _name, size_t _start, size_t _end, size_t _subscript) const {
for (size_t i = 0; i < Children.Size(); i++) {
Node* child = Children.Data()[i];
if (child->Name.Length() == (_end - _start)) {
if (ZStringAlgo::Equal(child->Name, 0, child->Name.Length(), _name, _start, _end)) {
if (_subscript-- == 0) {
return child;
}
}
}
}
return NULL;
}
//Finds the number of children with the given name
size_t GetChildCountByName(const ZString& _name, size_t _start, size_t _end) const {
size_t num = 0;
for (size_t i = 0; i < Children.Size(); i++) {
Node* child = Children.Data()[i];
if (child->Name.Length() == (_end - _start)) {
if (ZStringAlgo::Equal(child->Name, 0, child->Name.Length(), _name, _start, _end)) {
num++;
}
}
}
return num;
}
//Finds the index of the last occurrence of a node with the given name
size_t GetLastIndexByName(const ZString& _name, size_t _start, size_t _end) const {
size_t idx = 0;
for (size_t i = 0; i < Children.Size(); i++) {
Node* child = Children.Data()[i];
if (child->Name.Length() == (_end - _start)) {
if (ZStringAlgo::Equal(child->Name, 0, child->Name.Length(), _name, _start, _end)) {
idx = i;
}
}
}
return idx;
}
//Gets the path to this node
void GetPath(ZString& _out, Node* _end = NULL) const {
if (this != _end && ParentNode != NULL) {
ParentNode->GetPath(_out, _end);
} else return;
if (!_out.Empty()) {
_out.PushBack(ZKVTREE_PATH_SEPARATOR);
}
if (!IsRootNode()) {
size_t siblings = ParentNode->GetChildCountByName(Name, 0, Name.Length());
size_t last_idx = ParentNode->GetLastIndexByName(Name, 0, Name.Length());
_out += Name;
if (ParentNode != _end) {
ZString subscript;
ZStringAlgo::BuildPrintf(subscript, "[%i]", siblings - (1 + last_idx - Index));
_out += subscript;
}
}
}
// gets the simple path to this node (avoids [0] subscript)
void GetSimplePath(ZString& _out, Node* _end = NULL) const {
if (this != _end && ParentNode != NULL) {
ParentNode->GetSimplePath(_out, _end);
} else return;
if (!_out.Empty()) {
_out.PushBack(ZKVTREE_PATH_SEPARATOR);
}
if (!IsRootNode()) {
size_t siblings = ParentNode->GetChildCountByName(Name, 0, Name.Length());
size_t last_idx = ParentNode->GetLastIndexByName(Name, 0, Name.Length());
_out += Name;
if (ParentNode != _end && siblings - (1 + last_idx - Index) != 0) {
ZString subscript;
ZStringAlgo::BuildPrintf(subscript, "[%i]", siblings - (1 + last_idx - Index));
_out += subscript;
}
}
}
};
/*
KVTree iterator, used to directly iterate the nodes in the KVTree.
*/
class Iterator
{
friend class ZKVTree;
public:
/*
Parameterized Constructor.
@param _node - the node to start the iterator at
@param _tree - the KVTree we are iterating (reference needed for locking / unlocking)
*/
Iterator(Node* _node, ZKVTree* _tree)
: CurrentNode(_node), KVTree(_tree) { }
/*
Copy Constructor.
@param _other - the other iterator
*/
Iterator(const Iterator& _other)
:CurrentNode(_other.CurrentNode), KVTree(_other.KVTree) { }
/*
Destructor. Releases the lock (when 'Lock' is destructed).
*/
~Iterator() { }
/*
Gets the path to the current iterator location.
@return (ZString) - path to this node
*/
ZString GetPath() const
{ ZString path; CurrentNode->GetPath(path); return path; }
/*
Gets the path to the current iterator from an end node. If the end node
is not on the parent path, functionally equivalent to GetPath.
@param _end - node we should get path from
@return (ZString) - path to this node from provided node
*/
ZString GetPath(Iterator end) const
{ ZString path; CurrentNode->GetPath(path, end.CurrentNode); return path; }
/*
As GetPath, but avoids the [0] subscript.
@return (ZString) - path to this node
*/
ZString GetSimplePath() const
{ ZString path; CurrentNode->GetSimplePath(path); return path; }
/*
As GetPath, but avoids the [0] subscript.
@param _end - node we should get path from
@return (ZString) - path to this node from provided node
*/
ZString GetSimplePath(Iterator end) const
{ ZString path; CurrentNode->GetSimplePath(path, end.CurrentNode); return path; }
/*
Gets a reference to the name of the current node.
@return (const ZString&) - reference to the name of the current node
*/
const ZString& GetName() const
{ ZASSERT(!CurrentNode->IsRootNode(), "Cannot get name on root node!"); return CurrentNode->Name; }
/*
Gets a reference to the value of the current node.
@return (ZString&) - reference to the value of the current node
*/
const ZString& GetValue() const
{ ZASSERT(!CurrentNode->IsRootNode(), "Cannot get value on root node!"); return CurrentNode->Value; }
/*
Gets the index of the current node (sibling index).
@return (size_t) - the index of the current node.
*/
size_t GetIndex() const
{ return CurrentNode->Index; }
/*
Gets the number of children contained by this node.
*/
size_t GetChildCount() const
{ return CurrentNode->Children.Size(); }
/*
Gets the number of children of this node with the given name.
*/
size_t GetChildCountByName(const ZString& _name) const
{ return CurrentNode->GetChildCountByName(_name, 0, _name.Length()); }
/*
Gets the index of the nth child of the given name (ZSTL::InvalidPos if not found).
*/
size_t GetChildIndexByName(const ZString& _name, size_t _n = 0) const
{
Node* childNode = CurrentNode->GetChildByName(_name, 0, _name.Length(), _n);
return (childNode == NULL ? ZSTL::InvalidPos : childNode->Index);
}
/*
Gets the number of siblings to the current node, including the current node.
*/
size_t GetSiblingCount() const
{
if (CurrentNode->ParentNode == NULL)
return 0;
return CurrentNode->ParentNode->Children.Size();
}
/*
Gets the number of siblings to the current node with the given name (can
include this node if name is equivalent).
*/
size_t GetSiblingCountByName(const ZString& _name) const
{
if (CurrentNode->ParentNode == NULL)
return 0;
return CurrentNode->ParentNode->GetChildCountByName(_name, 0, _name.Length());
}
/*
Gets the index of the nth sibling of the given name (ZSTL::InvalidPos if not found, can
be the node this iterator points to).
*/
size_t GetSiblingIndexByName(const ZString& _name, size_t _n = 0) const
{
if (CurrentNode->ParentNode == NULL)
return ZSTL::InvalidPos;
Node* siblingNode = CurrentNode->ParentNode->GetChildByName(_name, 0, _name.Length(), _n);
return (siblingNode == NULL ? ZSTL::InvalidPos : siblingNode->Index);
}
//Checks to see if this is an end node
bool CheckEnd()
{ return CurrentNode->IsRootNode(); }
//Checks to see if we can move to the parent node
bool CheckParent()
{ return CurrentNode->ParentNode != NULL; }
//Checks to see if we can move to the child node
bool CheckChild(size_t _index = 0)
{ return _index < CurrentNode->Children.Size(); }
//Checks to see if we can move to the sibling node
bool CheckSibling(size_t _index = 0)
{ return CurrentNode->ParentNode != NULL && _index < CurrentNode->ParentNode->Children.Size() - 1; }
//Checks to see if we can move to the next sibling node
bool CheckNextSibling()
{ return CurrentNode->ParentNode != NULL && CurrentNode->Index < CurrentNode->ParentNode->Children.Size() - 1; }
//Checks to see if we can move to the previous sibling node
bool CheckPrevSibling()
{ return CurrentNode->Index > 0; }
/*
Sets the value of the current node.
@param (ZString&) - value to set this node to
*/
void SetValue(const ZString& _value)
{ CurrentNode->Value = _value; }
/*
public ZKVTree::Iterator::Next
This operation attempts to move this iterator to the first child of this node. If this
is an invalid move, then it attempts to iterate to the next sibling. If this is invalid,
it will attempt to iterate to the next sibling of the parent, and will continue to
attempt this until it has either reached the end or it can do so.
This basically means using nothing but 'Next' from beginning to end will result in
a depth-first traversal of the KVTree.
@return (Iterator&) - this iterator
*/
Iterator& Next()
{
if (CheckChild())
Child();
else if (CheckNextSibling())
NextSibling();
else {
while (CurrentNode->ParentNode != NULL) {
if (CheckParent()) {
Parent();
if (CheckNextSibling()) {
NextSibling();
break;
}
}
}
}
return *this;
}
/*
public ZKVTree::Iterator::Parent
This operation attempts to move the iterator to the parent node of this node.
@return (Iterator&) - this iterator
*/
Iterator& Parent()
{
if (CheckParent()) {
CurrentNode = CurrentNode->ParentNode;
} else *this = KVTree->End();
return *this;
}
/*
public ZKVTree::Iterator::Child
This operation moves the iterator to child node at the given index.
@param _index - the child number to move to
@return (Iterator&) - this iterator
*/
Iterator& Child(size_t _index = 0)
{
if (CheckChild(_index)) {
CurrentNode = CurrentNode->Children[_index];
} else *this = KVTree->End();
return *this;
}
/*
public ZKVTree::Iterator::Sibling
This operation moves the iterator to the sibling node at the given index.
@param _index - the sibling index
@return (Iterator&) - this iterator
*/
Iterator& Sibling(size_t _index = 0)
{
ZASSERT(CheckSibling(_index), "ZKVTree::Iterator unable to move to sibling node!");
if (CheckSibling(_index)) {
CurrentNode = CurrentNode->ParentNode->Children[_index];
} else *this = KVTree->End();
return *this;
}
/*
public ZKVTree::Iterator::PrevSibling
This operation moves the iterator to the previous sibling node of this node.
@return (Iterator&) - this iterator
*/
Iterator& PrevSibling()
{
if (CheckPrevSibling()) {
CurrentNode = CurrentNode->ParentNode->Children[CurrentNode->Index - 1];
} else *this = KVTree->End();
return *this;
}
/*
public ZKVTree::Iterator::NextSibling
This operation moves the iterator to the next sibling node of this node.
@return (Iterator&) - this iterator
*/
Iterator& NextSibling()
{
if (CheckNextSibling()) {
CurrentNode = CurrentNode->ParentNode->Children[CurrentNode->Index + 1];
} else *this = KVTree->End();
return *this;
}
/*
public ZKVTree::Iterator::ParentItr
This operation returns an iterator to the parent node.
@return (ZKVTree::Iterator) - iterator to the parent node
*/
Iterator ParentItr() const
{
ZASSERT(CurrentNode->ParentNode != NULL, "Unable to get KVTree parent!");
return Iterator(CurrentNode->ParentNode, KVTree);
}
/*
public ZKVTree::Iterator::ChildItr
This operation returns an iterator to the first child node of this iterator,
or the end iterator if no child is found.
@param _index - the child node index to get an iterator to
@return (Iterator) - iterator to the child node
*/
Iterator ChildItr() const
{
return ChildItr(0);
}
/*
public ZKVTree::Iterator::ChildItr
This operation returns an iterator to the child node at the given index.
@param _index - the child node index to get an iterator to
@return (Iterator) - iterator to the child node
*/
Iterator ChildItr(size_t _index) const
{
if (_index == ZSTL::InvalidPos || _index >= CurrentNode->Children.Size()) {
return KVTree->End();
} else return Iterator(CurrentNode->Children.Data()[_index], KVTree);
}
/*
public ZKVTree::Iterator::ChildItr
This returns an iterator to the nth child of the given name.
@param _name - the name of the child to get an iterator to
@param _n - the occurrence of the child to get (0 = first occurrence)
@return (Iterator) - iterator to the child node
*/
Iterator ChildItr(const ZString& name, size_t _n = 0) const
{
return ChildItr(GetChildIndexByName(name, _n));
}
/*
public ZKVTree::Iterator::GetSibling
This operation returns an iterator to the sibling node at the given index.
@param _index - the child node index to get an iterator to
@return (Iterator) - iterator to the child node
*/
Iterator SiblingItr(size_t _index) const
{
if (_index == ZSTL::InvalidPos || _index >= CurrentNode->ParentNode->Children.Size()) {
return KVTree->End();
} else return Iterator(CurrentNode->ParentNode->Children.Data()[_index], KVTree);
}
/*
public ZKVTree::Iterator::GetSibling
This operation returns an iterator to the nth sibling of the given name.
@param _name - the name of the sibling to get an iterator to
@param _n - the occurrence of the sibling to get (0 = first occurrence)
@return (Iterator) - iterator to the sibling node
*/
Iterator SiblingItr(const ZString& name, size_t _n = 0) const
{
return SiblingItr(GetSiblingIndexByName(name, _n));
}
//Operator Overloads
Iterator& operator ++ () { return Next(); }
Iterator operator ++ (int) { Iterator itr = *this; Next(); return itr; }
Iterator& operator = (const Iterator& _other) { CurrentNode = _other.CurrentNode; KVTree = _other.KVTree; return *this; }
bool operator == (const Iterator& _other) const { return CurrentNode == _other.CurrentNode; }
bool operator != (const Iterator& _other) const { return !(*this == _other); }
private:
Node* CurrentNode; //Our current KVTree node
ZKVTree* KVTree; //The KVTree we are iterating
};
/*
Constructor.
*/
ZKVTree();
/*
Copy Constructor.
*/
ZKVTree(const ZKVTree& _other);
/*
Destructor.
*/
~ZKVTree();
/*
= operator. Performs a copy of node names and data.
@param _other - the KVTree to copy from
*/
ZKVTree& operator = (const ZKVTree& _other);
/*
public ZKVTree::Add
Adds a node to the tree under the given parent node. The version that takes no parent path
will add the child under the root node. The iterator returned is used to directly address the
node.
The two parameter version of this function adds children to the root node.
@param _parent - the path to the parent node
@param _itr - iterator to the parent node
@param _name - the name of the child node
@param _value - the value of the child node
@return (Iterator) - iterator to the created node
*/
Iterator Add(const ZString& _name, const ZString& _value);
Iterator Add(const ZString& _parent, const ZString& _name, const ZString& _value);
Iterator Add(const Iterator& _itr, const ZString& _name, const ZString& _value);
/*
public ZKVTree::Begin
Gets a ZKVTree::Iterator to the first child of the root node of this KVTree. If there
are no children, returns ZKVTree::End().
@return (ZKVTree::Iterator) - iterator to the beginning of the KVTree (first child node)
*/
Iterator Begin() const;
/*
public ZKVTree::Clear
Clears the KVTree of all values.
@return (void)
*/
void Clear();
/*
public ZKVTree::End
Gets a ZKVTree::Iterator to the end of the KVTree.
@return (ZKVTree::Iterator) - iterator to the end of the KVTree
*/
const Iterator End() const;
/*
public ZKVTree::Erase
Erases the node at the given position and all children.
@param _path - the path to the node
@param _itr - iterator to the node (invalidated by this call)
@return (void)
*/
void Erase(const ZString& _path);
void Erase(const Iterator& _itr);
/*
public ZKVTree::Find
Gets a ZKVTree::Iterator to the given element if found. Returns an iterator
equivalent to ZKVTree::End() if not found.
@param _path - path to the node to get an iterator to
@param _itr - parent iterator to search from (path will be searched from this node as root)
@return (ZKVTree::Iterator) - iterator to value if found, End() otherwise
*/
Iterator Find(const ZString& _path) const;
Iterator Find(const Iterator& _itr, const ZString& _path) const;
/*
public ZKVTree::Get
Gets a value from the KVTree that held by the node at the provided path.
@param _path - the path to the node to get the value from (if no subscript, [0] is assumed)
@return (const ZString&) - reference to the value held by the node at the provided path
@assert - if no value exists at the provided path
*/
const ZString& Get(const ZString& _path) const;
const ZString& Get(const Iterator& _itr, const ZString& _path);
/*
public ZKVTree::Merge
Merges this KVTree with another, bringing in the values defined in the other
KVTree.
@param _other - the KVTree to merge values from
@param _overwrite - if true, values will be overwritten when a conflict occurs
@return (void)
*/
void Merge(const ZKVTree& _other, bool _overwrite);
/*
public ZKVTree::Put
Puts a node with the given value into the KVTree at the provided path. Will overwrite
any existing value at that location.
If the path string has a child node that does not exist, it will be created so long as the
subscript is for the next child node, i.e., if A.B.c[1] is passed in, it will be created so
long as A.B.c[0] exists.
The iterator version overwrites the data at that location if the iterator was created by this
tree, and will attempt to create it as above if not from this tree.
@param _path - the path to the KVTree value (if no index, [0] is assumed)
@param _itr - iterator to the node to assign the value to (will overwrite)
@param _value - the value to assign to the node
@return (Iterator) - iterator to the created value
*/
Iterator Put(const ZString& _key, const ZString& _value);
Iterator Put(const Iterator& _itr, const ZString& _value);
/*
public ZKVTree::IsValidKeyName
Checks that a key name is able to be put into the KVTree.
This basically ensures that a key will be valid for use in pathing.
A valid key name doesn't contain whitespace, square brackets, or periods.
@param _name - the name being considered for validity.
@return (bool) - true if the keyname would be valid in a path, false otherwise
*/
bool IsValidKeyName( const ZString& _key ) const;
protected:
ZSlabAllocator<Node, ZKVTREE_NODE_COUNT> NodeAllocator;
Node RootNode; // The root node of the KVTree (also acts as the end node)
//Gets a node from the KVTree given a path (NULL if not found)
Node* GetFromPath(const ZString& _path) const;
//Creates all the nodes needed along a path to be able to get and set the value, returning the node
Node* CreatePath(const ZString& _path);
//Helper function used to check in all nodes
void NodeCheckIn(Node* _node);
};
#endif

269
Include/ZUtil/ZLog.hpp Normal file
View File

@@ -0,0 +1,269 @@
/*
ZLog.hpp
Author: James Russell
Purpose:
Logging utility. The logging class cannot be instantiated, but instead is utilized through
static public method calls. The logging system must be initialized before use and can be
shutdown at any time. Any logging calls placed after the system has been shutdown amount
to a no-op.
The logging system is thread-safe.
License:
TODO
*/
#ifndef _ZLOG_HPP
#define _ZLOG_HPP
#include <ZSTL/ZPair.hpp>
#include <ZSTL/ZString.hpp>
#include <ZUtil/ZMutex.hpp>
#include <ZUtil/ZSmartPointer.hpp>
#include <iostream>
#include <fstream>
//Typedef to define a log file handle
typedef size_t ZLogFile;
//Logging type enumeration used to specify which level of log is being performed
enum ZLogType
{
LOG_ERROR, //Used when an error condition has occurred
LOG_WARNING, //Used when a recoverable error condition has occurred
LOG_INFO, //Used when significant events have occurred
LOG_SPAM, //Used for insignificant events and process flow notification
LOG_SIZE
};
//Overall Logging Levels
#define ZLOG_LEVEL_NONE 0
#define ZLOG_LEVEL_ERROR 1
#define ZLOG_LEVEL_WARNING 2
#define ZLOG_LEVEL_INFO 3
#define ZLOG_LEVEL_SPAM 4
//If the log level is not defined by the user, then ensure all logging is handled
#ifndef ZLOG_LEVEL
#define ZLOG_LEVEL ZLOG_LEVEL_SPAM
#endif
//Define used to enumerate the default log file
#define ZLOGFILE_DEFAULT 0
#if defined(_MSC_VER) || defined(__GNUC__) || defined(__SUNPRO_CC) //C99 style variadic macros
#define SystemLogError(...) ZLog::Printf(LOG_ERROR, ZLOGFILE_DEFAULT, 0, 0, __FUNCTION__, __VA_ARGS__)
#define SystemLogWarning(...) ZLog::Printf(LOG_WARNING, ZLOGFILE_DEFAULT, 0, 0, __FUNCTION__, __VA_ARGS__)
#define SystemLogInfo(...) ZLog::Printf(LOG_INFO, ZLOGFILE_DEFAULT, 0, 0, __FUNCTION__, __VA_ARGS__)
#define SystemLogSpam(...) ZLog::Printf(LOG_SPAM, ZLOGFILE_DEFAULT, 0, 0, __FUNCTION__, __VA_ARGS__)
#if ZLOG_LEVEL < ZLOG_LEVEL_SPAM
#undef SystemLogSpam
#define SystemLogSpam(...)
#endif
#if ZLOG_LEVEL < ZLOG_LEVEL_INFO
#undef SystemLogInfo
#define SystemLogInfo(...)
#endif
#if ZLOG_LEVEL < ZLOG_LEVEL_WARNING
#undef SystemLogWarning
#define SystemLogWarning(...)
#endif
#if ZLOG_LEVEL < ZLOG_LEVEL_ERROR
#undef SystemLogError
#define SystemLogError(...)
#endif
#if (ZLOG_LEVEL < ZLOG_LEVEL_NONE) || (ZLOG_LEVEL > ZLOG_LEVEL_SPAM)
#error ZLOG_LEVEL Set to Invalid Value!
#endif
#else //Not C99-style variadic macro
#error Define variadic macro flavor for your compiler in ZLog.hpp
#endif
/*
Logging delegate. Called when a log entry has been made.
*/
class ZLogDelegate
{
public:
virtual ~ZLogDelegate() { }
/*
virtual public ZLogDelegate::Execute
Delegate execute method. This is called whenever a logging entry has been made.
@param _type - the type of logging entry
@param _file - the log file written to
@param _logEntry - the logging entry made
@return (void)
*/
virtual void Execute(ZLogType _type, ZLogFile _file, const ZString& _logEntry) = 0;
};
/*
ZEngine logging class.
*/
class ZLog
{
private:
//Mutex for logging system
static ZMutex LogLock;
//Boolean indicating the logging system is activated
static bool bIsInitialized;
//Array of logging output streams (second pair parameter indicates active / suspended)
static ZArray< ZPair<std::ofstream*, bool> > LogFiles;
//Array of logging delegates
static ZArray< ZPtr<ZLogDelegate> > Delegates;
//Root path for logging
static ZString LogFileRoot;
//Maintained Tick Count
static uint64_t *UserTick;
//Maintained Update Frame Count
static uint64_t *UserUpdate;
//Tick Estimate when NULL is passed in as Tick
static uint64_t TickEstimate;
//Update Frame estimate when NULL is passed in as Update tick
static uint64_t UpdateFrameEstimate;
//Private Constructor
ZLog() { }
//Private Copy Constructor
ZLog(const ZLog& _other) { URFP(_other); }
//Private Destructor
~ZLog() { }
public:
/////////////////////////////////
/* Initialization and Shutdown */
/////////////////////////////////
/*
static public ZFileSystem::Init
Initialization method for ZLog. Until this is called, all logging calls return immediately.
@param _logFileRoot - the directory to place log files in
@param _defaultLogFile - log file name for the 'default' log file (NULL log file)
@param _ticks - pointer to a value that will be updated with tick count (NULL to use parameter value only)
@param _update - pointer to a value that will be updated with update frame count (NULL to use parameter value only)
@return (void)
*/
static void Init(const ZString& _logFileRoot, const ZString& _defaultLogFile, uint64_t* _ticks = NULL, uint64_t* _update = NULL);
/*
static public ZFileSystem::Shutdown
Shutdown method for ZLog. Closes out the opened log files and flushes the output buffers. After
this is called, all logging operations return immediately.
@return (void)
*/
static void Shutdown();
///////////////////////////////
/* Logging System Operations */
///////////////////////////////
/*
static public ZFileSystem::AddLoggingDelegate
Adds a logging delegate to the system which is called whenever logging takes
place.
@param _delegate - the logging delegate to call when logging takes place
@return (void)
*/
static void AddLoggingDelegate(ZPtr<ZLogDelegate> _delegate);
/*
static public ZFileSystem::CreateLogFile
Creates a log file for use in the system.
@param _fileName - the name to use for the log file
@return (ZLOG_FILE) - the created log file (will be NULL if could not create)
*/
static ZLogFile CreateLogFile(const ZString& _fileName);
/*
public static ZLog::Resume
Resumes logging operations on a given log file.
@param _logFile - the file to suspend logging operations on
@return (void)
*/
static void Resume(ZLogFile _logFile);
/*
public static ZLog::SuspendLogging
Suspends logging operations on a given log file.
@param _logFile - the file to suspend logging operations on
@return (void)
*/
static void Suspend(ZLogFile _logFile);
/////////////////////
/* Logging Methods */
/////////////////////
/*
static public ZFileSystem::Printf
Varardic logging function, which writes the given string out to the log file. This version takes varargs in the
same way as printf. This logging function has a limit on the length of the output string of 4096 characters - excess
characters will be truncated.
@param _type - the logging type
@param _file - the file to write to (if ZLOG_DEFAULT, uses the default file)
@param _ticks - the tick count at which the log file is written
@param _updateFrame - the update 'frame' during which the log is written
@param _str - the string to write to the log file
@param ... - the variable arguments to provide to format _str
@param args - parsed va_list
@return (void)
*/
static void Printf(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char *_function, const char *_str, ...);
/*
static public ZFileSystem::WriteLine
Writes a string out to the given log file.
@param _type - the logging type
@param _file - the file to write to (if ZLOG_DEFAULT, uses the default file)
@param _ticks - the tick count at which the log file is written
@param _updateFrame - the update 'frame' during which the log is written
@param _renderFrame - the render 'frame' during which the log is written
@param _str - the string to write to the log file
@return (void)
*/
static void WriteLine(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char* _str);
};
#endif

91
Include/ZUtil/ZMutex.hpp Normal file
View File

@@ -0,0 +1,91 @@
/*
ZMutex.hpp
Author: James Russell <jcrussell@762studios.com>
Purpose: RAII Wrapper for libsst-concurrency SST_Mutex objects.
Changelog
2011/11/27 - creation (jcrussell)
*/
#pragma once
#ifndef _ZMUTEX_H
#define _ZMUTEX_H
#include <ZUtil/ZUtilBuild.hpp>
#include <SST/SST_Mutex.h>
/*
ZMutex class. Used to allocate and deallocate a mutex within the scope of a class.
Cannot be copied or assigned, which prevents it from being used in stl-like containers.
*/
class ZMutex
{
private:
DISABLE_COPY_AND_ASSIGN(ZMutex);
//libsst Mutex
SST_Mutex Mutex;
public:
/*
Constructor. Creates a mutex from libsst-concurrency.
*/
ZMutex();
/*
Destructor. Frees our mutex from libsst-concurrency.
*/
~ZMutex();
/*
public ZLock::Acquire
Acquires this lock, which locks the contained mutex.
@return (void)
@context (all)
*/
void Acquire();
/*
public ZLock::Release
Releases this lock, which unlocks the contained mutex.
@return (void)
@context (all)
*/
void Release();
};
/*
Scoped lock. Acquires the provided lock so long as it remains in scope. Releases the lock when
it goes out of scope.
*/
class ZLock
{
private:
DISABLE_COPY_AND_ASSIGN(ZLock);
//The Mutex
ZMutex& Mutex;
public:
/*
Constructor. Acquires the mutex during construction.
@param _mutex - the mutex we are to acquire
*/
ZLock(ZMutex& _lock);
/*
Destructor. Releases the mutex when the object is destructed (goes out of scope).
*/
~ZLock();
};
#endif

172
Include/ZUtil/ZName.hpp Normal file
View File

@@ -0,0 +1,172 @@
/*
ZName.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 4/6/2011
Purpose:
'Name' implementation, which is a bit like a ZBasicString but remains constant after
construction. This allows for fast comparison and copy.
In addition this allows the name to be compared to a hash of the name and determine equality.
License:
TODO
*/
#ifndef _ZNAME_H
#define _ZNAME_H
#include <ZSTL/ZString.hpp>
#include <ZUtil/ZUtilBuild.hpp>
//This is the maximum allowed length of a name
#ifndef ZNAME_MAX_LENGTH
#define ZNAME_MAX_LENGTH (128)
#endif
/*
ZName Implementation.
*/
class ZName
{
private:
//The string
char String[ZNAME_MAX_LENGTH + 1];
//Length of the string
size_t Length;
//Hash of the string
uint64_t Hash;
public:
/*
Constructor.
*/
ZName();
/*
Parameterized constructor.
@param _string - the string name (null terminated)
*/
ZName(const char *_string);
/*
Parameterized constructor.
@param _string - the string name
*/
explicit ZName(const ZString& _string);
/*
Parameterized constructor that takes the pre-computed hash value
for the name. When a ZName is constructed in this fashion, the
ToString() function will return '<precomputed>'.
@param _hash - the precomputed hash value for this string
*/
ZName(uint64_t _hash);
/*
Copy Constructor.
@param _other - the other name
*/
ZName(const ZName& _other);
/*
Destructor.
*/
~ZName();
/*
= operator overload, that assigns this name to be another.
@param _other - the name to assign this to
@return - this name
*/
ZName& operator = (const ZName& _other);
/*
= operator overload, that assigns this name to be a string.
@param _string - the string to create this name from
@return - this name
*/
ZName& operator = (const ZString& _string);
/*
= operator overload, that assigns this name to be equal to a C-style string.
@param _string - the string to create this name from
@return - this name
*/
ZName& operator = (const char* _string);
/*
== operator. Because names are constant, this is a fast comparison.
@param _other - the name to compare this to
@return - true if equal, false otherwise
*/
bool operator == (const ZName& _other) const;
/*
== operator for comparison with strings. Less fast.
@param _other - the string to compare this to
@return - true if equal, false otherwise
*/
bool operator == (const ZString& _other) const;
/*
== operator. Compares a name against hash value only.
@param hash - the hash value to compare
@return - true if equivalent hashes, false otherwise
*/
bool operator == (const ZHashValue hash) const;
/*
!= operator. Because names are constant, this is a fast comparison.
@param _other - the name to compare this to
@return (bool) - true if not equal, false otherwise
*/
bool operator != (const ZName& _other) const;
/*
Hash code override. Returns the (pre-computed) hash code.
@return - hash code for this name
*/
operator ZHashValue () const;
/*
Returns this name as a string.
@return (ZString) - this name as a ZString
*/
operator ZString () const;
/*
Gets this name as a string.
@return (ZString) - this name as a ZString
*/
ZString ToString() const;
/*
Returns the string data for this name.
@return (char*) - string data
*/
const char* Data() const;
};
#endif

79
Include/ZUtil/ZNoise.hpp Normal file
View File

@@ -0,0 +1,79 @@
/*
ZNoise.hpp
Author : Chris Ertel
Purpose : Interface class to call noise generation functions.
Changelog
2/13/11 - Creation (crertel)
*/
#ifndef _ZNOISE_H
#define _ZNOISE_H
#include <ZUtil/ZUtilBuild.hpp>
class ZNoise
{
public:
virtual ~ZNoise() {}
/*
virtual public ZNoise::reseed
Function to set seed for the noise generator.
@param _seed - int to seed the noise with.
@return (void)
*/
virtual void reseed (const int _seed) = 0;
/*
virtual public ZNoise::noise1
Function for getting 1D noise.
@param _x - float x coord
@return (float) - value of noise at x
*/
virtual float noise1(const float _x) = 0;
/*
virtual public ZNoise::noise2
Function for getting 2D noise.
@param _x - float x coord
@param _y - float y coord
@return (float) - value of noise at (x,y)
*/
virtual float noise2(const float _x, const float _y) = 0;
/*
virtual public ZNoise::noise3
Function for getting 3D noise.
@param _x - float x coord
@param _y - float y coord
@param _z - float z coord
@return (float) - value of noise at (x,y,z)
*/
virtual float noise3(const float _x, const float _y, const float _z) = 0;
/*
virtual public ZNoise::noise4
Function for getting 4D noise.
@param _x - float x coord
@param _y - float y coord
@param _z - float z coord
@param _w - float w coord
@return (float) - value of noise at (x,y,z,w)
*/
virtual float noise4(const float _x, const float _y, const float _z, const float _w) = 0;
};
#endif

185
Include/ZUtil/ZNoiseMap.hpp Normal file
View File

@@ -0,0 +1,185 @@
/*
ZNoiseMap.hpp
Author : Chris Ertel
Purpose : Interface to create a map for noise values.
Changelog
2/13/11 - Creation (crertel)
2/20/11 - Changed interface to be useful. (crertel)
*/
#ifndef _ZNOISEMAP_H
#define _ZNOISEMAP_H
#include <ZUtil/ZSimplexNoise.hpp>
class ZNoiseMap
{
public:
virtual ~ZNoiseMap() {}
/*
virtual public ZNoiseMap::GetDimensionality
Gets dimension of noise map (1,2,etc.).
@return (int) - dimension of noise map
*/
virtual int GetDimensionality() = 0;
/*
virtual public ZNoiseMap::GetLacunarity
Get lacunarity (scaling of successive frequencies in noise series).
@return (float) - lacunarity of noise map
*/
virtual float GetLacunarity() = 0; // scaling of successive frequencies in noise octaves
/*
virtual public ZNoiseMap::GetPersistence
Get persistence (scaling of successive amplitudes in noise series).
@return (float)
*/
virtual float GetPersistence() = 0; // scaling of successive amplitudes in noise octaves
/*
virtual public ZNoiseMap::GetNumberOfOctaves
Get number of octaves in noise series.
@return (int) - number of terms in noise series.
*/
virtual int GetNumberOfOctaves() = 0;
/*
virtual public ZNoiseMap::GetNumberSamplesInX
Get number of samples in X dimensions of noise map.
@return (int) - number of samples in X.
*/
virtual int GetNumberSamplesInX() = 0;
/*
virtual public ZNoiseMap::GetNumberSamplesInY
Get number of samples in Y dimensions of noise map.
@return (int) - number of samples in Y.
*/
virtual int GetNumberSamplesInY() = 0;
/*
virtual public ZNoiseMap::GetNumberSamplesInZ
Get number of samples in Z dimensions of noise map.
@return (int) - number of samples in Z.
*/
virtual int GetNumberSamplesInZ() = 0;
/*
virtual public ZNoiseMap::GetNumberSamplesInW
Get number of samples in Z dimensions of noise map.
@return (int) - number of samples in W.
*/
virtual int GetNumberSamplesInW() = 0;
/*
virtual public ZNoiseMap::SetLacunarity
Sets the lacunarity (scaling of successive frequencies in noise series).
@param _lac - lacunarity to use.
@return (void)
*/
virtual void SetLacunarity(float _lac) = 0; // scaling of successive frequencies in noise octaves
/*
virtual public ZNoiseMap::SetPersistence
Sets the persistence (scaling of successive amplitudes in noise series).
@param _per - persistence to set noise map to.
@return (void)
*/
virtual void SetPersistence(float _per) = 0; // scaling of successive amplitudes in noise octaves
/*
virtual public ZNoiseMap::SetNumberOfOctaves
Set number of octave in noise series.
@param _numOctaves - number of octaves to use.
@return (void)
*/
virtual void SetNumberOfOctaves(int _numOctaves ) = 0;
/*
virtual public ZNoiseMap::SetNumberSamplesInX
Sets number of samples in X direction.
@param _numSamples - number of samples in X direction.
@return (void)
*/
virtual void SetNumberSamplesInX(int _numSamples) = 0;
/*
virtual public ZNoiseMap::SetNumberSamplesInY
Sets number of samples in Y direction.
@param _numSamples - number of samples in Y direction.
@return (void)
*/
virtual void SetNumberSamplesInY(int _numSamples) = 0;
/*
virtual public ZNoiseMap::SetNumberSamplesInZ
Sets number of samples in Z direction.
@param _numSamples - number of samples in Z direction.
@return (void)
*/
virtual void SetNumberSamplesInZ(int _numSamples) = 0;
/*
virtual public ZNoiseMap::SetNumberSamplesInW
Sets number of samples in W direction.
@param _numSamples - number of samples in W direction.
@return (void)
*/
virtual void SetNumberSamplesInW(int _numSamples) = 0;
/*
virtual public ZNoiseMap::Generate
Generates noise map values.
@return (bool) - True if successful, false otherwise.
*/
virtual bool Generate(int _seed) = 0;
/*
virtual public ZNoiseMap::Cleanup
Cleans up resources for noise map.
@return (void)
*/
virtual void Cleanup() = 0;
};
#endif

View File

@@ -0,0 +1,245 @@
/*
ZRandomGeneratorBase.hpp
Author: James Russell <jcrussell@762studios.com>
Purpose:
This is an RAII wrapper class for the libsst-random pseudo-random number generators that
also introduces some extra functionality.
License:
TODO
*/
#pragma once
#ifndef _ZRANDOMGENERATOR_H
#define _ZRANDOMGENERATOR_H
#include <ZUtil/ZUtilBuild.hpp>
#include <SST/SST_PRNG.h>
class ZRandomGenerator
{
private:
DISABLE_COPY_AND_ASSIGN(ZRandomGenerator);
protected:
//Our random generator type
const SST_PRNG_TYPE Type;
//Random Seed
uint32_t Seed;
//Random Sequence
uint64_t Sequence;
//Our SST RNG Instance
SST_PRNG RNG;
public:
/*
Default Constructor.
This constructor will create a random generator that uses type SST_PRNG_SMALLPRNG,
that is seeded with the current time, and starts at sequence 0.
*/
ZRandomGenerator();
/*
Parameterized Constructor.
@param _type - the type of random number generator to create
@param _seed - the seed to create the generator with
@param _sequence - the sequence number to start at
*/
ZRandomGenerator(SST_PRNG_TYPE _type, uint32_t _seed, uint64_t _sequence = 0);
/*
Destructor.
*/
~ZRandomGenerator();
/*
public ZRandomGenerator::GetFloat
Gets next float from random generator in the range [0, 1).
@return (float) - next float from the PRNG
*/
float GetFloat();
/*
public ZRandomGenerator::GetFloatArray
Gets an array of floats from the random generator in the range [0, 1).
@param _array - array to store floats into
@param _count - number of elements in array
@return (void)
*/
void GetFloatArray(float *_array, size_t _count);
/*
public ZRandomGenerator::GetFloatInRange
Gets a float in the range [_min, _max)
@param _min - inclusive lower bound of range.
@param _max - exclusive upper bound of range.
@return (float) - next float in range.
*/
float GetFloatInRange(float _min, float _max);
/*
public ZRandomGenerator::GetFloatArrayInRange
Gets an array of floats in range [_min, _max).
@param _array - array to store floats into
@param _count - number of elements in array
@param _min - inclusive lower bound of range
@param _max - exclusive upper bound of range
@return (void)
*/
void GetFloatArrayInRange(float *_array, size_t _count, float _min, float _max);
/*
public ZRandomGeneratorGenerator::GetInt
Gets an int in the range [STDINT_MIN, STDINT_MAX).
@return (int) - next int from generator
*/
int GetInt();
/*
public ZRandomGenerator::GetIntArray
Gets an array of ints in the range [STDINT_MIN, STDINT_MAX).
@param _array - array to store ints into
@param _count - number of elements in
@return (void)
*/
void GetIntArray(int *_array, size_t _count);
/*
public ZRandomGenerator::GetIntInRange
Gets an int in the range [_min, _max).
@param _min - inclusive lower bound of range
@param _max - exclusive upper bound of range
@return (int) - next int from range
*/
int GetIntInRange(int _min, int _max);
/*
public ZRandomGenerator::GetIntArrayInRange
Gets an array of ints in the range [_min, _max).
@param _array - array to store floats into
@param _count - number of elements in array
@param _min - inclusive lower bound of range
@param _max - exclusive upper bound of range
@return (void)
*/
void GetIntArrayInRange( int *_array, size_t _count, int _min, int _max);
/*
public ZRandomGenerator::GetGaussianFloat
Gets a gaussian-distributed float in the range [_min, _max). This is expected to generate
two random numbers to get the gaussian distributed number, which will increase sequence by two.
@param _min - inclusive lower bound of range
@param _max - exclusive upper bound of range
@return (float) - floating point number in range
*/
float GetGaussianFloat(float _min, float _max);
/*
public ZRandomGenerator::GetGaussianFloatArray
Gets an array of guassian-distributed floats in the range [_min, _max). This is expected to generate
two random numbers to get the gaussian distributed number, which will increase sequence by two.
@param _array - array to store floats into
@param _count - number of elements in array
@param _min - inclusive lower bound of range
@param _max - exclusive upper bound of range
@return (void)
*/
void GetGaussianFloatArray(float *_array, size_t _count, float _min, float _max);
/*
public ZRandomGenerator::GetGaussianInt
Gets a gaussian-distributed int in the range [_min, _max). This is expected to generate
two random numbers to get the gaussian distributed number, which will increase sequence by two.
@param _min - inclusive lower bound of range
@param _max - exclusive upper bound of range
@return (int)
*/
int GetGaussianInt(int _min, int _max);
/*
public ZRandomGenerator::GetGaussianIntArray
Gets an array of gaussian-distributed int in the range [_min, _max). This is expected to generate
two random numbers to get the gaussian distributed number, which will increase sequence by two.
@param _array - array to store ints into
@param _count - number of elements in array
@param _min - inclusive lower bound of range
@param _max - exclusive upper bound of range
@return (void)
*/
void GetGaussianIntArray(int *_array, size_t _count, int _min, int _max);
/*
public ZRandomGenerator::GetSeed
Gets the seed of this random generator.
@return (uint32_t) - PRNG seed
*/
uint32_t GetSeed();
/*
public ZRandomGenerator::GetSequence
Gets the sequence of this random number generator, which is the number of random
numbers that have currently been generated.
@return (uint64_t) - sequence of this random generator
*/
uint64_t GetSequence();
/*
public ZRandomGenerator::SetSequence
Sets the sequence (amount of numbers generated) for this PRNG.
@param _seq - sequence to set this generator to.
@return (void)
*/
void SetSequence(uint64_t _seq);
/*
public ZRandomGenerator::SetSeed
Sets the seed on this PRNG.
@param _seed - 32 bit unsigned integer seed to use
@return (void)
*/
void SetSeed(uint32_t _seed);
};
#endif

View File

@@ -0,0 +1,84 @@
/*
ZReadWriteLock.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 5/17/2012
Purpose:
RAII wrapper for SST_ReadWriteLock from libsst-concurrency.
License:
TODO
*/
#pragma once
#ifndef _ZREADWRITELOCK_HPP
#define _ZREADWRITELOCK_HPP
#include <SST/SST_ReadWriteLock.h>
#include <ZUtil/ZUtilBuild.hpp>
class ZReadWriteLock
{
private:
DISABLE_COPY_AND_ASSIGN(ZReadWriteLock);
//The SST_ReadWriteLock
SST_ReadWriteLock Lock;
public:
/*
Default Constructor.
*/
ZReadWriteLock();
/*
Destructor.
*/
~ZReadWriteLock();
/*
public LockForReading
Locks this read write lock for reading. Blocks until the lock is obtained.
@param ticks - the maximum amount of time to block
@return (bool) - true if the lock was obtained, false otherwise
*/
bool LockForReading(uint32_t ticks) const;
/*
public LockForWriting
Locks this read write lock for writing. Blocks until the lock is obtained.
@param ticks - the maximum amount of time to block
@return (bool) - true if the lock was obtained, false otherwise
*/
bool LockForWriting(uint32_t ticks);
/*
public EndReading
Signals that a read operation has completed.
@return (void)
*/
void EndReading() const;
/*
public EndWriting
Signals that a write operation has completed.
@return (void)
*/
void EndWriting();
};
#endif

View File

@@ -0,0 +1,399 @@
/*
ZReferenceBuffer.hpp
Author: James Russell
Purpose : Acts as a means of storing arbitrary types of values in an array which gives back index-based references to
pointers of those types of values. Handles, internally, the Buffer overflowing and looping back around
the end of the storage array.
Changelog :
2/11/10 - Creation (jcr2)
2/13/10 - Should be working as advertised (jcr)
3/04/10 - NOW working as advertised (jcr)
*/
#ifndef _ZREFERENCEBUFFER_H
#define _ZREFERENCEBUFFER_H
#include <ZUtil/ZAlloc.hpp>
#include <ZUtil/ZAssert.hpp>
#include <ZSTL/ZArray.hpp>
#include <ZSTL/ZList.hpp>
#define ZRB_DEFAULT_BUFFER_SIZE (10)
#define ZRB_INVALID_HANDLE (-1)
typedef int ZReferenceBufferHandle;
template <typename T>
class ZReferenceBuffer
{
protected:
//The Current Index Value (next value to be assigned)
int CurrentIndex;
//The Current Size of the Buffer (Storage Capacity)
int BufferSize;
//The Current Number of Items contained in the Buffer
int ItemCount;
//Indicator array used to indicate which indices of the Buffer are valid
ZArray<int> Indicator;
//Buffer of T* Values
ZArray<T*> Buffer;
//Checks if a given reference is valid
inline bool IsValid(int index);
//Checks if a given reference is invalid
inline bool IsInvalid(int index);
//Sets the Indicator of an index to valid
inline void SetValid(int index);
//Sets the Indicator of an index to invalid
inline void SetInvalid(int index);
public:
/*
Default constructor.
*/
ZReferenceBuffer();
/*
Constructor.
@param _size - The starting size of the reference buffer.
*/
ZReferenceBuffer(int _size);
/*
Constructor.
@param _allocator - the allocator to use for allocations / deallocations in the reference buffer
*/
ZReferenceBuffer(ZArrayAllocator<T> *_allocator);
/*
Constructor.
@param _size - The starting size of the reference buffer.
@param _allocator - the allocator to use for allocations / deallocations in the reference buffer
*/
ZReferenceBuffer( int _size, ZArrayAllocator<T> *_allocator);
/*
Destructor.
*/
~ZReferenceBuffer();
/*
public ZReferenceBuffer::AddItem
Adds the item to the reference Buffer, returning a handle. Resizes the Buffer automatically to
increase the size of the buffer if full.
@param _item - the item to add to the buffer
@return (ZReferenceBufferHandle) - a ZReferenceBufferHandle which can be used to reference item, Will never return NULL.
*/
ZReferenceBufferHandle AddItem(T _item);
/*
public ZReferenceBuffer::GetItem
Gets an item in the Buffer given a reference handle.
@param _ref - the reference handle to the item you wish to get
@return (T&) - the item the handle refers to
*/
T& GetItem(ZReferenceBufferHandle _ref);
/*
public ZReferenceBuffer::SetItem
Attempts to set the reference to map to the provided item. Used for updating references.
@param _ref - a valid reference handle to update. If NULL, will set the null handle, allowing a NULL reference to be valid.
@param _item - the item to update the reference to
@return (T) - the overwritten value that ref pointed to
*/
T SetItem(ZReferenceBufferHandle _ref, T _item);
/*
public ZReferenceBuffer::RemoveItem
Removes an item from the Buffer given a reference handle and invalidates the handle (until reassigned).
@param _ref - the reference handle to the item you wish to remove
@return (T) - the item removed
*/
T RemoveItem(ZReferenceBufferHandle _ref);
/*
public ZReferenceBuffer::Remove
Removes all occurrences of an item from the Buffer given a pointer to the item.
@param _item - the item you wish to remove
@return (void)
*/
void Remove(T _item);
/*
public ZReferenceBuffer::Size
Gets the current size of the buffer.
@return (int) - the size (capacity) of the buffer
*/
int Size();
/*
public ZReferenceBuffer::Count
Returns the number of elements currently stored in the Buffer
@return (int) - the count (number of items) in the buffer
*/
int Count();
/*
public ZReferenceBuffer::Items
Returns a ZList containing the elements of the reference Buffer.
@return (ZList<T>) - a list containing all the values currently in the buffer
*/
ZList<T> Items();
/*
inline public ZReferenceBuffer::IsFull
Returns true if the Buffer is full, false otherwise.
@return (bool) - boolean indicating the buffer is full
*/
inline bool IsFull();
/*
public ZReferenceBuffer::Resize
Resizes the Buffer to store _newSize number of elements. Already existing references remain valid. Returns true
on success, false otherwise. Newsize must be greater than the current size of the reference Buffer.
@param _newSize - the ZNew capacity of the buffer
@return (bool) - boolean indicating success or failure
*/
bool Resize( int _newSize);
};
template <typename T>
ZReferenceBuffer<T>::ZReferenceBuffer( int _size, ZArrayAllocator<T>* _allocator)
: CurrentIndex(1), BufferSize(_size+1), ItemCount(0), Allocator(_allocator)
{
this->Buffer.Resize(BufferSize);
this->Indicator.Resize(this->BufferSize, false);
}
template <typename T>
ZReferenceBuffer<T>::ZReferenceBuffer( int _size)
: CurrentIndex(1), BufferSize(_size+1), ItemCount(0)
{
this->Buffer.Resize(BufferSize);
this->Indicator.Resize(this->BufferSize, false);
}
template <typename T>
ZReferenceBuffer<T>::ZReferenceBuffer(ZArrayAllocator<T>* _allocator)
: CurrentIndex(1), BufferSize(ZRB_DEFAULT_BUFFER_SIZE+1), ItemCount(0), Allocator(_allocator)
{
this->Buffer.Resize(BufferSize);
this->Indicator.Resize(this->BufferSize, false);
}
template <typename T>
ZReferenceBuffer<T>::ZReferenceBuffer()
: CurrentIndex(1), BufferSize(ZRB_DEFAULT_BUFFER_SIZE+1), ItemCount(0)
{
this->Buffer.Resize(BufferSize);
this->Indicator.Resize(this->BufferSize, false);
}
template <typename T>
ZReferenceBuffer<T>::~ZReferenceBuffer()
{
}
template <typename T>
bool ZReferenceBuffer<T>::IsValid(int _index)
{
if (_index >= 0)
return this->Indicator[_index] != 0;
return false;
}
template <typename T>
bool ZReferenceBuffer<T>::IsInvalid(int _index)
{
return !IsValid(_index);
}
template <typename T>
void ZReferenceBuffer<T>::SetValid( int _index)
{
this->Indicator[_index] = 1;
}
template <typename T>
void ZReferenceBuffer<T>::SetInvalid( int _index)
{
this->Indicator[_index] = 0;
}
template <typename T>
ZReferenceBufferHandle ZReferenceBuffer<T>::AddItem(T _item)
{
int startIndex;
int ref;
//CurrentIndex should only be zero if Buffer is full
if (this->CurrentIndex == 0)
return this->CurrentIndex;
ref = startIndex = this->CurrentIndex;
while (this->IsValid(this->CurrentIndex))
{
this->CurrentIndex++;
ref = this->CurrentIndex;
if (this->CurrentIndex == startIndex)
this->Resize(this->BufferSize * 2);
if (this->CurrentIndex >= this->BufferSize)
ref = this->CurrentIndex = 1;
}
if (ref != -1)
{
this->Buffer[ref] = _item;
this->SetValid(ref);
this->ItemCount++;
}
return ref;
}
template <typename T>
T& ZReferenceBuffer<T>::GetItem(ZReferenceBufferHandle _ref)
{
ZASSERT(this->IsValid(_ref), "ERROR: ZReferenceBuffer::GetItemRef passed invalid reference!");
return this->Buffer[_ref];
}
template <typename T>
T ZReferenceBuffer<T>::RemoveItem(ZReferenceBufferHandle _ref)
{
T item;
ZASSERT( this->IsValid(_ref) , "ERROR: ZReferenceBuffer::RemoveItem passed invalid reference!" );
this->ItemCount--;
this->SetInvalid(_ref);
item = this->Buffer[_ref];
return item;
}
template <typename T>
void ZReferenceBuffer<T>::Remove(T _item)
{
for ( int i = 0; i < this->BufferSize; i++)
if (this->Buffer[i] == _item)
this->RemoveItem(i);
}
template <typename T>
T ZReferenceBuffer<T>::SetItem(int _ref, T _item)
{
T ret;
ret = this->Buffer[_ref];
this->Buffer[_ref] = _item;
this->SetValid(_ref);
this->ItemCount++;
return ret;
}
template <typename T>
int ZReferenceBuffer<T>::Size()
{
return this->BufferSize;
}
template <typename T>
int ZReferenceBuffer<T>::Count()
{
return this->ItemCount;
}
template <typename T>
bool ZReferenceBuffer<T>::IsFull()
{
return (!this->CurrentIndex);
}
template <typename T>
bool ZReferenceBuffer<T>::Resize( int _newSize)
{
if (_newSize < this->BufferSize)
return false;
this->BufferSize = _newSize + 1;
ZArray<T*> newBuffer;
newBuffer.Resize(this->BufferSize);
for ( int i = 0; i < this->BufferSize; i++)
newBuffer[i] = this->Buffer[i];
this->Indicator.Resize(this->BufferSize, false);
this->Buffer = newBuffer;
return true;
}
template <typename T>
ZList<T> ZReferenceBuffer<T>::Items()
{
int i;
ZList<T> items;
for (i = 1; i < this->BufferSize; i++)
{
if (this->IsValid(i))
items.PushBack(this->Buffer[i]);
}
return items;
}
#endif

View File

@@ -0,0 +1,243 @@
/*
ZReferenceCounter.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 3/22/2012
Purpose:
Defines a structure that is usually allocated on the heap and will maintain a strong
reference count, a weak reference count, and an integer flag used to signal state. This
reference counter is designed to be thread safe by using atomic operations.
License:
TODO
*/
#pragma once
#ifndef _ZREFERENCECOUNTER_HPP
#define _ZREFERENCECOUNTER_HPP
#include <SST/SST_Atomic.h>
#include <ZUtil/ZUtilBuild.hpp>
#include <ZUtil/ZAssert.hpp>
#include <ZUtil/ZAlloc.hpp>
//The leading (negative) bit is used to indicate deallocation on the State int
#define ZREFCOUNTER_DEALLOC_BIT (0x80000000)
/*
ZReferenceCounter::CombinedCount is a 32-bit integer value containing
2x16-bit integer values -- the strong and weak reference counts. They
are stored as 0xWWWWSSSS, i.e. upper 16 bits are the weak reference
count, and the lower 16 bits are the strong reference count.
Do realize that this limits us to 65565 strong and 65565 weak references
without error conditions. We find this to be an acceptable limit.
*/
//These define how much to shift by to affect the strong/weak counters
#define ZREFCOUNTER_STRONG_SHIFT (0)
#define ZREFCOUNTER_WEAK_SHIFT (16)
//These masks are what we will use to mask the upper half (weak) and lower half (strong) parts
//of the integer reference count
#define ZREFCOUNTER_STRONG_MASK (0xFFFF << ZREFCOUNTER_STRONG_SHIFT)
#define ZREFCOUNTER_WEAK_MASK (0xFFFF << ZREFCOUNTER_WEAK_SHIFT)
//These values are used to add a single weak reference or a single strong reference to the
//reference count
#define ZREFCOUNTER_STRONG_REF (1 << ZREFCOUNTER_STRONG_SHIFT)
#define ZREFCOUNTER_WEAK_REF (1 << ZREFCOUNTER_WEAK_SHIFT)
//These macros extract the strong/weak reference counts respectively from the combined counts
#define ZREFCOUNTER_EXTRACT_STRONG_REF(x) (((x) >> ZREFCOUNTER_STRONG_SHIFT) & 0xFFFF)
#define ZREFCOUNTER_EXTRACT_WEAK_REF(x) (((x) >> ZREFCOUNTER_WEAK_SHIFT) & 0xFFFF)
/*
Reference counting struct. Keeps a reference count to an
object (both strong and weak), and a state signaling integer.
*/
struct ZReferenceCounter
{
/*
Integer we use for keeping track of strong and weak references within the
space of a single native integer. The upper half is used to determine
weak count. The lower half is used to determine strong count. This allows
us to use atomic operations on both the strong reference count and weak
reference count on architectures that do not have a DoubleCAS operation.
Must be unsigned so >> doesn't do arthimetic shift.
*/
volatile uint32_t CombinedCount;
/*
Flag used for signaling object usage state
> 0 - in use (number of users)
0 - not in use
< 0 - ready for deallocation (discounting deallocation bit gives number of users)
*/
volatile int State;
/*
Default constructor.
*/
ZReferenceCounter()
: CombinedCount(0), State(0) { }
/*
Destructor.
*/
~ZReferenceCounter()
{ }
/*
Using atomic operations, will increment the strong reference count.
*/
inline void GainStrongRef()
{
SST_Atomic_Add((volatile int*)&CombinedCount, ZREFCOUNTER_STRONG_REF);
}
/*
Using atomic operations, will increment the weak reference count.
*/
inline void GainWeakRef()
{
SST_Atomic_Add((volatile int*)&CombinedCount, ZREFCOUNTER_WEAK_REF);
}
/*
Gets the current strong reference count.
*/
inline uint32_t GetStrongRefCount()
{
return ZREFCOUNTER_EXTRACT_STRONG_REF(CombinedCount);
}
/*
Gets the current weak reference count.
*/
inline uint32_t GetWeakRefCount()
{
return ZREFCOUNTER_EXTRACT_WEAK_REF(CombinedCount);
}
/*
Using atomic operations, will decrement the strong reference count and
return the number of remaining references, both strong and weak, as part
of the same value.
To get the strong reference count, use ZREFCOUNTER_EXTRACT_STRONG_REF() on the return value.
To get the weak reference count, use ZREFCOUNTER_EXTRACT_WEAK_REF() on the return value.
*/
inline uint32_t LoseStrongRef()
{
return SST_Atomic_AddReturn((volatile int*)&CombinedCount, -ZREFCOUNTER_STRONG_REF);
}
/*
Using atomic operations, will decrement the weak reference count and
return the number of remaining references, both strong and weak, as part
of the same value.
To get the strong reference count, use ZREFCOUNTER_EXTRACT_STRONG_REF() on the return value.
To get the weak reference count, use ZREFCOUNTER_EXTRACT_WEAK_REF() on the return value.
*/
inline uint32_t LoseWeakRef()
{
return SST_Atomic_AddReturn((volatile int*)&CombinedCount, -ZREFCOUNTER_WEAK_REF);
}
/*
Using atomic operations, will set the state flag as 'deallocated' as soon as possible,
which will ensure anyone using 'SignalInUse' will get a 'false' return value.
*/
inline void SignalDeallocateObject()
{
//Check deallocated
if (State & ZREFCOUNTER_DEALLOC_BIT)
return;
//Set high bit
SST_Atomic_Or(&State, ZREFCOUNTER_DEALLOC_BIT);
//Wait logic
while ((State & ~ZREFCOUNTER_DEALLOC_BIT) != 0)
continue;
//State is guaranteed here to be == ZREFCOUNTER_DEALLOC_BIT
}
/*
Using atomic operations, will set the state flag as 'in use'. If unable to set
state flag as 'in use' because the object is deallocated, will return false.
This is important to weak reference holders to signal to strong reference holders that
the object should not be deallocated until the object is no longer in use.
*/
inline bool SignalInUse()
{
//Check deallocated
if (State & ZREFCOUNTER_DEALLOC_BIT)
return false;
int val = SST_Atomic_IncReturn(&State);
if (val & ZREFCOUNTER_DEALLOC_BIT)
{
SST_Atomic_Dec(&State); //Atomic decrement to ensure we don't starve the waiting deallocation thread
return false;
}
else
return true;
}
/*
Using atomic operations, will set the state flag as 'no longer in use'.
*/
inline void SignalUnused()
{
SST_Atomic_Dec(&State);
}
};
/*
Allocator class for ZReferenceCounter. Responsible for heap allocation and deletion of
ZReferenceCounter instances.
*/
class ZReferenceCounterAllocator
{
public:
/*
public ZSmartPointerAllocator::AllocateCounter
Allocation method that allocates a reference counter for use by the smart pointer.
@return (ZSmartPointerRefCounter*)
*/
ZReferenceCounter* AllocateCounter()
{
return znew ZReferenceCounter();
}
/*
public ZSmartPointerAllocator::DeallocateCounter
Deallocates a reference counter that was provided by AllocateCounter.
@param _counter - the counter to deallocate
*/
void DeallocateCounter(ZReferenceCounter* _counter)
{
zdelete _counter;
}
};
#endif

145
Include/ZUtil/ZRegistry.hpp Normal file
View File

@@ -0,0 +1,145 @@
/*
ZRegistry.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 2/18/2013
Purpose:
ZRegistry defines a use case for ZKVTree as a concurrent data store. A ZRegistry
maps keys to values using path strings, just as ZKVTree does, but the path string
must be unique as subscripts are not supported and siblings with the same name
are not supported.
ZRegistry is thread-safe on all operations.
ZRegistry (currently) supports only string value types, but the return value struct
from 'Get' can be converted to integer and double types with the Convert() function.
License:
TODO
*/
#pragma once
#ifndef _ZREGISTRY_HPP
#define _ZREGISTRY_HPP
#include <ZUtil/ZConcurrency.hpp>
#include <ZUtil/ZKVTree.hpp>
class ZRegistry
{
public:
/*
Default Constructor.
*/
ZRegistry();
/*
Constructs this registry from a KVTree.
*/
ZRegistry(const ZKVTree& _tree);
/*
Destructor.
*/
~ZRegistry();
/*
ZRegistry value type, which will evaluate to true if the value was found
and false otherwise.
*/
class Value
{
friend class ZRegistry;
public:
/*
Operator overload used to get the value.
*/
operator ZString () const
{ return Val; }
/*
Function used to verify validity of the returned value.
*/
bool Valid() const
{ return bValid; }
/*
Function used to get the string value.
*/
const ZString& GetString() const
{ return Val; }
int GetInt() const
{ return ZStringAlgo::NumericInt(Val); }
double GetDouble() const
{ return ZStringAlgo::NumericDouble(Val); }
private:
/*
Constructor, which initializes the reference and the flag indicating
whether or not this is a valid value.
*/
Value(const ZString& _val, bool _valid)
: Val(_val), bValid(_valid) { }
ZString Val; //Value copy (cannot maintain reference into data structure)
bool bValid; //Validity flag
};
/*
public ZRegistry::operator []
[] operator overload, equivalent to Get(_key).
@param _key - the key to look up
@return (const ZString&) - the value looked up
*/
const Value operator [] (const ZString& _key) const
{ return Get(_key); }
/*
public ZRegistry::Erase
Erases a key/value pair (and all child key/value pairs) from the registry.
@param _key - the key to erase
@return (void)
*/
void Erase(const ZString& _key);
/*
public ZRegistry::Get
Returns the value instance bound to the given key.
@param _key - the key to evaluate
@return (Value) - value instance for this key
*/
const Value Get(const ZString& _key) const;
/*
public ZRegistry::Put
Places a key / value pair into the registry. Will create any necessary nodes
to place the key and value pair.
@param _key - the key to map
@param _value - the value to map to the key
@return (bool) - true if able to map the key/value, false otherwise
*/
bool Put(const ZString& _key, const ZString& _value);
private:
DISABLE_COPY_AND_ASSIGN(ZRegistry);
ZReadWriteLock Lock; //The concurrency read write lock
ZKVTree Tree; //The tree we store out data in
};
#endif

View File

@@ -0,0 +1,89 @@
/*
ZSema.hpp
Author: James Russell <jcrussell@762studios.com>
Purpose: RAII wrapper for libsst-concurrency SST_Semaphore.
Changelog
2011/11/27 - creation (jcrussell)
*/
#pragma once
#ifndef _ZSEMAPHORE_H
#define _ZSEMAPHORE_H
#include <ZUtil/ZUtilBuild.hpp>
#include <SST/SST_Semaphore.h>
/*
ZSemaphore class. Used to allocate and deallocate a semaphore within the scope of a class.
Cannot be copied or assigned, which prevents it from being used in stl-like containers.
*/
class ZSemaphore
{
private:
DISABLE_COPY_AND_ASSIGN(ZSemaphore);
//libsst Semaphore
SST_Semaphore Semaphore;
public:
/*
Constructor.
@param _initialCount - initial count of the semaphore
*/
ZSemaphore(int _initialCount);
/*
Destructor.
*/
~ZSemaphore();
/*
public ZSema::Post
TODO
@return (void)
@context (all)
*/
void Post();
/*
public ZSema::Post
TODO
@param _count -
@return (void)
@context (all)
*/
void Post(uint32_t _count);
/*
public ZSema::Wait
TODO
@return (bool)
@context (all)
*/
bool Wait();
/*
public ZSema::Wait
TODO
@param _ms -
@return (bool)
@context (all)
*/
bool Wait(uint32_t _ms);
};
#endif

View File

@@ -0,0 +1,41 @@
/*
ZSimplexNoise.hpp
Author : Chris Ertel
Purpose : Math namespace for the ZEngine which will contain functions for mathematical operations on primitives
and arrays of primitives.
Changelog
2/13/11 - Creation (crertel)
*/
#pragma once
#ifndef _ZSIMPLEXNOISE_H
#define _ZSIMPLEXNOISE_H
#include <ZUtil/ZNoise.hpp>
#include <SST/SST_SimplexNoise.h>
class ZSimplexNoise : public ZNoise
{
protected:
SST_SimplexNoise simplexGenerator;
public:
ZSimplexNoise();
virtual ~ZSimplexNoise() {}
//Subclass implementation
void reseed(const int _seed);
//Subclass implementation
float noise1(const float _x);
//Subclass implementation
float noise2(const float _x, const float _y);
//Subclass implementation
float noise3(const float _x, const float _y, const float _z);
//Subclass implementation
float noise4(const float _x, const float _y, const float _z, const float _w);
};
#endif

View File

@@ -0,0 +1,261 @@
/*
ZSimplexNoiseMap.hpp
Author : Chris Ertel
Purpose : Interface to create a map for simplex noise values.
Changelog
2/20/11 - Creation (crertel)
*/
#pragma once
#ifndef _ZSIMPLEXNOISEMAP_H
#define _ZSIMPLEXNOISEMAP_H
#include <ZUtil/ZSimplexNoise.hpp>
#include <ZUtil/ZNoiseMap.hpp>
#include <ZUtil/ZUtil.hpp>
class ZSimplexNoiseMap : public ZNoiseMap
{
protected:
ZSimplexNoise noiseGen;
float lacunarity;
float persistence;
int numberofoctaves;
float* values;
public:
ZSimplexNoiseMap()
: lacunarity(.5), persistence(.5), numberofoctaves(8), values(NULL)
{
}
virtual ~ZSimplexNoiseMap()
{
}
virtual int GetDimensionality() = 0;
//Subclass implementation
float GetLacunarity() { return this->lacunarity; }
//Subclass implementation
float GetPersistence() { return this->persistence; }
//Subclass implementation
int GetNumberOfOctaves() { return this->numberofoctaves; }
//Not implemented
virtual int GetNumberSamplesInX() = 0;
//Not implemented
virtual int GetNumberSamplesInY() = 0;
//Not implemented
virtual int GetNumberSamplesInZ() = 0;
//Not implemented
virtual int GetNumberSamplesInW() = 0;
/*
public ZSimplexNoiseMap::GetSamples
Function to get array of values for noise map.
@return (float*) - array of values
*/
float* GetSamples() { return this->values; }
//Subclass implementation
void SetLacunarity(float _lac) { this->lacunarity = _lac; } // scaling of successive frequencies in noise octaves
//Subclass implementation
void SetPersistence(float _per) { this->persistence = _per; } // scaling of successive amplitudes in noise octaves
//Subclass implementation
void SetNumberOfOctaves(int _numOctaves ) { this->numberofoctaves = _numOctaves; }
//Not implemented
virtual void SetNumberSamplesInX(int _numSamples) = 0;
//Not implemented
virtual void SetNumberSamplesInY(int _numSamples) = 0;
//Not implemented
virtual void SetNumberSamplesInZ(int _numSamples) = 0;
//Not implemented
virtual void SetNumberSamplesInW(int _numSamples) = 0;
//Not implemented
virtual bool Generate(int _seed) = 0;
//Not implemented
virtual void Cleanup() = 0;
};
class ZSimplexNoiseMap2D : public ZSimplexNoiseMap
{
protected:
int numberSamplesInX;
int numberSamplesInY;
public:
ZSimplexNoiseMap2D()
: ZSimplexNoiseMap(), numberSamplesInX(0), numberSamplesInY(0)
{
}
~ZSimplexNoiseMap2D()
{
this->Cleanup();
}
//Subclass implementation
int GetDimensionality() { return 2; }
//Subclass implementation
int GetNumberSamplesInX() { return this->numberSamplesInX; }
//Subclass implementation
int GetNumberSamplesInY() { return this->numberSamplesInY; }
//Subclass implementation
int GetNumberSamplesInZ() { return 0; }
//Subclass implementation
int GetNumberSamplesInW() { return 0; }
//Subclass implementation
void SetNumberSamplesInX(int _numSamples) { this->numberSamplesInX = _numSamples; }
//Subclass implementation
void SetNumberSamplesInY(int _numSamples) { this->numberSamplesInY = _numSamples; }
//Subclass implementation
void SetNumberSamplesInZ(int _numSamples) { URFP ( _numSamples) ; }
//Subclass implementation
void SetNumberSamplesInW(int _numSamples) { URFP ( _numSamples) ; }
/*
public ZSimplexNoiseMap2D::getValue
Gets value at a particular point on the noise map.
@param _x - x-coordinate to sample
@param _y - y-coordinate to sample
@return (double) - value at point (x,y)
*/
float getValue(int _x, int _y);
//Subclass implementation
bool Generate(int _seed = 0);
//Subclass implementation
void Cleanup();
};
class ZSimplexNoiseMap3D : public ZSimplexNoiseMap
{
protected:
int numberSamplesInX;
int numberSamplesInY;
int numberSamplesInZ;
public:
ZSimplexNoiseMap3D()
: ZSimplexNoiseMap(), numberSamplesInX(0), numberSamplesInY(0), numberSamplesInZ(0)
{
}
~ZSimplexNoiseMap3D()
{
this->Cleanup();
}
//Subclass implementation
int GetDimensionality() { return 3; }
//Subclass implementation
int GetNumberSamplesInX() { return this->numberSamplesInX; }
//Subclass implementation
int GetNumberSamplesInY() { return this->numberSamplesInY; }
//Subclass implementation
int GetNumberSamplesInZ() { return this->numberSamplesInZ; }
//Subclass implementation
int GetNumberSamplesInW() { return 0; }
//Subclass implementation
void SetNumberSamplesInX(int _numSamples) { this->numberSamplesInX = _numSamples; }
//Subclass implementation
void SetNumberSamplesInY(int _numSamples) { this->numberSamplesInY = _numSamples; }
//Subclass implementation
void SetNumberSamplesInZ(int _numSamples) { this->numberSamplesInZ = _numSamples; }
//Subclass implementation
void SetNumberSamplesInW(int _numSamples) { URFP ( _numSamples) ; }
/*
public ZSimplexNoiseMap3D::getValue
Gets value at a particular point on the noise map.
@param _x - x-coordinate to sample
@param _y - y-coordinate to sample
@param _z - z-coordinate to sample
@return (float) - value at point in noise map.
*/
float getValue(int _x, int _y, int _z);
//Subclass implementation
bool Generate(int _seed = 0);
//Subclass implementation
void Cleanup();
};
class ZSimplexNoiseMap4D : public ZSimplexNoiseMap
{
protected:
int numberSamplesInX;
int numberSamplesInY;
int numberSamplesInZ;
int numberSamplesInW;
public:
ZSimplexNoiseMap4D()
: ZSimplexNoiseMap(), numberSamplesInX(0), numberSamplesInY(0), numberSamplesInZ(0),
numberSamplesInW(0)
{
}
~ZSimplexNoiseMap4D()
{
this->Cleanup();
}
//Subclass implementation
int GetDimensionality() { return 4; }
//Subclass implementation
int GetNumberSamplesInX() { return this->numberSamplesInX; }
//Subclass implementation
int GetNumberSamplesInY() { return this->numberSamplesInY; }
//Subclass implementation
int GetNumberSamplesInZ() { return this->numberSamplesInZ; }
//Subclass implementation
int GetNumberSamplesInW() { return this->numberSamplesInW; }
//Subclass implementation
void SetNumberSamplesInX(int _numSamples) { this->numberSamplesInX = _numSamples; }
//Subclass implementation
void SetNumberSamplesInY(int _numSamples) { this->numberSamplesInY = _numSamples; }
//Subclass implementation
void SetNumberSamplesInZ(int _numSamples) { this->numberSamplesInZ = _numSamples; }
//Subclass implementation
void SetNumberSamplesInW(int _numSamples) { this->numberSamplesInW = _numSamples; }
/*
public ZSimplexNoiseMap4D::getValue
Gets value at a particular point on the noise map.
@param _x - x-coordinate to sample
@param _y - y-coordinate to sample
@param _z - z-coordinate to sample
@param _w - w-coordinate to sample
@return (float) - value at point in noise map.
*/
float getValue(int _x, int _y, int _z, int _w);
//Subclass implementation
bool Generate(int _seed = 0);
//Subclass implementation
void Cleanup();
};
#endif

View File

@@ -0,0 +1,237 @@
/*
ZSlabAllocator.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 9/12/2011
Purpose:
Used to pre-allocate a large pool of objects whose size is fixed. These objects can
then be allocated and deallocated as needed, which will return a pointer to an already
allocated member.
Will correctly handle allocation of more objects than is allocated at compile time, but
performance will be impacted as another slab of equivalent size to the original is
allocated.
This is not a multithreaded access allocator. The user of this is required to provide
their own thread safety mechanisms.
License:
TODO
*/
#pragma once
#ifndef _ZSLABALLOCATOR_H
#define _ZSLABALLOCATOR_H
#include <ZUtil/ZUtilBuild.hpp>
#include <ZUtil/ZAlloc.hpp>
#include <ZUtil/ZAssert.hpp>
#include <ZUtil/ZLog.hpp>
/*
Slab Allocator, which holds a contiguous array of objects and leases them out for use.
The template parameter T is the type of object to hold.
The template parameter N is the size of the slab (how many objects to allocate statically).
*/
template <typename T, size_t N>
class ZSlabAllocator
{
private:
DISABLE_COPY_AND_ASSIGN(ZSlabAllocator);
protected:
/*
Allocated slab of objects, that links to the next
slab of objects.
*/
class Slab
{
private:
T Pool[N]; //The object pool
T* Handles[N]; //Handles to objects in the object pool
size_t HandleIndex; //Handle index to the next available handle
Slab* NextPool; //Next pool
public:
Slab() :
HandleIndex(0), NextPool(NULL)
{
//Populate our handles pool
for (size_t i = 0; i < N; i++)
Handles[i] = &(Pool[i]);
}
//Used to verify that a handle belongs to the pool of objects
bool IsPoolMember(T* _handle)
{
uintptr_t handle = (uintptr_t) _handle;
uintptr_t poolLower = (uintptr_t) &Pool[0];
uintptr_t poolUpper = (uintptr_t) &Pool[N - 1];
if ((handle >= poolLower) && (handle <= poolUpper)) //Checks to see if handle is within the range of the pool
if (((handle - poolLower) % sizeof(T)) == 0) //Checks to see if handle is aligned on an object in the pool
return true;
return false;
}
T* Allocate()
{
T* object = NULL;
if (HandleIndex < N)
{
//Grab an object from the object pool
object = Handles[HandleIndex++];
}
return object;
}
void Deallocate(T* object)
{
Handles[--HandleIndex] = object;
}
Slab* GetNextPool() { return NextPool; }
void SetNextPool(Slab* p) { NextPool = p; }
};
//ZSlabAllocator members
Slab FirstPool;
size_t NrAllocated;
size_t NrSlabs;
public:
/*
Default Constructor.
*/
ZSlabAllocator() :
NrAllocated(0), NrSlabs(1)
{
}
/*
Destructor.
*/
~ZSlabAllocator()
{
Slab* slab = FirstPool.GetNextPool();
while(slab)
{
Slab* next = slab->GetNextPool();
zdelete slab;
slab = next;
}
}
/*
public ZSlabAllocator<T,N>::Allocate
Gets a valid object of type T and returns a pointer.
@return (T*) - a valid object pointer of type T
*/
T* Allocate()
{
T* object = NULL;
Slab* slab = &FirstPool; //Begin with first pool
while(object == NULL)
{
//Any objects left in this pool?
object = slab->Allocate();
if(object == NULL)
{
//Doh, try next pool
Slab* next = slab->GetNextPool();
//Unless there is no next pool...
if(next == NULL)
{
//Try to allocate another one
Slab* newPool = znew Slab;
if(newPool == NULL)
return NULL; //Doh, out of memory. :(
else
NrSlabs++;
//Save this pool
slab->SetNextPool(newPool);
next = newPool;
}
//Try next pool
slab = next;
}
else
NrAllocated++;
}
return object;
}
/*
public ZSlabAllocator<T,N>::Capacity
Gets the size of the object pool. Returns the total capacity of the pool.
@return (size_t) - the capacity of the object pool
*/
size_t Capacity() const
{
return NrSlabs * N;
}
/*
public ZSlabAllocator<T,N>::Count
Gets the number of objects contained by the object pool.
@return (size_t) - the number of objects contained by this pool
*/
size_t Available() const
{
return NrSlabs * N - NrAllocated;
}
size_t Allocated() const
{
return NrAllocated;
}
/*
public ZSlabAllocator<T,N>::Deallocate
Allocates an object from the slab.
@param _object - a valid object pointer of type T gained through 'Allocate'
@return (void)
*/
void Deallocate(T *_object)
{
for(Slab* slab = &FirstPool; slab != NULL; slab = slab->GetNextPool())
{
if(slab->IsPoolMember(_object))
{
NrAllocated--;
slab->Deallocate(_object);
return;
}
}
ZASSERT_RUNTIME_FAIL("ZSlabAllocator: Object deallocated that was not allocated here!");
}
};
#endif

View File

@@ -0,0 +1,944 @@
/*
ZSmartPointer.hpp
Author: James Russell
Created: 08/12/2011
Purpose:
Smart pointer implementation for the ZEngine. Frees up the programmer from having to
worry too hard about the minutiae of memory management for allocated objects. Not to
use on arrays; use ZArray for dynamic array management.
Uses atomic operations to enable the smart pointer to work across threads.
Don't pass these things around by pointer or reference unless you really know what you
are doing. You won't like the results.
License:
TODO
*/
#pragma once
#ifndef _ZSMARTPOINTER_H
#define _ZSMARTPOINTER_H
#include <SST/SST_Atomic.h>
#include <SST/SST_Concurrency.h>
#include <ZUtil/ZUtilBuild.hpp>
#include <ZUtil/ZAlloc.hpp>
#include <ZUtil/ZAssert.hpp>
#include <ZUtil/ZReferenceCounter.hpp>
#include <ZSTL/ZArray.hpp>
#include <ZSTL/ZList.hpp>
#include <ZSTL/ZRingBuffer.hpp>
//Shorthand used for ZSmartPointer
#define ZPtr ZSmartPointer
/*
Default deallocator functor for ZSmartPointer, which is responsible for deallocating
the managed object. This default version uses 'zdelete'.
The template parameter T is the type of object pointed to by the smart pointer.
The unary functor takes a single argument of type T*, which is the object to be deallocated.
*/
template <typename T>
struct ZSmartPointerDeallocator {
void operator () (T* _object) {
zdelete _object;
}
};
/*
NULL deallocator functor for ZSmartPointer, which doesn't actually deallocate anything.
The template parameter T is the type of object pointed to by the smart pointer.
The unary functor takes a single argument of type T*, which is destroyed.
*/
template <typename T>
struct ZSmartPointerNullDeallocator {
void operator() (T* _object) {
URFP(_object);
}
};
/*
Smart pointer class, used to share a references to an allocated object. This smart pointer
uses atomic operations to ensure that the reference count is maintained properly even when
the object is shared among threads.
The template parameter T is the type of the object pointed to.
The template parameter DF is the type of object deallocator functor to use.
The template parameter R is the type of reference counter allocator to use.
*/
template <typename T, typename DF = ZSmartPointerDeallocator<T>, typename R = ZReferenceCounterAllocator >
class ZSmartPointer
{
protected:
//The pointed to object
T* Object;
//Object Deallocator
DF ObjDeallocator;
//Reference Counter Allocator
R RefAllocator;
//Reference Counter for the pointer (also contains the pointer)
ZReferenceCounter* Ref;
//Checks to see if we need a reference counter, allocates if so, and increments the strong
//reference count
inline void ReferenceGained()
{
if (Object == NULL)
return;
if (Ref == NULL)
{
Ref = RefAllocator.AllocateCounter();
ZASSERT_RUNTIME(Ref != NULL, "ZSmartPointer: Reference counter allocator returned NULL!");
}
Ref->GainStrongRef();
}
//Checks to see if we can delete the reference and lowers the count
inline void ReferenceLost()
{
if (Ref == NULL)
{
ZASSERT_UTIL(Object == NULL, "ZSmartPointer: Reference lost with no reference counter, but object is still present!");
return;
}
ZASSERT_UTIL(Ref->GetStrongRefCount() > 0 && Object != NULL, "ZSmartPointer: Reference lost but object is already deallocated!");
uint32_t combinedCount = Ref->LoseStrongRef(); //Decrement our strong count and get the combined count
//Check if we lost the last strong ref
if ((combinedCount & ZREFCOUNTER_STRONG_MASK) == 0) //Note we don't use the EXTRACT_STRONG_REF() since 0 bitshifted is still 0
{
Ref->SignalDeallocateObject(); //Signal object deallocation
ObjDeallocator(Object); //Deallocate the object
//Check if we lost the last weak reference
if ((combinedCount & ZREFCOUNTER_WEAK_MASK) == 0) //Note we don't use the EXTRACT_WEAK_REF() since 0 bitshifted is still 0
{
RefAllocator.DeallocateCounter(Ref); //Deallocate the counter
}
}
//We lost our reference, so we don't need these
Object = NULL;
Ref = NULL;
}
public:
/*
Default constructor. Sets the reference to NULL and does not allocate a reference
counter.
*/
ZSmartPointer()
: Object(NULL), Ref(NULL)
{ }
/*
Constructor. Explicit to ensure we don't accidentally take ownership of
a pointer. Allocates a reference counter from the reference counter allocator.
@param _ptr - pointer to be managed
*/
explicit ZSmartPointer(T* _ptr)
: Object(_ptr), Ref(NULL)
{
ReferenceGained();
}
/*
Copy constructor.
@param _other - the other smart pointer
*/
ZSmartPointer(const ZSmartPointer<T, DF, R>& _other)
: Object(_other.Pointer()), Ref(_other.Counter())
{
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZSmartPointer: Copy constructor called from smart pointer with invalid reference counter!");
ReferenceGained();
}
/*
Conversion constructor. Used to auto up-cast derived classes or other
classes that can be converted.
@param D - the typename of the derived class
@param EF - the deallocator functor type of the other class
@param S - the reference counter allocator type of the other class
@param _other - the other smart pointer
*/
template <typename D, typename EF, typename S>
ZSmartPointer(const ZSmartPointer<D, EF, S>& _other)
: Object(static_cast<T*>(_other.Pointer())), Ref(_other.Counter())
{
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZSmartPointer: Copy constructor called from smart pointer with invalid reference counter!");
ReferenceGained();
}
/*
Destructor. Causes a strong reference to be lost.
*/
~ZSmartPointer()
{
ReferenceLost();
}
/*
= operator overload. Sets this smart pointer to be the owner of the provided pointer,
which may require allocation of a reference counter.
@param _ptr - the pointer to the object to own
@return (ZSmartPointer<T, DF, R>&) - this smart pointer
*/
ZSmartPointer<T, DF, R>& operator = (T* _ptr)
{
if (Object == _ptr)
return *this;
if (_ptr == NULL)
{
ReferenceLost(); //Ditch our reference
Object = NULL; //Nullify our object pointer
Ref = NULL; //Nullify our counter
}
else
{
if (Object != NULL)
ReferenceLost(); //Lose our reference to the valid object
Object = _ptr; //Own it
Ref = NULL; //Make sure Ref is set to NULL
ReferenceGained(); //Create a new reference counter
}
return *this;
}
/*
= operator overload. Sets this smart pointer to provide a strong reference to the same object
managed by the other smart pointer.
@param _other - the other smart pointer
@return (ZSmartPointer<T, DF, R>&) - this smart pointer
*/
ZSmartPointer<T, DF, R>& operator = (const ZSmartPointer<T, DF, R>& _other)
{
if (*this == _other || Ref == _other.Counter())
return *this;
ReferenceLost(); //Lose a reference to our current object
Object = _other.Pointer(); //Own the new one
Ref = _other.Counter(); //Get our new reference counter
ReferenceGained(); //Increment the reference
return *this;
}
/*
= operator overload. Used to assign to derived classes and classes that can
be converted to T.
@param D - the type held by the other smart pointer
@param EF - the deallocator type of the other smart pointer
@param S - the reference counter allocator type of the other smart pointer
@param _other - the other smart pointer
@return (ZSmartPointer<T, DF, R>&) - this smart pointer
*/
template <typename D, typename EF, typename S>
ZSmartPointer<T, DF, R>& operator = (const ZSmartPointer<D, EF, S>& _other)
{
T* testCast = static_cast<T*>(_other.Pointer()); ((void)testCast); //This will fail to compile if T* cannot static cast to D*
return *this = static_cast< ZSmartPointer<T, DF, R> >(_other);
}
/*
== operator overload. Checks to see if this smart pointer owns the provided raw pointer.
@param _ptr - the pointer to check
@return (bool) - true if the pointer is managed by this smart pointer, false otherwise
*/
bool operator == (const T* _ptr) const
{
return Object == _ptr;
}
/*
== operator overload. Checks to see if these pointers reference the same object.
@param _other - the other smart pointer
@return (bool) - true if equal, false otherwise
*/
bool operator == (const ZSmartPointer<T, DF, R>& _other) const
{
return Object == _other.Object;
}
/*
== operator overload. Used to compare with smart pointers referencing derived
classes or a class that can be converted to T.
@param _other - the other smart pointer
@return (bool) - true if equal, false otherwise
*/
template <typename D, typename EF, typename S>
bool operator == (const ZSmartPointer<D, EF, S>& _other) const
{
return Object == static_cast<T*>( _other.Pointer());
}
/*
!= operator overload. Checks to see if this smart pointer does not
own the provided raw pointer.
@param _ptr - the pointer to check
@return (bool) - true if this smart pointer does not reference the provided, false otherwise
*/
bool operator != (const T* _ptr) const
{
return !(*this == _ptr);
}
/*
!= operator overload. Checks to see if the smart pointers reference different objects.
@param _other - the other smart pointer
@return (bool) - true if this smart pointer and the other do not reference the same object, false otherwise
*/
bool operator != (const ZSmartPointer<T, DF, R>& _other) const
{
return !(*this == _other);
}
/*
!= operator overload. Checks to see if these pointers reference different objects. Used
to compare with derived classes.
@param D - the type contained by the other smart pointer
@param EF - the allocator used by the other smart pointer
@param S - the reference counter allocator type used by the other smart pointer
@param _other - the other smart pointer
@return (bool) - true if this smart pointer and the other do not reference the same object, false otherwise
*/
template <typename D, typename EF, typename S>
bool operator != (const ZSmartPointer<D, EF, S>& _other) const
{
return !(*this == _other);
}
/*
-> operator overload. Allows this to be accessed as a T* would be.
@return (T*) - raw pointer to the object
@assert - if the pointer is NULL
*/
T* operator -> () const
{
ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");
return Object;
}
/*
'*' operator overload. Allows this to be dereferenced as a T* would be.
@return (T&) - reference to the object
@assert - if the object is NULL
*/
T& operator * () const
{
ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");
return *Object;
}
/*
public ZSmartPointer<T, DF, R>::CounterAllocator
Gets the reference counter allocator for this smart pointer.
@return (R&) - the reference counter allocator
*/
R& CounterAllocator() const
{
return RefAllocator;
}
/*
public ZSmartPointer<T, DF, R>::Cast
Used to cast this smart pointer into another type. This will construct an
additional smart pointer that also references the object. The owned
object must be convertible to type C* via static_cast.
@param C - the type contained by the other type
@return (ZSmartPointer<C, DF, R>) - this smart pointer as another type
*/
template <typename C>
ZSmartPointer<C, DF, R> Cast()
{
return static_cast< ZSmartPointer<C, DF, R> >(*this);
}
/*
public ZSmartPointer<T, DF, R>::Counter
Gets the ZRefrenceCounter instance used by this smart pointer.
@return (ZReferenceCounter*)- ZRefCounter instance
*/
ZReferenceCounter* Counter() const
{
return Ref;
}
/*
public ZSmartPointer<T, DF, R>::Deallocator
Gets the object deallocator for this smart pointer.
@return (DF&) - reference to the object deallocator
*/
DF& Deallocator() const
{
return ObjDeallocator;
}
/*
public ZSmartPointer<T, DF, R>::Detach
Detaches the pointer from memory management by the smart pointer. Should only be
called if there is a single strong reference to the object, otherwise it will return
NULL. Weak references will be nullified as if the object has been deallocated.
@return (T*) - raw pointer detached from this smart pointer, or NULL if more
than one reference and unable to detach
*/
T* Detach()
{
if (Object == NULL || Ref == NULL || Ref->GetStrongRefCount() != 1)
return NULL;
else
{
uint32_t combinedCount = Ref->LoseStrongRef(); //Notify everyone we are losing this strong reference
Ref->SignalDeallocateObject(); //Signal that we are deallocating the object
if ((combinedCount & ZREFCOUNTER_WEAK_MASK) == 0)
RefAllocator.DeallocateCounter(Ref); //Deallocate our reference counter
T* ptr;
ptr = Object; //Detach the pointer
Object = NULL; //Nullify our object reference
Ref = NULL; //Nullify our reference counter
return ptr;
}
}
/*
public ZSmartPointer<T, DF, R>::Pointer
Gets the smart pointer as a raw pointer. Buyer beware.
@return (T*) - raw pointer that this smart pointer manages
*/
T* Pointer() const
{
return Object;
}
};
////////////////////////////////////////
/* ZArray Containment Specializations */
////////////////////////////////////////
//Helper function used to nullify references in a range
template <typename T, typename DF, typename R>
void ZSmartPointerArrayNullify(ZSmartPointer<T, DF, R>* _array, size_t _start, size_t _end)
{
for (size_t i = _start; i < _end; i++)
_array[i] = NULL;
}
//Specialization for ZArray_ClearImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_ClearImpl< ZSmartPointer<T, DF, R>, A> {
inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self)
{
//Nullify references
ZSmartPointerArrayNullify(_self.Array, 0, _self.ArraySize);
//Reset size and check integrity
_self.ArraySize = 0;
_self.CheckIntegrity();
}
inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, size_t _newCapacity)
{
//Nullify references
ZSmartPointerArrayNullify(_self.Array, 0, _self.ArraySize);
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(_newCapacity > 0, "ZArray: Cannot set capacity to zero!");
#endif
//Reallocate if needed, drop our size to zero, and check integrity
if (_newCapacity > _self.ArrayCapacity)
{
_self.Deallocate(_self.Array, _self.ArrayCapacity);
_self.ArrayCapacity = _newCapacity;
_self.Allocate(_self.ArrayCapacity);
}
_self.ArraySize = 0;
_self.CheckIntegrity();
}
};
//Specialization for ZArray_EraseImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_EraseImpl< ZSmartPointer<T, DF, R>, A> {
inline static ZSmartPointer<T, DF, R> Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, size_t _index)
{
size_t index = _self.BoundsCheck(_index, _self.ArraySize);
//Grab the currently held element, shift the array down, reduce size, and check integrity
ZSmartPointer<T, DF, R> element = _self.Array[index];
for (size_t i = index; i + 1 < _self.ArraySize; i++)
_self.Array[i] = _self.Array[i + 1];
_self.ArraySize--;
_self.CheckIntegrity();
//Nullify reference
ZSmartPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1);
return element;
}
inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, const size_t _start, const size_t _end)
{
size_t start = _self.BoundsCheck(_start, _self.ArraySize);
size_t end = _self.BoundsCheck(_end, _self.ArraySize + 1);
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(start <= end, "ZArray: cannot erase with start < end!");
#endif
//Copy the elements down, compute new size, and check integrity
for (size_t idx = start; idx + (end - start) < _self.ArraySize; idx++)
_self.Array[idx] = _self.Array[idx + (end - start)];
_self.ArraySize = _self.ArraySize - (end - start);
_self.CheckIntegrity();
//Nullify references (where we moved from)
ZSmartPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + (end - start));
}
};
//Specialization for ZArray_PopBackImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_PopBackImpl< ZSmartPointer<T, DF, R>, A> {
inline static ZSmartPointer<T, DF, R> Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self)
{
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!");
#endif
ZSmartPointer<T, DF, R> ptr = _self.Array[--(_self.ArraySize)];
//Nullify reference
ZSmartPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1);
//Grab the last element in the array and decrease our array size
return ptr;
}
};
//Specialization for ZArray_PopFrontImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_PopFrontImpl< ZSmartPointer<T, DF, R>, A> {
inline static ZSmartPointer<T, DF, R> Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self)
{
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!");
#endif
//This will nullify the reference
return _self.Erase(0);
}
};
//Specialization for ZArray_ResizeImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_ResizeImpl< ZSmartPointer<T, DF, R>, A> {
inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, const size_t _size)
{
//Nullify references if needed
if (_size < _self.ArraySize)
ZSmartPointerArrayNullify(_self.Array, _size, _self.ArraySize);
//Check to see if we need more space, change our size, and check integrity
if (_size > _self.ArrayCapacity)
_self.Reserve(_size);
_self.ArraySize = _size;
_self.CheckIntegrity();
}
inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, const size_t _size, const ZSmartPointer<T, DF, R>& _value)
{
//Nullify references if needed
if (_size < _self.ArraySize)
ZSmartPointerArrayNullify(_self.Array, _size, _self.ArraySize);
//See if we need more space, copy in the new value, change our size, and check integrity
if (_size > _self.ArrayCapacity)
_self.Reserve(_size);
for (size_t i = _self.ArraySize; i < _size; i++)
_self.Array[i] = _value;
_self.ArraySize = _size;
_self.CheckIntegrity();
}
};
///////////////////////////////////////
/* ZList Containment Specializations */
///////////////////////////////////////
//Specialization for ZList_ClearImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZList_ClearImpl < ZSmartPointer<T, DF, R>, A> {
inline static void Call(ZList<ZSmartPointer<T, DF, R>, A>& _self, ZListIterator< ZSmartPointer<T, DF, R> >& _itr) {
ZListNode<ZSmartPointer<T, DF, R> >* next;
ZListNode<ZSmartPointer<T, DF, R> >* current = _itr.GetNode();
_self.CheckIntegrity();
//Early out
if (_self.Empty())
return;
//If we are the starting node, be sure to reset the EmptyNode.Next pointer
if (current == _self.EmptyNode.Next)
_self.EmptyNode.Next = &_self.EmptyNode;
//This is always true
_self.EmptyNode.Previous = current->Previous;
current->Previous->Next = &_self.EmptyNode;
//Iterate and deallocate the nodes
while (current != &_self.EmptyNode)
{
next = current->Next;
current->Element = NULL; //This is the specialization
_self.DeallocateNode(current);
current = next;
}
//Set the node on the iterator equal to the end node
_itr.SetNode(&_self.EmptyNode);
_self.CheckIntegrity();
}
};
//Specialization for ZList_EraseImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZList_EraseImpl < ZSmartPointer<T, DF, R>, A> {
inline static ZSmartPointer<T, DF, R> Call(ZList<ZSmartPointer<T, DF, R>, A>& _self, ZListIterator< ZSmartPointer<T, DF, R> >& _itr)
{
ZSmartPointer<T, DF, R> elem;
ZListNode< ZSmartPointer<T, DF, R> > *node = _itr.GetNode();
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(node != NULL, "ZList: Iterator is invalid!");
ZSTL_ASSERT(node != &_self.EmptyNode, "ZList: Cannot erase end node!");
#endif
//Increment the iterator to the next list node to keep the iterator valid
++_itr;
//Rearrange the pointers
node->Previous->Next = node->Next;
node->Next->Previous = node->Previous;
elem = node->Element;
node->Element = NULL; //This is the specialization
_self.DeallocateNode(node);
_self.CheckIntegrity();
return elem;
}
inline static void Call(ZList<ZSmartPointer<T, DF, R>, A>& _self, ZListIterator< ZSmartPointer<T, DF, R> >& _start, const ZListIterator< ZSmartPointer<T, DF, R> >& _end)
{
ZListNode< ZSmartPointer<T, DF, R> > *nodeStart = _start.GetNode();
ZListNode< ZSmartPointer<T, DF, R> > *nodeEnd = _end.GetNode();
ZListNode< ZSmartPointer<T, DF, R> > *curNode;
ZListNode< ZSmartPointer<T, DF, R> > *prevNode;
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(nodeStart != NULL && nodeEnd != NULL, "ZList: Cannot erase with invalid iterator!");
ZSTL_ASSERT(nodeStart != &_self.EmptyNode, "ZList: Cannot erase end node!");
#endif
//Rearrange the pointers
nodeStart->Previous->Next = nodeEnd;
nodeEnd->Previous = nodeStart->Previous;
//Erase each element between from and to
curNode = nodeStart;
prevNode = NULL;
while (curNode != nodeEnd)
{
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(curNode != &_self.EmptyNode, "ZList: Cannot erase end node!");
#endif
prevNode = curNode;
curNode = curNode->Next;
prevNode->Element = NULL; //This is the specialization
_self.DeallocateNode(prevNode);
}
_start = _end;
}
};
//Specialization for ZList_PopBackImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZList_PopBackImpl < ZSmartPointer<T, DF, R>, A> {
inline static ZSmartPointer<T, DF, R> Call(ZList<ZSmartPointer<T, DF, R>, A>& _self) {
ZSmartPointer<T, DF, R> elem;
ZListNode< ZSmartPointer<T, DF, R> > *node;
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from back of empty list!");
#endif
//Grab the element at the back of the list
node = _self.EmptyNode.Previous;
//Remove the node from the list
node->Previous->Next = &_self.EmptyNode;
_self.EmptyNode.Previous = node->Previous;
//Get the element value and lose our reference
elem = node->Element;
node->Element = NULL;
//Deallocate and then return
_self.DeallocateNode(node);
_self.CheckIntegrity();
return elem;
}
};
//Specialization for ZList_PopFrontImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZList_PopFrontImpl < ZSmartPointer<T, DF, R>, A> {
inline static ZSmartPointer<T, DF, R> Call(ZList<ZSmartPointer<T, DF, R>, A>& _self) {
ZSmartPointer<T, DF, R> elem;
ZListNode< ZSmartPointer<T, DF, R> > *node;
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from front of empty list!");
#endif
//Grab the element at the front of the list
node = _self.EmptyNode.Next;
//Remove the node from the list
node->Next->Previous = node->Previous;
node->Previous->Next = node->Next;
//Get the element value and lose our reference
elem = node->Element;
node->Element = NULL;
//Deallocate and then return
_self.DeallocateNode(node);
_self.CheckIntegrity();
return elem;
}
};
/////////////////////////////////////////////
/* ZRingBuffer Containment Specializations */
/////////////////////////////////////////////
//Specialization for ZRingBuffer_ClearImpl containing ZSmartPointer
template <typename T, typename P, typename A, typename DF, typename R>
struct ZRingBuffer_ClearImpl < ZSmartPointer<T, DF, R>, P, A> {
inline static void Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self )
{
// set to null to remove references
for (size_t i = 0; i < _self.BufferSize; i++)
_self.At(i) = ZSmartPointer<T,DF,R>(NULL);
_self.BufferSize = 0;
_self.FrontIndex = 0;
_self.BackIndex = 0;
}
inline static void Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self, size_t _newCapacity )
{
// set to null to remove references
for (size_t i = 0; i < _self.BufferSize; i++)
_self.At(i) = ZSmartPointer<T,DF,R>(NULL);
_self.Buffer.Resize(_newCapacity);
_self.BufferSize = 0;
_self.FrontIndex = 0;
_self.BackIndex = 0;
}
};
//Specialization for ZRingBuffer_EraseImpl containing ZSmartPointer
template <typename T, typename P, typename A, typename DF, typename R>
struct ZRingBuffer_EraseImpl < ZSmartPointer<T, DF, R>, P, A> {
inline static T Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self, size_t _index)
{
//We are going to do this in a very naive fashion, as this container is not intended for these
//kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome.
_self.AlignBuffer();
_self.BufferSize--;
_self.BackIndex--;
// set to null to remove references
ZSmartPointer<T, DF, R> ret = _self.Buffer.At(_index);
_self.Buffer.At(_index) = ZSmartPointer<T, DF, R>(NULL);
return ret;
}
inline static void Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self, size_t _i, size_t _j )
{
//We are going to do this in a very naive fashion, as this container is not intended for these
//kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome.
size_t count;
_self.AlignBuffer();
count = (size_t)(_j - _i);
_self.BufferSize = _self.BufferSize - count;
_self.BackIndex = _self.BackIndex - count;
// set to null to remove references
for( size_t i = _i; i < _j; i++)
_self.Buffer.At(i) = ZSmartPointer<T, DF, R>(NULL);
_self.Buffer.Erase(_i, _j);
}
};
//Specialization for ZRingBuffer_PopBackImpl containing ZSmartPointer
template <typename T, typename P, typename A, typename DF, typename R>
struct ZRingBuffer_PopBackImpl < ZSmartPointer<T, DF, R>, P, A> {
inline static T Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self )
{
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopBack() caused underflow!");
#endif
size_t index = _self.BackIndex;
_self.DecrementBack();
_self.CheckIntegrity();
// set to NULL to fix ref count issues
ZSmartPointer< T, DF, R > ret = _self.Buffer.At(index);
_self.Buffer.At(index) = ZSmartPointer< T, DF, R>(NULL);
return ret;
}
};
//Specialization for ZRingBuffer_PopFrontImpl containing ZSmartPointer
template <typename T, typename P, typename A, typename DF, typename R>
struct ZRingBuffer_PopFrontImpl < ZSmartPointer<T, DF, R>, P, A> {
inline static T Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self )
{
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopFront() caused underflow!");
#endif
size_t index = _self.FrontIndex;
_self.IncrementFront();
_self.CheckIntegrity();
// set to NULL to fix ref count issues
ZSmartPointer< T, DF, R > ret = _self.Buffer.At(index);
_self.Buffer.At(index) = ZSmartPointer< T, DF, R>(NULL);
return ret;
}
};
#endif

View File

@@ -0,0 +1,404 @@
/*
ZTaskStream.hpp
Author: James Russell <jcrussell@762studios.com>
Purpose: Manages the execution of 'Tasks' by a number of threads determined at runtime. Attempts to parallelize
execution as well as possible with the provided information.
Changelog
2011/04/10 - creation (jcrussell)
*/
#ifndef _ZTASKSTREAM_H
#define _ZTASKSTREAM_H
#include <ZUtil/ZThread.hpp>
#include <stdlib.h> //size_t
//Forward Declarations
class ZTaskStream;
typedef size_t ZTaskPriority; //Task Priority
typedef size_t ZTaskThreadId; //Task Thread Id
//Definition for immediate task execution priority
#define ZTASK_PRIORITY_IMMEDIATE (0)
//Default allocator buffer size for the task thread
#define ZTT_DEFAULT_BUFFER_SIZE 256
//Default allocator buffer size for the task stream
#define ZTS_DEFAULT_BUFFER_SIZE 1024
/*
ZTask execute return values.
*/
enum ZTaskReturnStatus
{
ZTRS_SUCCESS, // Task has succeeded
ZTRS_FAILURE, // Task has failed
ZTRS_ENUM_SIZE
};
/*
ZTask thread Status enumeration.
*/
enum ZTaskThreadStatus
{
ZTTS_UNINITIALIZED, // Task thread is uninitialized
ZTTS_WAITING, // Task thread is awaiting tasks
ZTTS_EXECUTING, // Task thread is executing tasks
ZTTS_ENUM_SIZE
};
/*
Tasks are the basic unit of execution for a ZTaskStream. They are added to the ZTaskStream and
assigned to a thread for execution. They are then executed as TaskThreads
become available.
*/
class ZTask
{
friend class ZTaskThread;
friend class ZTaskStream;
public:
ZTaskStream* TaskStream; // The task stream that is executing this task
ZTaskPriority Priority; // Priority, assigned at construction, decreased each time it is delayed to zero, which is immediate priority
bool bCancelTask; // Cancel Boolean, if set to true, will prevent the task from being executed
/*
Parameterized c'tor (with default arguments).
@param _priority - The amount of time (in ms) the task can be delayed is priority. This means the closer to zero
the priority is set, the faster it will be executed.
*/
ZTask(ZTaskPriority _priority = ZTASK_PRIORITY_IMMEDIATE)
: TaskStream(NULL), Priority(_priority), bCancelTask(false), Func(NULL), TaskArgument(NULL) { }
/*
Parameterized c'tor.
@param _func - function to execute
@param _taskArg - argument to the task
@param _priority - The amount of time (in ms) the task can be delayed is priority. This means the closer to zero
the priority is set, the faster it will be executed.
*/
ZTask(ZTaskReturnStatus (*_func)(ZTaskStream*, ZTask*, void*), void *_taskArg, ZTaskPriority _priority = ZTASK_PRIORITY_IMMEDIATE)
: TaskStream(NULL), Priority(_priority), bCancelTask(false), Func(_func),TaskArgument(_taskArg) { }
/*
Destructor.
*/
virtual ~ZTask() { }
/*
virtual public ZTask::Execute
Execute method. Defined by the task implementation.
@param _arg - argument to the task (NULL by default)
@return (ZTaskReturnStatus) - task return value
*/
virtual ZTaskReturnStatus Execute(void *_arg)
{ URFP(_arg); if (Func != NULL) return Func(TaskStream, this, TaskArgument); else return ZTRS_FAILURE; }
/*
virtual public ZTask::OnTaskFailed
Handler function for task failure. No-op by default.
@return (void)
*/
virtual void OnTaskFailed(void *_taskArgument)
{ URFP(_taskArgument); }
protected:
ZTaskReturnStatus (*Func)(ZTaskStream*, ZTask*, void*); // function for the ZTask to execute if not implemented as a subtask
void* TaskArgument; // Argument passed to this task
};
/*
Future. Used to asynchronously execute a function that will return a value when completed.
*/
template <typename R, typename A>
class ZFuture
{
friend class ZTaskStream;
protected:
// Future Task
class ZFutureTask : public ZTask
{
public:
R (*Func)(A); // The Function
A Arg; // The argument
R Ret; // The return value
bool Completed; // Completed flag
ZEvent CompletedEvent; // Completed Event
// c'tor
ZFutureTask(R (*_func)(A), A _arg)
: ZTask(), Func(_func), Arg(_arg), Ret(), Completed(false), CompletedEvent() { }
// d'tor
~ZFutureTask() { }
// subclass override
virtual ZTaskReturnStatus Execute(void *_arg)
{
URFP(_arg);
CompletedEvent.Reset();
Ret = Func(Arg);
Completed = true;
CompletedEvent.Notify();
return ZTRS_SUCCESS;
}
};
ZPtr<ZFutureTask> FutureTask; // The function execute task
public:
/*
Parameterized c'tor.
@param _func - the function to execute, must return a value of type R
@param _arg - argument to the function
*/
ZFuture(R (_func)(A), A _arg) : FutureTask(znew ZFutureTask(_func, _arg)) { }
/*
public ZFuture<R, A>::IsComplete
Returns whether or not the future has completed.
@return (bool) - true if the task has completed
*/
bool IsComplete() { return FutureTask->Completed; }
/*
public ZFuture<R, A>::GetValue
Gets the return value from the future.
@return (R) - return from the task
*/
R GetValue() { if (!FutureTask->Completed) FutureTask->CompletedEvent.Wait(); return FutureTask->Ret; }
/*
public ZFuture<R, A>::GetValueRef
Gets the return value from the future as a reference.
@return (R&) - reference to return from the task
*/
R& GetValueRef() { if (!FutureTask->Completed) FutureTask->CompletedEvent.Wait(); return FutureTask->Ret; }
};
/*
Threads which execute tasks in the ZTaskStream. The number of operating Task Threads is
assigned at construction of a ZTaskStream and can be changed.
*/
class ZTaskThread : public ZThread
{
friend class ZTaskStream;
public:
/*
Parameterized c'tor.
@param _stream - the stream giving us tasks
@param _id - the id of this task
*/
ZTaskThread(ZTaskStream *_stream, ZTaskThreadId _id);
// d'tor
virtual ~ZTaskThread();
/*
public ZTaskThread::PushTask()
Adds a task to the task thread.
@param _task - the task to add to this task thread (argument already set)
@return (void)
*/
void PushTask(ZPtr<ZTask> _task);
protected:
// Subclass implementation of thread run, which executes tasks
ZThreadReturn run(uint64_t _dt);
private:
ZMutex TaskLock; // Concurrency lock
ZSemaphore TaskSema; // Event that is set when new tasks are available
ZTaskStream* Stream; // The task stream providing us with tasks
ZTaskThreadId Id; // Task thread ID, used to identify this task thread
ZTaskThreadStatus ThrStatus; // Status of this task thread
ZTaskPriority CurrentTaskPriority; //The priority of the currently executing task
ZArray< ZPtr<ZTask> > Tasks; //Set of tasks to execute
};
/*
The task stream. Assigns tasks to task threads that execute when desired. Can also
handle 'background' tasks.
*/
class ZTaskStream
{
public:
/*
Default c'tor.
Creates a single task thread. The amount of task threads running concurrently can be changed
using SetTaskThreadCount.
*/
ZTaskStream();
// d'tor
~ZTaskStream();
/*
public ZTaskStream::ExecuteTasks
Begins execution on the currently loaded set of tasks and any further tasks generated
during the execution of those tasks. Returns after all tasks that will be executed this
frame are done executing.
Tasks that were not completed have had their priority values reduced, meaning that if
they are again added to the ZTaskStream for execution repeatedly until executed, they
are guaranteed to eventually execute within their priority time frame.
@param _frameTime - (given in ms) is the desired amount of time that execution of all tasks
should take; if any time is remaining after execution of ALL priority zero
tasks, a number of extra priority > 0 tasks are executed as can be fit into
the extra time. Because of this definition, frameTime is an estimate and
not a guarantee - execution of priority 0 tasks can take more than frameTime.
@return (void)
*/
void ExecuteTasks(int _frameTime);
/*
public ZTaskStream::GetTaskThreadCount
Gets the current number of worker threads.
@return (size_t) - number of task stream worker threads
*/
size_t GetTaskThreadCount();
/*
public ZTaskStream::HaltFrame
Notifies the ZTaskStream to stop assigning tasks tasks and return from the ExecuteTasks
call that started the process. This does not stop the execution of tasks that have already
been assigned.
@return (void)
*/
void HaltFrame();
/*
public ZTaskStream::Pause
Notifies the ZTaskStream to pause task execution for all tasks.
@param _pause - true to pause the stream, false to unpause
@return (void)
*/
void PauseFrame(bool _pause);
/*
public ZTaskStream::PushFuture
Adds a ZFuture to the task stream, which will execute the future at the soonest available
opportunity.
The ZSmartPointer version will hold a reference to the future until after execution. If
the raw pointer version is used, the user is required to keep the pointer valid until after
execution.
@param _future - the future to execute
@return (void)
*/
template <typename R, typename A>
void PushFuture(ZPtr< ZFuture<R, A> > _future) {
TaskThreads[AssignTask(_future->FutureTask.Pointer())]->PushTask(_future->FutureTask);
}
template <typename R, typename A>
void PushFuture(ZFuture<R, A>* _future) {
// TODO
}
/*
public ZTaskStream::PushTask
Adds a task to the task list. The task is added to the task queue in the currently executing
frame phase, or if a phase is not yet executing, it will be added to the next frame phase to
execute.
The ZSmartPointer version will hold a reference to the task until after execution. If the
raw pointer version is used, the user is required to keep the pointer valid until after
execution.
@param _task - the task to add
@return (void) - the id of the task
*/
void PushTask(ZPtr<ZTask> _task);
void PushTask(ZTask* _task);
/*
public ZTaskStream::PushTasks
Adds a list of tasks. Identical to PushTask() but with less locking overhead. The list of
tasks is not emptied (i.e _tasks.Clear() is not called).
The ZSmartPointer version will hold a reference to the tasks until after execution. If the
raw pointer version is used, the user is required to keep the pointer valid until after
execution.
@param _tasks - the tasks to add
@param _count - the number of tasks
@return (void)
*/
void PushTasks(ZArray< ZPtr<ZTask> >& _tasks);
void PushTasks(ZTask* _tasks, size_t _count);
/*
public ZTaskStream::SetTaskThreadCount
Sets the number of task threads that will be running. Should be greater than zero, or the
call has no effect.
@param _count - the number of task threads to run simultaneously
@return (void)
*/
void SetTaskThreadCount(size_t _count);
protected:
ZMutex TaskStreamLock; // Lock for controlling access to the ZTaskStream objects
ZSemaphore TaskStreamSema; // Semaphore for signaling events
ZEvent FrameCompletedEvent; // Event for notifying the execute caller thread that a frame is completed
ZEvent PausedEvent; // Event for pausing the Task Stream
ZArray<ZTaskThread*> TaskThreads; // Task threads that run the set of tasks
ZArray< ZPtr<ZTask> > Tasks; // The task list
// Pause flag, which indicates that task execution should be paused
// This is only used for debugging purposes, 'PausedEvent' has the same state
// wrapped into an OS object.
bool bPaused;
//Halt flag, which indicates that task execution should halt
bool bShouldHalt;
//Assigns a task to one of the task threads
ZTaskThreadId AssignTask( ZTask *_task);
//Kills a given task thread
void KillTaskThread(size_t _idx);
};
#endif

368
Include/ZUtil/ZThread.hpp Normal file
View File

@@ -0,0 +1,368 @@
/*
ZThread.hpp
Author : James Russell <jcrussell@762studios.com>
Created: 07/04/09
Purpose :
Wrapper class to allow easy thread creation. By making a class that is
a subclass of ZThread and defining the run() method, a thread 'object' can
be created that allows for greater consistency and when dealing with thread
resources.
License:
TODO
*/
#ifndef _ZTHREAD_H
#define _ZTHREAD_H
#include <ZSTL/ZList.hpp>
#include <ZSTL/ZString.hpp>
#include <ZUtil/ZConcurrency.hpp>
#include <ZUtil/ZSmartPointer.hpp>
class ZThread;
typedef void (*ZThreadCallbackFunc)(ZThread* executor, void* arg);
/*
Macro that creates an anonymous request object for marshalling code into a thread request.
Example:
TODO
@param zthread - the zthread object that should execute the request
@param argument - the void* argument to pass in (accessible as Arg)
@param wait - a boolean indicating if we should wait or not
@param code - the actual code that should be executed as part of the request (wrap in parenthesis)
*/
#define ZTHREAD_EXECUTE(zthread, argument, wait, code) \
{ \
class Z##__FUNCTION__##__LINE__##ThreadRequest : public ZThreadRequest \
{ \
protected: \
void *Arg; \
public: \
Z##__FUNCTION__##__LINE__##ThreadRequest() : ZThreadRequest(), Arg(argument) { } \
\
virtual void Execute(ZThread *_threadObj) \
{ \
code \
} \
}; \
\
zthread->AddThreadRequest(ZPtr<ZThreadRequest>(znew Z##__FUNCTION__##__LINE__##ThreadRequest), wait); \
}
//Forward declaration of ZThread
class ZThread;
//Possible return values from ZThread run
typedef enum ZThreadReturn
{
ZTR_TERMINATE, //Indicates the thread should terminate after returning from run
ZTR_LOOP, //Indicates the thread should loop after returning from run
ZTR_PAUSE, //Indicates the thread should pause after returning from run
ZTR_SIZE
} ZThreadReturn;
/*
A ZThread 'Request' object. Used for thread marshaling.
*/
class ZThreadRequest
{
friend class ZThread;
private:
//Completion Event
ZEvent CompletedEvent;
//Indicates this 'ThreadRequest' should persist until removed
bool Persist;
//Indicates to the ZThread that this request should stop running immediately
//This value is checked before execution
bool Stop;
public:
/*
Default Constructor.
@param _persist - boolean indicating this thread request should execute continuously until
the ZThread object is deleted
*/
ZThreadRequest(bool _persist = false)
: CompletedEvent(), Persist(_persist), Stop(false) { }
/*
Destructor.
Destroys the concurrency event.
*/
virtual ~ZThreadRequest() { }
/*
virtual public ZThreadRequest::Execute
Virtual method, which defines the thread request to be executed. The function will be executed
from within the ZThread object's thread context. If this method is not overridden and Func is not
NULL, Func is called with the provided argument.
@param _threadObj - the ZThread object executing this request
@return (void)
*/
virtual void Execute(ZThread *_threadObj) = 0;
/*
public ZThreadRequest::StopExecution
Stops execution of the thread request, provided it has not executed yet.
@return (void)
*/
void StopExecution() { this->Stop = true; }
/*
public ZThreadRequest::Wait
Blocks until after the thread request has been executed.
@return (void)
*/
void Wait() { CompletedEvent.Wait(); }
};
/*
ZThread object class. Should be subclassed to make a threadable 'object'.
*/
class ZThread
{
private:
DISABLE_COPY_AND_ASSIGN(ZThread);
public:
/*
Default Constructor.
@param _threadName - the name of this thread
*/
ZThread(ZString _threadName = "");
/*
Destructor for the ZThread Object. When the ZThread object is deleted, the destructor will wait on
the thread to terminate and return resources to the system.
*/
virtual ~ZThread();
/*
public ZThread::AddThreadRequest()
Adds a callback that will be executed when the thread loops.
@param _request - the thread request to add to the thread's context
@return (void)
*/
void AddThreadRequest(ZPtr<ZThreadRequest> _request, bool _wait = false);
/*
public ZThread::AddCallbackRequest()
Adds a callback to be executed by the thread. It can be executed synchronously or asynchronously.
@param function - The function to execute
@param arg - The argument
@param async - If true, this returns immediately, otherwise it waits for the function to execute.
@return (void)
*/
void AddCallbackRequest(ZThreadCallbackFunc function, void* arg, bool async);
/*
public ZThread::GetThreadID
Gets the thread ID of the thread object.
@return (uint32_t) - int that is the thread id of the thread object
*/
uint32_t GetThreadId();
/*
public ZThread::GetThreadName
Gets the thread name of the ZThread object. The name of a thread is either a
string value of the thread id or a name that was set by the ZThread object.
@return (ZString) - string representing the 'name' of this thread
*/
ZString GetThreadName();
/*
public ZThread::PauseThread
Tells the user thread to pause.
@return (void)
*/
void PauseThread();
/*
public ZThread::RestartThread
Restarts a paused thread.
@return (void)
*/
void RestartThread();
/*
public ZThread::ThreadRunning
Indicates if a ZThread object is executing it's run method or is paused.
@return (bool) - boolean indicating thread is running or is paused
*/
bool ThreadRunning();
/*
public ZThread::ThreadInitialized
Returns true if the ZThread object has called it's initThread() method and returned.
@return (bool) - boolean indicating the thread is initialized
*/
bool ThreadInitialized();
/*
public ZThread::ShutdownThread
Tells the user thread to shutdown. Blocks until it happens.
@return (void)
*/
void ShutdownThread();
/*
public ZThread::StartThread
When StartThread is called on a class that extends ZThread, a thread will be created
that will call the run() function implemented by the subclass.
@return (bool) - boolean indicating the thread has started successfully
*/
bool StartThread();
/*
public ZThread::WaitInitialized
Caller waits until the ZThread has initialized.
@return (void)
@context (all)
*/
void WaitInitialized();
/*
public ZThread::WaitShutdown
Caller waits until the ZThread has shutdown.
@return (void)
@context (all)
*/
void WaitShutdown();
protected:
//Thread 'name' of this thread
ZString ThreadName;
//Boolean field which, when set to true, indicates the thread should terminate.
bool bShouldShutdown;
//Boolean field which, when set to true, indicates the thread should pause.
bool bShouldPause;
/*
This is a wrapper around the user run() method, which calls that method in a loop, executing
thread requests and setting the condition variables appropriately.
*/
void Run();
/*
Executes the thread requests that may be pending at the time it is called by the subclass.
*/
void ExecuteThreadRequests();
/*
Initialization method which is called when the thread starts. Does not have to be overridden, but any
thread specific initialization that must be done in the thread context of the ZThread object needs
to be defined here.
*/
virtual void initThread() { }
/*
Shutdown method which is called when the thread terminates. Does not have to be overridden, but any
thread specific shutdown requirements that must be done in the thread context of the ZThread object
needs to be defined here.
*/
virtual void shutdownThread() { }
/*
This method must be implemented by the ZThread subclass. This is the 'main' function of execution for
the newly created thread.
@param _dt - the time (in ms) since last time run was called
@return - a ZTHREAD_RETURN value indicating whether the thread should run once (ZTR_TERMINATE),
loop (ZTR_RETURN), or pause (ZTR_PAUSE).
*/
virtual ZThreadReturn run(uint64_t _dt) = 0;
bool IsCallerTheThread();
private:
struct ZThreadCallbackRequest {
ZThreadCallbackFunc callback;
void* arg;
SST_Event doneEvent;
};
//Thread context of this thread
ZThreadContext ThreadContext;
//The mutex for use by this thread object for handling thread marshaling.
ZMutex ThreadLock;
//The event signaled when the thread has finished initializing
ZEvent InitEvent;
//Previous tick count for this thread object
uint64_t PreviousTickCount;
//Current tick count for this thread object
uint64_t CurrentTickCount;
//Boolean field which, when set to true, indicates the thread is initialized and running.
bool bIsRunning;
//Boolean field which, when set to true, indicates the thread has called and returned from initThread()
bool bIsInitialized;
//List of callbacks that will occur when the ZThread object runs.
ZList< ZPtr<ZThreadRequest> > ZTRCallbacks; // ZTR callbacks
ZList< ZThreadCallbackRequest > Callbacks; // Simple (non-object) callbacks
/*
Proxy method called by StartThread() which will call initThread and Run on the ZThread Object.
@param _runnable - a pointer to the ZThread object to run
@return - integer condition (not used)
*/
static int InitThread(void *_runnable);
};
#endif

49
Include/ZUtil/ZUtil.hpp Normal file
View File

@@ -0,0 +1,49 @@
/*
ZUtil.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 12/26/2011
Purpose:
Header for the ZUtil project that includes all other ZUtil headers
in the proper order.
License:
TODO
*/
#pragma once
#ifndef _ZUTIL_HPP
#define _ZUTIL_HPP
/* ZUtil Project Build File */
#include <ZUtil/ZUtilBuild.hpp>
/* External Includes */
#include <ZSTL/ZSTL.hpp>
/* Standard Util Includes */
#include <ZUtil/ZAssert.hpp>
#include <ZUtil/ZAlloc.hpp>
#include <ZUtil/ZConcurrency.hpp>
#include <ZUtil/ZLog.hpp>
#include <ZUtil/ZThread.hpp>
#include <ZUtil/ZTaskStream.hpp>
#include <ZUtil/ZName.hpp>
#include <ZUtil/ZBitmap.hpp>
#include <ZUtil/ZSmartPointer.hpp>
#include <ZUtil/ZWeakPointer.hpp>
#include <ZUtil/ZSlabAllocator.hpp>
#include <ZUtil/ZBinaryBufferReader.hpp>
#include <ZUtil/ZBinaryBufferWriter.hpp>
#include <ZUtil/ZKVTree.hpp>
#endif

View File

@@ -0,0 +1,121 @@
/*
ZUtilBuild.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 11/7/2010
Purpose:
Used to generate definitions for the preprocessor using only compiler-set
preprocessor variables, mostly to force a semblance of cross-system compatibility.
License:
TODO
*/
#pragma once
#ifndef _ZUTILBUILD_HPP
#define _ZUTILBUILD_HPP
//This gives us our standard int types
#include <pstdint.h>
#include "ZBuild.hpp"
//Version number constants for ZUtil
#define ZUTIL_VERSION_MAJOR 0x01
#define ZUTIL_VERSION_MINOR 0x00
#define ZUTIL_VERSION_PATCH 0x0000
#define ZUTIL_VERSION (ZUTIL_VERSION_MAJOR << 24) | (ZUTIL_VERSION_MINOR << 16) | (ZUTIL_VERSION_PATCH)
#define ZUTIL_VERSION_STRING "1.0.0"
//Make sure we get proper C-style TRUE, FALSE, and NULL
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#define NULL 0
#endif
//Get our numeric limits
#include <limits>
#undef min
#undef max
#define STDINT_MAX std::numeric_limits<int>::max()
#define STDINT_MIN std::numeric_limits<int>::min()
#define STDFLT_MAX std::numeric_limits<float>::max()
#define STDFLT_MIN std::numeric_limits<float>::min()
#define STDDBL_MAX std::numeric_limits<double>::max()
#define STDDBL_MIN std::numeric_limits<double>::min()
//Used to get rid of the (/W4 or -Wall) warning 'Unreferenced Formal Parameter'
#if !defined(URFP)
#define URFP(x) ((void)x)
#endif
//Use this to disable copy construction and assignment on a class
#define DISABLE_COPY_AND_ASSIGN(ClassName) \
ClassName(const ClassName&); \
void operator = (const ClassName&)
//Directory separators and line terminators for the various platforms
#define DIRECTORY_SEPARATOR_WIN32 "\\"
#define LINE_TERMINATOR_WIN32 "\r\n"
#define DIRECTORY_SEPARATOR_UNIX "/"
#define LINE_TERMINATOR_UNIX "\n"
#define DIRECTORY_SEPARATOR_OSX ":"
#define LINE_TERMINATOR_OSX "\n"
//Windows specialized defines
#ifdef _WIN32
#define WINDOWS 1
#define UNIX 0
#define OSX 0
#define DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR_WIN32
#define LINE_TERMINATOR LINE_TERMINATOR_WIN32
#define _SCL_SECURE_NO_WARNINGS
#endif
//UNIX specialized defines
#ifdef _UNIX
#define WINDOWS 0
#define UNIX 1
#define OSX 0
#define DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR_UNIX
#define LINE_TERMINATOR LINE_TERMINATOR_UNIX
//Macros to get around gcc's lack of *_s and _* functions and vc9's insistence on using them
#define _stricmp(a, b) strcasecmp(a, b)
#define sprintf_s(a, b, c, d...) snprintf(a, b, c, ## d)
#define vsnprintf_s(a, b, c, d, e...) vsnprintf(a, b, d, ## e)
#endif
//Mac specialized defines
#ifdef _MACOS
#define WINDOWS 0
#define UNIX 0
#define OSX 1
#define DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR_OSX
#define LINE_TERMINATOR LINE_TERMINATOR_OSX
#define _stricmp(a, b) strcasecmp(a, b)
#define sprintf_s(a, b, c, d...) snprintf(a, b, c, ## d)
#define vsnprintf_s(a, b, c, d, e...) vsnprintf(a, b, d, ## e)
#endif
#endif //_ZUTILBUILD_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,160 @@
/*
ZXMLReader.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 5/11/2012
Purpose:
Reads in data from the given XML input and parses the data into a ZKVTree instance
that can be used for path-based lookup and iteration of values. For example, the following
XML data:
<node type="emitter">
<position x="100" y="100" z="1" />
<facing x="0" y="0" z="1" />
This is a particle emitter node.
</node>
<node type="time" value="2200" />
Is given the following ZKVTree layout (node values in parenthesis):
Root
|
+-> node (This is a particle emitter node.)
| |
| +-> type (emitter)
| |
| +-> position ()
| | |
| | +-> x (100)
| | +-> y (100)
| | +-> z (1)
| |
| +-> facing ()
| | |
| +-> x (0)
| +-> y (0)
| +-> z (1)
|
+-> node
|
+-> type (time)
+-> value (2200)
Note that all XML elements will have the body assigned to the value of the node. Attributes
will have their attribute value assigned to the node value, but will never have child nodes.
This does mean that an XML element with a body value but no attributes will be functionally
identical in the KVTree representation to an attribute of the parent element. For example, the
following two XML snippets will have an identical layout in the KVTree:
<node type="emitter">
<flags>1</flags>
</node>
<node type="emitter" flags="1" />
The parsed layout in ZKVTree form is as follows:
Root
|
+-> node ()
|
+-> type (emitter)
|
+-> flags (1)
Note that the current implementation uses rapidxml, and will technically parse a superset of W3C
compliant XML as valid. In particular, closing tags are not checked for matching, meaning that
any closing tag will close any node. There are other non-W3C compliance issues with rapidxml
as well, although it will never refuse to parse valid XML.
More information about rapidxml can be found here: http://rapidxml.sourceforge.net/manual.html
License:
TODO
*/
#pragma once
#ifndef _ZXMLREADER_HPP
#define _ZXMLREADER_HPP
#include <ZUtil/ZKVTree.hpp>
#include <ZUtil/ZSmartPointer.hpp>
/*
ZXMLReader class, which converts XML data into a ZKVtree that can be used to access / iterate
the data.
*/
class ZXMLReader
{
public:
/*
Default Constructor.
*/
ZXMLReader()
: ErrorMessage() { }
/*
Destructor.
*/
~ZXMLReader()
{ Tree.Clear(); }
/*
public ZXMLReader::Read
Reads in XML data stored as a ZString and parses it into an internal format.
@param _xml - Pointer to XML data
@return (bool) - true if successful, false if failure (use GetErrorString() to get the message)
*/
bool Read(const ZString& _xml)
{ return Read(_xml.Data(), _xml.Length()); }
/*
public ZXMLReader::Read
Reads in XML data stored as a memory block and parses it into an internal format.
@param _data - Pointer to XML data
@param _length - Length of XML data
@return (bool) - true if successful, false if failure (use GetErrorString() to get the message)
*/
bool Read(const char* _data, size_t _length);
/*
public ZXMLReader::GetErrorString
Gets the error message generated while loading the data if loading failed. If loading
the data was successful, this returns an empty string.
@return (const ZString&) - error message string
*/
const ZString& GetErrorString();
/*
public ZXMLReader::GetKVTree
Gets the data from the parsed XML as a key-value tree. If the loading failed,
the tree is returned empty.
@param _kvtree - the tree to fill with parsed xml data
*/
void GetKVTree(ZKVTree& _kvtree);
private:
DISABLE_COPY_AND_ASSIGN(ZXMLReader);
ZString ErrorMessage; // error message (if there has been an error)
ZKVTree Tree; // tree to store the xml in
};
#endif

View File

@@ -0,0 +1,110 @@
/*
ZXMLWriter.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 5/13/2012
Purpose:
Interprets a ZKVTree as XML, writing the node structure and values into XML elements. Acts as
an inverse of ZXMLReader (see header for details on format).
Note that the same ambiguity is present for elements with no attributes and body data - they will
be written out as attributes. For example, consider the following ZKVTree structure:
Root
|
+-> node (This is a particle emitter node.)
| |
| +-> type (emitter)
| |
| +-> position ()
| | |
| | +-> x (100)
| | +-> y (100)
| | +-> z (1)
| |
| +-> facing ()
| | |
| | +-> x (0)
| | +-> y (0)
| | +-> z (1)
| |
| +-> flags (1)
|
+-> node
|
+-> type (time)
+-> value (2200)
The above will be written out as follows:
<node type="emitter" flags="1">
<position x="100" y="100" z="1" />
<facing x="0" y="0" z="1" />
This is a particle emitter node.
</node>
<node type="time" value="2200" />
Notice that the ambiguous case described in ZXMLReader.hpp for an attribute of an XML
element and the body of an attribute-free element will always be written out as an
attribute.
The body of 'node' is not ambiguous because the 'node' element has attributes and child
elements.
License:
TODO
*/
#pragma once
#ifndef _ZXMLWRITER_HPP
#define _ZXMLWRITER_HPP
#include <ZUtil/ZKVTree.hpp>
class ZXMLWriter
{
private:
DISABLE_COPY_AND_ASSIGN(ZXMLWriter);
//Error message (if an error has happened)
ZString ErrorMessage;
// recursive functions for writing XML
bool writeAttributes(ZString& _output, const ZKVTree::Iterator& _itr);
bool writeElements(ZString& _output, bool _useNewlines, const ZKVTree::Iterator& _itr);
public:
/*
Default Constructor.
*/
ZXMLWriter() { }
/*
public ZXMLWriter::GetErrorString
Gets the error message generated while writing the data if writing failed. If writing
the data was successful, this returns an empty string.
@return (const ZString&)
*/
const ZString& GetErrorString();
/*
public ZXMLWriter::Write
Writes the data from the registry into the provided output string in XML format.
@param _input - the KVTree we wish to represent as XML
@param _output - the string to write the data into (the data is appended)
@param _useNewlines - indicates whether or not we should use newlines in the output
@return (bool) - true if successful, false otherwise
*/
bool Write(const ZKVTree& _input, ZString& _output, bool _useNewlines);
};
#endif