384 lines
9.1 KiB
C++
384 lines
9.1 KiB
C++
/*
|
|
ZSTLCommon.hpp
|
|
Author: James Russell <jcrussell@762studios.com>
|
|
Created: 9/13/2011
|
|
|
|
Purpose:
|
|
|
|
Common include file used by all ZSTL components.
|
|
|
|
License:
|
|
|
|
This program is free software. It comes without any warranty, to
|
|
the extent permitted by applicable law. You can redistribute it
|
|
and/or modify it under the terms of the Do What The Fuck You Want
|
|
To Public License, Version 2, as published by Sam Hocevar. See
|
|
http://sam.zoy.org/wtfpl/COPYING for more details.
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifndef _ZSTLCOMMON_HPP
|
|
#define _ZSTLCOMMON_HPP
|
|
|
|
#include <pstdint.h> //Need this for our int types
|
|
#include <new> //This gives us (std::nothrow)
|
|
#include <assert.h> //This gives us assert
|
|
#include <stdlib.h> //This gives us a definition for NULL
|
|
|
|
//Hash Value Type
|
|
typedef uint64_t ZHashValue;
|
|
|
|
//Used to get rid of the (/W4 or -Wall) warning 'Unreferenced Formal Parameter'
|
|
#ifndef URFP
|
|
#define URFP(x) ((void)x)
|
|
#endif
|
|
|
|
//Default allocation macro used by ZSTL default allocators
|
|
#ifndef ZSTL_NEW
|
|
#define ZSTL_NEW(_type) new (std::nothrow) _type()
|
|
#endif
|
|
|
|
//Default delete macro used by ZSTL default allocators
|
|
#ifndef ZSTL_DEL
|
|
#define ZSTL_DEL(_object) delete _object
|
|
#endif
|
|
|
|
//Default array allocation macro used by ZSTL default allocators
|
|
#ifndef ZSTL_NEW_ARRAY
|
|
#define ZSTL_NEW_ARRAY(_type, _size) new (std::nothrow) _type[_size]
|
|
#endif
|
|
|
|
//Default array delete macro used by ZSTL default allocators
|
|
#ifndef ZSTL_DEL_ARRAY
|
|
#define ZSTL_DEL_ARRAY(_ptr, _size) ((void)_size); delete[] _ptr
|
|
#endif
|
|
|
|
//Default assert macro used by ZSTL
|
|
#ifndef ZSTL_ASSERT
|
|
#define ZSTL_ASSERT(condition, message) (assert(condition && message))
|
|
#endif
|
|
|
|
//Error condition macro used by ZSTL
|
|
#ifndef ZSTL_ERROR
|
|
#define ZSTL_ERROR(message) (assert(0 && message))
|
|
#endif
|
|
|
|
//Swap used in array quicksort (takes array, first index, second index)
|
|
#define ZSTL_ARRAY_ELEMENT_SWAP(_a, _i, _j) temp = _a[_j]; _a[_j] = _a[_i]; _a[_i] = temp
|
|
|
|
//Push used in list mergesort (takes list node and new node)
|
|
#define ZSTL_LIST_ELEMENT_PUSH(_l, _n) if (_l == NULL) { _l = _n; } else { _l->Next = _n; _n->Previous = _l; _l = _n; }
|
|
|
|
/*
|
|
public BoundsCheck<I>
|
|
|
|
Function that checks the provided index against the provided boundary, asserting if an
|
|
out of bounds access occurs. Calls to this will be compiled out if ZSTL_DISABLE_RUNTIME_CHECKS
|
|
is not zero.
|
|
|
|
@param I - the type of index
|
|
@param _index - index to check
|
|
@param _boundary - the (exclusive) boundary to use for bounds checking
|
|
@return (size_t) - unsigned index
|
|
@assert - if the index is not less than boundary
|
|
*/
|
|
template <typename I>
|
|
size_t BoundsCheck(I _index, I _boundary)
|
|
{
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(_index < _boundary, "ZSTL: Out of bounds access!");
|
|
#endif
|
|
|
|
return (size_t)_index;
|
|
}
|
|
|
|
/*
|
|
Node class, which is used by ZList to contain list data and previous / next pointers. Could
|
|
be used by other classes that also need basic list-like functionality.
|
|
|
|
The template parameter T is the type contained by the list node.
|
|
*/
|
|
template <typename T>
|
|
struct ZListNode
|
|
{
|
|
//Default Constructor
|
|
ZListNode()
|
|
: Next(NULL), Previous(NULL), Element() { }
|
|
|
|
//Parameterized Constructor
|
|
ZListNode(ZListNode<T>* _next, ZListNode<T>* _previous)
|
|
: Next(_next), Previous(_previous), Element() { }
|
|
|
|
//Parameterized Constructor
|
|
ZListNode(ZListNode<T>* _next, ZListNode<T>* _previous, const T& _value)
|
|
: Next(_next), Previous(_previous), Element(_value) { }
|
|
|
|
//The next node
|
|
ZListNode* Next;
|
|
|
|
//The previous node
|
|
ZListNode* Previous;
|
|
|
|
//The contained element
|
|
T Element;
|
|
|
|
};
|
|
|
|
/*
|
|
Comparator functor, used when a delegate is needed to provide comparison information on
|
|
elements. This implementation uses operator < on elements.
|
|
|
|
The template parameter T is the type we will be comparing to each other.
|
|
*/
|
|
template <typename T>
|
|
struct ZComparator
|
|
{
|
|
ZComparator() { } //Silence Sun C++ warnings about uninitialized structs
|
|
|
|
//operator overload which returns -1 if a < b, 0 if a == b, and 1 if a > b
|
|
int operator () (const T& _a, const T& _b) const
|
|
{
|
|
if (_a < _b)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (_b < _a)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
/*
|
|
Array quicksort functor. Uses a recursive in-place sort. This implementation is
|
|
not a stable sort.
|
|
|
|
The template parameter T is the type contained by the array we will be sorting.
|
|
*/
|
|
template <typename T>
|
|
struct ZArrayQuickSort
|
|
{
|
|
ZArrayQuickSort() { } //Silence Sun C++ warnings about uninitialized structs
|
|
|
|
//Helper function which partitions the array
|
|
template <typename CF>
|
|
inline size_t Partition(CF& _comparator, T* _array, size_t _left, size_t _right, size_t _pivot)
|
|
{
|
|
size_t i, j;
|
|
T temp;
|
|
|
|
//Get the value at the pivot point
|
|
T pivotValue = _array[_pivot];
|
|
|
|
//Move pivot to end
|
|
ZSTL_ARRAY_ELEMENT_SWAP(_array, _pivot, _right);
|
|
|
|
//Check values from left up to pivot
|
|
for (i = _left, j = _left; i < _right; i++)
|
|
{
|
|
//If less than the pivot value
|
|
if (_comparator(_array[i], pivotValue) < 0)
|
|
{
|
|
//Swap back and increment our 'target' index j
|
|
ZSTL_ARRAY_ELEMENT_SWAP(_array, i, j);
|
|
j++;
|
|
}
|
|
}
|
|
|
|
//Move pivot to final location (all values with index < j are < pivotValue)
|
|
ZSTL_ARRAY_ELEMENT_SWAP(_array, j, _right);
|
|
|
|
return j;
|
|
}
|
|
|
|
//Helper function which performs the sorting
|
|
template <typename CF>
|
|
void QuickSort(CF& _comparator, T* _array, size_t _left, size_t _right)
|
|
{
|
|
size_t pivot;
|
|
|
|
if (_right > _left)
|
|
{
|
|
//Center pivot point (guarded against overflow)
|
|
pivot = _left + (_right - _left) / 2;
|
|
|
|
//Get our next pivot after partitioning around the current
|
|
pivot = Partition(_comparator, _array, _left, _right, pivot);
|
|
|
|
//Sort the left partition
|
|
if (pivot != 0)
|
|
QuickSort(_comparator, _array, _left, pivot - 1);
|
|
|
|
//Sort the right partition
|
|
QuickSort(_comparator, _array, pivot + 1, _right);
|
|
}
|
|
}
|
|
|
|
//Functor operator () override
|
|
template <typename CF>
|
|
void operator () (CF& _comparator, T* _array, size_t _size)
|
|
{
|
|
QuickSort(_comparator, _array, 0, _size - 1);
|
|
}
|
|
};
|
|
|
|
/*
|
|
List merge sort functor. This implementation is a 'stable' sort.
|
|
|
|
The template parameter T is the type contained by the underlying list we will be sorting.
|
|
*/
|
|
template <typename T>
|
|
struct ZListMergeSort
|
|
{
|
|
ZListMergeSort() { } //Silence Sun C++ warnings about initialized structs
|
|
|
|
//Special 'Len' function which uses no end node
|
|
inline size_t Length(ZListNode<T>* _list)
|
|
{
|
|
size_t i = 0;
|
|
ZListNode<T>* node;
|
|
|
|
//for (i = 0, node = _list; node != NULL; i++, node = node->Next);
|
|
|
|
node = _list;
|
|
while (node != NULL)
|
|
{
|
|
node = node->Next;
|
|
i++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
//Helper function which merges two lists, returns the last node
|
|
template <typename CF>
|
|
inline ZListNode<T>* Merge(CF& _comparator, ZListNode<T>* _left, ZListNode<T>* _right)
|
|
{
|
|
ZListNode<T>* merged = NULL;
|
|
|
|
//While left and right still have elements
|
|
while (_left != NULL && _right != NULL)
|
|
{
|
|
//Compare first elements
|
|
if (_comparator(_left->Element, _right->Element) < 0)
|
|
{
|
|
//Add the left element
|
|
ZSTL_LIST_ELEMENT_PUSH(merged, _left);
|
|
_left = _left->Next;
|
|
}
|
|
else
|
|
{
|
|
//Add the right element
|
|
ZSTL_LIST_ELEMENT_PUSH(merged, _right);
|
|
_right = _right->Next;
|
|
}
|
|
}
|
|
|
|
//While the left still has elements
|
|
while (_left != NULL)
|
|
{
|
|
//Add them
|
|
ZSTL_LIST_ELEMENT_PUSH(merged, _left);
|
|
_left = _left->Next;
|
|
}
|
|
|
|
//While the right still has elements
|
|
while (_right != NULL)
|
|
{
|
|
//Add them
|
|
ZSTL_LIST_ELEMENT_PUSH(merged, _right);
|
|
_right = _right->Next;
|
|
}
|
|
|
|
//Return the end node
|
|
return merged;
|
|
}
|
|
|
|
//Helper function which merge sorts a list, returns the last node
|
|
template <typename CF>
|
|
inline ZListNode<T>* MergeSort(CF& _comparator, ZListNode<T>* _start)
|
|
{
|
|
size_t i;
|
|
size_t middle;
|
|
|
|
ZListNode<T>* left;
|
|
ZListNode<T>* right;
|
|
|
|
//If none or one element
|
|
if (_start == NULL || _start->Next == NULL)
|
|
return _start;
|
|
|
|
//Determine midpoint
|
|
middle = Length(_start) / 2;
|
|
|
|
//Set our left and right
|
|
left = right = _start;
|
|
|
|
//Set right to midpoint
|
|
for (i = 0; i < middle; i++)
|
|
right = right->Next;
|
|
|
|
//Seperate the list
|
|
right->Previous->Next = NULL;
|
|
right->Previous = NULL;
|
|
|
|
//Sort left and right recursively
|
|
MergeSort(_comparator, left);
|
|
MergeSort(_comparator, right);
|
|
|
|
//Set back our left list pointer
|
|
while (left != NULL && left->Previous != NULL)
|
|
left = left->Previous;
|
|
|
|
//Set back our right list pointer
|
|
while (right != NULL && right->Previous != NULL)
|
|
right = right->Previous;
|
|
|
|
//Return the last node from the merged lists
|
|
return Merge(_comparator, left, right);
|
|
}
|
|
|
|
//Functor operator () override
|
|
template <typename CF>
|
|
void operator () (CF& _comparator, ZListNode<T>* _start, ZListNode<T>* _end)
|
|
{
|
|
ZListNode<T>* prev;
|
|
|
|
//Check to see if list is empty
|
|
if (_start == _end)
|
|
return;
|
|
|
|
//Get the node before the starting node
|
|
prev = _start->Previous;
|
|
|
|
//Split the end node off
|
|
_end->Previous->Next = NULL;
|
|
_start->Previous = NULL;
|
|
//Reset the end node back
|
|
_end->Previous = MergeSort(_comparator, _start);
|
|
|
|
//Attach
|
|
_end->Previous->Next = _end;
|
|
|
|
//Reattach the node before _start
|
|
if (prev != NULL)
|
|
{
|
|
ZListNode<T>* current = _end;
|
|
|
|
while (current->Previous != NULL)
|
|
current = current->Previous;
|
|
|
|
current->Previous = prev;
|
|
prev->Next = current;
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif
|