nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: PublicHeader: OVR_Kernel.h nuclear@0: Filename : OVR_Alg.h nuclear@0: Content : Simple general purpose algorithms: Sort, Binary Search, etc. nuclear@0: Created : September 19, 2012 nuclear@0: Notes : nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: ************************************************************************************/ nuclear@0: nuclear@0: #ifndef OVR_Alg_h nuclear@0: #define OVR_Alg_h nuclear@0: nuclear@0: #include "OVR_Types.h" nuclear@0: #include nuclear@0: nuclear@0: namespace OVR { namespace Alg { nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Operator extensions nuclear@0: nuclear@0: template OVR_FORCE_INLINE void Swap(T &a, T &b) nuclear@0: { T temp(a); a = b; b = temp; } nuclear@0: nuclear@0: nuclear@0: // ***** min/max are not implemented in Visual Studio 6 standard STL nuclear@0: nuclear@0: template OVR_FORCE_INLINE const T Min(const T a, const T b) nuclear@0: { return (a < b) ? a : b; } nuclear@0: nuclear@0: template OVR_FORCE_INLINE const T Max(const T a, const T b) nuclear@0: { return (b < a) ? a : b; } nuclear@0: nuclear@0: template OVR_FORCE_INLINE const T Clamp(const T v, const T minVal, const T maxVal) nuclear@0: { return Max(minVal, Min(v, maxVal)); } nuclear@0: nuclear@0: template OVR_FORCE_INLINE int Chop(T f) nuclear@0: { return (int)f; } nuclear@0: nuclear@0: template OVR_FORCE_INLINE T Lerp(T a, T b, T f) nuclear@0: { return (b - a) * f + a; } nuclear@0: nuclear@0: nuclear@0: // These functions stand to fix a stupid VC++ warning (with /Wp64 on): nuclear@0: // "warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned', possible loss of data" nuclear@0: // Use these functions instead of gmin/gmax if the argument has size nuclear@0: // of the pointer to avoid the warning. Though, functionally they are nuclear@0: // absolutelly the same as regular gmin/gmax. nuclear@0: template OVR_FORCE_INLINE const T PMin(const T a, const T b) nuclear@0: { nuclear@0: OVR_COMPILER_ASSERT(sizeof(T) == sizeof(size_t)); nuclear@0: return (a < b) ? a : b; nuclear@0: } nuclear@0: template OVR_FORCE_INLINE const T PMax(const T a, const T b) nuclear@0: { nuclear@0: OVR_COMPILER_ASSERT(sizeof(T) == sizeof(size_t)); nuclear@0: return (b < a) ? a : b; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: template OVR_FORCE_INLINE const T Abs(const T v) nuclear@0: { return (v>=0) ? v : -v; } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** OperatorLess nuclear@0: // nuclear@0: template struct OperatorLess nuclear@0: { nuclear@0: static bool Compare(const T& a, const T& b) nuclear@0: { nuclear@0: return a < b; nuclear@0: } nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** QuickSortSliced nuclear@0: // nuclear@0: // Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. nuclear@0: // The range is specified with start, end, where "end" is exclusive! nuclear@0: // The comparison predicate must be specified. nuclear@0: template nuclear@0: void QuickSortSliced(Array& arr, size_t start, size_t end, Less less) nuclear@0: { nuclear@0: enum nuclear@0: { nuclear@0: Threshold = 9 nuclear@0: }; nuclear@0: nuclear@0: if(end - start < 2) return; nuclear@0: nuclear@0: intptr_t stack[80]; nuclear@0: intptr_t* top = stack; nuclear@0: intptr_t base = (intptr_t)start; nuclear@0: intptr_t limit = (intptr_t)end; nuclear@0: nuclear@0: for(;;) nuclear@0: { nuclear@0: intptr_t len = limit - base; nuclear@0: intptr_t i, j, pivot; nuclear@0: nuclear@0: if(len > Threshold) nuclear@0: { nuclear@0: // we use base + len/2 as the pivot nuclear@0: pivot = base + len / 2; nuclear@0: Swap(arr[base], arr[pivot]); nuclear@0: nuclear@0: i = base + 1; nuclear@0: j = limit - 1; nuclear@0: nuclear@0: // now ensure that *i <= *base <= *j nuclear@0: if(less(arr[j], arr[i])) Swap(arr[j], arr[i]); nuclear@0: if(less(arr[base], arr[i])) Swap(arr[base], arr[i]); nuclear@0: if(less(arr[j], arr[base])) Swap(arr[j], arr[base]); nuclear@0: nuclear@0: for(;;) nuclear@0: { nuclear@0: do i++; while( less(arr[i], arr[base]) ); nuclear@0: do j--; while( less(arr[base], arr[j]) ); nuclear@0: nuclear@0: if( i > j ) nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: Swap(arr[i], arr[j]); nuclear@0: } nuclear@0: nuclear@0: Swap(arr[base], arr[j]); nuclear@0: nuclear@0: // now, push the largest sub-array nuclear@0: if(j - base > limit - i) nuclear@0: { nuclear@0: top[0] = base; nuclear@0: top[1] = j; nuclear@0: base = i; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: top[0] = i; nuclear@0: top[1] = limit; nuclear@0: limit = j; nuclear@0: } nuclear@0: top += 2; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // the sub-array is small, perform insertion sort nuclear@0: j = base; nuclear@0: i = j + 1; nuclear@0: nuclear@0: for(; i < limit; j = i, i++) nuclear@0: { nuclear@0: for(; less(arr[j + 1], arr[j]); j--) nuclear@0: { nuclear@0: Swap(arr[j + 1], arr[j]); nuclear@0: if(j == base) nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: if(top > stack) nuclear@0: { nuclear@0: top -= 2; nuclear@0: base = top[0]; nuclear@0: limit = top[1]; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** QuickSortSliced nuclear@0: // nuclear@0: // Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. nuclear@0: // The range is specified with start, end, where "end" is exclusive! nuclear@0: // The data type must have a defined "<" operator. nuclear@0: template nuclear@0: void QuickSortSliced(Array& arr, size_t start, size_t end) nuclear@0: { nuclear@0: typedef typename Array::ValueType ValueType; nuclear@0: QuickSortSliced(arr, start, end, OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: // Same as corresponding G_QuickSortSliced but with checking array limits to avoid nuclear@0: // crash in the case of wrong comparator functor. nuclear@0: template nuclear@0: bool QuickSortSlicedSafe(Array& arr, size_t start, size_t end, Less less) nuclear@0: { nuclear@0: enum nuclear@0: { nuclear@0: Threshold = 9 nuclear@0: }; nuclear@0: nuclear@0: if(end - start < 2) return true; nuclear@0: nuclear@0: intptr_t stack[80]; nuclear@0: intptr_t* top = stack; nuclear@0: intptr_t base = (intptr_t)start; nuclear@0: intptr_t limit = (intptr_t)end; nuclear@0: nuclear@0: for(;;) nuclear@0: { nuclear@0: intptr_t len = limit - base; nuclear@0: intptr_t i, j, pivot; nuclear@0: nuclear@0: if(len > Threshold) nuclear@0: { nuclear@0: // we use base + len/2 as the pivot nuclear@0: pivot = base + len / 2; nuclear@0: Swap(arr[base], arr[pivot]); nuclear@0: nuclear@0: i = base + 1; nuclear@0: j = limit - 1; nuclear@0: nuclear@0: // now ensure that *i <= *base <= *j nuclear@0: if(less(arr[j], arr[i])) Swap(arr[j], arr[i]); nuclear@0: if(less(arr[base], arr[i])) Swap(arr[base], arr[i]); nuclear@0: if(less(arr[j], arr[base])) Swap(arr[j], arr[base]); nuclear@0: nuclear@0: for(;;) nuclear@0: { nuclear@0: do nuclear@0: { nuclear@0: i++; nuclear@0: if (i >= limit) nuclear@0: return false; nuclear@0: } while( less(arr[i], arr[base]) ); nuclear@0: do nuclear@0: { nuclear@0: j--; nuclear@0: if (j < 0) nuclear@0: return false; nuclear@0: } while( less(arr[base], arr[j]) ); nuclear@0: nuclear@0: if( i > j ) nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: Swap(arr[i], arr[j]); nuclear@0: } nuclear@0: nuclear@0: Swap(arr[base], arr[j]); nuclear@0: nuclear@0: // now, push the largest sub-array nuclear@0: if(j - base > limit - i) nuclear@0: { nuclear@0: top[0] = base; nuclear@0: top[1] = j; nuclear@0: base = i; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: top[0] = i; nuclear@0: top[1] = limit; nuclear@0: limit = j; nuclear@0: } nuclear@0: top += 2; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // the sub-array is small, perform insertion sort nuclear@0: j = base; nuclear@0: i = j + 1; nuclear@0: nuclear@0: for(; i < limit; j = i, i++) nuclear@0: { nuclear@0: for(; less(arr[j + 1], arr[j]); j--) nuclear@0: { nuclear@0: Swap(arr[j + 1], arr[j]); nuclear@0: if(j == base) nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: if(top > stack) nuclear@0: { nuclear@0: top -= 2; nuclear@0: base = top[0]; nuclear@0: limit = top[1]; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: template nuclear@0: bool QuickSortSlicedSafe(Array& arr, size_t start, size_t end) nuclear@0: { nuclear@0: typedef typename Array::ValueType ValueType; nuclear@0: return QuickSortSlicedSafe(arr, start, end, OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** QuickSort nuclear@0: // nuclear@0: // Sort an array Array, ArrayPaged, ArrayUnsafe. nuclear@0: // The array must have GetSize() function. nuclear@0: // The comparison predicate must be specified. nuclear@0: template nuclear@0: void QuickSort(Array& arr, Less less) nuclear@0: { nuclear@0: QuickSortSliced(arr, 0, arr.GetSize(), less); nuclear@0: } nuclear@0: nuclear@0: // checks for boundaries nuclear@0: template nuclear@0: bool QuickSortSafe(Array& arr, Less less) nuclear@0: { nuclear@0: return QuickSortSlicedSafe(arr, 0, arr.GetSize(), less); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** QuickSort nuclear@0: // nuclear@0: // Sort an array Array, ArrayPaged, ArrayUnsafe. nuclear@0: // The array must have GetSize() function. nuclear@0: // The data type must have a defined "<" operator. nuclear@0: template nuclear@0: void QuickSort(Array& arr) nuclear@0: { nuclear@0: typedef typename Array::ValueType ValueType; nuclear@0: QuickSortSliced(arr, 0, arr.GetSize(), OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: template nuclear@0: bool QuickSortSafe(Array& arr) nuclear@0: { nuclear@0: typedef typename Array::ValueType ValueType; nuclear@0: return QuickSortSlicedSafe(arr, 0, arr.GetSize(), OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** InsertionSortSliced nuclear@0: // nuclear@0: // Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. nuclear@0: // The range is specified with start, end, where "end" is exclusive! nuclear@0: // The comparison predicate must be specified. nuclear@0: // Unlike Quick Sort, the Insertion Sort works much slower in average, nuclear@0: // but may be much faster on almost sorted arrays. Besides, it guarantees nuclear@0: // that the elements will not be swapped if not necessary. For example, nuclear@0: // an array with all equal elements will remain "untouched", while nuclear@0: // Quick Sort will considerably shuffle the elements in this case. nuclear@0: template nuclear@0: void InsertionSortSliced(Array& arr, size_t start, size_t end, Less less) nuclear@0: { nuclear@0: size_t j = start; nuclear@0: size_t i = j + 1; nuclear@0: size_t limit = end; nuclear@0: nuclear@0: for(; i < limit; j = i, i++) nuclear@0: { nuclear@0: for(; less(arr[j + 1], arr[j]); j--) nuclear@0: { nuclear@0: Swap(arr[j + 1], arr[j]); nuclear@0: if(j <= start) nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** InsertionSortSliced nuclear@0: // nuclear@0: // Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. nuclear@0: // The range is specified with start, end, where "end" is exclusive! nuclear@0: // The data type must have a defined "<" operator. nuclear@0: template nuclear@0: void InsertionSortSliced(Array& arr, size_t start, size_t end) nuclear@0: { nuclear@0: typedef typename Array::ValueType ValueType; nuclear@0: InsertionSortSliced(arr, start, end, OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** InsertionSort nuclear@0: // nuclear@0: // Sort an array Array, ArrayPaged, ArrayUnsafe. nuclear@0: // The array must have GetSize() function. nuclear@0: // The comparison predicate must be specified. nuclear@0: nuclear@0: template nuclear@0: void InsertionSort(Array& arr, Less less) nuclear@0: { nuclear@0: InsertionSortSliced(arr, 0, arr.GetSize(), less); nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** InsertionSort nuclear@0: // nuclear@0: // Sort an array Array, ArrayPaged, ArrayUnsafe. nuclear@0: // The array must have GetSize() function. nuclear@0: // The data type must have a defined "<" operator. nuclear@0: template nuclear@0: void InsertionSort(Array& arr) nuclear@0: { nuclear@0: typedef typename Array::ValueType ValueType; nuclear@0: InsertionSortSliced(arr, 0, arr.GetSize(), OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Median nuclear@0: // Returns a median value of the input array. nuclear@0: // Caveats: partially sorts the array, returns a reference to the array element nuclear@0: // TBD: This needs to be optimized and generalized nuclear@0: // nuclear@0: template nuclear@0: typename Array::ValueType& Median(Array& arr) nuclear@0: { nuclear@0: size_t count = arr.GetSize(); nuclear@0: size_t mid = (count - 1) / 2; nuclear@0: OVR_ASSERT(count > 0); nuclear@0: nuclear@0: for (size_t j = 0; j <= mid; j++) nuclear@0: { nuclear@0: size_t min = j; nuclear@0: for (size_t k = j + 1; k < count; k++) nuclear@0: if (arr[k] < arr[min]) nuclear@0: min = k; nuclear@0: Swap(arr[j], arr[min]); nuclear@0: } nuclear@0: return arr[mid]; nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** LowerBoundSliced nuclear@0: // nuclear@0: template nuclear@0: size_t LowerBoundSliced(const Array& arr, size_t start, size_t end, const Value& val, Less less) nuclear@0: { nuclear@0: intptr_t first = (intptr_t)start; nuclear@0: intptr_t len = (intptr_t)(end - start); nuclear@0: intptr_t half; nuclear@0: intptr_t middle; nuclear@0: nuclear@0: while(len > 0) nuclear@0: { nuclear@0: half = len >> 1; nuclear@0: middle = first + half; nuclear@0: if(less(arr[middle], val)) nuclear@0: { nuclear@0: first = middle + 1; nuclear@0: len = len - half - 1; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: len = half; nuclear@0: } nuclear@0: } nuclear@0: return (size_t)first; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** LowerBoundSliced nuclear@0: // nuclear@0: template nuclear@0: size_t LowerBoundSliced(const Array& arr, size_t start, size_t end, const Value& val) nuclear@0: { nuclear@0: return LowerBoundSliced(arr, start, end, val, OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** LowerBoundSized nuclear@0: // nuclear@0: template nuclear@0: size_t LowerBoundSized(const Array& arr, size_t size, const Value& val) nuclear@0: { nuclear@0: return LowerBoundSliced(arr, 0, size, val, OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** LowerBound nuclear@0: // nuclear@0: template nuclear@0: size_t LowerBound(const Array& arr, const Value& val, Less less) nuclear@0: { nuclear@0: return LowerBoundSliced(arr, 0, arr.GetSize(), val, less); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** LowerBound nuclear@0: // nuclear@0: template nuclear@0: size_t LowerBound(const Array& arr, const Value& val) nuclear@0: { nuclear@0: return LowerBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** UpperBoundSliced nuclear@0: // nuclear@0: template nuclear@0: size_t UpperBoundSliced(const Array& arr, size_t start, size_t end, const Value& val, Less less) nuclear@0: { nuclear@0: intptr_t first = (intptr_t)start; nuclear@0: intptr_t len = (intptr_t)(end - start); nuclear@0: intptr_t half; nuclear@0: intptr_t middle; nuclear@0: nuclear@0: while(len > 0) nuclear@0: { nuclear@0: half = len >> 1; nuclear@0: middle = first + half; nuclear@0: if(less(val, arr[middle])) nuclear@0: { nuclear@0: len = half; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: first = middle + 1; nuclear@0: len = len - half - 1; nuclear@0: } nuclear@0: } nuclear@0: return (size_t)first; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** UpperBoundSliced nuclear@0: // nuclear@0: template nuclear@0: size_t UpperBoundSliced(const Array& arr, size_t start, size_t end, const Value& val) nuclear@0: { nuclear@0: return UpperBoundSliced(arr, start, end, val, OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** UpperBoundSized nuclear@0: // nuclear@0: template nuclear@0: size_t UpperBoundSized(const Array& arr, size_t size, const Value& val) nuclear@0: { nuclear@0: return UpperBoundSliced(arr, 0, size, val, OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** UpperBound nuclear@0: // nuclear@0: template nuclear@0: size_t UpperBound(const Array& arr, const Value& val, Less less) nuclear@0: { nuclear@0: return UpperBoundSliced(arr, 0, arr.GetSize(), val, less); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** UpperBound nuclear@0: // nuclear@0: template nuclear@0: size_t UpperBound(const Array& arr, const Value& val) nuclear@0: { nuclear@0: return UpperBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess::Compare); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** ReverseArray nuclear@0: // nuclear@0: template void ReverseArray(Array& arr) nuclear@0: { nuclear@0: intptr_t from = 0; nuclear@0: intptr_t to = arr.GetSize() - 1; nuclear@0: while(from < to) nuclear@0: { nuclear@0: Swap(arr[from], arr[to]); nuclear@0: ++from; nuclear@0: --to; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // ***** AppendArray nuclear@0: // nuclear@0: template nuclear@0: void AppendArray(CDst& dst, const CSrc& src) nuclear@0: { nuclear@0: size_t i; nuclear@0: for(i = 0; i < src.GetSize(); i++) nuclear@0: dst.PushBack(src[i]); nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** ArrayAdaptor nuclear@0: // nuclear@0: // A simple adapter that provides the GetSize() method and overloads nuclear@0: // operator []. Used to wrap plain arrays in QuickSort and such. nuclear@0: template class ArrayAdaptor nuclear@0: { nuclear@0: public: nuclear@0: typedef T ValueType; nuclear@0: ArrayAdaptor() : Data(0), Size(0) {} nuclear@0: ArrayAdaptor(T* ptr, size_t size) : Data(ptr), Size(size) {} nuclear@0: size_t GetSize() const { return Size; } nuclear@0: int GetSizeI() const { return (int)GetSize(); } nuclear@0: const T& operator [] (size_t i) const { return Data[i]; } nuclear@0: T& operator [] (size_t i) { return Data[i]; } nuclear@0: private: nuclear@0: T* Data; nuclear@0: size_t Size; nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** GConstArrayAdaptor nuclear@0: // nuclear@0: // A simple const adapter that provides the GetSize() method and overloads nuclear@0: // operator []. Used to wrap plain arrays in LowerBound and such. nuclear@0: template class ConstArrayAdaptor nuclear@0: { nuclear@0: public: nuclear@0: typedef T ValueType; nuclear@0: ConstArrayAdaptor() : Data(0), Size(0) {} nuclear@0: ConstArrayAdaptor(const T* ptr, size_t size) : Data(ptr), Size(size) {} nuclear@0: size_t GetSize() const { return Size; } nuclear@0: int GetSizeI() const { return (int)GetSize(); } nuclear@0: const T& operator [] (size_t i) const { return Data[i]; } nuclear@0: private: nuclear@0: const T* Data; nuclear@0: size_t Size; nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: extern const uint8_t UpperBitTable[256]; nuclear@0: extern const uint8_t LowerBitTable[256]; nuclear@0: nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: inline uint8_t UpperBit(size_t val) nuclear@0: { nuclear@0: #ifndef OVR_64BIT_POINTERS nuclear@0: nuclear@0: if (val & 0xFFFF0000) nuclear@0: { nuclear@0: return (val & 0xFF000000) ? nuclear@0: UpperBitTable[(val >> 24) ] + 24: nuclear@0: UpperBitTable[(val >> 16) & 0xFF] + 16; nuclear@0: } nuclear@0: return (val & 0xFF00) ? nuclear@0: UpperBitTable[(val >> 8) & 0xFF] + 8: nuclear@0: UpperBitTable[(val ) & 0xFF]; nuclear@0: nuclear@0: #else nuclear@0: nuclear@0: if (val & 0xFFFFFFFF00000000) nuclear@0: { nuclear@0: if (val & 0xFFFF000000000000) nuclear@0: { nuclear@0: return (val & 0xFF00000000000000) ? nuclear@0: UpperBitTable[(val >> 56) ] + 56: nuclear@0: UpperBitTable[(val >> 48) & 0xFF] + 48; nuclear@0: } nuclear@0: return (val & 0xFF0000000000) ? nuclear@0: UpperBitTable[(val >> 40) & 0xFF] + 40: nuclear@0: UpperBitTable[(val >> 32) & 0xFF] + 32; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: if (val & 0xFFFF0000) nuclear@0: { nuclear@0: return (val & 0xFF000000) ? nuclear@0: UpperBitTable[(val >> 24) ] + 24: nuclear@0: UpperBitTable[(val >> 16) & 0xFF] + 16; nuclear@0: } nuclear@0: return (val & 0xFF00) ? nuclear@0: UpperBitTable[(val >> 8) & 0xFF] + 8: nuclear@0: UpperBitTable[(val ) & 0xFF]; nuclear@0: } nuclear@0: nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: inline uint8_t LowerBit(size_t val) nuclear@0: { nuclear@0: #ifndef OVR_64BIT_POINTERS nuclear@0: nuclear@0: if (val & 0xFFFF) nuclear@0: { nuclear@0: return (val & 0xFF) ? nuclear@0: LowerBitTable[ val & 0xFF]: nuclear@0: LowerBitTable[(val >> 8) & 0xFF] + 8; nuclear@0: } nuclear@0: return (val & 0xFF0000) ? nuclear@0: LowerBitTable[(val >> 16) & 0xFF] + 16: nuclear@0: LowerBitTable[(val >> 24) & 0xFF] + 24; nuclear@0: nuclear@0: #else nuclear@0: nuclear@0: if (val & 0xFFFFFFFF) nuclear@0: { nuclear@0: if (val & 0xFFFF) nuclear@0: { nuclear@0: return (val & 0xFF) ? nuclear@0: LowerBitTable[ val & 0xFF]: nuclear@0: LowerBitTable[(val >> 8) & 0xFF] + 8; nuclear@0: } nuclear@0: return (val & 0xFF0000) ? nuclear@0: LowerBitTable[(val >> 16) & 0xFF] + 16: nuclear@0: LowerBitTable[(val >> 24) & 0xFF] + 24; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: if (val & 0xFFFF00000000) nuclear@0: { nuclear@0: return (val & 0xFF00000000) ? nuclear@0: LowerBitTable[(val >> 32) & 0xFF] + 32: nuclear@0: LowerBitTable[(val >> 40) & 0xFF] + 40; nuclear@0: } nuclear@0: return (val & 0xFF000000000000) ? nuclear@0: LowerBitTable[(val >> 48) & 0xFF] + 48: nuclear@0: LowerBitTable[(val >> 56) & 0xFF] + 56; nuclear@0: } nuclear@0: nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: // ******* Special (optimized) memory routines nuclear@0: // Note: null (bad) pointer is not tested nuclear@0: class MemUtil nuclear@0: { nuclear@0: public: nuclear@0: nuclear@0: // Memory compare nuclear@0: static int Cmp (const void* p1, const void* p2, size_t byteCount) { return memcmp(p1, p2, byteCount); } nuclear@0: static int Cmp16(const void* p1, const void* p2, size_t int16Count); nuclear@0: static int Cmp32(const void* p1, const void* p2, size_t int32Count); nuclear@0: static int Cmp64(const void* p1, const void* p2, size_t int64Count); nuclear@0: }; nuclear@0: nuclear@0: // ** Inline Implementation nuclear@0: nuclear@0: inline int MemUtil::Cmp16(const void* p1, const void* p2, size_t int16Count) nuclear@0: { nuclear@0: int16_t* pa = (int16_t*)p1; nuclear@0: int16_t* pb = (int16_t*)p2; nuclear@0: unsigned ic = 0; nuclear@0: if (int16Count == 0) nuclear@0: return 0; nuclear@0: while (pa[ic] == pb[ic]) nuclear@0: if (++ic==int16Count) nuclear@0: return 0; nuclear@0: return pa[ic] > pb[ic] ? 1 : -1; nuclear@0: } nuclear@0: inline int MemUtil::Cmp32(const void* p1, const void* p2, size_t int32Count) nuclear@0: { nuclear@0: int32_t* pa = (int32_t*)p1; nuclear@0: int32_t* pb = (int32_t*)p2; nuclear@0: unsigned ic = 0; nuclear@0: if (int32Count == 0) nuclear@0: return 0; nuclear@0: while (pa[ic] == pb[ic]) nuclear@0: if (++ic==int32Count) nuclear@0: return 0; nuclear@0: return pa[ic] > pb[ic] ? 1 : -1; nuclear@0: } nuclear@0: inline int MemUtil::Cmp64(const void* p1, const void* p2, size_t int64Count) nuclear@0: { nuclear@0: int64_t* pa = (int64_t*)p1; nuclear@0: int64_t* pb = (int64_t*)p2; nuclear@0: unsigned ic = 0; nuclear@0: if (int64Count == 0) nuclear@0: return 0; nuclear@0: while (pa[ic] == pb[ic]) nuclear@0: if (++ic==int64Count) nuclear@0: return 0; nuclear@0: return pa[ic] > pb[ic] ? 1 : -1; nuclear@0: } nuclear@0: nuclear@0: // ** End Inline Implementation nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ******* Byte Order Conversions nuclear@0: namespace ByteUtil { nuclear@0: nuclear@0: // *** Swap Byte Order nuclear@0: nuclear@0: // Swap the byte order of a byte array nuclear@0: inline void SwapOrder(void* pv, int size) nuclear@0: { nuclear@0: uint8_t* pb = (uint8_t*)pv; nuclear@0: uint8_t temp; nuclear@0: for (int i = 0; i < size>>1; i++) nuclear@0: { nuclear@0: temp = pb[size-1-i]; nuclear@0: pb[size-1-i] = pb[i]; nuclear@0: pb[i] = temp; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Swap the byte order of primitive types nuclear@0: inline uint8_t SwapOrder(uint8_t v) { return v; } nuclear@0: inline int8_t SwapOrder(int8_t v) { return v; } nuclear@0: inline uint16_t SwapOrder(uint16_t v) { return uint16_t(v>>8)|uint16_t(v<<8); } nuclear@0: inline int16_t SwapOrder(int16_t v) { return int16_t((uint16_t(v)>>8)|(v<<8)); } nuclear@0: inline uint32_t SwapOrder(uint32_t v) { return (v>>24)|((v&0x00FF0000)>>8)|((v&0x0000FF00)<<8)|(v<<24); } nuclear@0: inline int32_t SwapOrder(int32_t p) { return (int32_t)SwapOrder(uint32_t(p)); } nuclear@0: inline uint64_t SwapOrder(uint64_t v) nuclear@0: { nuclear@0: return (v>>56) | nuclear@0: ((v&uint64_t(0x00FF000000000000ULL))>>40) | nuclear@0: ((v&uint64_t(0x0000FF0000000000ULL))>>24) | nuclear@0: ((v&uint64_t(0x000000FF00000000ULL))>>8) | nuclear@0: ((v&uint64_t(0x00000000FF000000ULL))<<8) | nuclear@0: ((v&uint64_t(0x0000000000FF0000ULL))<<24) | nuclear@0: ((v&uint64_t(0x000000000000FF00ULL))<<40) | nuclear@0: (v<<56); nuclear@0: } nuclear@0: inline int64_t SwapOrder(int64_t v) { return (int64_t)SwapOrder(uint64_t(v)); } nuclear@0: inline float SwapOrder(float p) nuclear@0: { nuclear@0: union { nuclear@0: float p; nuclear@0: uint32_t v; nuclear@0: } u; nuclear@0: u.p = p; nuclear@0: u.v = SwapOrder(u.v); nuclear@0: return u.p; nuclear@0: } nuclear@0: nuclear@0: inline double SwapOrder(double p) nuclear@0: { nuclear@0: union { nuclear@0: double p; nuclear@0: uint64_t v; nuclear@0: } u; nuclear@0: u.p = p; nuclear@0: u.v = SwapOrder(u.v); nuclear@0: return u.p; nuclear@0: } nuclear@0: nuclear@0: // *** Byte-order conversion nuclear@0: nuclear@0: #if (OVR_BYTE_ORDER == OVR_LITTLE_ENDIAN) nuclear@0: // Little Endian to System (LE) nuclear@0: inline uint8_t LEToSystem(uint8_t v) { return v; } nuclear@0: inline int8_t LEToSystem(int8_t v) { return v; } nuclear@0: inline uint16_t LEToSystem(uint16_t v) { return v; } nuclear@0: inline int16_t LEToSystem(int16_t v) { return v; } nuclear@0: inline uint32_t LEToSystem(uint32_t v) { return v; } nuclear@0: inline int32_t LEToSystem(int32_t v) { return v; } nuclear@0: inline uint64_t LEToSystem(uint64_t v) { return v; } nuclear@0: inline int64_t LEToSystem(int64_t v) { return v; } nuclear@0: inline float LEToSystem(float v) { return v; } nuclear@0: inline double LEToSystem(double v) { return v; } nuclear@0: nuclear@0: // Big Endian to System (LE) nuclear@0: inline uint8_t BEToSystem(uint8_t v) { return SwapOrder(v); } nuclear@0: inline int8_t BEToSystem(int8_t v) { return SwapOrder(v); } nuclear@0: inline uint16_t BEToSystem(uint16_t v) { return SwapOrder(v); } nuclear@0: inline int16_t BEToSystem(int16_t v) { return SwapOrder(v); } nuclear@0: inline uint32_t BEToSystem(uint32_t v) { return SwapOrder(v); } nuclear@0: inline int32_t BEToSystem(int32_t v) { return SwapOrder(v); } nuclear@0: inline uint64_t BEToSystem(uint64_t v) { return SwapOrder(v); } nuclear@0: inline int64_t BEToSystem(int64_t v) { return SwapOrder(v); } nuclear@0: inline float BEToSystem(float v) { return SwapOrder(v); } nuclear@0: inline double BEToSystem(double v) { return SwapOrder(v); } nuclear@0: nuclear@0: // System (LE) to Little Endian nuclear@0: inline uint8_t SystemToLE(uint8_t v) { return v; } nuclear@0: inline int8_t SystemToLE(int8_t v) { return v; } nuclear@0: inline uint16_t SystemToLE(uint16_t v) { return v; } nuclear@0: inline int16_t SystemToLE(int16_t v) { return v; } nuclear@0: inline uint32_t SystemToLE(uint32_t v) { return v; } nuclear@0: inline int32_t SystemToLE(int32_t v) { return v; } nuclear@0: inline uint64_t SystemToLE(uint64_t v) { return v; } nuclear@0: inline int64_t SystemToLE(int64_t v) { return v; } nuclear@0: inline float SystemToLE(float v) { return v; } nuclear@0: inline double SystemToLE(double v) { return v; } nuclear@0: nuclear@0: // System (LE) to Big Endian nuclear@0: inline uint8_t SystemToBE(uint8_t v) { return SwapOrder(v); } nuclear@0: inline int8_t SystemToBE(int8_t v) { return SwapOrder(v); } nuclear@0: inline uint16_t SystemToBE(uint16_t v) { return SwapOrder(v); } nuclear@0: inline int16_t SystemToBE(int16_t v) { return SwapOrder(v); } nuclear@0: inline uint32_t SystemToBE(uint32_t v) { return SwapOrder(v); } nuclear@0: inline int32_t SystemToBE(int32_t v) { return SwapOrder(v); } nuclear@0: inline uint64_t SystemToBE(uint64_t v) { return SwapOrder(v); } nuclear@0: inline int64_t SystemToBE(int64_t v) { return SwapOrder(v); } nuclear@0: inline float SystemToBE(float v) { return SwapOrder(v); } nuclear@0: inline double SystemToBE(double v) { return SwapOrder(v); } nuclear@0: nuclear@0: #elif (OVR_BYTE_ORDER == OVR_BIG_ENDIAN) nuclear@0: // Little Endian to System (BE) nuclear@0: inline uint8_t LEToSystem(uint8_t v) { return SwapOrder(v); } nuclear@0: inline int8_t LEToSystem(int8_t v) { return SwapOrder(v); } nuclear@0: inline uint16_t LEToSystem(uint16_t v) { return SwapOrder(v); } nuclear@0: inline int16_t LEToSystem(int16_t v) { return SwapOrder(v); } nuclear@0: inline uint32_t LEToSystem(uint32_t v) { return SwapOrder(v); } nuclear@0: inline int32_t LEToSystem(int32_t v) { return SwapOrder(v); } nuclear@0: inline uint64_t LEToSystem(uint64_t v) { return SwapOrder(v); } nuclear@0: inline int64_t LEToSystem(int64_t v) { return SwapOrder(v); } nuclear@0: inline float LEToSystem(float v) { return SwapOrder(v); } nuclear@0: inline double LEToSystem(double v) { return SwapOrder(v); } nuclear@0: nuclear@0: // Big Endian to System (BE) nuclear@0: inline uint8_t BEToSystem(uint8_t v) { return v; } nuclear@0: inline int8_t BEToSystem(int8_t v) { return v; } nuclear@0: inline uint16_t BEToSystem(uint16_t v) { return v; } nuclear@0: inline int16_t BEToSystem(int16_t v) { return v; } nuclear@0: inline uint32_t BEToSystem(uint32_t v) { return v; } nuclear@0: inline int32_t BEToSystem(int32_t v) { return v; } nuclear@0: inline uint64_t BEToSystem(uint64_t v) { return v; } nuclear@0: inline int64_t BEToSystem(int64_t v) { return v; } nuclear@0: inline float BEToSystem(float v) { return v; } nuclear@0: inline double BEToSystem(double v) { return v; } nuclear@0: nuclear@0: // System (BE) to Little Endian nuclear@0: inline uint8_t SystemToLE(uint8_t v) { return SwapOrder(v); } nuclear@0: inline int8_t SystemToLE(int8_t v) { return SwapOrder(v); } nuclear@0: inline uint16_t SystemToLE(uint16_t v) { return SwapOrder(v); } nuclear@0: inline int16_t SystemToLE(int16_t v) { return SwapOrder(v); } nuclear@0: inline uint32_t SystemToLE(uint32_t v) { return SwapOrder(v); } nuclear@0: inline int32_t SystemToLE(int32_t v) { return SwapOrder(v); } nuclear@0: inline uint64_t SystemToLE(uint64_t v) { return SwapOrder(v); } nuclear@0: inline int64_t SystemToLE(int64_t v) { return SwapOrder(v); } nuclear@0: inline float SystemToLE(float v) { return SwapOrder(v); } nuclear@0: inline double SystemToLE(double v) { return SwapOrder(v); } nuclear@0: nuclear@0: // System (BE) to Big Endian nuclear@0: inline uint8_t SystemToBE(uint8_t v) { return v; } nuclear@0: inline int8_t SystemToBE(int8_t v) { return v; } nuclear@0: inline uint16_t SystemToBE(uint16_t v) { return v; } nuclear@0: inline int16_t SystemToBE(int16_t v) { return v; } nuclear@0: inline uint32_t SystemToBE(uint32_t v) { return v; } nuclear@0: inline int32_t SystemToBE(int32_t v) { return v; } nuclear@0: inline uint64_t SystemToBE(uint64_t v) { return v; } nuclear@0: inline int64_t SystemToBE(int64_t v) { return v; } nuclear@0: inline float SystemToBE(float v) { return v; } nuclear@0: inline double SystemToBE(double v) { return v; } nuclear@0: nuclear@0: #else nuclear@0: #error "OVR_BYTE_ORDER must be defined to OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN" nuclear@0: #endif nuclear@0: nuclear@0: } // namespace ByteUtil nuclear@0: nuclear@0: nuclear@0: nuclear@0: // Used primarily for hardware interfacing such as sensor reports, firmware, etc. nuclear@0: // Reported data is all little-endian. nuclear@0: inline uint16_t DecodeUInt16(const uint8_t* buffer) nuclear@0: { nuclear@0: return ByteUtil::LEToSystem ( *(const uint16_t*)buffer ); nuclear@0: } nuclear@0: nuclear@0: inline int16_t DecodeSInt16(const uint8_t* buffer) nuclear@0: { nuclear@0: return ByteUtil::LEToSystem ( *(const int16_t*)buffer ); nuclear@0: } nuclear@0: nuclear@0: inline uint32_t DecodeUInt32(const uint8_t* buffer) nuclear@0: { nuclear@0: return ByteUtil::LEToSystem ( *(const uint32_t*)buffer ); nuclear@0: } nuclear@0: nuclear@0: inline int32_t DecodeSInt32(const uint8_t* buffer) nuclear@0: { nuclear@0: return ByteUtil::LEToSystem ( *(const int32_t*)buffer ); nuclear@0: } nuclear@0: nuclear@0: inline float DecodeFloat(const uint8_t* buffer) nuclear@0: { nuclear@0: union { nuclear@0: uint32_t U; nuclear@0: float F; nuclear@0: }; nuclear@0: nuclear@0: U = DecodeUInt32(buffer); nuclear@0: return F; nuclear@0: } nuclear@0: nuclear@0: inline void EncodeUInt16(uint8_t* buffer, uint16_t val) nuclear@0: { nuclear@0: *(uint16_t*)buffer = ByteUtil::SystemToLE ( val ); nuclear@0: } nuclear@0: nuclear@0: inline void EncodeSInt16(uint8_t* buffer, int16_t val) nuclear@0: { nuclear@0: *(int16_t*)buffer = ByteUtil::SystemToLE ( val ); nuclear@0: } nuclear@0: nuclear@0: inline void EncodeUInt32(uint8_t* buffer, uint32_t val) nuclear@0: { nuclear@0: *(uint32_t*)buffer = ByteUtil::SystemToLE ( val ); nuclear@0: } nuclear@0: nuclear@0: inline void EncodeSInt32(uint8_t* buffer, int32_t val) nuclear@0: { nuclear@0: *(int32_t*)buffer = ByteUtil::SystemToLE ( val ); nuclear@0: } nuclear@0: nuclear@0: inline void EncodeFloat(uint8_t* buffer, float val) nuclear@0: { nuclear@0: union { nuclear@0: uint32_t U; nuclear@0: float F; nuclear@0: }; nuclear@0: nuclear@0: F = val; nuclear@0: EncodeUInt32(buffer, U); nuclear@0: } nuclear@0: nuclear@0: // Converts an 8-bit binary-coded decimal nuclear@0: inline int8_t DecodeBCD(uint8_t byte) nuclear@0: { nuclear@0: uint8_t digit1 = (byte >> 4) & 0x0f; nuclear@0: uint8_t digit2 = byte & 0x0f; nuclear@0: int decimal = digit1 * 10 + digit2; // maximum value = 99 nuclear@0: return (int8_t)decimal; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: }} // OVR::Alg nuclear@0: nuclear@0: #endif