/* ZSTLCommon.hpp Author: James Russell 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 //Need this for our int types #include //This gives us (std::nothrow) #include //This gives us assert #include //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 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 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 struct ZListNode { //Default Constructor ZListNode() : Next(NULL), Previous(NULL), Element() { } //Parameterized Constructor ZListNode(ZListNode* _next, ZListNode* _previous) : Next(_next), Previous(_previous), Element() { } //Parameterized Constructor ZListNode(ZListNode* _next, ZListNode* _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 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 struct ZArrayQuickSort { ZArrayQuickSort() { } //Silence Sun C++ warnings about uninitialized structs //Helper function which partitions the array template 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 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 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 struct ZListMergeSort { ZListMergeSort() { } //Silence Sun C++ warnings about initialized structs //Special 'Len' function which uses no end node inline size_t Length(ZListNode* _list) { size_t i = 0; ZListNode* 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 inline ZListNode* Merge(CF& _comparator, ZListNode* _left, ZListNode* _right) { ZListNode* 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 inline ZListNode* MergeSort(CF& _comparator, ZListNode* _start) { size_t i; size_t middle; ZListNode* left; ZListNode* 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 void operator () (CF& _comparator, ZListNode* _start, ZListNode* _end) { ZListNode* 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* current = _end; while (current->Previous != NULL) current = current->Previous; current->Previous = prev; prev->Next = current; } } }; #endif