nuclear@3: /************************************************************************************ nuclear@3: nuclear@3: PublicHeader: OVR.h nuclear@3: Filename : OVR_Alg.h nuclear@3: Content : Simple general purpose algorithms: Sort, Binary Search, etc. nuclear@3: Created : September 19, 2012 nuclear@3: Notes : nuclear@3: nuclear@3: Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. nuclear@3: nuclear@3: Use of this software is subject to the terms of the Oculus license nuclear@3: agreement provided at the time of installation or download, or which nuclear@3: otherwise accompanies this software in either electronic or hard copy form. nuclear@3: nuclear@3: ************************************************************************************/ nuclear@3: nuclear@3: #ifndef OVR_Alg_h nuclear@3: #define OVR_Alg_h nuclear@3: nuclear@3: #include "OVR_Types.h" nuclear@3: #include nuclear@3: nuclear@3: namespace OVR { namespace Alg { nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** Operator extensions nuclear@3: nuclear@3: template OVR_FORCE_INLINE void Swap(T &a, T &b) nuclear@3: { T temp(a); a = b; b = temp; } nuclear@3: nuclear@3: nuclear@3: // ***** min/max are not implemented in Visual Studio 6 standard STL nuclear@3: nuclear@3: template OVR_FORCE_INLINE const T Min(const T a, const T b) nuclear@3: { return (a < b) ? a : b; } nuclear@3: nuclear@3: template OVR_FORCE_INLINE const T Max(const T a, const T b) nuclear@3: { return (b < a) ? a : b; } nuclear@3: nuclear@3: template OVR_FORCE_INLINE const T Clamp(const T v, const T minVal, const T maxVal) nuclear@3: { return Max(minVal, Min(v, maxVal)); } nuclear@3: nuclear@3: template OVR_FORCE_INLINE int Chop(T f) nuclear@3: { return (int)f; } nuclear@3: nuclear@3: template OVR_FORCE_INLINE T Lerp(T a, T b, T f) nuclear@3: { return (b - a) * f + a; } nuclear@3: nuclear@3: nuclear@3: // These functions stand to fix a stupid VC++ warning (with /Wp64 on): nuclear@3: // "warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned', possible loss of data" nuclear@3: // Use these functions instead of gmin/gmax if the argument has size nuclear@3: // of the pointer to avoid the warning. Though, functionally they are nuclear@3: // absolutelly the same as regular gmin/gmax. nuclear@3: template OVR_FORCE_INLINE const T PMin(const T a, const T b) nuclear@3: { nuclear@3: OVR_COMPILER_ASSERT(sizeof(T) == sizeof(UPInt)); nuclear@3: return (a < b) ? a : b; nuclear@3: } nuclear@3: template OVR_FORCE_INLINE const T PMax(const T a, const T b) nuclear@3: { nuclear@3: OVR_COMPILER_ASSERT(sizeof(T) == sizeof(UPInt)); nuclear@3: return (b < a) ? a : b; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: template OVR_FORCE_INLINE const T Abs(const T v) nuclear@3: { return (v>=0) ? v : -v; } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** OperatorLess nuclear@3: // nuclear@3: template struct OperatorLess nuclear@3: { nuclear@3: static bool Compare(const T& a, const T& b) nuclear@3: { nuclear@3: return a < b; nuclear@3: } nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** QuickSortSliced nuclear@3: // nuclear@3: // Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. nuclear@3: // The range is specified with start, end, where "end" is exclusive! nuclear@3: // The comparison predicate must be specified. nuclear@3: template nuclear@3: void QuickSortSliced(Array& arr, UPInt start, UPInt end, Less less) nuclear@3: { nuclear@3: enum nuclear@3: { nuclear@3: Threshold = 9 nuclear@3: }; nuclear@3: nuclear@3: if(end - start < 2) return; nuclear@3: nuclear@3: SPInt stack[80]; nuclear@3: SPInt* top = stack; nuclear@3: SPInt base = (SPInt)start; nuclear@3: SPInt limit = (SPInt)end; nuclear@3: nuclear@3: for(;;) nuclear@3: { nuclear@3: SPInt len = limit - base; nuclear@3: SPInt i, j, pivot; nuclear@3: nuclear@3: if(len > Threshold) nuclear@3: { nuclear@3: // we use base + len/2 as the pivot nuclear@3: pivot = base + len / 2; nuclear@3: Swap(arr[base], arr[pivot]); nuclear@3: nuclear@3: i = base + 1; nuclear@3: j = limit - 1; nuclear@3: nuclear@3: // now ensure that *i <= *base <= *j nuclear@3: if(less(arr[j], arr[i])) Swap(arr[j], arr[i]); nuclear@3: if(less(arr[base], arr[i])) Swap(arr[base], arr[i]); nuclear@3: if(less(arr[j], arr[base])) Swap(arr[j], arr[base]); nuclear@3: nuclear@3: for(;;) nuclear@3: { nuclear@3: do i++; while( less(arr[i], arr[base]) ); nuclear@3: do j--; while( less(arr[base], arr[j]) ); nuclear@3: nuclear@3: if( i > j ) nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: nuclear@3: Swap(arr[i], arr[j]); nuclear@3: } nuclear@3: nuclear@3: Swap(arr[base], arr[j]); nuclear@3: nuclear@3: // now, push the largest sub-array nuclear@3: if(j - base > limit - i) nuclear@3: { nuclear@3: top[0] = base; nuclear@3: top[1] = j; nuclear@3: base = i; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: top[0] = i; nuclear@3: top[1] = limit; nuclear@3: limit = j; nuclear@3: } nuclear@3: top += 2; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: // the sub-array is small, perform insertion sort nuclear@3: j = base; nuclear@3: i = j + 1; nuclear@3: nuclear@3: for(; i < limit; j = i, i++) nuclear@3: { nuclear@3: for(; less(arr[j + 1], arr[j]); j--) nuclear@3: { nuclear@3: Swap(arr[j + 1], arr[j]); nuclear@3: if(j == base) nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: if(top > stack) nuclear@3: { nuclear@3: top -= 2; nuclear@3: base = top[0]; nuclear@3: limit = top[1]; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** QuickSortSliced nuclear@3: // nuclear@3: // Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. nuclear@3: // The range is specified with start, end, where "end" is exclusive! nuclear@3: // The data type must have a defined "<" operator. nuclear@3: template nuclear@3: void QuickSortSliced(Array& arr, UPInt start, UPInt end) nuclear@3: { nuclear@3: typedef typename Array::ValueType ValueType; nuclear@3: QuickSortSliced(arr, start, end, OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: // Same as corresponding G_QuickSortSliced but with checking array limits to avoid nuclear@3: // crash in the case of wrong comparator functor. nuclear@3: template nuclear@3: bool QuickSortSlicedSafe(Array& arr, UPInt start, UPInt end, Less less) nuclear@3: { nuclear@3: enum nuclear@3: { nuclear@3: Threshold = 9 nuclear@3: }; nuclear@3: nuclear@3: if(end - start < 2) return true; nuclear@3: nuclear@3: SPInt stack[80]; nuclear@3: SPInt* top = stack; nuclear@3: SPInt base = (SPInt)start; nuclear@3: SPInt limit = (SPInt)end; nuclear@3: nuclear@3: for(;;) nuclear@3: { nuclear@3: SPInt len = limit - base; nuclear@3: SPInt i, j, pivot; nuclear@3: nuclear@3: if(len > Threshold) nuclear@3: { nuclear@3: // we use base + len/2 as the pivot nuclear@3: pivot = base + len / 2; nuclear@3: Swap(arr[base], arr[pivot]); nuclear@3: nuclear@3: i = base + 1; nuclear@3: j = limit - 1; nuclear@3: nuclear@3: // now ensure that *i <= *base <= *j nuclear@3: if(less(arr[j], arr[i])) Swap(arr[j], arr[i]); nuclear@3: if(less(arr[base], arr[i])) Swap(arr[base], arr[i]); nuclear@3: if(less(arr[j], arr[base])) Swap(arr[j], arr[base]); nuclear@3: nuclear@3: for(;;) nuclear@3: { nuclear@3: do nuclear@3: { nuclear@3: i++; nuclear@3: if (i >= limit) nuclear@3: return false; nuclear@3: } while( less(arr[i], arr[base]) ); nuclear@3: do nuclear@3: { nuclear@3: j--; nuclear@3: if (j < 0) nuclear@3: return false; nuclear@3: } while( less(arr[base], arr[j]) ); nuclear@3: nuclear@3: if( i > j ) nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: nuclear@3: Swap(arr[i], arr[j]); nuclear@3: } nuclear@3: nuclear@3: Swap(arr[base], arr[j]); nuclear@3: nuclear@3: // now, push the largest sub-array nuclear@3: if(j - base > limit - i) nuclear@3: { nuclear@3: top[0] = base; nuclear@3: top[1] = j; nuclear@3: base = i; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: top[0] = i; nuclear@3: top[1] = limit; nuclear@3: limit = j; nuclear@3: } nuclear@3: top += 2; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: // the sub-array is small, perform insertion sort nuclear@3: j = base; nuclear@3: i = j + 1; nuclear@3: nuclear@3: for(; i < limit; j = i, i++) nuclear@3: { nuclear@3: for(; less(arr[j + 1], arr[j]); j--) nuclear@3: { nuclear@3: Swap(arr[j + 1], arr[j]); nuclear@3: if(j == base) nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: if(top > stack) nuclear@3: { nuclear@3: top -= 2; nuclear@3: base = top[0]; nuclear@3: limit = top[1]; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: return true; nuclear@3: } nuclear@3: nuclear@3: template nuclear@3: bool QuickSortSlicedSafe(Array& arr, UPInt start, UPInt end) nuclear@3: { nuclear@3: typedef typename Array::ValueType ValueType; nuclear@3: return QuickSortSlicedSafe(arr, start, end, OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** QuickSort nuclear@3: // nuclear@3: // Sort an array Array, ArrayPaged, ArrayUnsafe. nuclear@3: // The array must have GetSize() function. nuclear@3: // The comparison predicate must be specified. nuclear@3: template nuclear@3: void QuickSort(Array& arr, Less less) nuclear@3: { nuclear@3: QuickSortSliced(arr, 0, arr.GetSize(), less); nuclear@3: } nuclear@3: nuclear@3: // checks for boundaries nuclear@3: template nuclear@3: bool QuickSortSafe(Array& arr, Less less) nuclear@3: { nuclear@3: return QuickSortSlicedSafe(arr, 0, arr.GetSize(), less); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** QuickSort nuclear@3: // nuclear@3: // Sort an array Array, ArrayPaged, ArrayUnsafe. nuclear@3: // The array must have GetSize() function. nuclear@3: // The data type must have a defined "<" operator. nuclear@3: template nuclear@3: void QuickSort(Array& arr) nuclear@3: { nuclear@3: typedef typename Array::ValueType ValueType; nuclear@3: QuickSortSliced(arr, 0, arr.GetSize(), OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: template nuclear@3: bool QuickSortSafe(Array& arr) nuclear@3: { nuclear@3: typedef typename Array::ValueType ValueType; nuclear@3: return QuickSortSlicedSafe(arr, 0, arr.GetSize(), OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** InsertionSortSliced nuclear@3: // nuclear@3: // Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. nuclear@3: // The range is specified with start, end, where "end" is exclusive! nuclear@3: // The comparison predicate must be specified. nuclear@3: // Unlike Quick Sort, the Insertion Sort works much slower in average, nuclear@3: // but may be much faster on almost sorted arrays. Besides, it guarantees nuclear@3: // that the elements will not be swapped if not necessary. For example, nuclear@3: // an array with all equal elements will remain "untouched", while nuclear@3: // Quick Sort will considerably shuffle the elements in this case. nuclear@3: template nuclear@3: void InsertionSortSliced(Array& arr, UPInt start, UPInt end, Less less) nuclear@3: { nuclear@3: UPInt j = start; nuclear@3: UPInt i = j + 1; nuclear@3: UPInt limit = end; nuclear@3: nuclear@3: for(; i < limit; j = i, i++) nuclear@3: { nuclear@3: for(; less(arr[j + 1], arr[j]); j--) nuclear@3: { nuclear@3: Swap(arr[j + 1], arr[j]); nuclear@3: if(j <= start) nuclear@3: { nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** InsertionSortSliced nuclear@3: // nuclear@3: // Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. nuclear@3: // The range is specified with start, end, where "end" is exclusive! nuclear@3: // The data type must have a defined "<" operator. nuclear@3: template nuclear@3: void InsertionSortSliced(Array& arr, UPInt start, UPInt end) nuclear@3: { nuclear@3: typedef typename Array::ValueType ValueType; nuclear@3: InsertionSortSliced(arr, start, end, OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** InsertionSort nuclear@3: // nuclear@3: // Sort an array Array, ArrayPaged, ArrayUnsafe. nuclear@3: // The array must have GetSize() function. nuclear@3: // The comparison predicate must be specified. nuclear@3: nuclear@3: template nuclear@3: void InsertionSort(Array& arr, Less less) nuclear@3: { nuclear@3: InsertionSortSliced(arr, 0, arr.GetSize(), less); nuclear@3: } nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** InsertionSort nuclear@3: // nuclear@3: // Sort an array Array, ArrayPaged, ArrayUnsafe. nuclear@3: // The array must have GetSize() function. nuclear@3: // The data type must have a defined "<" operator. nuclear@3: template nuclear@3: void InsertionSort(Array& arr) nuclear@3: { nuclear@3: typedef typename Array::ValueType ValueType; nuclear@3: InsertionSortSliced(arr, 0, arr.GetSize(), OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** LowerBoundSliced nuclear@3: // nuclear@3: template nuclear@3: UPInt LowerBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val, Less less) nuclear@3: { nuclear@3: SPInt first = (SPInt)start; nuclear@3: SPInt len = (SPInt)(end - start); nuclear@3: SPInt half; nuclear@3: SPInt middle; nuclear@3: nuclear@3: while(len > 0) nuclear@3: { nuclear@3: half = len >> 1; nuclear@3: middle = first + half; nuclear@3: if(less(arr[middle], val)) nuclear@3: { nuclear@3: first = middle + 1; nuclear@3: len = len - half - 1; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: len = half; nuclear@3: } nuclear@3: } nuclear@3: return (UPInt)first; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** LowerBoundSliced nuclear@3: // nuclear@3: template nuclear@3: UPInt LowerBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val) nuclear@3: { nuclear@3: return LowerBoundSliced(arr, start, end, val, OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** LowerBoundSized nuclear@3: // nuclear@3: template nuclear@3: UPInt LowerBoundSized(const Array& arr, UPInt size, const Value& val) nuclear@3: { nuclear@3: return LowerBoundSliced(arr, 0, size, val, OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** LowerBound nuclear@3: // nuclear@3: template nuclear@3: UPInt LowerBound(const Array& arr, const Value& val, Less less) nuclear@3: { nuclear@3: return LowerBoundSliced(arr, 0, arr.GetSize(), val, less); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** LowerBound nuclear@3: // nuclear@3: template nuclear@3: UPInt LowerBound(const Array& arr, const Value& val) nuclear@3: { nuclear@3: return LowerBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** UpperBoundSliced nuclear@3: // nuclear@3: template nuclear@3: UPInt UpperBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val, Less less) nuclear@3: { nuclear@3: SPInt first = (SPInt)start; nuclear@3: SPInt len = (SPInt)(end - start); nuclear@3: SPInt half; nuclear@3: SPInt middle; nuclear@3: nuclear@3: while(len > 0) nuclear@3: { nuclear@3: half = len >> 1; nuclear@3: middle = first + half; nuclear@3: if(less(val, arr[middle])) nuclear@3: { nuclear@3: len = half; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: first = middle + 1; nuclear@3: len = len - half - 1; nuclear@3: } nuclear@3: } nuclear@3: return (UPInt)first; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** UpperBoundSliced nuclear@3: // nuclear@3: template nuclear@3: UPInt UpperBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val) nuclear@3: { nuclear@3: return UpperBoundSliced(arr, start, end, val, OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** UpperBoundSized nuclear@3: // nuclear@3: template nuclear@3: UPInt UpperBoundSized(const Array& arr, UPInt size, const Value& val) nuclear@3: { nuclear@3: return UpperBoundSliced(arr, 0, size, val, OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** UpperBound nuclear@3: // nuclear@3: template nuclear@3: UPInt UpperBound(const Array& arr, const Value& val, Less less) nuclear@3: { nuclear@3: return UpperBoundSliced(arr, 0, arr.GetSize(), val, less); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** UpperBound nuclear@3: // nuclear@3: template nuclear@3: UPInt UpperBound(const Array& arr, const Value& val) nuclear@3: { nuclear@3: return UpperBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess::Compare); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** ReverseArray nuclear@3: // nuclear@3: template void ReverseArray(Array& arr) nuclear@3: { nuclear@3: SPInt from = 0; nuclear@3: SPInt to = arr.GetSize() - 1; nuclear@3: while(from < to) nuclear@3: { nuclear@3: Swap(arr[from], arr[to]); nuclear@3: ++from; nuclear@3: --to; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: nuclear@3: // ***** AppendArray nuclear@3: // nuclear@3: template nuclear@3: void AppendArray(CDst& dst, const CSrc& src) nuclear@3: { nuclear@3: UPInt i; nuclear@3: for(i = 0; i < src.GetSize(); i++) nuclear@3: dst.PushBack(src[i]); nuclear@3: } nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** ArrayAdaptor nuclear@3: // nuclear@3: // A simple adapter that provides the GetSize() method and overloads nuclear@3: // operator []. Used to wrap plain arrays in QuickSort and such. nuclear@3: template class ArrayAdaptor nuclear@3: { nuclear@3: public: nuclear@3: typedef T ValueType; nuclear@3: ArrayAdaptor() : Data(0), Size(0) {} nuclear@3: ArrayAdaptor(T* ptr, UPInt size) : Data(ptr), Size(size) {} nuclear@3: UPInt GetSize() const { return Size; } nuclear@3: const T& operator [] (UPInt i) const { return Data[i]; } nuclear@3: T& operator [] (UPInt i) { return Data[i]; } nuclear@3: private: nuclear@3: T* Data; nuclear@3: UPInt Size; nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** GConstArrayAdaptor nuclear@3: // nuclear@3: // A simple const adapter that provides the GetSize() method and overloads nuclear@3: // operator []. Used to wrap plain arrays in LowerBound and such. nuclear@3: template class ConstArrayAdaptor nuclear@3: { nuclear@3: public: nuclear@3: typedef T ValueType; nuclear@3: ConstArrayAdaptor() : Data(0), Size(0) {} nuclear@3: ConstArrayAdaptor(const T* ptr, UPInt size) : Data(ptr), Size(size) {} nuclear@3: UPInt GetSize() const { return Size; } nuclear@3: const T& operator [] (UPInt i) const { return Data[i]; } nuclear@3: private: nuclear@3: const T* Data; nuclear@3: UPInt Size; nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: extern const UByte UpperBitTable[256]; nuclear@3: extern const UByte LowerBitTable[256]; nuclear@3: nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: inline UByte UpperBit(UPInt val) nuclear@3: { nuclear@3: #ifndef OVR_64BIT_POINTERS nuclear@3: nuclear@3: if (val & 0xFFFF0000) nuclear@3: { nuclear@3: return (val & 0xFF000000) ? nuclear@3: UpperBitTable[(val >> 24) ] + 24: nuclear@3: UpperBitTable[(val >> 16) & 0xFF] + 16; nuclear@3: } nuclear@3: return (val & 0xFF00) ? nuclear@3: UpperBitTable[(val >> 8) & 0xFF] + 8: nuclear@3: UpperBitTable[(val ) & 0xFF]; nuclear@3: nuclear@3: #else nuclear@3: nuclear@3: if (val & 0xFFFFFFFF00000000) nuclear@3: { nuclear@3: if (val & 0xFFFF000000000000) nuclear@3: { nuclear@3: return (val & 0xFF00000000000000) ? nuclear@3: UpperBitTable[(val >> 56) ] + 56: nuclear@3: UpperBitTable[(val >> 48) & 0xFF] + 48; nuclear@3: } nuclear@3: return (val & 0xFF0000000000) ? nuclear@3: UpperBitTable[(val >> 40) & 0xFF] + 40: nuclear@3: UpperBitTable[(val >> 32) & 0xFF] + 32; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: if (val & 0xFFFF0000) nuclear@3: { nuclear@3: return (val & 0xFF000000) ? nuclear@3: UpperBitTable[(val >> 24) ] + 24: nuclear@3: UpperBitTable[(val >> 16) & 0xFF] + 16; nuclear@3: } nuclear@3: return (val & 0xFF00) ? nuclear@3: UpperBitTable[(val >> 8) & 0xFF] + 8: nuclear@3: UpperBitTable[(val ) & 0xFF]; nuclear@3: } nuclear@3: nuclear@3: #endif nuclear@3: } nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: inline UByte LowerBit(UPInt val) nuclear@3: { nuclear@3: #ifndef OVR_64BIT_POINTERS nuclear@3: nuclear@3: if (val & 0xFFFF) nuclear@3: { nuclear@3: return (val & 0xFF) ? nuclear@3: LowerBitTable[ val & 0xFF]: nuclear@3: LowerBitTable[(val >> 8) & 0xFF] + 8; nuclear@3: } nuclear@3: return (val & 0xFF0000) ? nuclear@3: LowerBitTable[(val >> 16) & 0xFF] + 16: nuclear@3: LowerBitTable[(val >> 24) & 0xFF] + 24; nuclear@3: nuclear@3: #else nuclear@3: nuclear@3: if (val & 0xFFFFFFFF) nuclear@3: { nuclear@3: if (val & 0xFFFF) nuclear@3: { nuclear@3: return (val & 0xFF) ? nuclear@3: LowerBitTable[ val & 0xFF]: nuclear@3: LowerBitTable[(val >> 8) & 0xFF] + 8; nuclear@3: } nuclear@3: return (val & 0xFF0000) ? nuclear@3: LowerBitTable[(val >> 16) & 0xFF] + 16: nuclear@3: LowerBitTable[(val >> 24) & 0xFF] + 24; nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: if (val & 0xFFFF00000000) nuclear@3: { nuclear@3: return (val & 0xFF00000000) ? nuclear@3: LowerBitTable[(val >> 32) & 0xFF] + 32: nuclear@3: LowerBitTable[(val >> 40) & 0xFF] + 40; nuclear@3: } nuclear@3: return (val & 0xFF000000000000) ? nuclear@3: LowerBitTable[(val >> 48) & 0xFF] + 48: nuclear@3: LowerBitTable[(val >> 56) & 0xFF] + 56; nuclear@3: } nuclear@3: nuclear@3: #endif nuclear@3: } nuclear@3: nuclear@3: nuclear@3: nuclear@3: // ******* Special (optimized) memory routines nuclear@3: // Note: null (bad) pointer is not tested nuclear@3: class MemUtil nuclear@3: { nuclear@3: public: nuclear@3: nuclear@3: // Memory compare nuclear@3: static int Cmp (const void* p1, const void* p2, UPInt byteCount) { return memcmp(p1, p2, byteCount); } nuclear@3: static int Cmp16(const void* p1, const void* p2, UPInt int16Count); nuclear@3: static int Cmp32(const void* p1, const void* p2, UPInt int32Count); nuclear@3: static int Cmp64(const void* p1, const void* p2, UPInt int64Count); nuclear@3: }; nuclear@3: nuclear@3: // ** Inline Implementation nuclear@3: nuclear@3: inline int MemUtil::Cmp16(const void* p1, const void* p2, UPInt int16Count) nuclear@3: { nuclear@3: SInt16* pa = (SInt16*)p1; nuclear@3: SInt16* pb = (SInt16*)p2; nuclear@3: unsigned ic = 0; nuclear@3: if (int16Count == 0) nuclear@3: return 0; nuclear@3: while (pa[ic] == pb[ic]) nuclear@3: if (++ic==int16Count) nuclear@3: return 0; nuclear@3: return pa[ic] > pb[ic] ? 1 : -1; nuclear@3: } nuclear@3: inline int MemUtil::Cmp32(const void* p1, const void* p2, UPInt int32Count) nuclear@3: { nuclear@3: SInt32* pa = (SInt32*)p1; nuclear@3: SInt32* pb = (SInt32*)p2; nuclear@3: unsigned ic = 0; nuclear@3: if (int32Count == 0) nuclear@3: return 0; nuclear@3: while (pa[ic] == pb[ic]) nuclear@3: if (++ic==int32Count) nuclear@3: return 0; nuclear@3: return pa[ic] > pb[ic] ? 1 : -1; nuclear@3: } nuclear@3: inline int MemUtil::Cmp64(const void* p1, const void* p2, UPInt int64Count) nuclear@3: { nuclear@3: SInt64* pa = (SInt64*)p1; nuclear@3: SInt64* pb = (SInt64*)p2; nuclear@3: unsigned ic = 0; nuclear@3: if (int64Count == 0) nuclear@3: return 0; nuclear@3: while (pa[ic] == pb[ic]) nuclear@3: if (++ic==int64Count) nuclear@3: return 0; nuclear@3: return pa[ic] > pb[ic] ? 1 : -1; nuclear@3: } nuclear@3: nuclear@3: // ** End Inline Implementation nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ******* Byte Order Conversions nuclear@3: namespace ByteUtil { nuclear@3: nuclear@3: // *** Swap Byte Order nuclear@3: nuclear@3: // Swap the byte order of a byte array nuclear@3: inline void SwapOrder(void* pv, int size) nuclear@3: { nuclear@3: UByte* pb = (UByte*)pv; nuclear@3: UByte temp; nuclear@3: for (int i = 0; i < size>>1; i++) nuclear@3: { nuclear@3: temp = pb[size-1-i]; nuclear@3: pb[size-1-i] = pb[i]; nuclear@3: pb[i] = temp; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: // Swap the byte order of primitive types nuclear@3: inline UByte SwapOrder(UByte v) { return v; } nuclear@3: inline SByte SwapOrder(SByte v) { return v; } nuclear@3: inline UInt16 SwapOrder(UInt16 v) { return UInt16(v>>8)|UInt16(v<<8); } nuclear@3: inline SInt16 SwapOrder(SInt16 v) { return SInt16((UInt16(v)>>8)|(v<<8)); } nuclear@3: inline UInt32 SwapOrder(UInt32 v) { return (v>>24)|((v&0x00FF0000)>>8)|((v&0x0000FF00)<<8)|(v<<24); } nuclear@3: inline SInt32 SwapOrder(SInt32 p) { return (SInt32)SwapOrder(UInt32(p)); } nuclear@3: inline UInt64 SwapOrder(UInt64 v) nuclear@3: { nuclear@3: return (v>>56) | nuclear@3: ((v&UInt64(0x00FF000000000000))>>40) | nuclear@3: ((v&UInt64(0x0000FF0000000000))>>24) | nuclear@3: ((v&UInt64(0x000000FF00000000))>>8) | nuclear@3: ((v&UInt64(0x00000000FF000000))<<8) | nuclear@3: ((v&UInt64(0x0000000000FF0000))<<24) | nuclear@3: ((v&UInt64(0x000000000000FF00))<<40) | nuclear@3: (v<<56); nuclear@3: } nuclear@3: inline SInt64 SwapOrder(SInt64 v) { return (SInt64)SwapOrder(UInt64(v)); } nuclear@3: inline float SwapOrder(float p) nuclear@3: { nuclear@3: union { nuclear@3: float p; nuclear@3: UInt32 v; nuclear@3: } u; nuclear@3: u.p = p; nuclear@3: u.v = SwapOrder(u.v); nuclear@3: return u.p; nuclear@3: } nuclear@3: nuclear@3: inline double SwapOrder(double p) nuclear@3: { nuclear@3: union { nuclear@3: double p; nuclear@3: UInt64 v; nuclear@3: } u; nuclear@3: u.p = p; nuclear@3: u.v = SwapOrder(u.v); nuclear@3: return u.p; nuclear@3: } nuclear@3: nuclear@3: // *** Byte-order conversion nuclear@3: nuclear@3: #if (OVR_BYTE_ORDER == OVR_LITTLE_ENDIAN) nuclear@3: // Little Endian to System (LE) nuclear@3: inline UByte LEToSystem(UByte v) { return v; } nuclear@3: inline SByte LEToSystem(SByte v) { return v; } nuclear@3: inline UInt16 LEToSystem(UInt16 v) { return v; } nuclear@3: inline SInt16 LEToSystem(SInt16 v) { return v; } nuclear@3: inline UInt32 LEToSystem(UInt32 v) { return v; } nuclear@3: inline SInt32 LEToSystem(SInt32 v) { return v; } nuclear@3: inline UInt64 LEToSystem(UInt64 v) { return v; } nuclear@3: inline SInt64 LEToSystem(SInt64 v) { return v; } nuclear@3: inline float LEToSystem(float v) { return v; } nuclear@3: inline double LEToSystem(double v) { return v; } nuclear@3: nuclear@3: // Big Endian to System (LE) nuclear@3: inline UByte BEToSystem(UByte v) { return SwapOrder(v); } nuclear@3: inline SByte BEToSystem(SByte v) { return SwapOrder(v); } nuclear@3: inline UInt16 BEToSystem(UInt16 v) { return SwapOrder(v); } nuclear@3: inline SInt16 BEToSystem(SInt16 v) { return SwapOrder(v); } nuclear@3: inline UInt32 BEToSystem(UInt32 v) { return SwapOrder(v); } nuclear@3: inline SInt32 BEToSystem(SInt32 v) { return SwapOrder(v); } nuclear@3: inline UInt64 BEToSystem(UInt64 v) { return SwapOrder(v); } nuclear@3: inline SInt64 BEToSystem(SInt64 v) { return SwapOrder(v); } nuclear@3: inline float BEToSystem(float v) { return SwapOrder(v); } nuclear@3: inline double BEToSystem(double v) { return SwapOrder(v); } nuclear@3: nuclear@3: // System (LE) to Little Endian nuclear@3: inline UByte SystemToLE(UByte v) { return v; } nuclear@3: inline SByte SystemToLE(SByte v) { return v; } nuclear@3: inline UInt16 SystemToLE(UInt16 v) { return v; } nuclear@3: inline SInt16 SystemToLE(SInt16 v) { return v; } nuclear@3: inline UInt32 SystemToLE(UInt32 v) { return v; } nuclear@3: inline SInt32 SystemToLE(SInt32 v) { return v; } nuclear@3: inline UInt64 SystemToLE(UInt64 v) { return v; } nuclear@3: inline SInt64 SystemToLE(SInt64 v) { return v; } nuclear@3: inline float SystemToLE(float v) { return v; } nuclear@3: inline double SystemToLE(double v) { return v; } nuclear@3: nuclear@3: // System (LE) to Big Endian nuclear@3: inline UByte SystemToBE(UByte v) { return SwapOrder(v); } nuclear@3: inline SByte SystemToBE(SByte v) { return SwapOrder(v); } nuclear@3: inline UInt16 SystemToBE(UInt16 v) { return SwapOrder(v); } nuclear@3: inline SInt16 SystemToBE(SInt16 v) { return SwapOrder(v); } nuclear@3: inline UInt32 SystemToBE(UInt32 v) { return SwapOrder(v); } nuclear@3: inline SInt32 SystemToBE(SInt32 v) { return SwapOrder(v); } nuclear@3: inline UInt64 SystemToBE(UInt64 v) { return SwapOrder(v); } nuclear@3: inline SInt64 SystemToBE(SInt64 v) { return SwapOrder(v); } nuclear@3: inline float SystemToBE(float v) { return SwapOrder(v); } nuclear@3: inline double SystemToBE(double v) { return SwapOrder(v); } nuclear@3: nuclear@3: #elif (OVR_BYTE_ORDER == OVR_BIG_ENDIAN) nuclear@3: // Little Endian to System (BE) nuclear@3: inline UByte LEToSystem(UByte v) { return SwapOrder(v); } nuclear@3: inline SByte LEToSystem(SByte v) { return SwapOrder(v); } nuclear@3: inline UInt16 LEToSystem(UInt16 v) { return SwapOrder(v); } nuclear@3: inline SInt16 LEToSystem(SInt16 v) { return SwapOrder(v); } nuclear@3: inline UInt32 LEToSystem(UInt32 v) { return SwapOrder(v); } nuclear@3: inline SInt32 LEToSystem(SInt32 v) { return SwapOrder(v); } nuclear@3: inline UInt64 LEToSystem(UInt64 v) { return SwapOrder(v); } nuclear@3: inline SInt64 LEToSystem(SInt64 v) { return SwapOrder(v); } nuclear@3: inline float LEToSystem(float v) { return SwapOrder(v); } nuclear@3: inline double LEToSystem(double v) { return SwapOrder(v); } nuclear@3: nuclear@3: // Big Endian to System (BE) nuclear@3: inline UByte BEToSystem(UByte v) { return v; } nuclear@3: inline SByte BEToSystem(SByte v) { return v; } nuclear@3: inline UInt16 BEToSystem(UInt16 v) { return v; } nuclear@3: inline SInt16 BEToSystem(SInt16 v) { return v; } nuclear@3: inline UInt32 BEToSystem(UInt32 v) { return v; } nuclear@3: inline SInt32 BEToSystem(SInt32 v) { return v; } nuclear@3: inline UInt64 BEToSystem(UInt64 v) { return v; } nuclear@3: inline SInt64 BEToSystem(SInt64 v) { return v; } nuclear@3: inline float BEToSystem(float v) { return v; } nuclear@3: inline double BEToSystem(double v) { return v; } nuclear@3: nuclear@3: // System (BE) to Little Endian nuclear@3: inline UByte SystemToLE(UByte v) { return SwapOrder(v); } nuclear@3: inline SByte SystemToLE(SByte v) { return SwapOrder(v); } nuclear@3: inline UInt16 SystemToLE(UInt16 v) { return SwapOrder(v); } nuclear@3: inline SInt16 SystemToLE(SInt16 v) { return SwapOrder(v); } nuclear@3: inline UInt32 SystemToLE(UInt32 v) { return SwapOrder(v); } nuclear@3: inline SInt32 SystemToLE(SInt32 v) { return SwapOrder(v); } nuclear@3: inline UInt64 SystemToLE(UInt64 v) { return SwapOrder(v); } nuclear@3: inline SInt64 SystemToLE(SInt64 v) { return SwapOrder(v); } nuclear@3: inline float SystemToLE(float v) { return SwapOrder(v); } nuclear@3: inline double SystemToLE(double v) { return SwapOrder(v); } nuclear@3: nuclear@3: // System (BE) to Big Endian nuclear@3: inline UByte SystemToBE(UByte v) { return v; } nuclear@3: inline SByte SystemToBE(SByte v) { return v; } nuclear@3: inline UInt16 SystemToBE(UInt16 v) { return v; } nuclear@3: inline SInt16 SystemToBE(SInt16 v) { return v; } nuclear@3: inline UInt32 SystemToBE(UInt32 v) { return v; } nuclear@3: inline SInt32 SystemToBE(SInt32 v) { return v; } nuclear@3: inline UInt64 SystemToBE(UInt64 v) { return v; } nuclear@3: inline SInt64 SystemToBE(SInt64 v) { return v; } nuclear@3: inline float SystemToBE(float v) { return v; } nuclear@3: inline double SystemToBE(double v) { return v; } nuclear@3: nuclear@3: #else nuclear@3: #error "OVR_BYTE_ORDER must be defined to OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN" nuclear@3: #endif nuclear@3: nuclear@3: } // namespace ByteUtil nuclear@3: nuclear@3: nuclear@3: nuclear@3: }} // OVR::Alg nuclear@3: nuclear@3: #endif