diff options
Diffstat (limited to 'LibOVR/Src/Kernel')
40 files changed, 16344 insertions, 0 deletions
diff --git a/LibOVR/Src/Kernel/OVR_Alg.cpp b/LibOVR/Src/Kernel/OVR_Alg.cpp new file mode 100644 index 0000000..ea82f2a --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Alg.cpp @@ -0,0 +1,46 @@ +/************************************************************************************
+
+Filename : OVR_Alg.cpp
+Content : Static lookup tables for Alg functions
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Types.h"
+
+namespace OVR { namespace Alg {
+
+//------------------------------------------------------------------------
+extern const UByte UpperBitTable[256] =
+{
+ 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+extern const UByte LowerBitTable[256] =
+{
+ 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+};
+
+
+}} // OVE::Alg
diff --git a/LibOVR/Src/Kernel/OVR_Alg.h b/LibOVR/Src/Kernel/OVR_Alg.h new file mode 100644 index 0000000..841e8f0 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Alg.h @@ -0,0 +1,953 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Alg.h
+Content : Simple general purpose algorithms: Sort, Binary Search, etc.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Alg_h
+#define OVR_Alg_h
+
+#include "OVR_Types.h"
+#include <string.h>
+
+namespace OVR { namespace Alg {
+
+
+//-----------------------------------------------------------------------------------
+// ***** Operator extensions
+
+template <typename T> OVR_FORCE_INLINE void Swap(T &a, T &b)
+{ T temp(a); a = b; b = temp; }
+
+
+// ***** min/max are not implemented in Visual Studio 6 standard STL
+
+template <typename T> OVR_FORCE_INLINE const T Min(const T a, const T b)
+{ return (a < b) ? a : b; }
+
+template <typename T> OVR_FORCE_INLINE const T Max(const T a, const T b)
+{ return (b < a) ? a : b; }
+
+template <typename T> OVR_FORCE_INLINE const T Clamp(const T v, const T minVal, const T maxVal)
+{ return Max<T>(minVal, Min<T>(v, maxVal)); }
+
+template <typename T> OVR_FORCE_INLINE int Chop(T f)
+{ return (int)f; }
+
+template <typename T> OVR_FORCE_INLINE T Lerp(T a, T b, T f)
+{ return (b - a) * f + a; }
+
+
+// These functions stand to fix a stupid VC++ warning (with /Wp64 on):
+// "warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned', possible loss of data"
+// Use these functions instead of gmin/gmax if the argument has size
+// of the pointer to avoid the warning. Though, functionally they are
+// absolutelly the same as regular gmin/gmax.
+template <typename T> OVR_FORCE_INLINE const T PMin(const T a, const T b)
+{
+ OVR_COMPILER_ASSERT(sizeof(T) == sizeof(UPInt));
+ return (a < b) ? a : b;
+}
+template <typename T> OVR_FORCE_INLINE const T PMax(const T a, const T b)
+{
+ OVR_COMPILER_ASSERT(sizeof(T) == sizeof(UPInt));
+ return (b < a) ? a : b;
+}
+
+
+template <typename T> OVR_FORCE_INLINE const T Abs(const T v)
+{ return (v>=0) ? v : -v; }
+
+
+//-----------------------------------------------------------------------------------
+// ***** OperatorLess
+//
+template<class T> struct OperatorLess
+{
+ static bool Compare(const T& a, const T& b)
+ {
+ return a < b;
+ }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** QuickSortSliced
+//
+// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
+// The range is specified with start, end, where "end" is exclusive!
+// The comparison predicate must be specified.
+template<class Array, class Less>
+void QuickSortSliced(Array& arr, UPInt start, UPInt end, Less less)
+{
+ enum
+ {
+ Threshold = 9
+ };
+
+ if(end - start < 2) return;
+
+ SPInt stack[80];
+ SPInt* top = stack;
+ SPInt base = (SPInt)start;
+ SPInt limit = (SPInt)end;
+
+ for(;;)
+ {
+ SPInt len = limit - base;
+ SPInt i, j, pivot;
+
+ if(len > Threshold)
+ {
+ // we use base + len/2 as the pivot
+ pivot = base + len / 2;
+ Swap(arr[base], arr[pivot]);
+
+ i = base + 1;
+ j = limit - 1;
+
+ // now ensure that *i <= *base <= *j
+ if(less(arr[j], arr[i])) Swap(arr[j], arr[i]);
+ if(less(arr[base], arr[i])) Swap(arr[base], arr[i]);
+ if(less(arr[j], arr[base])) Swap(arr[j], arr[base]);
+
+ for(;;)
+ {
+ do i++; while( less(arr[i], arr[base]) );
+ do j--; while( less(arr[base], arr[j]) );
+
+ if( i > j )
+ {
+ break;
+ }
+
+ Swap(arr[i], arr[j]);
+ }
+
+ Swap(arr[base], arr[j]);
+
+ // now, push the largest sub-array
+ if(j - base > limit - i)
+ {
+ top[0] = base;
+ top[1] = j;
+ base = i;
+ }
+ else
+ {
+ top[0] = i;
+ top[1] = limit;
+ limit = j;
+ }
+ top += 2;
+ }
+ else
+ {
+ // the sub-array is small, perform insertion sort
+ j = base;
+ i = j + 1;
+
+ for(; i < limit; j = i, i++)
+ {
+ for(; less(arr[j + 1], arr[j]); j--)
+ {
+ Swap(arr[j + 1], arr[j]);
+ if(j == base)
+ {
+ break;
+ }
+ }
+ }
+ if(top > stack)
+ {
+ top -= 2;
+ base = top[0];
+ limit = top[1];
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** QuickSortSliced
+//
+// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
+// The range is specified with start, end, where "end" is exclusive!
+// The data type must have a defined "<" operator.
+template<class Array>
+void QuickSortSliced(Array& arr, UPInt start, UPInt end)
+{
+ typedef typename Array::ValueType ValueType;
+ QuickSortSliced(arr, start, end, OperatorLess<ValueType>::Compare);
+}
+
+// Same as corresponding G_QuickSortSliced but with checking array limits to avoid
+// crash in the case of wrong comparator functor.
+template<class Array, class Less>
+bool QuickSortSlicedSafe(Array& arr, UPInt start, UPInt end, Less less)
+{
+ enum
+ {
+ Threshold = 9
+ };
+
+ if(end - start < 2) return true;
+
+ SPInt stack[80];
+ SPInt* top = stack;
+ SPInt base = (SPInt)start;
+ SPInt limit = (SPInt)end;
+
+ for(;;)
+ {
+ SPInt len = limit - base;
+ SPInt i, j, pivot;
+
+ if(len > Threshold)
+ {
+ // we use base + len/2 as the pivot
+ pivot = base + len / 2;
+ Swap(arr[base], arr[pivot]);
+
+ i = base + 1;
+ j = limit - 1;
+
+ // now ensure that *i <= *base <= *j
+ if(less(arr[j], arr[i])) Swap(arr[j], arr[i]);
+ if(less(arr[base], arr[i])) Swap(arr[base], arr[i]);
+ if(less(arr[j], arr[base])) Swap(arr[j], arr[base]);
+
+ for(;;)
+ {
+ do
+ {
+ i++;
+ if (i >= limit)
+ return false;
+ } while( less(arr[i], arr[base]) );
+ do
+ {
+ j--;
+ if (j < 0)
+ return false;
+ } while( less(arr[base], arr[j]) );
+
+ if( i > j )
+ {
+ break;
+ }
+
+ Swap(arr[i], arr[j]);
+ }
+
+ Swap(arr[base], arr[j]);
+
+ // now, push the largest sub-array
+ if(j - base > limit - i)
+ {
+ top[0] = base;
+ top[1] = j;
+ base = i;
+ }
+ else
+ {
+ top[0] = i;
+ top[1] = limit;
+ limit = j;
+ }
+ top += 2;
+ }
+ else
+ {
+ // the sub-array is small, perform insertion sort
+ j = base;
+ i = j + 1;
+
+ for(; i < limit; j = i, i++)
+ {
+ for(; less(arr[j + 1], arr[j]); j--)
+ {
+ Swap(arr[j + 1], arr[j]);
+ if(j == base)
+ {
+ break;
+ }
+ }
+ }
+ if(top > stack)
+ {
+ top -= 2;
+ base = top[0];
+ limit = top[1];
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+template<class Array>
+bool QuickSortSlicedSafe(Array& arr, UPInt start, UPInt end)
+{
+ typedef typename Array::ValueType ValueType;
+ return QuickSortSlicedSafe(arr, start, end, OperatorLess<ValueType>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** QuickSort
+//
+// Sort an array Array, ArrayPaged, ArrayUnsafe.
+// The array must have GetSize() function.
+// The comparison predicate must be specified.
+template<class Array, class Less>
+void QuickSort(Array& arr, Less less)
+{
+ QuickSortSliced(arr, 0, arr.GetSize(), less);
+}
+
+// checks for boundaries
+template<class Array, class Less>
+bool QuickSortSafe(Array& arr, Less less)
+{
+ return QuickSortSlicedSafe(arr, 0, arr.GetSize(), less);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** QuickSort
+//
+// Sort an array Array, ArrayPaged, ArrayUnsafe.
+// The array must have GetSize() function.
+// The data type must have a defined "<" operator.
+template<class Array>
+void QuickSort(Array& arr)
+{
+ typedef typename Array::ValueType ValueType;
+ QuickSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
+}
+
+template<class Array>
+bool QuickSortSafe(Array& arr)
+{
+ typedef typename Array::ValueType ValueType;
+ return QuickSortSlicedSafe(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** InsertionSortSliced
+//
+// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
+// The range is specified with start, end, where "end" is exclusive!
+// The comparison predicate must be specified.
+// Unlike Quick Sort, the Insertion Sort works much slower in average,
+// but may be much faster on almost sorted arrays. Besides, it guarantees
+// that the elements will not be swapped if not necessary. For example,
+// an array with all equal elements will remain "untouched", while
+// Quick Sort will considerably shuffle the elements in this case.
+template<class Array, class Less>
+void InsertionSortSliced(Array& arr, UPInt start, UPInt end, Less less)
+{
+ UPInt j = start;
+ UPInt i = j + 1;
+ UPInt limit = end;
+
+ for(; i < limit; j = i, i++)
+ {
+ for(; less(arr[j + 1], arr[j]); j--)
+ {
+ Swap(arr[j + 1], arr[j]);
+ if(j <= start)
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** InsertionSortSliced
+//
+// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
+// The range is specified with start, end, where "end" is exclusive!
+// The data type must have a defined "<" operator.
+template<class Array>
+void InsertionSortSliced(Array& arr, UPInt start, UPInt end)
+{
+ typedef typename Array::ValueType ValueType;
+ InsertionSortSliced(arr, start, end, OperatorLess<ValueType>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** InsertionSort
+//
+// Sort an array Array, ArrayPaged, ArrayUnsafe.
+// The array must have GetSize() function.
+// The comparison predicate must be specified.
+
+template<class Array, class Less>
+void InsertionSort(Array& arr, Less less)
+{
+ InsertionSortSliced(arr, 0, arr.GetSize(), less);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** InsertionSort
+//
+// Sort an array Array, ArrayPaged, ArrayUnsafe.
+// The array must have GetSize() function.
+// The data type must have a defined "<" operator.
+template<class Array>
+void InsertionSort(Array& arr)
+{
+ typedef typename Array::ValueType ValueType;
+ InsertionSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
+}
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBoundSliced
+//
+template<class Array, class Value, class Less>
+UPInt LowerBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val, Less less)
+{
+ SPInt first = (SPInt)start;
+ SPInt len = (SPInt)(end - start);
+ SPInt half;
+ SPInt middle;
+
+ while(len > 0)
+ {
+ half = len >> 1;
+ middle = first + half;
+ if(less(arr[middle], val))
+ {
+ first = middle + 1;
+ len = len - half - 1;
+ }
+ else
+ {
+ len = half;
+ }
+ }
+ return (UPInt)first;
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBoundSliced
+//
+template<class Array, class Value>
+UPInt LowerBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val)
+{
+ return LowerBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBoundSized
+//
+template<class Array, class Value>
+UPInt LowerBoundSized(const Array& arr, UPInt size, const Value& val)
+{
+ return LowerBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBound
+//
+template<class Array, class Value, class Less>
+UPInt LowerBound(const Array& arr, const Value& val, Less less)
+{
+ return LowerBoundSliced(arr, 0, arr.GetSize(), val, less);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBound
+//
+template<class Array, class Value>
+UPInt LowerBound(const Array& arr, const Value& val)
+{
+ return LowerBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare);
+}
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBoundSliced
+//
+template<class Array, class Value, class Less>
+UPInt UpperBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val, Less less)
+{
+ SPInt first = (SPInt)start;
+ SPInt len = (SPInt)(end - start);
+ SPInt half;
+ SPInt middle;
+
+ while(len > 0)
+ {
+ half = len >> 1;
+ middle = first + half;
+ if(less(val, arr[middle]))
+ {
+ len = half;
+ }
+ else
+ {
+ first = middle + 1;
+ len = len - half - 1;
+ }
+ }
+ return (UPInt)first;
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBoundSliced
+//
+template<class Array, class Value>
+UPInt UpperBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val)
+{
+ return UpperBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBoundSized
+//
+template<class Array, class Value>
+UPInt UpperBoundSized(const Array& arr, UPInt size, const Value& val)
+{
+ return UpperBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBound
+//
+template<class Array, class Value, class Less>
+UPInt UpperBound(const Array& arr, const Value& val, Less less)
+{
+ return UpperBoundSliced(arr, 0, arr.GetSize(), val, less);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBound
+//
+template<class Array, class Value>
+UPInt UpperBound(const Array& arr, const Value& val)
+{
+ return UpperBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** ReverseArray
+//
+template<class Array> void ReverseArray(Array& arr)
+{
+ SPInt from = 0;
+ SPInt to = arr.GetSize() - 1;
+ while(from < to)
+ {
+ Swap(arr[from], arr[to]);
+ ++from;
+ --to;
+ }
+}
+
+
+// ***** AppendArray
+//
+template<class CDst, class CSrc>
+void AppendArray(CDst& dst, const CSrc& src)
+{
+ UPInt i;
+ for(i = 0; i < src.GetSize(); i++)
+ dst.PushBack(src[i]);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayAdaptor
+//
+// A simple adapter that provides the GetSize() method and overloads
+// operator []. Used to wrap plain arrays in QuickSort and such.
+template<class T> class ArrayAdaptor
+{
+public:
+ typedef T ValueType;
+ ArrayAdaptor() : Data(0), Size(0) {}
+ ArrayAdaptor(T* ptr, UPInt size) : Data(ptr), Size(size) {}
+ UPInt GetSize() const { return Size; }
+ const T& operator [] (UPInt i) const { return Data[i]; }
+ T& operator [] (UPInt i) { return Data[i]; }
+private:
+ T* Data;
+ UPInt Size;
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** GConstArrayAdaptor
+//
+// A simple const adapter that provides the GetSize() method and overloads
+// operator []. Used to wrap plain arrays in LowerBound and such.
+template<class T> class ConstArrayAdaptor
+{
+public:
+ typedef T ValueType;
+ ConstArrayAdaptor() : Data(0), Size(0) {}
+ ConstArrayAdaptor(const T* ptr, UPInt size) : Data(ptr), Size(size) {}
+ UPInt GetSize() const { return Size; }
+ const T& operator [] (UPInt i) const { return Data[i]; }
+private:
+ const T* Data;
+ UPInt Size;
+};
+
+
+
+//-----------------------------------------------------------------------------------
+extern const UByte UpperBitTable[256];
+extern const UByte LowerBitTable[256];
+
+
+
+//-----------------------------------------------------------------------------------
+inline UByte UpperBit(UPInt val)
+{
+#ifndef OVR_64BIT_POINTERS
+
+ if (val & 0xFFFF0000)
+ {
+ return (val & 0xFF000000) ?
+ UpperBitTable[(val >> 24) ] + 24:
+ UpperBitTable[(val >> 16) & 0xFF] + 16;
+ }
+ return (val & 0xFF00) ?
+ UpperBitTable[(val >> 8) & 0xFF] + 8:
+ UpperBitTable[(val ) & 0xFF];
+
+#else
+
+ if (val & 0xFFFFFFFF00000000)
+ {
+ if (val & 0xFFFF000000000000)
+ {
+ return (val & 0xFF00000000000000) ?
+ UpperBitTable[(val >> 56) ] + 56:
+ UpperBitTable[(val >> 48) & 0xFF] + 48;
+ }
+ return (val & 0xFF0000000000) ?
+ UpperBitTable[(val >> 40) & 0xFF] + 40:
+ UpperBitTable[(val >> 32) & 0xFF] + 32;
+ }
+ else
+ {
+ if (val & 0xFFFF0000)
+ {
+ return (val & 0xFF000000) ?
+ UpperBitTable[(val >> 24) ] + 24:
+ UpperBitTable[(val >> 16) & 0xFF] + 16;
+ }
+ return (val & 0xFF00) ?
+ UpperBitTable[(val >> 8) & 0xFF] + 8:
+ UpperBitTable[(val ) & 0xFF];
+ }
+
+#endif
+}
+
+//-----------------------------------------------------------------------------------
+inline UByte LowerBit(UPInt val)
+{
+#ifndef OVR_64BIT_POINTERS
+
+ if (val & 0xFFFF)
+ {
+ return (val & 0xFF) ?
+ LowerBitTable[ val & 0xFF]:
+ LowerBitTable[(val >> 8) & 0xFF] + 8;
+ }
+ return (val & 0xFF0000) ?
+ LowerBitTable[(val >> 16) & 0xFF] + 16:
+ LowerBitTable[(val >> 24) & 0xFF] + 24;
+
+#else
+
+ if (val & 0xFFFFFFFF)
+ {
+ if (val & 0xFFFF)
+ {
+ return (val & 0xFF) ?
+ LowerBitTable[ val & 0xFF]:
+ LowerBitTable[(val >> 8) & 0xFF] + 8;
+ }
+ return (val & 0xFF0000) ?
+ LowerBitTable[(val >> 16) & 0xFF] + 16:
+ LowerBitTable[(val >> 24) & 0xFF] + 24;
+ }
+ else
+ {
+ if (val & 0xFFFF00000000)
+ {
+ return (val & 0xFF00000000) ?
+ LowerBitTable[(val >> 32) & 0xFF] + 32:
+ LowerBitTable[(val >> 40) & 0xFF] + 40;
+ }
+ return (val & 0xFF000000000000) ?
+ LowerBitTable[(val >> 48) & 0xFF] + 48:
+ LowerBitTable[(val >> 56) & 0xFF] + 56;
+ }
+
+#endif
+}
+
+
+
+// ******* Special (optimized) memory routines
+// Note: null (bad) pointer is not tested
+class MemUtil
+{
+public:
+
+ // Memory compare
+ static int Cmp (const void* p1, const void* p2, UPInt byteCount) { return memcmp(p1, p2, byteCount); }
+ static int Cmp16(const void* p1, const void* p2, UPInt int16Count);
+ static int Cmp32(const void* p1, const void* p2, UPInt int32Count);
+ static int Cmp64(const void* p1, const void* p2, UPInt int64Count);
+};
+
+// ** Inline Implementation
+
+inline int MemUtil::Cmp16(const void* p1, const void* p2, UPInt int16Count)
+{
+ SInt16* pa = (SInt16*)p1;
+ SInt16* pb = (SInt16*)p2;
+ unsigned ic = 0;
+ if (int16Count == 0)
+ return 0;
+ while (pa[ic] == pb[ic])
+ if (++ic==int16Count)
+ return 0;
+ return pa[ic] > pb[ic] ? 1 : -1;
+}
+inline int MemUtil::Cmp32(const void* p1, const void* p2, UPInt int32Count)
+{
+ SInt32* pa = (SInt32*)p1;
+ SInt32* pb = (SInt32*)p2;
+ unsigned ic = 0;
+ if (int32Count == 0)
+ return 0;
+ while (pa[ic] == pb[ic])
+ if (++ic==int32Count)
+ return 0;
+ return pa[ic] > pb[ic] ? 1 : -1;
+}
+inline int MemUtil::Cmp64(const void* p1, const void* p2, UPInt int64Count)
+{
+ SInt64* pa = (SInt64*)p1;
+ SInt64* pb = (SInt64*)p2;
+ unsigned ic = 0;
+ if (int64Count == 0)
+ return 0;
+ while (pa[ic] == pb[ic])
+ if (++ic==int64Count)
+ return 0;
+ return pa[ic] > pb[ic] ? 1 : -1;
+}
+
+// ** End Inline Implementation
+
+
+//-----------------------------------------------------------------------------------
+// ******* Byte Order Conversions
+namespace ByteUtil {
+
+ // *** Swap Byte Order
+
+ // Swap the byte order of a byte array
+ inline void SwapOrder(void* pv, int size)
+ {
+ UByte* pb = (UByte*)pv;
+ UByte temp;
+ for (int i = 0; i < size>>1; i++)
+ {
+ temp = pb[size-1-i];
+ pb[size-1-i] = pb[i];
+ pb[i] = temp;
+ }
+ }
+
+ // Swap the byte order of primitive types
+ inline UByte SwapOrder(UByte v) { return v; }
+ inline SByte SwapOrder(SByte v) { return v; }
+ inline UInt16 SwapOrder(UInt16 v) { return UInt16(v>>8)|UInt16(v<<8); }
+ inline SInt16 SwapOrder(SInt16 v) { return SInt16((UInt16(v)>>8)|(v<<8)); }
+ inline UInt32 SwapOrder(UInt32 v) { return (v>>24)|((v&0x00FF0000)>>8)|((v&0x0000FF00)<<8)|(v<<24); }
+ inline SInt32 SwapOrder(SInt32 p) { return (SInt32)SwapOrder(UInt32(p)); }
+ inline UInt64 SwapOrder(UInt64 v)
+ {
+ return (v>>56) |
+ ((v&UInt64(0x00FF000000000000))>>40) |
+ ((v&UInt64(0x0000FF0000000000))>>24) |
+ ((v&UInt64(0x000000FF00000000))>>8) |
+ ((v&UInt64(0x00000000FF000000))<<8) |
+ ((v&UInt64(0x0000000000FF0000))<<24) |
+ ((v&UInt64(0x000000000000FF00))<<40) |
+ (v<<56);
+ }
+ inline SInt64 SwapOrder(SInt64 v) { return (SInt64)SwapOrder(UInt64(v)); }
+ inline float SwapOrder(float p)
+ {
+ union {
+ float p;
+ UInt32 v;
+ } u;
+ u.p = p;
+ u.v = SwapOrder(u.v);
+ return u.p;
+ }
+
+ inline double SwapOrder(double p)
+ {
+ union {
+ double p;
+ UInt64 v;
+ } u;
+ u.p = p;
+ u.v = SwapOrder(u.v);
+ return u.p;
+ }
+
+ // *** Byte-order conversion
+
+#if (OVR_BYTE_ORDER == OVR_LITTLE_ENDIAN)
+ // Little Endian to System (LE)
+ inline UByte LEToSystem(UByte v) { return v; }
+ inline SByte LEToSystem(SByte v) { return v; }
+ inline UInt16 LEToSystem(UInt16 v) { return v; }
+ inline SInt16 LEToSystem(SInt16 v) { return v; }
+ inline UInt32 LEToSystem(UInt32 v) { return v; }
+ inline SInt32 LEToSystem(SInt32 v) { return v; }
+ inline UInt64 LEToSystem(UInt64 v) { return v; }
+ inline SInt64 LEToSystem(SInt64 v) { return v; }
+ inline float LEToSystem(float v) { return v; }
+ inline double LEToSystem(double v) { return v; }
+
+ // Big Endian to System (LE)
+ inline UByte BEToSystem(UByte v) { return SwapOrder(v); }
+ inline SByte BEToSystem(SByte v) { return SwapOrder(v); }
+ inline UInt16 BEToSystem(UInt16 v) { return SwapOrder(v); }
+ inline SInt16 BEToSystem(SInt16 v) { return SwapOrder(v); }
+ inline UInt32 BEToSystem(UInt32 v) { return SwapOrder(v); }
+ inline SInt32 BEToSystem(SInt32 v) { return SwapOrder(v); }
+ inline UInt64 BEToSystem(UInt64 v) { return SwapOrder(v); }
+ inline SInt64 BEToSystem(SInt64 v) { return SwapOrder(v); }
+ inline float BEToSystem(float v) { return SwapOrder(v); }
+ inline double BEToSystem(double v) { return SwapOrder(v); }
+
+ // System (LE) to Little Endian
+ inline UByte SystemToLE(UByte v) { return v; }
+ inline SByte SystemToLE(SByte v) { return v; }
+ inline UInt16 SystemToLE(UInt16 v) { return v; }
+ inline SInt16 SystemToLE(SInt16 v) { return v; }
+ inline UInt32 SystemToLE(UInt32 v) { return v; }
+ inline SInt32 SystemToLE(SInt32 v) { return v; }
+ inline UInt64 SystemToLE(UInt64 v) { return v; }
+ inline SInt64 SystemToLE(SInt64 v) { return v; }
+ inline float SystemToLE(float v) { return v; }
+ inline double SystemToLE(double v) { return v; }
+
+ // System (LE) to Big Endian
+ inline UByte SystemToBE(UByte v) { return SwapOrder(v); }
+ inline SByte SystemToBE(SByte v) { return SwapOrder(v); }
+ inline UInt16 SystemToBE(UInt16 v) { return SwapOrder(v); }
+ inline SInt16 SystemToBE(SInt16 v) { return SwapOrder(v); }
+ inline UInt32 SystemToBE(UInt32 v) { return SwapOrder(v); }
+ inline SInt32 SystemToBE(SInt32 v) { return SwapOrder(v); }
+ inline UInt64 SystemToBE(UInt64 v) { return SwapOrder(v); }
+ inline SInt64 SystemToBE(SInt64 v) { return SwapOrder(v); }
+ inline float SystemToBE(float v) { return SwapOrder(v); }
+ inline double SystemToBE(double v) { return SwapOrder(v); }
+
+#elif (OVR_BYTE_ORDER == OVR_BIG_ENDIAN)
+ // Little Endian to System (BE)
+ inline UByte LEToSystem(UByte v) { return SwapOrder(v); }
+ inline SByte LEToSystem(SByte v) { return SwapOrder(v); }
+ inline UInt16 LEToSystem(UInt16 v) { return SwapOrder(v); }
+ inline SInt16 LEToSystem(SInt16 v) { return SwapOrder(v); }
+ inline UInt32 LEToSystem(UInt32 v) { return SwapOrder(v); }
+ inline SInt32 LEToSystem(SInt32 v) { return SwapOrder(v); }
+ inline UInt64 LEToSystem(UInt64 v) { return SwapOrder(v); }
+ inline SInt64 LEToSystem(SInt64 v) { return SwapOrder(v); }
+ inline float LEToSystem(float v) { return SwapOrder(v); }
+ inline double LEToSystem(double v) { return SwapOrder(v); }
+
+ // Big Endian to System (BE)
+ inline UByte BEToSystem(UByte v) { return v; }
+ inline SByte BEToSystem(SByte v) { return v; }
+ inline UInt16 BEToSystem(UInt16 v) { return v; }
+ inline SInt16 BEToSystem(SInt16 v) { return v; }
+ inline UInt32 BEToSystem(UInt32 v) { return v; }
+ inline SInt32 BEToSystem(SInt32 v) { return v; }
+ inline UInt64 BEToSystem(UInt64 v) { return v; }
+ inline SInt64 BEToSystem(SInt64 v) { return v; }
+ inline float BEToSystem(float v) { return v; }
+ inline double BEToSystem(double v) { return v; }
+
+ // System (BE) to Little Endian
+ inline UByte SystemToLE(UByte v) { return SwapOrder(v); }
+ inline SByte SystemToLE(SByte v) { return SwapOrder(v); }
+ inline UInt16 SystemToLE(UInt16 v) { return SwapOrder(v); }
+ inline SInt16 SystemToLE(SInt16 v) { return SwapOrder(v); }
+ inline UInt32 SystemToLE(UInt32 v) { return SwapOrder(v); }
+ inline SInt32 SystemToLE(SInt32 v) { return SwapOrder(v); }
+ inline UInt64 SystemToLE(UInt64 v) { return SwapOrder(v); }
+ inline SInt64 SystemToLE(SInt64 v) { return SwapOrder(v); }
+ inline float SystemToLE(float v) { return SwapOrder(v); }
+ inline double SystemToLE(double v) { return SwapOrder(v); }
+
+ // System (BE) to Big Endian
+ inline UByte SystemToBE(UByte v) { return v; }
+ inline SByte SystemToBE(SByte v) { return v; }
+ inline UInt16 SystemToBE(UInt16 v) { return v; }
+ inline SInt16 SystemToBE(SInt16 v) { return v; }
+ inline UInt32 SystemToBE(UInt32 v) { return v; }
+ inline SInt32 SystemToBE(SInt32 v) { return v; }
+ inline UInt64 SystemToBE(UInt64 v) { return v; }
+ inline SInt64 SystemToBE(SInt64 v) { return v; }
+ inline float SystemToBE(float v) { return v; }
+ inline double SystemToBE(double v) { return v; }
+
+#else
+ #error "OVR_BYTE_ORDER must be defined to OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN"
+#endif
+
+} // namespace ByteUtil
+
+
+
+}} // OVR::Alg
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Allocator.cpp b/LibOVR/Src/Kernel/OVR_Allocator.cpp new file mode 100644 index 0000000..1f17ffe --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Allocator.cpp @@ -0,0 +1,84 @@ +/************************************************************************************
+
+Filename : OVR_Allocator.cpp
+Content : Installable memory allocator implementation
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Allocator.h"
+#ifdef OVR_OS_MAC
+ #include <stdlib.h>
+#else
+ #include <malloc.h>
+#endif
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Allocator
+
+Allocator* Allocator::pInstance = 0;
+
+// Default AlignedAlloc implementation will delegate to Alloc/Free after doing rounding.
+void* Allocator::AllocAligned(UPInt size, UPInt align)
+{
+ OVR_ASSERT((align & (align-1)) == 0);
+ align = (align > sizeof(UPInt)) ? align : sizeof(UPInt);
+ UPInt p = (UPInt)Alloc(size+align);
+ UPInt aligned = 0;
+ if (p)
+ {
+ aligned = (UPInt(p) + align-1) & ~(align-1);
+ if (aligned == p)
+ aligned += align;
+ *(((UPInt*)aligned)-1) = aligned-p;
+ }
+ return (void*)aligned;
+}
+
+void Allocator::FreeAligned(void* p)
+{
+ UPInt src = UPInt(p) - *(((UPInt*)p)-1);
+ Free((void*)src);
+}
+
+
+//------------------------------------------------------------------------
+// ***** Default Allocator
+
+// This allocator is created and used if no other allocator is installed.
+// Default allocator delegates to system malloc.
+
+void* DefaultAllocator::Alloc(UPInt size)
+{
+ return malloc(size);
+}
+void* DefaultAllocator::AllocDebug(UPInt size, const char* file, unsigned line)
+{
+#if defined(OVR_CC_MSVC) && defined(_CRTDBG_MAP_ALLOC)
+ return _malloc_dbg(size, _NORMAL_BLOCK, file, line);
+#else
+ OVR_UNUSED2(file, line);
+ return malloc(size);
+#endif
+}
+
+void* DefaultAllocator::Realloc(void* p, UPInt newSize)
+{
+ return realloc(p, newSize);
+}
+void DefaultAllocator::Free(void *p)
+{
+ return free(p);
+}
+
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_Allocator.h b/LibOVR/Src/Kernel/OVR_Allocator.h new file mode 100644 index 0000000..88cbb42 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Allocator.h @@ -0,0 +1,336 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Allocator.h
+Content : Installable memory allocator
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Allocator_h
+#define OVR_Allocator_h
+
+#include "OVR_Types.h"
+
+//-----------------------------------------------------------------------------------
+
+// ***** Disable template-unfriendly MS VC++ warnings
+#if defined(OVR_CC_MSVC)
+// Pragma to prevent long name warnings in in VC++
+#pragma warning(disable : 4503)
+#pragma warning(disable : 4786)
+// In MSVC 7.1, warning about placement new POD default initializer
+#pragma warning(disable : 4345)
+#endif
+
+// Un-define new so that placement constructors work
+#undef new
+
+
+//-----------------------------------------------------------------------------------
+// ***** Placement new overrides
+
+// Calls constructor on own memory created with "new(ptr) type"
+#ifndef __PLACEMENT_NEW_INLINE
+#define __PLACEMENT_NEW_INLINE
+
+# if defined(OVR_CC_MWERKS) || defined(OVR_CC_BORLAND) || defined(OVR_CC_GNU)
+# include <new>
+# else
+ // Useful on MSVC
+ OVR_FORCE_INLINE void* operator new (OVR::UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; }
+ OVR_FORCE_INLINE void operator delete (void *, void *) { }
+# endif
+
+#endif // __PLACEMENT_NEW_INLINE
+
+
+
+//------------------------------------------------------------------------
+// ***** Macros to redefine class new/delete operators
+
+// Types specifically declared to allow disambiguation of address in
+// class member operator new.
+
+#define OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, check_delete) \
+ void* operator new(UPInt sz) \
+ { void *p = OVR_ALLOC_DEBUG(sz, __FILE__, __LINE__); return p; } \
+ void* operator new(UPInt sz, const char* file, int line) \
+ { void* p = OVR_ALLOC_DEBUG(sz, file, line); OVR_UNUSED2(file, line); return p; } \
+ void operator delete(void *p) \
+ { check_delete(class_name, p); OVR_FREE(p); } \
+ void operator delete(void *p, const char*, int) \
+ { check_delete(class_name, p); OVR_FREE(p); }
+
+#define OVR_MEMORY_DEFINE_PLACEMENT_NEW \
+ void* operator new (UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; } \
+ void operator delete (void *ptr, void *ptr2) { OVR_UNUSED2(ptr,ptr2); }
+
+
+#define OVR_MEMORY_CHECK_DELETE_NONE(class_name, p)
+
+// Redefined all delete/new operators in a class without custom memory initialization
+#define OVR_MEMORY_REDEFINE_NEW(class_name) \
+ OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, OVR_MEMORY_CHECK_DELETE_NONE)
+
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Construct / Destruct
+
+// Construct/Destruct functions are useful when new is redefined, as they can
+// be called instead of placement new constructors.
+
+
+template <class T>
+OVR_FORCE_INLINE T* Construct(void *p)
+{
+ return ::new(p) T;
+}
+
+template <class T>
+OVR_FORCE_INLINE T* Construct(void *p, const T& source)
+{
+ return ::new(p) T(source);
+}
+
+// Same as above, but allows for a different type of constructor.
+template <class T, class S>
+OVR_FORCE_INLINE T* ConstructAlt(void *p, const S& source)
+{
+ return ::new(p) T(source);
+}
+
+template <class T, class S1, class S2>
+OVR_FORCE_INLINE T* ConstructAlt(void *p, const S1& src1, const S2& src2)
+{
+ return ::new(p) T(src1, src2);
+}
+
+template <class T>
+OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count)
+{
+ UByte *pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ {
+ Construct<T>(pdata);
+ }
+}
+
+template <class T>
+OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count, const T& source)
+{
+ UByte *pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ {
+ Construct<T>(pdata, source);
+ }
+}
+
+template <class T>
+OVR_FORCE_INLINE void Destruct(T *pobj)
+{
+ pobj->~T();
+ OVR_UNUSED1(pobj); // Fix incorrect 'unused variable' MSVC warning.
+}
+
+template <class T>
+OVR_FORCE_INLINE void DestructArray(T *pobj, UPInt count)
+{
+ for (UPInt i=0; i<count; ++i, ++pobj)
+ pobj->~T();
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** Allocator
+
+// Allocator defines a memory allocation interface that developers can override
+// to to provide memory for OVR; an instance of this class is typically created on
+// application startup and passed into System or OVR::System constructor.
+//
+//
+// Users implementing this interface must provide three functions: Alloc, Free,
+// and Realloc. Implementations of these functions must honor the requested alignment.
+// Although arbitrary alignment requests are possible, requested alignment will
+// typically be small, such as 16 bytes or less.
+
+class Allocator
+{
+ friend class System;
+public:
+
+ // *** Standard Alignment Alloc/Free
+
+ // Allocate memory of specified size with default alignment.
+ // Alloc of size==0 will allocate a tiny block & return a valid pointer;
+ // this makes it suitable for new operator.
+ virtual void* Alloc(UPInt size) = 0;
+ // Same as Alloc, but provides an option of passing debug data.
+ virtual void* AllocDebug(UPInt size, const char* file, unsigned line)
+ { OVR_UNUSED2(file, line); return Alloc(size); }
+
+ // Reallocate memory block to a new size, copying data if necessary. Returns the pointer to
+ // new memory block, which may be the same as original pointer. Will return 0 if reallocation
+ // failed, in which case previous memory is still valid.
+ // Realloc to decrease size will never fail.
+ // Realloc of pointer == 0 is equivalent to Alloc
+ // Realloc to size == 0, shrinks to the minimal size, pointer remains valid and requires Free().
+ virtual void* Realloc(void* p, UPInt newSize) = 0;
+
+ // Frees memory allocated by Alloc/Realloc.
+ // Free of null pointer is valid and will do nothing.
+ virtual void Free(void *p) = 0;
+
+
+ // *** Standard Alignment Alloc/Free
+
+ // Allocate memory of specified alignment.
+ // Memory allocated with AllocAligned MUST be freed with FreeAligned.
+ // Default implementation will delegate to Alloc/Free after doing rounding.
+ virtual void* AllocAligned(UPInt size, UPInt align);
+ // Frees memory allocated with AllocAligned.
+ virtual void FreeAligned(void* p);
+
+ // Returns the pointer to the current globally installed Allocator instance.
+ // This pointer is used for most of the memory allocations.
+ static Allocator* GetInstance() { return pInstance; }
+
+
+protected:
+ // onSystemShutdown is called on the allocator during System::Shutdown.
+ // At this point, all allocations should've been freed.
+ virtual void onSystemShutdown() { }
+
+public:
+ static void setInstance(Allocator* palloc)
+ {
+ OVR_ASSERT((pInstance == 0) || (palloc == 0));
+ pInstance = palloc;
+ }
+
+private:
+
+ static Allocator* pInstance;
+};
+
+
+
+//------------------------------------------------------------------------
+// ***** Allocator_SingletonSupport
+
+// Allocator_SingletonSupport is a Allocator wrapper class that implements
+// the InitSystemSingleton static function, used to create a global singleton
+// used for the OVR::System default argument initialization.
+//
+// End users implementing custom Allocator interface don't need to make use of this base
+// class; they can just create an instance of their own class on stack and pass it to System.
+
+template<class D>
+class Allocator_SingletonSupport : public Allocator
+{
+ struct AllocContainer
+ {
+ UPInt Data[(sizeof(D) + sizeof(UPInt)-1) / sizeof(UPInt)];
+ bool Initialized;
+ AllocContainer() : Initialized(0) { }
+ };
+
+ AllocContainer* pContainer;
+
+public:
+ Allocator_SingletonSupport() : pContainer(0) { }
+
+ // Creates a singleton instance of this Allocator class used
+ // on OVR_DEFAULT_ALLOCATOR during System initialization.
+ static D* InitSystemSingleton()
+ {
+ static AllocContainer Container;
+ OVR_ASSERT(Container.Initialized == false);
+
+ Allocator_SingletonSupport<D> *presult = Construct<D>((void*)Container.Data);
+ presult->pContainer = &Container;
+ Container.Initialized = true;
+ return (D*)presult;
+ }
+
+protected:
+ virtual void onSystemShutdown()
+ {
+ Allocator::onSystemShutdown();
+ if (pContainer)
+ {
+ pContainer->Initialized = false;
+ Destruct((D*)this);
+ pContainer = 0;
+ }
+ }
+};
+
+//------------------------------------------------------------------------
+// ***** Default Allocator
+
+// This allocator is created and used if no other allocator is installed.
+// Default allocator delegates to system malloc.
+
+class DefaultAllocator : public Allocator_SingletonSupport<DefaultAllocator>
+{
+public:
+ virtual void* Alloc(UPInt size);
+ virtual void* AllocDebug(UPInt size, const char* file, unsigned line);
+ virtual void* Realloc(void* p, UPInt newSize);
+ virtual void Free(void *p);
+};
+
+
+//------------------------------------------------------------------------
+// ***** Memory Allocation Macros
+
+// These macros should be used for global allocation. In the future, these
+// macros will allows allocation to be extended with debug file/line information
+// if necessary.
+
+#define OVR_REALLOC(p,s) OVR::Allocator::GetInstance()->Realloc((p),(s))
+#define OVR_FREE(p) OVR::Allocator::GetInstance()->Free((p))
+#define OVR_ALLOC_ALIGNED(s,a) OVR::Allocator::GetInstance()->AllocAligned((s),(a))
+#define OVR_FREE_ALIGNED(p) OVR::Allocator::GetInstance()->FreeAligned((p))
+
+#ifdef OVR_BUILD_DEBUG
+#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->AllocDebug((s), __FILE__, __LINE__)
+#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->AllocDebug((s), f, l)
+#else
+#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->Alloc((s))
+#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->Alloc((s))
+#endif
+
+//------------------------------------------------------------------------
+
+// Base class that overrides the new and delete operators.
+// Deriving from this class, even as a multiple base, incurs no space overhead.
+class NewOverrideBase
+{
+public:
+
+ // Redefine all new & delete operators.
+ OVR_MEMORY_REDEFINE_NEW(NewOverrideBase)
+};
+
+
+} // OVR
+
+
+// Redefine operator 'new' if necessary.
+#if defined(OVR_DEFINE_NEW)
+#define new OVR_DEFINE_NEW
+#endif
+
+
+#endif // OVR_Memory
diff --git a/LibOVR/Src/Kernel/OVR_Array.h b/LibOVR/Src/Kernel/OVR_Array.h new file mode 100644 index 0000000..905d58f --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Array.h @@ -0,0 +1,793 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Array.h
+Content : Template implementation for Array
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Array_h
+#define OVR_Array_h
+
+#include "OVR_ContainerAllocator.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayDefaultPolicy
+//
+// Default resize behavior. No minimal capacity, Granularity=4,
+// Shrinking as needed. ArrayConstPolicy actually is the same as
+// ArrayDefaultPolicy, but parametrized with constants.
+// This struct is used only in order to reduce the template "matroska".
+struct ArrayDefaultPolicy
+{
+ ArrayDefaultPolicy() : Capacity(0) {}
+ ArrayDefaultPolicy(const ArrayDefaultPolicy&) : Capacity(0) {}
+
+ UPInt GetMinCapacity() const { return 0; }
+ UPInt GetGranularity() const { return 4; }
+ bool NeverShrinking() const { return 0; }
+
+ UPInt GetCapacity() const { return Capacity; }
+ void SetCapacity(UPInt capacity) { Capacity = capacity; }
+private:
+ UPInt Capacity;
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayConstPolicy
+//
+// Statically parametrized resizing behavior:
+// MinCapacity, Granularity, and Shrinking flag.
+template<int MinCapacity=0, int Granularity=4, bool NeverShrink=false>
+struct ArrayConstPolicy
+{
+ typedef ArrayConstPolicy<MinCapacity, Granularity, NeverShrink> SelfType;
+
+ ArrayConstPolicy() : Capacity(0) {}
+ ArrayConstPolicy(const SelfType&) : Capacity(0) {}
+
+ UPInt GetMinCapacity() const { return MinCapacity; }
+ UPInt GetGranularity() const { return Granularity; }
+ bool NeverShrinking() const { return NeverShrink; }
+
+ UPInt GetCapacity() const { return Capacity; }
+ void SetCapacity(UPInt capacity) { Capacity = capacity; }
+private:
+ UPInt Capacity;
+};
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayDataBase
+//
+// Basic operations with array data: Reserve, Resize, Free, ArrayPolicy.
+// For internal use only: ArrayData,ArrayDataCC and others.
+template<class T, class Allocator, class SizePolicy>
+struct ArrayDataBase
+{
+ typedef T ValueType;
+ typedef Allocator AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayDataBase<T, Allocator, SizePolicy> SelfType;
+
+ ArrayDataBase()
+ : Data(0), Size(0), Policy() {}
+
+ ArrayDataBase(const SizePolicy& p)
+ : Data(0), Size(0), Policy(p) {}
+
+ ~ArrayDataBase()
+ {
+ Allocator::DestructArray(Data, Size);
+ Allocator::Free(Data);
+ }
+
+ UPInt GetCapacity() const
+ {
+ return Policy.GetCapacity();
+ }
+
+ void ClearAndRelease()
+ {
+ Allocator::DestructArray(Data, Size);
+ Allocator::Free(Data);
+ Data = 0;
+ Size = 0;
+ Policy.SetCapacity(0);
+ }
+
+ void Reserve(UPInt newCapacity)
+ {
+ if (Policy.NeverShrinking() && newCapacity < GetCapacity())
+ return;
+
+ if (newCapacity < Policy.GetMinCapacity())
+ newCapacity = Policy.GetMinCapacity();
+
+ // Resize the buffer.
+ if (newCapacity == 0)
+ {
+ if (Data)
+ {
+ Allocator::Free(Data);
+ Data = 0;
+ }
+ Policy.SetCapacity(0);
+ }
+ else
+ {
+ UPInt gran = Policy.GetGranularity();
+ newCapacity = (newCapacity + gran - 1) / gran * gran;
+ if (Data)
+ {
+ if (Allocator::IsMovable())
+ {
+ Data = (T*)Allocator::Realloc(Data, sizeof(T) * newCapacity);
+ }
+ else
+ {
+ T* newData = (T*)Allocator::Alloc(sizeof(T) * newCapacity);
+ UPInt i, s;
+ s = (Size < newCapacity) ? Size : newCapacity;
+ for (i = 0; i < s; ++i)
+ {
+ Allocator::Construct(&newData[i], Data[i]);
+ Allocator::Destruct(&Data[i]);
+ }
+ for (i = s; i < Size; ++i)
+ {
+ Allocator::Destruct(&Data[i]);
+ }
+ Allocator::Free(Data);
+ Data = newData;
+ }
+ }
+ else
+ {
+ Data = (T*)Allocator::Alloc(sizeof(T) * newCapacity);
+ //memset(Buffer, 0, (sizeof(ValueType) * newSize)); // Do we need this?
+ }
+ Policy.SetCapacity(newCapacity);
+ // OVR_ASSERT(Data); // need to throw (or something) on alloc failure!
+ }
+ }
+
+ // This version of Resize DOES NOT construct the elements.
+ // It's done to optimize PushBack, which uses a copy constructor
+ // instead of the default constructor and assignment
+ void ResizeNoConstruct(UPInt newSize)
+ {
+ UPInt oldSize = Size;
+
+ if (newSize < oldSize)
+ {
+ Allocator::DestructArray(Data + newSize, oldSize - newSize);
+ if (newSize < (Policy.GetCapacity() >> 1))
+ {
+ Reserve(newSize);
+ }
+ }
+ else if(newSize >= Policy.GetCapacity())
+ {
+ Reserve(newSize + (newSize >> 2));
+ }
+ //! IMPORTANT to modify Size only after Reserve completes, because garbage collectable
+ // array may use this array and may traverse it during Reserve (in the case, if
+ // collection occurs because of heap limit exceeded).
+ Size = newSize;
+ }
+
+ ValueType* Data;
+ UPInt Size;
+ SizePolicy Policy;
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayData
+//
+// General purpose array data.
+// For internal use only in Array, ArrayLH, ArrayPOD and so on.
+template<class T, class Allocator, class SizePolicy>
+struct ArrayData : ArrayDataBase<T, Allocator, SizePolicy>
+{
+ typedef T ValueType;
+ typedef Allocator AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType;
+ typedef ArrayData <T, Allocator, SizePolicy> SelfType;
+
+ ArrayData()
+ : BaseType() { }
+
+ ArrayData(int size)
+ : BaseType() { Resize(size); }
+
+ ArrayData(const SelfType& a)
+ : BaseType(a.Policy) { Append(a.Data, a.Size); }
+
+
+ void Resize(UPInt newSize)
+ {
+ UPInt oldSize = this->Size;
+ BaseType::ResizeNoConstruct(newSize);
+ if(newSize > oldSize)
+ Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize);
+ }
+
+ void PushBack(const ValueType& val)
+ {
+ BaseType::ResizeNoConstruct(this->Size + 1);
+ Allocator::Construct(this->Data + this->Size - 1, val);
+ }
+
+ template<class S>
+ void PushBackAlt(const S& val)
+ {
+ BaseType::ResizeNoConstruct(this->Size + 1);
+ Allocator::ConstructAlt(this->Data + this->Size - 1, val);
+ }
+
+ // Append the given data to the array.
+ void Append(const ValueType other[], UPInt count)
+ {
+ if (count)
+ {
+ UPInt oldSize = this->Size;
+ BaseType::ResizeNoConstruct(this->Size + count);
+ Allocator::ConstructArray(this->Data + oldSize, count, other);
+ }
+ }
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayDataCC
+//
+// A modification of ArrayData that always copy-constructs new elements
+// using a specified DefaultValue. For internal use only in ArrayCC.
+template<class T, class Allocator, class SizePolicy>
+struct ArrayDataCC : ArrayDataBase<T, Allocator, SizePolicy>
+{
+ typedef T ValueType;
+ typedef Allocator AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType;
+ typedef ArrayDataCC <T, Allocator, SizePolicy> SelfType;
+
+ ArrayDataCC(const ValueType& defval)
+ : BaseType(), DefaultValue(defval) { }
+
+ ArrayDataCC(const ValueType& defval, int size)
+ : BaseType(), DefaultValue(defval) { Resize(size); }
+
+ ArrayDataCC(const SelfType& a)
+ : BaseType(a.Policy), DefaultValue(a.DefaultValue) { Append(a.Data, a.Size); }
+
+
+ void Resize(UPInt newSize)
+ {
+ UPInt oldSize = this->Size;
+ BaseType::ResizeNoConstruct(newSize);
+ if(newSize > oldSize)
+ Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize, DefaultValue);
+ }
+
+ void PushBack(const ValueType& val)
+ {
+ BaseType::ResizeNoConstruct(this->Size + 1);
+ Allocator::Construct(this->Data + this->Size - 1, val);
+ }
+
+ template<class S>
+ void PushBackAlt(const S& val)
+ {
+ BaseType::ResizeNoConstruct(this->Size + 1);
+ Allocator::ConstructAlt(this->Data + this->Size - 1, val);
+ }
+
+ // Append the given data to the array.
+ void Append(const ValueType other[], UPInt count)
+ {
+ if (count)
+ {
+ UPInt oldSize = this->Size;
+ BaseType::ResizeNoConstruct(this->Size + count);
+ Allocator::ConstructArray(this->Data + oldSize, count, other);
+ }
+ }
+
+ ValueType DefaultValue;
+};
+
+
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayBase
+//
+// Resizable array. The behavior can be POD (suffix _POD) and
+// Movable (no suffix) depending on the allocator policy.
+// In case of _POD the constructors and destructors are not called.
+//
+// Arrays can't handle non-movable objects! Don't put anything in here
+// that can't be moved around by bitwise copy.
+//
+// The addresses of elements are not persistent! Don't keep the address
+// of an element; the array contents will move around as it gets resized.
+template<class ArrayData>
+class ArrayBase
+{
+public:
+ typedef typename ArrayData::ValueType ValueType;
+ typedef typename ArrayData::AllocatorType AllocatorType;
+ typedef typename ArrayData::SizePolicyType SizePolicyType;
+ typedef ArrayBase<ArrayData> SelfType;
+
+
+#undef new
+ OVR_MEMORY_REDEFINE_NEW(ArrayBase)
+// Redefine operator 'new' if necessary.
+#if defined(OVR_DEFINE_NEW)
+#define new OVR_DEFINE_NEW
+#endif
+
+
+ ArrayBase()
+ : Data() {}
+ ArrayBase(int size)
+ : Data(size) {}
+ ArrayBase(const SelfType& a)
+ : Data(a.Data) {}
+
+ ArrayBase(const ValueType& defval)
+ : Data(defval) {}
+ ArrayBase(const ValueType& defval, int size)
+ : Data(defval, size) {}
+
+ SizePolicyType* GetSizePolicy() const { return Data.Policy; }
+ void SetSizePolicy(const SizePolicyType& p) { Data.Policy = p; }
+
+ bool NeverShrinking()const { return Data.Policy.NeverShrinking(); }
+ UPInt GetSize() const { return Data.Size; }
+ bool IsEmpty() const { return Data.Size == 0; }
+ UPInt GetCapacity() const { return Data.GetCapacity(); }
+ UPInt GetNumBytes() const { return Data.GetCapacity() * sizeof(ValueType); }
+
+ void ClearAndRelease() { Data.ClearAndRelease(); }
+ void Clear() { Data.Resize(0); }
+ void Resize(UPInt newSize) { Data.Resize(newSize); }
+
+ // Reserve can only increase the capacity
+ void Reserve(UPInt newCapacity)
+ {
+ if (newCapacity > Data.GetCapacity())
+ Data.Reserve(newCapacity);
+ }
+
+ // Basic access.
+ ValueType& At(UPInt index)
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+ const ValueType& At(UPInt index) const
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+
+ ValueType ValueAt(UPInt index) const
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+
+ // Basic access.
+ ValueType& operator [] (UPInt index)
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+ const ValueType& operator [] (UPInt index) const
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+
+ // Raw pointer to the data. Use with caution!
+ const ValueType* GetDataPtr() const { return Data.Data; }
+ ValueType* GetDataPtr() { return Data.Data; }
+
+ // Insert the given element at the end of the array.
+ void PushBack(const ValueType& val)
+ {
+ // DO NOT pass elements of your own vector into
+ // push_back()! Since we're using references,
+ // resize() may munge the element storage!
+ // OVR_ASSERT(&val < &Buffer[0] || &val > &Buffer[BufferSize]);
+ Data.PushBack(val);
+ }
+
+ template<class S>
+ void PushBackAlt(const S& val)
+ {
+ Data.PushBackAlt(val);
+ }
+
+ // Remove the last element.
+ void PopBack(UPInt count = 1)
+ {
+ OVR_ASSERT(Data.Size >= count);
+ Data.Resize(Data.Size - count);
+ }
+
+ ValueType& PushDefault()
+ {
+ Data.PushBack(ValueType());
+ return Back();
+ }
+
+ ValueType Pop()
+ {
+ ValueType t = Back();
+ PopBack();
+ return t;
+ }
+
+
+ // Access the first element.
+ ValueType& Front() { return At(0); }
+ const ValueType& Front() const { return At(0); }
+
+ // Access the last element.
+ ValueType& Back() { return At(Data.Size - 1); }
+ const ValueType& Back() const { return At(Data.Size - 1); }
+
+ // Array copy. Copies the contents of a into this array.
+ const SelfType& operator = (const SelfType& a)
+ {
+ Resize(a.GetSize());
+ for (UPInt i = 0; i < Data.Size; i++) {
+ *(Data.Data + i) = a[i];
+ }
+ return *this;
+ }
+
+ // Removing multiple elements from the array.
+ void RemoveMultipleAt(UPInt index, UPInt num)
+ {
+ OVR_ASSERT(index + num <= Data.Size);
+ if (Data.Size == num)
+ {
+ Clear();
+ }
+ else
+ {
+ AllocatorType::DestructArray(Data.Data + index, num);
+ AllocatorType::CopyArrayForward(
+ Data.Data + index,
+ Data.Data + index + num,
+ Data.Size - num - index);
+ Data.Size -= num;
+ }
+ }
+
+ // Removing an element from the array is an expensive operation!
+ // It compacts only after removing the last element.
+ void RemoveAt(UPInt index)
+ {
+ OVR_ASSERT(index < Data.Size);
+ if (Data.Size == 1)
+ {
+ Clear();
+ }
+ else
+ {
+ AllocatorType::Destruct(Data.Data + index);
+ AllocatorType::CopyArrayForward(
+ Data.Data + index,
+ Data.Data + index + 1,
+ Data.Size - 1 - index);
+ --Data.Size;
+ }
+ }
+
+ // Insert the given object at the given index shifting all the elements up.
+ void InsertAt(UPInt index, const ValueType& val = ValueType())
+ {
+ OVR_ASSERT(index <= Data.Size);
+
+ Data.Resize(Data.Size + 1);
+ if (index < Data.Size - 1)
+ {
+ AllocatorType::CopyArrayBackward(
+ Data.Data + index + 1,
+ Data.Data + index,
+ Data.Size - 1 - index);
+ }
+ AllocatorType::Construct(Data.Data + index, val);
+ }
+
+ // Insert the given object at the given index shifting all the elements up.
+ void InsertMultipleAt(UPInt index, UPInt num, const ValueType& val = ValueType())
+ {
+ OVR_ASSERT(index <= Data.Size);
+
+ Data.Resize(Data.Size + num);
+ if (index < Data.Size - num)
+ {
+ AllocatorType::CopyArrayBackward(
+ Data.Data + index + num,
+ Data.Data + index,
+ Data.Size - num - index);
+ }
+ for (UPInt i = 0; i < num; ++i)
+ AllocatorType::Construct(Data.Data + index + i, val);
+ }
+
+ // Append the given data to the array.
+ void Append(const SelfType& other)
+ {
+ Append(other.Data.Data, other.GetSize());
+ }
+
+ // Append the given data to the array.
+ void Append(const ValueType other[], UPInt count)
+ {
+ Data.Append(other, count);
+ }
+
+ class Iterator
+ {
+ SelfType* pArray;
+ SPInt CurIndex;
+
+ public:
+ Iterator() : pArray(0), CurIndex(-1) {}
+ Iterator(SelfType* parr, SPInt idx = 0) : pArray(parr), CurIndex(idx) {}
+
+ bool operator==(const Iterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; }
+ bool operator!=(const Iterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; }
+
+ Iterator& operator++()
+ {
+ if (pArray)
+ {
+ if (CurIndex < (SPInt)pArray->GetSize())
+ ++CurIndex;
+ }
+ return *this;
+ }
+ Iterator operator++(int)
+ {
+ Iterator it(*this);
+ operator++();
+ return it;
+ }
+ Iterator& operator--()
+ {
+ if (pArray)
+ {
+ if (CurIndex >= 0)
+ --CurIndex;
+ }
+ return *this;
+ }
+ Iterator operator--(int)
+ {
+ Iterator it(*this);
+ operator--();
+ return it;
+ }
+ Iterator operator+(int delta) const
+ {
+ return Iterator(pArray, CurIndex + delta);
+ }
+ Iterator operator-(int delta) const
+ {
+ return Iterator(pArray, CurIndex - delta);
+ }
+ SPInt operator-(const Iterator& right) const
+ {
+ OVR_ASSERT(pArray == right.pArray);
+ return CurIndex - right.CurIndex;
+ }
+ ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; }
+ ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
+ ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
+
+ bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); }
+
+ void Remove()
+ {
+ if (!IsFinished())
+ pArray->RemoveAt(CurIndex);
+ }
+
+ SPInt GetIndex() const { return CurIndex; }
+ };
+
+ Iterator Begin() { return Iterator(this); }
+ Iterator End() { return Iterator(this, (SPInt)GetSize()); }
+ Iterator Last() { return Iterator(this, (SPInt)GetSize() - 1); }
+
+ class ConstIterator
+ {
+ const SelfType* pArray;
+ SPInt CurIndex;
+
+ public:
+ ConstIterator() : pArray(0), CurIndex(-1) {}
+ ConstIterator(const SelfType* parr, SPInt idx = 0) : pArray(parr), CurIndex(idx) {}
+
+ bool operator==(const ConstIterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; }
+ bool operator!=(const ConstIterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; }
+
+ ConstIterator& operator++()
+ {
+ if (pArray)
+ {
+ if (CurIndex < (int)pArray->GetSize())
+ ++CurIndex;
+ }
+ return *this;
+ }
+ ConstIterator operator++(int)
+ {
+ ConstIterator it(*this);
+ operator++();
+ return it;
+ }
+ ConstIterator& operator--()
+ {
+ if (pArray)
+ {
+ if (CurIndex >= 0)
+ --CurIndex;
+ }
+ return *this;
+ }
+ ConstIterator operator--(int)
+ {
+ ConstIterator it(*this);
+ operator--();
+ return it;
+ }
+ ConstIterator operator+(int delta) const
+ {
+ return ConstIterator(pArray, CurIndex + delta);
+ }
+ ConstIterator operator-(int delta) const
+ {
+ return ConstIterator(pArray, CurIndex - delta);
+ }
+ SPInt operator-(const ConstIterator& right) const
+ {
+ OVR_ASSERT(pArray == right.pArray);
+ return CurIndex - right.CurIndex;
+ }
+ const ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; }
+ const ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
+ const ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
+
+ bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); }
+
+ SPInt GetIndex() const { return CurIndex; }
+ };
+ ConstIterator Begin() const { return ConstIterator(this); }
+ ConstIterator End() const { return ConstIterator(this, (SPInt)GetSize()); }
+ ConstIterator Last() const { return ConstIterator(this, (SPInt)GetSize() - 1); }
+
+protected:
+ ArrayData Data;
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Array
+//
+// General purpose array for movable objects that require explicit
+// construction/destruction.
+template<class T, class SizePolicy=ArrayDefaultPolicy>
+class Array : public ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> >
+{
+public:
+ typedef T ValueType;
+ typedef ContainerAllocator<T> AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef Array<T, SizePolicy> SelfType;
+ typedef ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> > BaseType;
+
+ Array() : BaseType() {}
+ Array(int size) : BaseType(size) {}
+ Array(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
+ Array(const SelfType& a) : BaseType(a) {}
+ const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
+};
+
+// ***** ArrayPOD
+//
+// General purpose array for movable objects that DOES NOT require
+// construction/destruction. Constructors and destructors are not called!
+// Global heap is in use.
+template<class T, class SizePolicy=ArrayDefaultPolicy>
+class ArrayPOD : public ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> >
+{
+public:
+ typedef T ValueType;
+ typedef ContainerAllocator_POD<T> AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayPOD<T, SizePolicy> SelfType;
+ typedef ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> > BaseType;
+
+ ArrayPOD() : BaseType() {}
+ ArrayPOD(int size) : BaseType(size) {}
+ ArrayPOD(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
+ ArrayPOD(const SelfType& a) : BaseType(a) {}
+ const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
+};
+
+
+// ***** ArrayCPP
+//
+// General purpose, fully C++ compliant array. Can be used with non-movable data.
+// Global heap is in use.
+template<class T, class SizePolicy=ArrayDefaultPolicy>
+class ArrayCPP : public ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> >
+{
+public:
+ typedef T ValueType;
+ typedef ContainerAllocator_CPP<T> AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayCPP<T, SizePolicy> SelfType;
+ typedef ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> > BaseType;
+
+ ArrayCPP() : BaseType() {}
+ ArrayCPP(int size) : BaseType(size) {}
+ ArrayCPP(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
+ ArrayCPP(const SelfType& a) : BaseType(a) {}
+ const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
+};
+
+
+// ***** ArrayCC
+//
+// A modification of the array that uses the given default value to
+// construct the elements. The constructors and destructors are
+// properly called, the objects must be movable.
+
+template<class T, class SizePolicy=ArrayDefaultPolicy>
+class ArrayCC : public ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> >
+{
+public:
+ typedef T ValueType;
+ typedef ContainerAllocator<T> AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayCC<T, SizePolicy> SelfType;
+ typedef ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> > BaseType;
+
+ ArrayCC(const ValueType& defval) : BaseType(defval) {}
+ ArrayCC(const ValueType& defval, int size) : BaseType(defval, size) {}
+ ArrayCC(const ValueType& defval, const SizePolicyType& p) : BaseType(defval) { SetSizePolicy(p); }
+ ArrayCC(const SelfType& a) : BaseType(a) {}
+ const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Atomic.cpp b/LibOVR/Src/Kernel/OVR_Atomic.cpp new file mode 100644 index 0000000..a2f9230 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Atomic.cpp @@ -0,0 +1,82 @@ +/************************************************************************************
+
+Filename : OVR_Atomic.cpp
+Content : Contains atomic operations and inline fastest locking
+ functionality. Will contain #ifdefs for OS efficiency.
+ Have non-thread-safe implementation if not available.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Atomic.h"
+
+#ifdef OVR_ENABLE_THREADS
+
+// Include Windows 8-Metro compatible Synchronization API
+#if defined(OVR_OS_WIN32) && defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
+#include <synchapi.h>
+#endif
+
+
+namespace OVR {
+
+// ***** Windows Lock implementation
+
+#if defined(OVR_OS_WIN32)
+
+// ***** Standard Win32 Lock implementation
+
+// Constructors
+Lock::Lock(unsigned spinCount)
+{
+#if defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
+ // On Windows 8 we use InitializeCriticalSectionEx due to Metro-Compatibility
+ InitializeCriticalSectionEx(&cs, spinCount,
+ OVR_DEBUG_SELECT(NULL, CRITICAL_SECTION_NO_DEBUG_INFO));
+#else
+ // Spin count init critical section function prototype for Window NT
+ typedef BOOL (WINAPI *Function_InitializeCriticalSectionAndSpinCount)
+ (LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount);
+
+
+ // Try to load function dynamically so that we don't require NT
+ // On Windows NT we will use InitializeCriticalSectionAndSpinCount
+ static bool initTried = 0;
+ static Function_InitializeCriticalSectionAndSpinCount pInitFn = 0;
+
+ if (!initTried)
+ {
+ HMODULE hmodule = ::LoadLibrary(OVR_STR("kernel32.dll"));
+ pInitFn = (Function_InitializeCriticalSectionAndSpinCount)
+ ::GetProcAddress(hmodule, "InitializeCriticalSectionAndSpinCount");
+ initTried = true;
+ }
+
+ // Initialize the critical section
+ if (pInitFn)
+ pInitFn(&cs, spinCount);
+ else
+ ::InitializeCriticalSection(&cs);
+#endif
+
+}
+
+
+Lock::~Lock()
+{
+ DeleteCriticalSection(&cs);
+}
+
+
+#endif
+
+} // OVR
+
+#endif // OVR_ENABLE_THREADS
diff --git a/LibOVR/Src/Kernel/OVR_Atomic.h b/LibOVR/Src/Kernel/OVR_Atomic.h new file mode 100644 index 0000000..089125b --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Atomic.h @@ -0,0 +1,859 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Atomic.h
+Content : Contains atomic operations and inline fastest locking
+ functionality. Will contain #ifdefs for OS efficiency.
+ Have non-thread-safe implementaion if not available.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+#ifndef OVR_Atomic_h
+#define OVR_Atomic_h
+
+#include "OVR_Types.h"
+
+// Include System thread functionality.
+#if defined(OVR_OS_WIN32)
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+
+namespace OVR {
+
+
+// ****** Declared classes
+
+// If there is NO thread support we implement AtomicOps and
+// Lock objects as no-ops. The other classes are not defined.
+template<class C> class AtomicOps;
+template<class T> class AtomicInt;
+template<class T> class AtomicPtr;
+
+class Lock;
+
+
+//-----------------------------------------------------------------------------------
+// ***** AtomicOps
+
+// Atomic operations are provided by the AtomicOps templates class,
+// implemented through system-specific AtomicOpsRaw specializations.
+// It provides several fundamental operations such as Exchange, ExchangeAdd
+// CompareAndSet, and Store_Release. Each function includes several memory
+// synchronization versions, important for multiprocessing CPUs with weak
+// memory consistency. The following memory fencing strategies are supported:
+//
+// - NoSync. No memory synchronization is done for atomic op.
+// - Release. All other memory writes are completed before atomic op
+// writes its results.
+// - Acquire. Further memory reads are forced to wait until atomic op
+// executes, guaranteeing that the right values will be seen.
+// - Sync. A combination of Release and Acquire.
+
+
+// *** AtomicOpsRaw
+
+// AtomicOpsRaw is a specialized template that provides atomic operations
+// used by AtomicOps. This class has two fundamental qualities: (1) it
+// defines a type T of correct size, and (2) provides operations that work
+// atomically, such as Exchange_Sync and CompareAndSet_Release.
+
+// AtomicOpsRawBase class contains shared constants/classes for AtomicOpsRaw.
+// The primary thing is does is define sync class objects, whose destructor and
+// constructor provide places to insert appropriate synchronization calls, on
+// systems where such calls are necessary. So far, the breakdown is as follows:
+//
+// - X86 systems don't need custom syncs, since their exchange/atomic
+// instructions are implicitly synchronized.
+// - PowerPC requires lwsync/isync instructions that can use this mechanism.
+// - If some other systems require a mechanism where syncing type is associated
+// with a particular instruction, the default implementation (which implements
+// all Sync, Acquire, and Release modes in terms of NoSync and fence) may not
+// work. Ii that case it will need to be #ifdef-ed conditionally.
+
+struct AtomicOpsRawBase
+{
+#if !defined(OVR_ENABLE_THREADS) || defined(OVR_CPU_X86) || defined(OVR_OS_WIN32) || defined(OVR_OS_IPHONE)
+ // Need to have empty constructor to avoid class 'unused' variable warning.
+ struct FullSync { inline FullSync() { } };
+ struct AcquireSync { inline AcquireSync() { } };
+ struct ReleaseSync { inline ReleaseSync() { } };
+
+#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
+ struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("isync\n"); } };
+ struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("isync\n"); } };
+ struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
+
+#elif defined(OVR_CPU_MIPS)
+ struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("sync\n"); } };
+ struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("sync\n"); } };
+ struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
+
+#elif defined(OVR_CPU_ARM)
+ struct FullSync { inline FullSync() { asm volatile("dmb\n"); } ~FullSync() { asm volatile("dmb\n"); } };
+ struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("dmb\n"); } };
+ struct ReleaseSync { inline ReleaseSync() { asm volatile("dmb\n"); } };
+
+
+#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4)
+ // __sync functions are already full sync
+ struct FullSync { inline FullSync() { } };
+ struct AcquireSync { inline AcquireSync() { } };
+ struct ReleaseSync { inline ReleaseSync() { } };
+#endif
+};
+
+
+// 4-Byte raw data atomic op implementation class.
+struct AtomicOpsRaw_4ByteImpl : public AtomicOpsRawBase
+{
+#if !defined(OVR_ENABLE_THREADS)
+
+ // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
+ typedef UInt32 T;
+
+ // *** Thread - Safe Atomic Versions.
+
+#elif defined(OVR_OS_WIN32)
+
+ // Use special defined for VC6, where volatile is not used and
+ // InterlockedCompareExchange is declared incorrectly.
+ typedef LONG T;
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC < 1300)
+ typedef T* InterlockTPtr;
+ typedef LPVOID ET;
+ typedef ET* InterlockETPtr;
+#else
+ typedef volatile T* InterlockTPtr;
+ typedef T ET;
+ typedef InterlockTPtr InterlockETPtr;
+#endif
+ inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange((InterlockTPtr)p, val); }
+ inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd((InterlockTPtr)p, val); }
+ inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange((InterlockETPtr)p, (ET)val, (ET)c) == (ET)c; }
+
+#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
+ typedef UInt32 T;
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret;
+
+ asm volatile("1:\n\t"
+ "lwarx %[r],0,%[i]\n\t"
+ "stwcx. %[j],0,%[i]\n\t"
+ "bne- 1b\n"
+ : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 dummy, ret;
+
+ asm volatile("1:\n\t"
+ "lwarx %[r],0,%[i]\n\t"
+ "add %[o],%[r],%[j]\n\t"
+ "stwcx. %[o],0,%[i]\n\t"
+ "bne- 1b\n"
+ : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ UInt32 ret;
+
+ asm volatile("1:\n\t"
+ "lwarx %[r],0,%[i]\n\t"
+ "cmpw 0,%[r],%[cmp]\n\t"
+ "mfcr %[r]\n\t"
+ "bne- 2f\n\t"
+ "stwcx. %[val],0,%[i]\n\t"
+ "bne- 1b\n\t"
+ "2:\n"
+ : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc", "memory");
+
+ return (ret & 0x20000000) ? 1 : 0;
+ }
+
+#elif defined(OVR_CPU_MIPS)
+ typedef UInt32 T;
+
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret;
+
+ asm volatile("1:\n\t"
+ "ll %[r],0(%[i])\n\t"
+ "sc %[j],0(%[i])\n\t"
+ "beq %[j],$0,1b\n\t"
+ "nop \n"
+ : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret;
+
+ asm volatile("1:\n\t"
+ "ll %[r],0(%[i])\n\t"
+ "addu %[j],%[r],%[j]\n\t"
+ "sc %[j],0(%[i])\n\t"
+ "beq %[j],$0,1b\n\t"
+ "nop \n"
+ : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ UInt32 ret, dummy;
+
+ asm volatile("1:\n\t"
+ "move %[r],$0\n\t"
+ "ll %[o],0(%[i])\n\t"
+ "bne %[o],%[c],2f\n\t"
+ "move %[r],%[v]\n\t"
+ "sc %[r],0(%[i])\n\t"
+ "beq %[r],$0,1b\n\t"
+ "nop \n\t"
+ "2:\n"
+ : "+m" (*i),[r] "=&d" (ret), [o] "=&d" (dummy) : [i] "d" (i), [c] "d" (c), [v] "d" (value)
+ : "cc", "memory");
+
+ return ret;
+ }
+
+#elif defined(OVR_CPU_ARM) && defined(OVR_CC_ARM)
+ typedef UInt32 T;
+
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ for(;;)
+ {
+ T r = __ldrex(i);
+ if (__strex(j, i) == 0)
+ return r;
+ }
+ }
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ for(;;)
+ {
+ T r = __ldrex(i);
+ if (__strex(r + j, i) == 0)
+ return r;
+ }
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ for(;;)
+ {
+ T r = __ldrex(i);
+ if (r != c)
+ return 0;
+ if (__strex(value, i) == 0)
+ return 1;
+ }
+ }
+
+#elif defined(OVR_CPU_ARM)
+ typedef UInt32 T;
+
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret, dummy;
+
+ asm volatile("1:\n\t"
+ "ldrex %[r],[%[i]]\n\t"
+ "strex %[t],%[j],[%[i]]\n\t"
+ "cmp %[t],#0\n\t"
+ "bne 1b\n\t"
+ : "+m" (*i), [r] "=&r" (ret), [t] "=&r" (dummy) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret, dummy, test;
+
+ asm volatile("1:\n\t"
+ "ldrex %[r],[%[i]]\n\t"
+ "add %[o],%[r],%[j]\n\t"
+ "strex %[t],%[o],[%[i]]\n\t"
+ "cmp %[t],#0\n\t"
+ "bne 1b\n\t"
+ : "+m" (*i), [r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ UInt32 ret = 1, dummy, test;
+
+ asm volatile("1:\n\t"
+ "ldrex %[o],[%[i]]\n\t"
+ "cmp %[o],%[c]\n\t"
+ "bne 2f\n\t"
+ "strex %[r],%[v],[%[i]]\n\t"
+ "cmp %[r],#0\n\t"
+ "bne 1b\n\t"
+ "2:\n"
+ : "+m" (*i),[r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [c] "r" (c), [v] "r" (value)
+ : "cc", "memory");
+
+ return !ret;
+ }
+
+#elif defined(OVR_CPU_X86)
+ typedef UInt32 T;
+
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ asm volatile("xchgl %1,%[i]\n"
+ : "+m" (*i), "=q" (j) : [i] "m" (*i), "1" (j) : "cc", "memory");
+
+ return j;
+ }
+
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ asm volatile("lock; xaddl %1,%[i]\n"
+ : "+m" (*i), "+q" (j) : [i] "m" (*i) : "cc", "memory");
+
+ return j;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ UInt32 ret;
+
+ asm volatile("lock; cmpxchgl %[v],%[i]\n"
+ : "+m" (*i), "=a" (ret) : [i] "m" (*i), "1" (c), [v] "q" (value) : "cc", "memory");
+
+ return (ret == c);
+ }
+
+#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
+
+ typedef UInt32 T;
+
+ static inline T Exchange_NoSync(volatile T *i, T j)
+ {
+ T v;
+ do {
+ v = *i;
+ } while (!__sync_bool_compare_and_swap(i, v, j));
+ return v;
+ }
+
+ static inline T ExchangeAdd_NoSync(volatile T *i, T j)
+ {
+ return __sync_fetch_and_add(i, j);
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
+ {
+ return __sync_bool_compare_and_swap(i, c, value);
+ }
+
+#endif // OS
+};
+
+
+// 8-Byte raw data data atomic op implementation class.
+// Currently implementation is provided only on systems with 64-bit pointers.
+struct AtomicOpsRaw_8ByteImpl : public AtomicOpsRawBase
+{
+#if !defined(OVR_64BIT_POINTERS) || !defined(OVR_ENABLE_THREADS)
+
+ // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
+ typedef UInt64 T;
+
+ // *** Thread - Safe OS specific versions.
+#elif defined(OVR_OS_WIN32)
+
+ // This is only for 64-bit systems.
+ typedef LONG64 T;
+ typedef volatile T* InterlockTPtr;
+ inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange64((InterlockTPtr)p, val); }
+ inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd64((InterlockTPtr)p, val); }
+ inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange64((InterlockTPtr)p, val, c) == c; }
+
+#elif defined(OVR_CPU_PPC64)
+
+ typedef UInt64 T;
+
+ static inline UInt64 Exchange_NoSync(volatile UInt64 *i, UInt64 j)
+ {
+ UInt64 dummy, ret;
+
+ asm volatile("1:\n\t"
+ "ldarx %[r],0,%[i]\n\t"
+ "mr %[o],%[j]\n\t"
+ "stdcx. %[o],0,%[i]\n\t"
+ "bne- 1b\n"
+ : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
+
+ return ret;
+ }
+
+ static inline UInt64 ExchangeAdd_NoSync(volatile UInt64 *i, UInt64 j)
+ {
+ UInt64 dummy, ret;
+
+ asm volatile("1:\n\t"
+ "ldarx %[r],0,%[i]\n\t"
+ "add %[o],%[r],%[j]\n\t"
+ "stdcx. %[o],0,%[i]\n\t"
+ "bne- 1b\n"
+ : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
+
+ return ret;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt64 *i, UInt64 c, UInt64 value)
+ {
+ UInt64 ret, dummy;
+
+ asm volatile("1:\n\t"
+ "ldarx %[r],0,%[i]\n\t"
+ "cmpw 0,%[r],%[cmp]\n\t"
+ "mfcr %[r]\n\t"
+ "bne- 2f\n\t"
+ "stdcx. %[val],0,%[i]\n\t"
+ "bne- 1b\n\t"
+ "2:\n"
+ : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc");
+
+ return (ret & 0x20000000) ? 1 : 0;
+ }
+
+#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
+
+ typedef UInt64 T;
+
+ static inline T Exchange_NoSync(volatile T *i, T j)
+ {
+ T v;
+ do {
+ v = *i;
+ } while (!__sync_bool_compare_and_swap(i, v, j));
+ return v;
+ }
+
+ static inline T ExchangeAdd_NoSync(volatile T *i, T j)
+ {
+ return __sync_fetch_and_add(i, j);
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
+ {
+ return __sync_bool_compare_and_swap(i, c, value);
+ }
+
+#endif // OS
+};
+
+
+// Default implementation for AtomicOpsRaw; provides implementation of mem-fenced
+// atomic operations where fencing is done with a sync object wrapped around a NoSync
+// operation implemented in the base class. If such implementation is not possible
+// on a given platform, #ifdefs can be used to disable it and then op functions can be
+// implemented individually in the appropriate AtomicOpsRaw<size> class.
+
+template<class O>
+struct AtomicOpsRaw_DefImpl : public O
+{
+ typedef typename O::T O_T;
+ typedef typename O::FullSync O_FullSync;
+ typedef typename O::AcquireSync O_AcquireSync;
+ typedef typename O::ReleaseSync O_ReleaseSync;
+
+ // If there is no thread support, provide the default implementation. In this case,
+ // the base class (0) must still provide the T declaration.
+#ifndef OVR_ENABLE_THREADS
+
+ // Atomic exchange of val with argument. Returns old val.
+ inline static O_T Exchange_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p = val; return old; }
+ // Adds a new val to argument; returns its old val.
+ inline static O_T ExchangeAdd_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p += val; return old; }
+ // Compares the argument data with 'c' val.
+ // If succeeded, stores val int '*p' and returns true; otherwise returns false.
+ inline static bool CompareAndSet_NoSync(volatile O_T* p, O_T c, O_T val) { if (*p==c) { *p = val; return 1; } return 0; }
+
+#endif
+
+ // If NoSync wrapped implementation may not be possible, it this block should be
+ // replaced with per-function implementation in O.
+ // "AtomicOpsRaw_DefImpl<O>::" prefix in calls below.
+ inline static O_T Exchange_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
+ inline static O_T Exchange_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
+ inline static O_T Exchange_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
+ inline static O_T ExchangeAdd_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
+ inline static O_T ExchangeAdd_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
+ inline static O_T ExchangeAdd_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
+ inline static bool CompareAndSet_Sync(volatile O_T* p, O_T c, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
+ inline static bool CompareAndSet_Release(volatile O_T* p, O_T c, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
+ inline static bool CompareAndSet_Acquire(volatile O_T* p, O_T c, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
+
+ // Loads and stores with memory fence. These have only the relevant versions.
+#ifdef OVR_CPU_X86
+ // On X86, Store_Release is implemented as exchange. Note that we can also
+ // consider 'sfence' in the future, although it is not as compatible with older CPUs.
+ inline static void Store_Release(volatile O_T* p, O_T val) { Exchange_Release(p, val); }
+#else
+ inline static void Store_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); *p = val; }
+#endif
+ inline static O_T Load_Acquire(const volatile O_T* p) { O_AcquireSync sync; OVR_UNUSED(sync); return *p; }
+};
+
+
+template<int size>
+struct AtomicOpsRaw : public AtomicOpsRawBase { };
+
+template<>
+struct AtomicOpsRaw<4> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>
+{
+ // Ensure that assigned type size is correct.
+ AtomicOpsRaw()
+ { OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>::T) == 4); }
+};
+template<>
+struct AtomicOpsRaw<8> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>
+{
+ AtomicOpsRaw()
+ { OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>::T) == 8); }
+};
+
+
+// *** AtomicOps - implementation of atomic Ops for specified class
+
+// Implements atomic ops on a class, provided that the object is either
+// 4 or 8 bytes in size (depending on the AtomicOpsRaw specializations
+// available). Relies on AtomicOpsRaw for much of implementation.
+
+template<class C>
+class AtomicOps
+{
+ typedef AtomicOpsRaw<sizeof(C)> Ops;
+ typedef typename Ops::T T;
+ typedef volatile typename Ops::T* PT;
+ // We cast through unions to (1) avoid pointer size compiler warnings
+ // and (2) ensure that there are no problems with strict pointer aliasing.
+ union C2T_union { C c; T t; };
+
+public:
+ // General purpose implementation for standard syncs.
+ inline static C Exchange_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Sync((PT)p, u.t); return u.c; }
+ inline static C Exchange_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Release((PT)p, u.t); return u.c; }
+ inline static C Exchange_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Acquire((PT)p, u.t); return u.c; }
+ inline static C Exchange_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_NoSync((PT)p, u.t); return u.c; }
+ inline static C ExchangeAdd_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Sync((PT)p, u.t); return u.c; }
+ inline static C ExchangeAdd_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Release((PT)p, u.t); return u.c; }
+ inline static C ExchangeAdd_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Acquire((PT)p, u.t); return u.c; }
+ inline static C ExchangeAdd_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_NoSync((PT)p, u.t); return u.c; }
+ inline static bool CompareAndSet_Sync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Sync((PT)p, cu.t, u.t); }
+ inline static bool CompareAndSet_Release(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Release((PT)p, cu.t, u.t); }
+ inline static bool CompareAndSet_Relse(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Acquire((PT)p, cu.t, u.t); }
+ inline static bool CompareAndSet_NoSync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_NoSync((PT)p, cu.t, u.t); }
+ // Loads and stores with memory fence. These have only the relevant versions.
+ inline static void Store_Release(volatile C* p, C val) { C2T_union u; u.c = val; Ops::Store_Release((PT)p, u.t); }
+ inline static C Load_Acquire(const volatile C* p) { C2T_union u; u.t = Ops::Load_Acquire((PT)p); return u.c; }
+};
+
+
+
+// Atomic value base class - implements operations shared for integers and pointers.
+template<class T>
+class AtomicValueBase
+{
+protected:
+ typedef AtomicOps<T> Ops;
+public:
+
+ volatile T Value;
+
+ inline AtomicValueBase() { }
+ explicit inline AtomicValueBase(T val) { Ops::Store_Release(&Value, val); }
+
+ // Most libraries (TBB and Joshua Scholar's) library do not do Load_Acquire
+ // here, since most algorithms do not require atomic loads. Needs some research.
+ inline operator T() const { return Value; }
+
+ // *** Standard Atomic inlines
+ inline T Exchange_Sync(T val) { return Ops::Exchange_Sync(&Value, val); }
+ inline T Exchange_Release(T val) { return Ops::Exchange_Release(&Value, val); }
+ inline T Exchange_Acquire(T val) { return Ops::Exchange_Acquire(&Value, val); }
+ inline T Exchange_NoSync(T val) { return Ops::Exchange_NoSync(&Value, val); }
+ inline bool CompareAndSet_Sync(T c, T val) { return Ops::CompareAndSet_Sync(&Value, c, val); }
+ inline bool CompareAndSet_Release(T c, T val) { return Ops::CompareAndSet_Release(&Value, c, val); }
+ inline bool CompareAndSet_Acquire(T c, T val) { return Ops::CompareAndSet_Relse(&Value, c, val); }
+ inline bool CompareAndSet_NoSync(T c, T val) { return Ops::CompareAndSet_NoSync(&Value, c, val); }
+ // Load & Store.
+ inline void Store_Release(T val) { Ops::Store_Release(&Value, val); }
+ inline T Load_Acquire() const { return Ops::Load_Acquire(&Value); }
+};
+
+
+// ***** AtomicPtr - Atomic pointer template
+
+// This pointer class supports atomic assignments with release,
+// increment / decrement operations, and conditional compare + set.
+
+template<class T>
+class AtomicPtr : public AtomicValueBase<T*>
+{
+ typedef typename AtomicValueBase<T*>::Ops Ops;
+
+public:
+ // Initialize pointer value to 0 by default; use Store_Release only with explicit constructor.
+ inline AtomicPtr() : AtomicValueBase<T*>() { this->Value = 0; }
+ explicit inline AtomicPtr(T* val) : AtomicValueBase<T*>(val) { }
+
+ // Pointer access.
+ inline T* operator -> () const { return this->Load_Acquire(); }
+
+ // It looks like it is convenient to have Load_Acquire characteristics
+ // for this, since that is convenient for algorithms such as linked
+ // list traversals that can be added to bu another thread.
+ inline operator T* () const { return this->Load_Acquire(); }
+
+
+ // *** Standard Atomic inlines (applicable to pointers)
+
+ // ExhangeAdd considers pointer size for pointers.
+ template<class I>
+ inline T* ExchangeAdd_Sync(I incr) { return Ops::ExchangeAdd_Sync(&this->Value, ((T*)0) + incr); }
+ template<class I>
+ inline T* ExchangeAdd_Release(I incr) { return Ops::ExchangeAdd_Release(&this->Value, ((T*)0) + incr); }
+ template<class I>
+ inline T* ExchangeAdd_Acquire(I incr) { return Ops::ExchangeAdd_Acquire(&this->Value, ((T*)0) + incr); }
+ template<class I>
+ inline T* ExchangeAdd_NoSync(I incr) { return Ops::ExchangeAdd_NoSync(&this->Value, ((T*)0) + incr); }
+
+ // *** Atomic Operators
+
+ inline T* operator = (T* val) { this->Store_Release(val); return val; }
+
+ template<class I>
+ inline T* operator += (I val) { return ExchangeAdd_Sync(val) + val; }
+ template<class I>
+ inline T* operator -= (I val) { return operator += (-val); }
+
+ inline T* operator ++ () { return ExchangeAdd_Sync(1) + 1; }
+ inline T* operator -- () { return ExchangeAdd_Sync(-1) - 1; }
+ inline T* operator ++ (int) { return ExchangeAdd_Sync(1); }
+ inline T* operator -- (int) { return ExchangeAdd_Sync(-1); }
+};
+
+
+// ***** AtomicInt - Atomic integer template
+
+// Implements an atomic integer type; the exact type to use is provided
+// as an argument. Supports atomic Acquire / Release semantics, atomic
+// arithmetic operations, and atomic conditional compare + set.
+
+template<class T>
+class AtomicInt : public AtomicValueBase<T>
+{
+ typedef typename AtomicValueBase<T>::Ops Ops;
+
+public:
+ inline AtomicInt() : AtomicValueBase<T>() { }
+ explicit inline AtomicInt(T val) : AtomicValueBase<T>(val) { }
+
+
+ // *** Standard Atomic inlines (applicable to int)
+ inline T ExchangeAdd_Sync(T val) { return Ops::ExchangeAdd_Sync(&this->Value, val); }
+ inline T ExchangeAdd_Release(T val) { return Ops::ExchangeAdd_Release(&this->Value, val); }
+ inline T ExchangeAdd_Acquire(T val) { return Ops::ExchangeAdd_Acquire(&this->Value, val); }
+ inline T ExchangeAdd_NoSync(T val) { return Ops::ExchangeAdd_NoSync(&this->Value, val); }
+ // These increments could be more efficient because they don't return a value.
+ inline void Increment_Sync() { ExchangeAdd_Sync((T)1); }
+ inline void Increment_Release() { ExchangeAdd_Release((T)1); }
+ inline void Increment_Acquire() { ExchangeAdd_Acquire((T)1); }
+ inline void Increment_NoSync() { ExchangeAdd_NoSync((T)1); }
+
+ // *** Atomic Operators
+
+ inline T operator = (T val) { this->Store_Release(val); return val; }
+ inline T operator += (T val) { return ExchangeAdd_Sync(val) + val; }
+ inline T operator -= (T val) { return ExchangeAdd_Sync(0 - val) - val; }
+
+ inline T operator ++ () { return ExchangeAdd_Sync((T)1) + 1; }
+ inline T operator -- () { return ExchangeAdd_Sync(((T)0)-1) - 1; }
+ inline T operator ++ (int) { return ExchangeAdd_Sync((T)1); }
+ inline T operator -- (int) { return ExchangeAdd_Sync(((T)0)-1); }
+
+ // More complex atomic operations. Leave it to compiler whether to optimize them or not.
+ T operator &= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp & arg;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator |= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp | arg;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator ^= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp ^ arg;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator *= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp * arg;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator /= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp / arg;
+ } while(!CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator >>= (unsigned bits)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp >> bits;
+ } while(!CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator <<= (unsigned bits)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp << bits;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Lock
+
+// Lock is a simplest and most efficient mutual-exclusion lock class.
+// Unlike Mutex, it cannot be waited on.
+
+class Lock
+{
+ // NOTE: Locks are not allocatable and they themselves should not allocate
+ // memory by standard means. This is the case because StandardAllocator
+ // relies on this class.
+ // Make 'delete' private. Don't do this for 'new' since it can be redefined.
+ void operator delete(void*) {}
+
+
+ // *** Lock implementation for various platforms.
+
+#if !defined(OVR_ENABLE_THREADS)
+
+public:
+ // With no thread support, lock does nothing.
+ inline Lock() { }
+ inline Lock(unsigned) { }
+ inline ~Lock() { }
+ inline void DoLock() { }
+ inline void Unlock() { }
+
+ // Windows.
+#elif defined(OVR_OS_WIN32)
+
+ CRITICAL_SECTION cs;
+public:
+ Lock(unsigned spinCount = 0);
+ ~Lock();
+ // Locking functions.
+ inline void DoLock() { ::EnterCriticalSection(&cs); }
+ inline void Unlock() { ::LeaveCriticalSection(&cs); }
+
+#else
+ pthread_mutex_t mutex;
+
+public:
+ static pthread_mutexattr_t RecursiveAttr;
+ static bool RecursiveAttrInit;
+
+ Lock (unsigned dummy = 0)
+ {
+ if (!RecursiveAttrInit)
+ {
+ pthread_mutexattr_init(&RecursiveAttr);
+ pthread_mutexattr_settype(&RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
+ RecursiveAttrInit = 1;
+ }
+ pthread_mutex_init(&mutex,&RecursiveAttr);
+ }
+ ~Lock () { pthread_mutex_destroy(&mutex); }
+ inline void DoLock() { pthread_mutex_lock(&mutex); }
+ inline void Unlock() { pthread_mutex_unlock(&mutex); }
+
+#endif // OVR_ENABLE_THREDS
+
+
+public:
+ // Locker class, used for automatic locking
+ class Locker
+ {
+ public:
+ Lock *pLock;
+ inline Locker(Lock *plock)
+ { pLock = plock; pLock->DoLock(); }
+ inline ~Locker()
+ { pLock->Unlock(); }
+ };
+};
+
+
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Color.h b/LibOVR/Src/Kernel/OVR_Color.h new file mode 100644 index 0000000..7980d57 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Color.h @@ -0,0 +1,55 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Color.h
+Content : Contains color struct.
+Created : February 7, 2013
+Notes :
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+#ifndef OVR_Color_h
+#define OVR_Color_h
+
+#include "OVR_Types.h"
+
+namespace OVR {
+
+struct Color
+{
+ UByte R,G,B,A;
+
+ Color() {}
+
+ // Constructs color by channel. Alpha is set to 0xFF (fully visible)
+ // if not specified.
+ Color(unsigned char r,unsigned char g,unsigned char b, unsigned char a = 0xFF)
+ : R(r), G(g), B(b), A(a) { }
+
+ // 0xAARRGGBB - Common HTML color Hex layout
+ Color(unsigned c)
+ : R((unsigned char)(c>>16)), G((unsigned char)(c>>8)),
+ B((unsigned char)c), A((unsigned char)(c>>24)) { }
+
+ bool operator==(const Color& b) const
+ {
+ return R == b.R && G == b.G && B == b.B && A == b.A;
+ }
+
+ void GetRGBA(float *r, float *g, float *b, float* a) const
+ {
+ *r = R / 255.0f;
+ *g = G / 255.0f;
+ *b = B / 255.0f;
+ *a = A / 255.0f;
+ }
+};
+
+}
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_ContainerAllocator.h b/LibOVR/Src/Kernel/OVR_ContainerAllocator.h new file mode 100644 index 0000000..d2adf49 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_ContainerAllocator.h @@ -0,0 +1,256 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_ContainerAllocator.h
+Content : Template allocators and constructors for containers.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_ContainerAllocator_h
+#define OVR_ContainerAllocator_h
+
+#include "OVR_Allocator.h"
+#include <string.h>
+
+
+namespace OVR {
+
+
+//-----------------------------------------------------------------------------------
+// ***** Container Allocator
+
+// ContainerAllocator serves as a template argument for allocations done by
+// containers, such as Array and Hash; replacing it could allow allocator
+// substitution in containers.
+
+class ContainerAllocatorBase
+{
+public:
+ static void* Alloc(UPInt size) { return OVR_ALLOC(size); }
+ static void* Realloc(void* p, UPInt newSize) { return OVR_REALLOC(p, newSize); }
+ static void Free(void *p) { OVR_FREE(p); }
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Constructors, Destructors, Copiers
+
+// Plain Old Data - movable, no special constructors/destructor.
+template<class T>
+class ConstructorPOD
+{
+public:
+ static void Construct(void *) {}
+ static void Construct(void *p, const T& source)
+ {
+ *(T*)p = source;
+ }
+
+ // Same as above, but allows for a different type of constructor.
+ template <class S>
+ static void ConstructAlt(void *p, const S& source)
+ {
+ *(T*)p = source;
+ }
+
+ static void ConstructArray(void*, UPInt) {}
+
+ static void ConstructArray(void* p, UPInt count, const T& source)
+ {
+ UByte *pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ *(T*)pdata = source;
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T* psource)
+ {
+ memcpy(p, psource, sizeof(T) * count);
+ }
+
+ static void Destruct(T*) {}
+ static void DestructArray(T*, UPInt) {}
+
+ static void CopyArrayForward(T* dst, const T* src, UPInt count)
+ {
+ memmove(dst, src, count * sizeof(T));
+ }
+
+ static void CopyArrayBackward(T* dst, const T* src, UPInt count)
+ {
+ memmove(dst, src, count * sizeof(T));
+ }
+
+ static bool IsMovable() { return true; }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** ConstructorMov
+//
+// Correct C++ construction and destruction for movable objects
+template<class T>
+class ConstructorMov
+{
+public:
+ static void Construct(void* p)
+ {
+ OVR::Construct<T>(p);
+ }
+
+ static void Construct(void* p, const T& source)
+ {
+ OVR::Construct<T>(p, source);
+ }
+
+ // Same as above, but allows for a different type of constructor.
+ template <class S>
+ static void ConstructAlt(void* p, const S& source)
+ {
+ OVR::ConstructAlt<T,S>(p, source);
+ }
+
+ static void ConstructArray(void* p, UPInt count)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata);
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T& source)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata, source);
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T* psource)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata, *psource++);
+ }
+
+ static void Destruct(T* p)
+ {
+ p->~T();
+ OVR_UNUSED(p); // Suppress silly MSVC warning
+ }
+
+ static void DestructArray(T* p, UPInt count)
+ {
+ p += count - 1;
+ for (UPInt i=0; i<count; ++i, --p)
+ p->~T();
+ }
+
+ static void CopyArrayForward(T* dst, const T* src, UPInt count)
+ {
+ memmove(dst, src, count * sizeof(T));
+ }
+
+ static void CopyArrayBackward(T* dst, const T* src, UPInt count)
+ {
+ memmove(dst, src, count * sizeof(T));
+ }
+
+ static bool IsMovable() { return true; }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** ConstructorCPP
+//
+// Correct C++ construction and destruction for movable objects
+template<class T>
+class ConstructorCPP
+{
+public:
+ static void Construct(void* p)
+ {
+ OVR::Construct<T>(p);
+ }
+
+ static void Construct(void* p, const T& source)
+ {
+ OVR::Construct<T>(p, source);
+ }
+
+ // Same as above, but allows for a different type of constructor.
+ template <class S>
+ static void ConstructAlt(void* p, const S& source)
+ {
+ OVR::ConstructAlt<T,S>(p, source);
+ }
+
+ static void ConstructArray(void* p, UPInt count)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata);
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T& source)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata, source);
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T* psource)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata, *psource++);
+ }
+
+ static void Destruct(T* p)
+ {
+ p->~T();
+ OVR_UNUSED(p); // Suppress silly MSVC warning
+ }
+
+ static void DestructArray(T* p, UPInt count)
+ {
+ p += count - 1;
+ for (UPInt i=0; i<count; ++i, --p)
+ p->~T();
+ }
+
+ static void CopyArrayForward(T* dst, const T* src, UPInt count)
+ {
+ for(UPInt i = 0; i < count; ++i)
+ dst[i] = src[i];
+ }
+
+ static void CopyArrayBackward(T* dst, const T* src, UPInt count)
+ {
+ for(UPInt i = count; i; --i)
+ dst[i-1] = src[i-1];
+ }
+
+ static bool IsMovable() { return false; }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Container Allocator with movement policy
+//
+// Simple wraps as specialized allocators
+template<class T> struct ContainerAllocator_POD : ContainerAllocatorBase, ConstructorPOD<T> {};
+template<class T> struct ContainerAllocator : ContainerAllocatorBase, ConstructorMov<T> {};
+template<class T> struct ContainerAllocator_CPP : ContainerAllocatorBase, ConstructorCPP<T> {};
+
+
+} // OVR
+
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_File.cpp b/LibOVR/Src/Kernel/OVR_File.cpp new file mode 100644 index 0000000..7620e37 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_File.cpp @@ -0,0 +1,571 @@ +/**************************************************************************
+
+Filename : OVR_File.cpp
+Content : File wrapper class implementation (Win32)
+
+Created : April 5, 1999
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+**************************************************************************/
+
+#define GFILE_CXX
+
+// Standard C library (Captain Obvious guarantees!)
+#include <stdio.h>
+
+#include "OVR_File.h"
+
+namespace OVR {
+
+// Buffered file adds buffering to an existing file
+// FILEBUFFER_SIZE defines the size of internal buffer, while
+// FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer
+#define FILEBUFFER_SIZE (8192-8)
+#define FILEBUFFER_TOLERANCE 4096
+
+// ** Constructor/Destructor
+
+// Hidden constructor
+// Not supposed to be used
+BufferedFile::BufferedFile() : DelegatedFile(0)
+{
+ pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
+ BufferMode = NoBuffer;
+ FilePos = 0;
+ Pos = 0;
+ DataSize = 0;
+}
+
+// Takes another file as source
+BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile)
+{
+ pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
+ BufferMode = NoBuffer;
+ FilePos = pfile->LTell();
+ Pos = 0;
+ DataSize = 0;
+}
+
+
+// Destructor
+BufferedFile::~BufferedFile()
+{
+ // Flush in case there's data
+ if (pFile)
+ FlushBuffer();
+ // Get rid of buffer
+ if (pBuffer)
+ OVR_FREE(pBuffer);
+}
+
+/*
+bool BufferedFile::VCopy(const Object &source)
+{
+ if (!DelegatedFile::VCopy(source))
+ return 0;
+
+ // Data members
+ BufferedFile *psource = (BufferedFile*)&source;
+
+ // Buffer & the mode it's in
+ pBuffer = psource->pBuffer;
+ BufferMode = psource->BufferMode;
+ Pos = psource->Pos;
+ DataSize = psource->DataSize;
+ return 1;
+}
+*/
+
+// Initializes buffering to a certain mode
+bool BufferedFile::SetBufferMode(BufferModeType mode)
+{
+ if (!pBuffer)
+ return false;
+ if (mode == BufferMode)
+ return true;
+
+ FlushBuffer();
+
+ // Can't set write mode if we can't write
+ if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) )
+ return 0;
+
+ // And SetMode
+ BufferMode = mode;
+ Pos = 0;
+ DataSize = 0;
+ return 1;
+}
+
+// Flushes buffer
+void BufferedFile::FlushBuffer()
+{
+ switch(BufferMode)
+ {
+ case WriteBuffer:
+ // Write data in buffer
+ FilePos += pFile->Write(pBuffer,Pos);
+ Pos = 0;
+ break;
+
+ case ReadBuffer:
+ // Seek back & reset buffer data
+ if ((DataSize-Pos)>0)
+ FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur);
+ DataSize = 0;
+ Pos = 0;
+ break;
+ default:
+ // not handled!
+ break;
+ }
+}
+
+// Reloads data for ReadBuffer
+void BufferedFile::LoadBuffer()
+{
+ if (BufferMode == ReadBuffer)
+ {
+ // We should only reload once all of pre-loaded buffer is consumed.
+ OVR_ASSERT(Pos == DataSize);
+
+ // WARNING: Right now LoadBuffer() assumes the buffer's empty
+ int sz = pFile->Read(pBuffer,FILEBUFFER_SIZE);
+ DataSize = sz<0 ? 0 : (unsigned)sz;
+ Pos = 0;
+ FilePos += DataSize;
+ }
+}
+
+
+// ** Overridden functions
+
+// We override all the functions that can possibly
+// require buffer mode switch, flush, or extra calculations
+
+// Tell() requires buffer adjustment
+int BufferedFile::Tell()
+{
+ if (BufferMode == ReadBuffer)
+ return int (FilePos - DataSize + Pos);
+
+ int pos = pFile->Tell();
+ // Adjust position based on buffer mode & data
+ if (pos!=-1)
+ {
+ OVR_ASSERT(BufferMode != ReadBuffer);
+ if (BufferMode == WriteBuffer)
+ pos += Pos;
+ }
+ return pos;
+}
+
+SInt64 BufferedFile::LTell()
+{
+ if (BufferMode == ReadBuffer)
+ return FilePos - DataSize + Pos;
+
+ SInt64 pos = pFile->LTell();
+ if (pos!=-1)
+ {
+ OVR_ASSERT(BufferMode != ReadBuffer);
+ if (BufferMode == WriteBuffer)
+ pos += Pos;
+ }
+ return pos;
+}
+
+int BufferedFile::GetLength()
+{
+ int len = pFile->GetLength();
+ // If writing through buffer, file length may actually be bigger
+ if ((len!=-1) && (BufferMode==WriteBuffer))
+ {
+ int currPos = pFile->Tell() + Pos;
+ if (currPos>len)
+ len = currPos;
+ }
+ return len;
+}
+SInt64 BufferedFile::LGetLength()
+{
+ SInt64 len = pFile->LGetLength();
+ // If writing through buffer, file length may actually be bigger
+ if ((len!=-1) && (BufferMode==WriteBuffer))
+ {
+ SInt64 currPos = pFile->LTell() + Pos;
+ if (currPos>len)
+ len = currPos;
+ }
+ return len;
+}
+
+/*
+bool BufferedFile::Stat(FileStats *pfs)
+{
+ // Have to fix up length is stat
+ if (pFile->Stat(pfs))
+ {
+ if (BufferMode==WriteBuffer)
+ {
+ SInt64 currPos = pFile->LTell() + Pos;
+ if (currPos > pfs->Size)
+ {
+ pfs->Size = currPos;
+ // ??
+ pfs->Blocks = (pfs->Size+511) >> 9;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+*/
+
+int BufferedFile::Write(const UByte *psourceBuffer, int numBytes)
+{
+ if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer))
+ {
+ // If not data space in buffer, flush
+ if ((FILEBUFFER_SIZE-(int)Pos)<numBytes)
+ {
+ FlushBuffer();
+ // If bigger then tolerance, just write directly
+ if (numBytes>FILEBUFFER_TOLERANCE)
+ {
+ int sz = pFile->Write(psourceBuffer,numBytes);
+ if (sz > 0)
+ FilePos += sz;
+ return sz;
+ }
+ }
+
+ // Enough space in buffer.. so copy to it
+ memcpy(pBuffer+Pos, psourceBuffer, numBytes);
+ Pos += numBytes;
+ return numBytes;
+ }
+ int sz = pFile->Write(psourceBuffer,numBytes);
+ if (sz > 0)
+ FilePos += sz;
+ return sz;
+}
+
+int BufferedFile::Read(UByte *pdestBuffer, int numBytes)
+{
+ if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer))
+ {
+ // Data in buffer... copy it
+ if ((int)(DataSize-Pos) >= numBytes)
+ {
+ memcpy(pdestBuffer, pBuffer+Pos, numBytes);
+ Pos += numBytes;
+ return numBytes;
+ }
+
+ // Not enough data in buffer, copy buffer
+ int readBytes = DataSize-Pos;
+ memcpy(pdestBuffer, pBuffer+Pos, readBytes);
+ numBytes -= readBytes;
+ pdestBuffer += readBytes;
+ Pos = DataSize;
+
+ // Don't reload buffer if more then tolerance
+ // (No major advantage, and we don't want to write a loop)
+ if (numBytes>FILEBUFFER_TOLERANCE)
+ {
+ numBytes = pFile->Read(pdestBuffer,numBytes);
+ if (numBytes > 0)
+ {
+ FilePos += numBytes;
+ Pos = DataSize = 0;
+ }
+ return readBytes + ((numBytes==-1) ? 0 : numBytes);
+ }
+
+ // Reload the buffer
+ // WARNING: Right now LoadBuffer() assumes the buffer's empty
+ LoadBuffer();
+ if ((int)(DataSize-Pos) < numBytes)
+ numBytes = (int)DataSize-Pos;
+
+ memcpy(pdestBuffer, pBuffer+Pos, numBytes);
+ Pos += numBytes;
+ return numBytes + readBytes;
+
+ /*
+ // Alternative Read implementation. The one above is probably better
+ // due to FILEBUFFER_TOLERANCE.
+ int total = 0;
+
+ do {
+ int bufferBytes = (int)(DataSize-Pos);
+ int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes;
+
+ memcpy(pdestBuffer, pBuffer+Pos, copyBytes);
+ numBytes -= copyBytes;
+ pdestBuffer += copyBytes;
+ Pos += copyBytes;
+ total += copyBytes;
+
+ if (numBytes == 0)
+ break;
+ LoadBuffer();
+
+ } while (DataSize > 0);
+
+ return total;
+ */
+ }
+ int sz = pFile->Read(pdestBuffer,numBytes);
+ if (sz > 0)
+ FilePos += sz;
+ return sz;
+}
+
+
+int BufferedFile::SkipBytes(int numBytes)
+{
+ int skippedBytes = 0;
+
+ // Special case for skipping a little data in read buffer
+ if (BufferMode==ReadBuffer)
+ {
+ skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos);
+ Pos += skippedBytes;
+ numBytes -= skippedBytes;
+ }
+
+ if (numBytes)
+ {
+ numBytes = pFile->SkipBytes(numBytes);
+ // Make sure we return the actual number skipped, or error
+ if (numBytes!=-1)
+ {
+ skippedBytes += numBytes;
+ FilePos += numBytes;
+ Pos = DataSize = 0;
+ }
+ else if (skippedBytes <= 0)
+ skippedBytes = -1;
+ }
+ return skippedBytes;
+}
+
+int BufferedFile::BytesAvailable()
+{
+ int available = pFile->BytesAvailable();
+ // Adjust available size based on buffers
+ switch(BufferMode)
+ {
+ case ReadBuffer:
+ available += DataSize-Pos;
+ break;
+ case WriteBuffer:
+ available -= Pos;
+ if (available<0)
+ available= 0;
+ break;
+ default:
+ break;
+ }
+ return available;
+}
+
+bool BufferedFile::Flush()
+{
+ FlushBuffer();
+ return pFile->Flush();
+}
+
+// Seeking could be optimized better..
+int BufferedFile::Seek(int offset, int origin)
+{
+ if (BufferMode == ReadBuffer)
+ {
+ if (origin == Seek_Cur)
+ {
+ // Seek can fall either before or after Pos in the buffer,
+ // but it must be within bounds.
+ if (((unsigned(offset) + Pos)) <= DataSize)
+ {
+ Pos += offset;
+ return int (FilePos - DataSize + Pos);
+ }
+
+ // Lightweight buffer "Flush". We do this to avoid an extra seek
+ // back operation which would take place if we called FlushBuffer directly.
+ origin = Seek_Set;
+ OVR_ASSERT(((FilePos - DataSize + Pos) + (UInt64)offset) < ~(UInt64)0);
+ offset = (int)(FilePos - DataSize + Pos) + offset;
+ Pos = DataSize = 0;
+ }
+ else if (origin == Seek_Set)
+ {
+ if (((unsigned)offset - (FilePos-DataSize)) <= DataSize)
+ {
+ OVR_ASSERT((FilePos-DataSize) < ~(UInt64)0);
+ Pos = (unsigned)offset - (unsigned)(FilePos-DataSize);
+ return offset;
+ }
+ Pos = DataSize = 0;
+ }
+ else
+ {
+ FlushBuffer();
+ }
+ }
+ else
+ {
+ FlushBuffer();
+ }
+
+ /*
+ // Old Seek Logic
+ if (origin == Seek_Cur && offset + Pos < DataSize)
+ {
+ //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset));
+ Pos += offset;
+ OVR_ASSERT(int (Pos) >= 0);
+ return int (FilePos - DataSize + Pos);
+ }
+ else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos)
+ {
+ Pos = unsigned(offset - FilePos + DataSize);
+ OVR_ASSERT(int (Pos) >= 0);
+ return int (FilePos - DataSize + Pos);
+ }
+
+ FlushBuffer();
+ */
+
+
+ FilePos = pFile->Seek(offset,origin);
+ return int (FilePos);
+}
+
+SInt64 BufferedFile::LSeek(SInt64 offset, int origin)
+{
+ if (BufferMode == ReadBuffer)
+ {
+ if (origin == Seek_Cur)
+ {
+ // Seek can fall either before or after Pos in the buffer,
+ // but it must be within bounds.
+ if (((unsigned(offset) + Pos)) <= DataSize)
+ {
+ Pos += (unsigned)offset;
+ return SInt64(FilePos - DataSize + Pos);
+ }
+
+ // Lightweight buffer "Flush". We do this to avoid an extra seek
+ // back operation which would take place if we called FlushBuffer directly.
+ origin = Seek_Set;
+ offset = (SInt64)(FilePos - DataSize + Pos) + offset;
+ Pos = DataSize = 0;
+ }
+ else if (origin == Seek_Set)
+ {
+ if (((UInt64)offset - (FilePos-DataSize)) <= DataSize)
+ {
+ Pos = (unsigned)((UInt64)offset - (FilePos-DataSize));
+ return offset;
+ }
+ Pos = DataSize = 0;
+ }
+ else
+ {
+ FlushBuffer();
+ }
+ }
+ else
+ {
+ FlushBuffer();
+ }
+
+/*
+ OVR_ASSERT(BufferMode != NoBuffer);
+
+ if (origin == Seek_Cur && offset + Pos < DataSize)
+ {
+ Pos += int (offset);
+ return FilePos - DataSize + Pos;
+ }
+ else if (origin == Seek_Set && offset >= SInt64(FilePos - DataSize) && offset < SInt64(FilePos))
+ {
+ Pos = unsigned(offset - FilePos + DataSize);
+ return FilePos - DataSize + Pos;
+ }
+
+ FlushBuffer();
+ */
+
+ FilePos = pFile->LSeek(offset,origin);
+ return FilePos;
+}
+
+int BufferedFile::CopyFromStream(File *pstream, int byteSize)
+{
+ // We can't rely on overridden Write()
+ // because delegation doesn't override virtual pointers
+ // So, just re-implement
+ UByte buff[0x4000];
+ int count = 0;
+ int szRequest, szRead, szWritten;
+
+ while(byteSize)
+ {
+ szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
+
+ szRead = pstream->Read(buff,szRequest);
+ szWritten = 0;
+ if (szRead > 0)
+ szWritten = Write(buff,szRead);
+
+ count +=szWritten;
+ byteSize-=szWritten;
+ if (szWritten < szRequest)
+ break;
+ }
+ return count;
+}
+
+// Closing files
+bool BufferedFile::Close()
+{
+ switch(BufferMode)
+ {
+ case WriteBuffer:
+ FlushBuffer();
+ break;
+ case ReadBuffer:
+ // No need to seek back on close
+ BufferMode = NoBuffer;
+ break;
+ default:
+ break;
+ }
+ return pFile->Close();
+}
+
+
+// ***** Global path helpers
+
+// Find trailing short filename in a path.
+const char* OVR_CDECL GetShortFilename(const char* purl)
+{
+ UPInt len = OVR_strlen(purl);
+ for (UPInt i=len; i>0; i--)
+ if (purl[i]=='\\' || purl[i]=='/')
+ return purl+i+1;
+ return purl;
+}
+
+} // OVR
+
diff --git a/LibOVR/Src/Kernel/OVR_File.h b/LibOVR/Src/Kernel/OVR_File.h new file mode 100644 index 0000000..262f5cf --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_File.h @@ -0,0 +1,518 @@ +/************************************************************************************
+
+PublicHeader: Kernel
+Filename : OVR_File.h
+Content : Header for all internal file management - functions and structures
+ to be inherited by OS specific subclasses.
+Created : September 19, 2012
+Notes :
+
+Notes : errno may not be preserved across use of BaseFile member functions
+ : Directories cannot be deleted while files opened from them are in use
+ (For the GetFullName function)
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_File_h
+#define OVR_File_h
+
+#include "OVR_RefCount.h"
+#include "OVR_Std.h"
+#include "OVR_Alg.h"
+
+#include <stdio.h>
+#include "OVR_String.h"
+
+namespace OVR {
+
+// ***** Declared classes
+class FileConstants;
+class File;
+class DelegatedFile;
+class BufferedFile;
+
+
+// ***** Flags for File & Directory accesses
+
+class FileConstants
+{
+public:
+
+ // *** File open flags
+ enum OpenFlags
+ {
+ Open_Read = 1,
+ Open_Write = 2,
+ Open_ReadWrite = 3,
+
+ // Opens file and truncates it to zero length
+ // - file must have write permission
+ // - when used with Create, it opens an existing
+ // file and empties it or creates a new file
+ Open_Truncate = 4,
+
+ // Creates and opens new file
+ // - does not erase contents if file already
+ // exists unless combined with Truncate
+ Open_Create = 8,
+
+ // Returns an error value if the file already exists
+ Open_CreateOnly = 24,
+
+ // Open file with buffering
+ Open_Buffered = 32
+ };
+
+ // *** File Mode flags
+ enum Modes
+ {
+ Mode_Read = 0444,
+ Mode_Write = 0222,
+ Mode_Execute = 0111,
+
+ Mode_ReadWrite = 0666
+ };
+
+ // *** Seek operations
+ enum SeekOps
+ {
+ Seek_Set = 0,
+ Seek_Cur = 1,
+ Seek_End = 2
+ };
+
+ // *** Errors
+ enum Errors
+ {
+ Error_FileNotFound = 0x1001,
+ Error_Access = 0x1002,
+ Error_IOError = 0x1003,
+ Error_DiskFull = 0x1004
+ };
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** File Class
+
+// The pure virtual base random-access file
+// This is a base class to all files
+
+class File : public RefCountBase<File>, public FileConstants
+{
+public:
+ File() { }
+ // ** Location Information
+
+ // Returns a file name path relative to the 'reference' directory
+ // This is often a path that was used to create a file
+ // (this is not a global path, global path can be obtained with help of directory)
+ virtual const char* GetFilePath() = 0;
+
+
+ // ** File Information
+
+ // Return 1 if file's usable (open)
+ virtual bool IsValid() = 0;
+ // Return 1 if file's writable, otherwise 0
+ virtual bool IsWritable() = 0;
+
+ // Return position
+ virtual int Tell() = 0;
+ virtual SInt64 LTell() = 0;
+
+ // File size
+ virtual int GetLength() = 0;
+ virtual SInt64 LGetLength() = 0;
+
+ // Returns file stats
+ // 0 for failure
+ //virtual bool Stat(FileStats *pfs) = 0;
+
+ // Return errno-based error code
+ // Useful if any other function failed
+ virtual int GetErrorCode() = 0;
+
+
+ // ** Stream implementation & I/O
+
+ // Blocking write, will write in the given number of bytes to the stream
+ // Returns : -1 for error
+ // Otherwise number of bytes read
+ virtual int Write(const UByte *pbufer, int numBytes) = 0;
+ // Blocking read, will read in the given number of bytes or less from the stream
+ // Returns : -1 for error
+ // Otherwise number of bytes read,
+ // if 0 or < numBytes, no more bytes available; end of file or the other side of stream is closed
+ virtual int Read(UByte *pbufer, int numBytes) = 0;
+
+ // Skips (ignores) a given # of bytes
+ // Same return values as Read
+ virtual int SkipBytes(int numBytes) = 0;
+
+ // Returns the number of bytes available to read from a stream without blocking
+ // For a file, this should generally be number of bytes to the end
+ virtual int BytesAvailable() = 0;
+
+ // Causes any implementation's buffered data to be delivered to destination
+ // Return 0 for error
+ virtual bool Flush() = 0;
+
+
+ // Need to provide a more optimized implementation that doe snot necessarily involve a lot of seeking
+ inline bool IsEOF() { return !BytesAvailable(); }
+
+
+ // Seeking
+ // Returns new position, -1 for error
+ virtual int Seek(int offset, int origin=Seek_Set) = 0;
+ virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set) = 0;
+ // Seek simplification
+ int SeekToBegin() {return Seek(0); }
+ int SeekToEnd() {return Seek(0,Seek_End); }
+ int Skip(int numBytes) {return Seek(numBytes,Seek_Cur); }
+
+
+ // Appends other file data from a stream
+ // Return -1 for error, else # of bytes written
+ virtual int CopyFromStream(File *pstream, int byteSize) = 0;
+
+ // Closes the file
+ // After close, file cannot be accessed
+ virtual bool Close() = 0;
+
+
+ // ***** Inlines for convenient primitive type serialization
+
+ // Read/Write helpers
+private:
+ UInt64 PRead64() { UInt64 v = 0; Read((UByte*)&v, 8); return v; }
+ UInt32 PRead32() { UInt32 v = 0; Read((UByte*)&v, 4); return v; }
+ UInt16 PRead16() { UInt16 v = 0; Read((UByte*)&v, 2); return v; }
+ UByte PRead8() { UByte v = 0; Read((UByte*)&v, 1); return v; }
+ void PWrite64(UInt64 v) { Write((UByte*)&v, 8); }
+ void PWrite32(UInt32 v) { Write((UByte*)&v, 4); }
+ void PWrite16(UInt16 v) { Write((UByte*)&v, 2); }
+ void PWrite8(UByte v) { Write((UByte*)&v, 1); }
+
+public:
+
+ // Writing primitive types - Little Endian
+ inline void WriteUByte(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSByte(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteUInt8(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSInt8(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteUInt16(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSInt16(SInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteUInt32(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSInt32(SInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteUInt64(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSInt64(SInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteFloat(float v) { v = Alg::ByteUtil::SystemToLE(v); Write((UByte*)&v, 4); }
+ inline void WriteDouble(double v) { v = Alg::ByteUtil::SystemToLE(v); Write((UByte*)&v, 8); }
+ // Writing primitive types - Big Endian
+ inline void WriteUByteBE(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSByteBE(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteUInt8BE(UInt16 v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSInt8BE(SInt16 v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteUInt16BE(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSInt16BE(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteUInt32BE(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSInt32BE(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteUInt64BE(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSInt64BE(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteFloatBE(float v) { v = Alg::ByteUtil::SystemToBE(v); Write((UByte*)&v, 4); }
+ inline void WriteDoubleBE(double v) { v = Alg::ByteUtil::SystemToBE(v); Write((UByte*)&v, 8); }
+
+ // Reading primitive types - Little Endian
+ inline UByte ReadUByte() { return (UByte)Alg::ByteUtil::LEToSystem(PRead8()); }
+ inline SByte ReadSByte() { return (SByte)Alg::ByteUtil::LEToSystem(PRead8()); }
+ inline UByte ReadUInt8() { return (UByte)Alg::ByteUtil::LEToSystem(PRead8()); }
+ inline SByte ReadSInt8() { return (SByte)Alg::ByteUtil::LEToSystem(PRead8()); }
+ inline UInt16 ReadUInt16() { return (UInt16)Alg::ByteUtil::LEToSystem(PRead16()); }
+ inline SInt16 ReadSInt16() { return (SInt16)Alg::ByteUtil::LEToSystem(PRead16()); }
+ inline UInt32 ReadUInt32() { return (UInt32)Alg::ByteUtil::LEToSystem(PRead32()); }
+ inline SInt32 ReadSInt32() { return (SInt32)Alg::ByteUtil::LEToSystem(PRead32()); }
+ inline UInt64 ReadUInt64() { return (UInt64)Alg::ByteUtil::LEToSystem(PRead64()); }
+ inline SInt64 ReadSInt64() { return (SInt64)Alg::ByteUtil::LEToSystem(PRead64()); }
+ inline float ReadFloat() { float v = 0.0f; Read((UByte*)&v, 4); return Alg::ByteUtil::LEToSystem(v); }
+ inline double ReadDouble() { double v = 0.0; Read((UByte*)&v, 8); return Alg::ByteUtil::LEToSystem(v); }
+ // Reading primitive types - Big Endian
+ inline UByte ReadUByteBE() { return (UByte)Alg::ByteUtil::BEToSystem(PRead8()); }
+ inline SByte ReadSByteBE() { return (SByte)Alg::ByteUtil::BEToSystem(PRead8()); }
+ inline UByte ReadUInt8BE() { return (UByte)Alg::ByteUtil::BEToSystem(PRead8()); }
+ inline SByte ReadSInt8BE() { return (SByte)Alg::ByteUtil::BEToSystem(PRead8()); }
+ inline UInt16 ReadUInt16BE() { return (UInt16)Alg::ByteUtil::BEToSystem(PRead16()); }
+ inline SInt16 ReadSInt16BE() { return (SInt16)Alg::ByteUtil::BEToSystem(PRead16()); }
+ inline UInt32 ReadUInt32BE() { return (UInt32)Alg::ByteUtil::BEToSystem(PRead32()); }
+ inline SInt32 ReadSInt32BE() { return (SInt32)Alg::ByteUtil::BEToSystem(PRead32()); }
+ inline UInt64 ReadUInt64BE() { return (UInt64)Alg::ByteUtil::BEToSystem(PRead64()); }
+ inline SInt64 ReadSInt64BE() { return (SInt64)Alg::ByteUtil::BEToSystem(PRead64()); }
+ inline float ReadFloatBE() { float v = 0.0f; Read((UByte*)&v, 4); return Alg::ByteUtil::BEToSystem(v); }
+ inline double ReadDoubleBE() { double v = 0.0; Read((UByte*)&v, 8); return Alg::ByteUtil::BEToSystem(v); }
+};
+
+
+// *** Delegated File
+
+class DelegatedFile : public File
+{
+protected:
+ // Delegating file pointer
+ Ptr<File> pFile;
+
+ // Hidden default constructor
+ DelegatedFile() : pFile(0) { }
+ DelegatedFile(const DelegatedFile &source) : File() { OVR_UNUSED(source); }
+public:
+ // Constructors
+ DelegatedFile(File *pfile) : pFile(pfile) { }
+
+ // ** Location Information
+ virtual const char* GetFilePath() { return pFile->GetFilePath(); }
+
+ // ** File Information
+ virtual bool IsValid() { return pFile && pFile->IsValid(); }
+ virtual bool IsWritable() { return pFile->IsWritable(); }
+// virtual bool IsRecoverable() { return pFile->IsRecoverable(); }
+
+ virtual int Tell() { return pFile->Tell(); }
+ virtual SInt64 LTell() { return pFile->LTell(); }
+
+ virtual int GetLength() { return pFile->GetLength(); }
+ virtual SInt64 LGetLength() { return pFile->LGetLength(); }
+
+ //virtual bool Stat(FileStats *pfs) { return pFile->Stat(pfs); }
+
+ virtual int GetErrorCode() { return pFile->GetErrorCode(); }
+
+ // ** Stream implementation & I/O
+ virtual int Write(const UByte *pbuffer, int numBytes) { return pFile->Write(pbuffer,numBytes); }
+ virtual int Read(UByte *pbuffer, int numBytes) { return pFile->Read(pbuffer,numBytes); }
+
+ virtual int SkipBytes(int numBytes) { return pFile->SkipBytes(numBytes); }
+
+ virtual int BytesAvailable() { return pFile->BytesAvailable(); }
+
+ virtual bool Flush() { return pFile->Flush(); }
+
+ // Seeking
+ virtual int Seek(int offset, int origin=Seek_Set) { return pFile->Seek(offset,origin); }
+ virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set) { return pFile->LSeek(offset,origin); }
+
+ virtual int CopyFromStream(File *pstream, int byteSize) { return pFile->CopyFromStream(pstream,byteSize); }
+
+ // Closing the file
+ virtual bool Close() { return pFile->Close(); }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Buffered File
+
+// This file class adds buffering to an existing file
+// Buffered file never fails by itself; if there's not
+// enough memory for buffer, no buffer's used
+
+class BufferedFile : public DelegatedFile
+{
+protected:
+ enum BufferModeType
+ {
+ NoBuffer,
+ ReadBuffer,
+ WriteBuffer
+ };
+
+ // Buffer & the mode it's in
+ UByte* pBuffer;
+ BufferModeType BufferMode;
+ // Position in buffer
+ unsigned Pos;
+ // Data in buffer if reading
+ unsigned DataSize;
+ // Underlying file position
+ UInt64 FilePos;
+
+ // Initializes buffering to a certain mode
+ bool SetBufferMode(BufferModeType mode);
+ // Flushes buffer
+ // WriteBuffer - write data to disk, ReadBuffer - reset buffer & fix file position
+ void FlushBuffer();
+ // Loads data into ReadBuffer
+ // WARNING: Right now LoadBuffer() assumes the buffer's empty
+ void LoadBuffer();
+
+ // Hidden constructor
+ BufferedFile();
+ inline BufferedFile(const BufferedFile &source) : DelegatedFile() { OVR_UNUSED(source); }
+public:
+
+ // Constructor
+ // - takes another file as source
+ BufferedFile(File *pfile);
+ ~BufferedFile();
+
+
+ // ** Overridden functions
+
+ // We override all the functions that can possibly
+ // require buffer mode switch, flush, or extra calculations
+ virtual int Tell();
+ virtual SInt64 LTell();
+
+ virtual int GetLength();
+ virtual SInt64 LGetLength();
+
+// virtual bool Stat(GFileStats *pfs);
+
+ virtual int Write(const UByte *pbufer, int numBytes);
+ virtual int Read(UByte *pbufer, int numBytes);
+
+ virtual int SkipBytes(int numBytes);
+
+ virtual int BytesAvailable();
+
+ virtual bool Flush();
+
+ virtual int Seek(int offset, int origin=Seek_Set);
+ virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set);
+
+ virtual int CopyFromStream(File *pstream, int byteSize);
+
+ virtual bool Close();
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Memory File
+
+class MemoryFile : public File
+{
+public:
+
+ const char* GetFilePath() { return FilePath.ToCStr(); }
+
+ bool IsValid() { return Valid; }
+ bool IsWritable() { return false; }
+
+ bool Flush() { return true; }
+ int GetErrorCode() { return 0; }
+
+ int Tell() { return FileIndex; }
+ SInt64 LTell() { return (SInt64) FileIndex; }
+
+ int GetLength() { return FileSize; }
+ SInt64 LGetLength() { return (SInt64) FileSize; }
+
+ bool Close()
+ {
+ Valid = false;
+ return false;
+ }
+
+ int CopyFromStream(File *pstream, int byteSize)
+ { OVR_UNUSED2(pstream, byteSize);
+ return 0;
+ }
+
+ int Write(const UByte *pbuffer, int numBytes)
+ { OVR_UNUSED2(pbuffer, numBytes);
+ return 0;
+ }
+
+ int Read(UByte *pbufer, int numBytes)
+ {
+ if (FileIndex + numBytes > FileSize)
+ {
+ numBytes = FileSize - FileIndex;
+ }
+
+ if (numBytes > 0)
+ {
+ ::memcpy (pbufer, &FileData [FileIndex], numBytes);
+
+ FileIndex += numBytes;
+ }
+
+ return numBytes;
+ }
+
+ int SkipBytes(int numBytes)
+ {
+ if (FileIndex + numBytes > FileSize)
+ {
+ numBytes = FileSize - FileIndex;
+ }
+
+ FileIndex += numBytes;
+
+ return numBytes;
+ }
+
+ int BytesAvailable()
+ {
+ return (FileSize - FileIndex);
+ }
+
+ int Seek(int offset, int origin = Seek_Set)
+ {
+ switch (origin)
+ {
+ case Seek_Set : FileIndex = offset; break;
+ case Seek_Cur : FileIndex += offset; break;
+ case Seek_End : FileIndex = FileSize - offset; break;
+ }
+
+ return FileIndex;
+ }
+
+ SInt64 LSeek(SInt64 offset, int origin = Seek_Set)
+ {
+ return (SInt64) Seek((int) offset, origin);
+ }
+
+public:
+
+ MemoryFile (const String& fileName, const UByte *pBuffer, int buffSize)
+ : FilePath(fileName)
+ {
+ FileData = pBuffer;
+ FileSize = buffSize;
+ FileIndex = 0;
+ Valid = (!fileName.IsEmpty() && pBuffer && buffSize > 0) ? true : false;
+ }
+
+ // pfileName should be encoded as UTF-8 to support international file names.
+ MemoryFile (const char* pfileName, const UByte *pBuffer, int buffSize)
+ : FilePath(pfileName)
+ {
+ FileData = pBuffer;
+ FileSize = buffSize;
+ FileIndex = 0;
+ Valid = (pfileName && pBuffer && buffSize > 0) ? true : false;
+ }
+private:
+
+ String FilePath;
+ const UByte *FileData;
+ int FileSize;
+ int FileIndex;
+ bool Valid;
+};
+
+
+// ***** Global path helpers
+
+// Find trailing short filename in a path.
+const char* OVR_CDECL GetShortFilename(const char* purl);
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_FileFILE.cpp b/LibOVR/Src/Kernel/OVR_FileFILE.cpp new file mode 100644 index 0000000..4ee32b6 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_FileFILE.cpp @@ -0,0 +1,583 @@ +/**************************************************************************
+
+Filename : OVR_FileFILE.cpp
+Content : File wrapper class implementation (Win32)
+
+Created : April 5, 1999
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+**************************************************************************/
+
+#define GFILE_CXX
+
+#include "OVR_Types.h"
+#include "OVR_Log.h"
+
+// Standard C library (Captain Obvious guarantees!)
+#include <stdio.h>
+#ifndef OVR_OS_WINCE
+#include <sys/stat.h>
+#endif
+
+#include "OVR_SysFile.h"
+
+#ifndef OVR_OS_WINCE
+#include <errno.h>
+#endif
+
+namespace OVR {
+
+// ***** File interface
+
+// ***** FILEFile - C streams file
+
+static int SFerror ()
+{
+ if (errno == ENOENT)
+ return FileConstants::Error_FileNotFound;
+ else if (errno == EACCES || errno == EPERM)
+ return FileConstants::Error_Access;
+ else if (errno == ENOSPC)
+ return FileConstants::Error_DiskFull;
+ else
+ return FileConstants::Error_IOError;
+};
+
+#ifdef OVR_OS_WIN32
+#include "windows.h"
+// A simple helper class to disable/enable system error mode, if necessary
+// Disabling happens conditionally only if a drive name is involved
+class SysErrorModeDisabler
+{
+ BOOL Disabled;
+ UINT OldMode;
+public:
+ SysErrorModeDisabler(const char* pfileName)
+ {
+ if (pfileName && (pfileName[0]!=0) && pfileName[1]==':')
+ {
+ Disabled = 1;
+ OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
+ }
+ else
+ Disabled = 0;
+ }
+
+ ~SysErrorModeDisabler()
+ {
+ if (Disabled) ::SetErrorMode(OldMode);
+ }
+};
+#else
+class SysErrorModeDisabler
+{
+public:
+ SysErrorModeDisabler(const char* pfileName) { }
+};
+#endif // OVR_OS_WIN32
+
+
+// This macro enables verification of I/O results after seeks against a pre-loaded
+// full file buffer copy. This is generally not necessary, but can been used to debug
+// memory corruptions; we've seen this fail due to EAX2/DirectSound corrupting memory
+// under FMOD with XP64 (32-bit) and Realtek HA Audio driver.
+//#define GFILE_VERIFY_SEEK_ERRORS
+
+
+// This is the simplest possible file implementation, it wraps around the descriptor
+// This file is delegated to by SysFile.
+
+class FILEFile : public File
+{
+protected:
+
+ // Allocated filename
+ String FileName;
+
+ // File handle & open mode
+ bool Opened;
+ FILE* fs;
+ int OpenFlags;
+ // Error code for last request
+ int ErrorCode;
+
+ int LastOp;
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ UByte* pFileTestBuffer;
+ unsigned FileTestLength;
+ unsigned TestPos; // File pointer position during tests.
+#endif
+
+public:
+
+ FILEFile()
+ {
+ Opened = 0; FileName = "";
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ pFileTestBuffer =0;
+ FileTestLength =0;
+ TestPos =0;
+#endif
+ }
+ // Initialize file by opening it
+ FILEFile(const String& fileName, int flags, int Mode);
+ // The 'pfileName' should be encoded as UTF-8 to support international file names.
+ FILEFile(const char* pfileName, int flags, int Mode);
+
+ ~FILEFile()
+ {
+ if (Opened)
+ Close();
+ }
+
+ virtual const char* GetFilePath();
+
+ // ** File Information
+ virtual bool IsValid();
+ virtual bool IsWritable();
+
+ // Return position / file size
+ virtual int Tell();
+ virtual SInt64 LTell();
+ virtual int GetLength();
+ virtual SInt64 LGetLength();
+
+// virtual bool Stat(FileStats *pfs);
+ virtual int GetErrorCode();
+
+ // ** Stream implementation & I/O
+ virtual int Write(const UByte *pbuffer, int numBytes);
+ virtual int Read(UByte *pbuffer, int numBytes);
+ virtual int SkipBytes(int numBytes);
+ virtual int BytesAvailable();
+ virtual bool Flush();
+ virtual int Seek(int offset, int origin);
+ virtual SInt64 LSeek(SInt64 offset, int origin);
+
+ virtual int CopyFromStream(File *pStream, int byteSize);
+ virtual bool Close();
+private:
+ void init();
+};
+
+
+// Initialize file by opening it
+FILEFile::FILEFile(const String& fileName, int flags, int mode)
+ : FileName(fileName), OpenFlags(flags)
+{
+ OVR_UNUSED(mode);
+ init();
+}
+
+// The 'pfileName' should be encoded as UTF-8 to support international file names.
+FILEFile::FILEFile(const char* pfileName, int flags, int mode)
+ : FileName(pfileName), OpenFlags(flags)
+{
+ OVR_UNUSED(mode);
+ init();
+}
+
+void FILEFile::init()
+{
+ // Open mode for file's open
+ const char *omode = "rb";
+
+ if (OpenFlags & Open_Truncate)
+ {
+ if (OpenFlags & Open_Read)
+ omode = "w+b";
+ else
+ omode = "wb";
+ }
+ else if (OpenFlags & Open_Create)
+ {
+ if (OpenFlags & Open_Read)
+ omode = "a+b";
+ else
+ omode = "ab";
+ }
+ else if (OpenFlags & Open_Write)
+ omode = "r+b";
+
+#ifdef OVR_OS_WIN32
+ SysErrorModeDisabler disabler(FileName.ToCStr());
+#endif
+
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ wchar_t womode[16];
+ wchar_t *pwFileName = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(FileName.ToCStr())+1) * sizeof(wchar_t));
+ UTF8Util::DecodeString(pwFileName, FileName.ToCStr());
+ OVR_ASSERT(strlen(omode) < sizeof(womode)/sizeof(womode[0]));
+ UTF8Util::DecodeString(womode, omode);
+ _wfopen_s(&fs, pwFileName, womode);
+ OVR_FREE(pwFileName);
+#else
+ fs = fopen(FileName.ToCStr(), omode);
+#endif
+ if (fs)
+ rewind (fs);
+ Opened = (fs != NULL);
+ // Set error code
+ if (!Opened)
+ ErrorCode = SFerror();
+ else
+ {
+ // If we are testing file seek correctness, pre-load the entire file so
+ // that we can do comparison tests later.
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ TestPos = 0;
+ fseek(fs, 0, SEEK_END);
+ FileTestLength = ftell(fs);
+ fseek(fs, 0, SEEK_SET);
+ pFileTestBuffer = (UByte*)OVR_ALLOC(FileTestLength);
+ if (pFileTestBuffer)
+ {
+ OVR_ASSERT(FileTestLength == (unsigned)Read(pFileTestBuffer, FileTestLength));
+ Seek(0, Seek_Set);
+ }
+#endif
+
+ ErrorCode = 0;
+ }
+ LastOp = 0;
+}
+
+
+const char* FILEFile::GetFilePath()
+{
+ return FileName.ToCStr();
+}
+
+
+// ** File Information
+bool FILEFile::IsValid()
+{
+ return Opened;
+}
+bool FILEFile::IsWritable()
+{
+ return IsValid() && (OpenFlags&Open_Write);
+}
+/*
+bool FILEFile::IsRecoverable()
+{
+ return IsValid() && ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC);
+}
+*/
+
+// Return position / file size
+int FILEFile::Tell()
+{
+ int pos = (int)ftell (fs);
+ if (pos < 0)
+ ErrorCode = SFerror();
+ return pos;
+}
+
+SInt64 FILEFile::LTell()
+{
+ SInt64 pos = ftell(fs);
+ if (pos < 0)
+ ErrorCode = SFerror();
+ return pos;
+}
+
+int FILEFile::GetLength()
+{
+ int pos = Tell();
+ if (pos >= 0)
+ {
+ Seek (0, Seek_End);
+ int size = Tell();
+ Seek (pos, Seek_Set);
+ return size;
+ }
+ return -1;
+}
+SInt64 FILEFile::LGetLength()
+{
+ SInt64 pos = LTell();
+ if (pos >= 0)
+ {
+ LSeek (0, Seek_End);
+ SInt64 size = LTell();
+ LSeek (pos, Seek_Set);
+ return size;
+ }
+ return -1;
+}
+
+int FILEFile::GetErrorCode()
+{
+ return ErrorCode;
+}
+
+// ** Stream implementation & I/O
+int FILEFile::Write(const UByte *pbuffer, int numBytes)
+{
+ if (LastOp && LastOp != Open_Write)
+ fflush(fs);
+ LastOp = Open_Write;
+ int written = (int) fwrite(pbuffer, 1, numBytes, fs);
+ if (written < numBytes)
+ ErrorCode = SFerror();
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ if (written > 0)
+ TestPos += written;
+#endif
+
+ return written;
+}
+
+int FILEFile::Read(UByte *pbuffer, int numBytes)
+{
+ if (LastOp && LastOp != Open_Read)
+ fflush(fs);
+ LastOp = Open_Read;
+ int read = (int) fread(pbuffer, 1, numBytes, fs);
+ if (read < numBytes)
+ ErrorCode = SFerror();
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ if (read > 0)
+ {
+ // Read-in data must match our pre-loaded buffer data!
+ UByte* pcompareBuffer = pFileTestBuffer + TestPos;
+ for (int i=0; i< read; i++)
+ {
+ OVR_ASSERT(pcompareBuffer[i] == pbuffer[i]);
+ }
+
+ //OVR_ASSERT(!memcmp(pFileTestBuffer + TestPos, pbuffer, read));
+ TestPos += read;
+ OVR_ASSERT(ftell(fs) == (int)TestPos);
+ }
+#endif
+
+ return read;
+}
+
+// Seeks ahead to skip bytes
+int FILEFile::SkipBytes(int numBytes)
+{
+ SInt64 pos = LTell();
+ SInt64 newPos = LSeek(numBytes, Seek_Cur);
+
+ // Return -1 for major error
+ if ((pos==-1) || (newPos==-1))
+ {
+ return -1;
+ }
+ //ErrorCode = ((NewPos-Pos)<numBytes) ? errno : 0;
+
+ return int (newPos-(int)pos);
+}
+
+// Return # of bytes till EOF
+int FILEFile::BytesAvailable()
+{
+ SInt64 pos = LTell();
+ SInt64 endPos = LGetLength();
+
+ // Return -1 for major error
+ if ((pos==-1) || (endPos==-1))
+ {
+ ErrorCode = SFerror();
+ return 0;
+ }
+ else
+ ErrorCode = 0;
+
+ return int (endPos-(int)pos);
+}
+
+// Flush file contents
+bool FILEFile::Flush()
+{
+ return !fflush(fs);
+}
+
+int FILEFile::Seek(int offset, int origin)
+{
+ int newOrigin = 0;
+ switch(origin)
+ {
+ case Seek_Set: newOrigin = SEEK_SET; break;
+ case Seek_Cur: newOrigin = SEEK_CUR; break;
+ case Seek_End: newOrigin = SEEK_END; break;
+ }
+
+ if (newOrigin == SEEK_SET && offset == Tell())
+ return Tell();
+
+ if (fseek (fs, offset, newOrigin))
+ {
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ OVR_ASSERT(0);
+#endif
+ return -1;
+ }
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ // Track file position after seeks for read verification later.
+ switch(origin)
+ {
+ case Seek_Set: TestPos = offset; break;
+ case Seek_Cur: TestPos += offset; break;
+ case Seek_End: TestPos = FileTestLength + offset; break;
+ }
+ OVR_ASSERT((int)TestPos == Tell());
+#endif
+
+ return (int)Tell();
+}
+
+SInt64 FILEFile::LSeek(SInt64 offset, int origin)
+{
+ return Seek((int)offset,origin);
+}
+
+int FILEFile::CopyFromStream(File *pstream, int byteSize)
+{
+ UByte buff[0x4000];
+ int count = 0;
+ int szRequest, szRead, szWritten;
+
+ while (byteSize)
+ {
+ szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
+
+ szRead = pstream->Read(buff, szRequest);
+ szWritten = 0;
+ if (szRead > 0)
+ szWritten = Write(buff, szRead);
+
+ count += szWritten;
+ byteSize -= szWritten;
+ if (szWritten < szRequest)
+ break;
+ }
+ return count;
+}
+
+
+bool FILEFile::Close()
+{
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ if (pFileTestBuffer)
+ {
+ OVR_FREE(pFileTestBuffer);
+ pFileTestBuffer = 0;
+ FileTestLength = 0;
+ }
+#endif
+
+ bool closeRet = !fclose(fs);
+
+ if (!closeRet)
+ {
+ ErrorCode = SFerror();
+ return 0;
+ }
+ else
+ {
+ Opened = 0;
+ fs = 0;
+ ErrorCode = 0;
+ }
+
+ // Handle safe truncate
+ /*
+ if ((OpenFlags & OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
+ {
+ // Delete original file (if it existed)
+ DWORD oldAttributes = FileUtilWin32::GetFileAttributes(FileName);
+ if (oldAttributes!=0xFFFFFFFF)
+ if (!FileUtilWin32::DeleteFile(FileName))
+ {
+ // Try to remove the readonly attribute
+ FileUtilWin32::SetFileAttributes(FileName, oldAttributes & (~FILE_ATTRIBUTE_READONLY) );
+ // And delete the file again
+ if (!FileUtilWin32::DeleteFile(FileName))
+ return 0;
+ }
+
+ // Rename temp file to real filename
+ if (!FileUtilWin32::MoveFile(TempName, FileName))
+ {
+ //ErrorCode = errno;
+ return 0;
+ }
+ }
+ */
+ return 1;
+}
+
+/*
+bool FILEFile::CloseCancel()
+{
+ bool closeRet = (bool)::CloseHandle(fd);
+
+ if (!closeRet)
+ {
+ //ErrorCode = errno;
+ return 0;
+ }
+ else
+ {
+ Opened = 0;
+ fd = INVALID_HANDLE_VALUE;
+ ErrorCode = 0;
+ }
+
+ // Handle safe truncate (delete tmp file, leave original unchanged)
+ if ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
+ if (!FileUtilWin32::DeleteFile(TempName))
+ {
+ //ErrorCode = errno;
+ return 0;
+ }
+ return 1;
+}
+*/
+
+File *FileFILEOpen(const String& path, int flags, int mode)
+{
+ return new FILEFile(path, flags, mode);
+}
+
+// Helper function: obtain file information time.
+bool SysFile::GetFileStat(FileStat* pfileStat, const String& path)
+{
+#if defined(OVR_OS_WIN32)
+ // 64-bit implementation on Windows.
+ struct __stat64 fileStat;
+ // Stat returns 0 for success.
+ wchar_t *pwpath = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(path.ToCStr())+1)*sizeof(wchar_t));
+ UTF8Util::DecodeString(pwpath, path.ToCStr());
+
+ int ret = _wstat64(pwpath, &fileStat);
+ OVR_FREE(pwpath);
+ if (ret) return false;
+#else
+ struct stat fileStat;
+ // Stat returns 0 for success.
+ if (stat(path, &fileStat) != 0)
+ return false;
+#endif
+ pfileStat->AccessTime = fileStat.st_atime;
+ pfileStat->ModifyTime = fileStat.st_mtime;
+ pfileStat->FileSize = fileStat.st_size;
+ return true;
+}
+
+} // Scaleform
diff --git a/LibOVR/Src/Kernel/OVR_Hash.h b/LibOVR/Src/Kernel/OVR_Hash.h new file mode 100644 index 0000000..6667ac2 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Hash.h @@ -0,0 +1,1291 @@ +/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_Hash.h
+Content : Template hash-table/set implementation
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Hash_h
+#define OVR_Hash_h
+
+#include "OVR_ContainerAllocator.h"
+#include "OVR_Alg.h"
+
+// 'new' operator is redefined/used in this file.
+#undef new
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Hash Table Implementation
+
+// HastSet and Hash.
+//
+// Hash table, linear probing, internal chaining. One interesting/nice thing
+// about this implementation is that the table itself is a flat chunk of memory
+// containing no pointers, only relative indices. If the key and value types
+// of the Hash contain no pointers, then the Hash can be serialized using raw IO.
+//
+// Never shrinks, unless you explicitly Clear() it. Expands on
+// demand, though. For best results, if you know roughly how big your
+// table will be, default it to that size when you create it.
+//
+// Key usability feature:
+//
+// 1. Allows node hash values to either be cached or not.
+//
+// 2. Allows for alternative keys with methods such as GetAlt(). Handy
+// if you need to search nodes by their components; no need to create
+// temporary nodes.
+//
+
+
+// *** Hash functors:
+//
+// IdentityHash - use when the key is already a good hash
+// HFixedSizeHash - general hash based on object's in-memory representation.
+
+
+// Hash is just the input value; can use this for integer-indexed hash tables.
+template<class C>
+class IdentityHash
+{
+public:
+ UPInt operator()(const C& data) const
+ { return (UPInt) data; }
+};
+
+// Computes a hash of an object's representation.
+template<class C>
+class FixedSizeHash
+{
+public:
+ // Alternative: "sdbm" hash function, suggested at same web page
+ // above, http::/www.cs.yorku.ca/~oz/hash.html
+ // This is somewhat slower then Bernstein, but it works way better than the above
+ // hash function for hashing large numbers of 32-bit ints.
+ static OVR_FORCE_INLINE UPInt SDBM_Hash(const void* data_in, UPInt size, UPInt seed = 5381)
+ {
+ const UByte* data = (const UByte*) data_in;
+ UPInt h = seed;
+ while (size > 0)
+ {
+ size--;
+ h = (h << 16) + (h << 6) - h + (UPInt)data[size];
+ }
+ return h;
+ }
+
+ UPInt operator()(const C& data) const
+ {
+ unsigned char* p = (unsigned char*) &data;
+ int size = sizeof(C);
+
+ return SDBM_Hash(p, size);
+ }
+};
+
+
+
+// *** HashsetEntry Entry types.
+
+// Compact hash table Entry type that re-computes hash keys during hash traversal.
+// Good to use if the hash function is cheap or the hash value is already cached in C.
+template<class C, class HashF>
+class HashsetEntry
+{
+public:
+ // Internal chaining for collisions.
+ SPInt NextInChain;
+ C Value;
+
+ HashsetEntry()
+ : NextInChain(-2) { }
+ HashsetEntry(const HashsetEntry& e)
+ : NextInChain(e.NextInChain), Value(e.Value) { }
+ HashsetEntry(const C& key, SPInt next)
+ : NextInChain(next), Value(key) { }
+
+ bool IsEmpty() const { return NextInChain == -2; }
+ bool IsEndOfChain() const { return NextInChain == -1; }
+
+ // Cached hash value access - can be optimized bu storing hash locally.
+ // Mask value only needs to be used if SetCachedHash is not implemented.
+ UPInt GetCachedHash(UPInt maskValue) const { return HashF()(Value) & maskValue; }
+ void SetCachedHash(UPInt) {}
+
+ void Clear()
+ {
+ Value.~C(); // placement delete
+ NextInChain = -2;
+ }
+ // Free is only used from dtor of hash; Clear is used during regular operations:
+ // assignment, hash reallocations, value reassignments, so on.
+ void Free() { Clear(); }
+};
+
+// Hash table Entry type that caches the Entry hash value for nodes, so that it
+// does not need to be re-computed during access.
+template<class C, class HashF>
+class HashsetCachedEntry
+{
+public:
+ // Internal chaining for collisions.
+ SPInt NextInChain;
+ UPInt HashValue;
+ C Value;
+
+ HashsetCachedEntry()
+ : NextInChain(-2) { }
+ HashsetCachedEntry(const HashsetCachedEntry& e)
+ : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { }
+ HashsetCachedEntry(const C& key, SPInt next)
+ : NextInChain(next), Value(key) { }
+
+ bool IsEmpty() const { return NextInChain == -2; }
+ bool IsEndOfChain() const { return NextInChain == -1; }
+
+ // Cached hash value access - can be optimized bu storing hash locally.
+ // Mask value only needs to be used if SetCachedHash is not implemented.
+ UPInt GetCachedHash(UPInt maskValue) const { OVR_UNUSED(maskValue); return HashValue; }
+ void SetCachedHash(UPInt hashValue) { HashValue = hashValue; }
+
+ void Clear()
+ {
+ Value.~C();
+ NextInChain = -2;
+ }
+ // Free is only used from dtor of hash; Clear is used during regular operations:
+ // assignment, hash reallocations, value reassignments, so on.
+ void Free() { Clear(); }
+};
+
+
+//-----------------------------------------------------------------------------------
+// *** HashSet implementation - relies on either cached or regular entries.
+//
+// Use: Entry = HashsetCachedEntry<C, HashF> if hashes are expensive to
+// compute and thus need caching in entries.
+// Entry = HashsetEntry<C, HashF> if hashes are already externally cached.
+//
+template<class C, class HashF = FixedSizeHash<C>,
+ class AltHashF = HashF,
+ class Allocator = ContainerAllocator<C>,
+ class Entry = HashsetCachedEntry<C, HashF> >
+class HashSetBase
+{
+ enum { HashMinSize = 8 };
+
+public:
+ OVR_MEMORY_REDEFINE_NEW(HashSetBase)
+
+ typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> SelfType;
+
+ HashSetBase() : pTable(NULL) { }
+ HashSetBase(int sizeHint) : pTable(NULL) { SetCapacity(this, sizeHint); }
+ HashSetBase(const SelfType& src) : pTable(NULL) { Assign(this, src); }
+
+ ~HashSetBase()
+ {
+ if (pTable)
+ {
+ // Delete the entries.
+ for (UPInt i = 0, n = pTable->SizeMask; i <= n; i++)
+ {
+ Entry* e = &E(i);
+ if (!e->IsEmpty())
+ e->Free();
+ }
+
+ Allocator::Free(pTable);
+ pTable = NULL;
+ }
+ }
+
+
+ void Assign(const SelfType& src)
+ {
+ Clear();
+ if (src.IsEmpty() == false)
+ {
+ SetCapacity(src.GetSize());
+
+ for (ConstIterator it = src.Begin(); it != src.End(); ++it)
+ {
+ Add(*it);
+ }
+ }
+ }
+
+
+ // Remove all entries from the HashSet table.
+ void Clear()
+ {
+ if (pTable)
+ {
+ // Delete the entries.
+ for (UPInt i = 0, n = pTable->SizeMask; i <= n; i++)
+ {
+ Entry* e = &E(i);
+ if (!e->IsEmpty())
+ e->Clear();
+ }
+
+ Allocator::Free(pTable);
+ pTable = NULL;
+ }
+ }
+
+ // Returns true if the HashSet is empty.
+ bool IsEmpty() const
+ {
+ return pTable == NULL || pTable->EntryCount == 0;
+ }
+
+
+ // Set a new or existing value under the key, to the value.
+ // Pass a different class of 'key' so that assignment reference object
+ // can be passed instead of the actual object.
+ template<class CRef>
+ void Set(const CRef& key)
+ {
+ UPInt hashValue = HashF()(key);
+ SPInt index = (SPInt)-1;
+
+ if (pTable != NULL)
+ index = findIndexCore(key, hashValue & pTable->SizeMask);
+
+ if (index >= 0)
+ {
+ E(index).Value = key;
+ }
+ else
+ {
+ // Entry under key doesn't exist.
+ add(key, hashValue);
+ }
+ }
+
+ template<class CRef>
+ inline void Add(const CRef& key)
+ {
+ UPInt hashValue = HashF()(key);
+ add(key, hashValue);
+ }
+
+ // Remove by alternative key.
+ template<class K>
+ void RemoveAlt(const K& key)
+ {
+ if (pTable == NULL)
+ return;
+
+ UPInt hashValue = AltHashF()(key);
+ SPInt index = hashValue & pTable->SizeMask;
+
+ Entry* e = &E(index);
+
+ // If empty node or occupied by collider, we have nothing to remove.
+ if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != (UPInt)index))
+ return;
+
+ // Save index
+ SPInt naturalIndex = index;
+ SPInt prevIndex = -1;
+
+ while ((e->GetCachedHash(pTable->SizeMask) != (UPInt)naturalIndex) || !(e->Value == key))
+ {
+ // Keep looking through the chain.
+ prevIndex = index;
+ index = e->NextInChain;
+ if (index == -1)
+ return; // End of chain, item not found
+ e = &E(index);
+ }
+
+ // Found it - our item is at index
+ if (naturalIndex == index)
+ {
+ // If we have a follower, move it to us
+ if (!e->IsEndOfChain())
+ {
+ Entry* enext = &E(e->NextInChain);
+ e->Clear();
+ new (e) Entry(*enext);
+ // Point us to the follower's cell that will be cleared
+ e = enext;
+ }
+ }
+ else
+ {
+ // We are not at natural index, so deal with the prev items next index
+ E(prevIndex).NextInChain = e->NextInChain;
+ }
+
+ // Clear us, of the follower cell that was moved.
+ e->Clear();
+ pTable->EntryCount --;
+ // Should we check the size to condense hash? ...
+ }
+
+ // Remove by main key.
+ template<class CRef>
+ void Remove(const CRef& key)
+ {
+ RemoveAlt(key);
+ }
+
+ // Retrieve the pointer to a value under the given key.
+ // - If there's no value under the key, then return NULL.
+ // - If there is a value, return the pointer.
+ template<class K>
+ C* Get(const K& key)
+ {
+ SPInt index = findIndex(key);
+ if (index >= 0)
+ return &E(index).Value;
+ return 0;
+ }
+
+ template<class K>
+ const C* Get(const K& key) const
+ {
+ SPInt index = findIndex(key);
+ if (index >= 0)
+ return &E(index).Value;
+ return 0;
+ }
+
+ // Alternative key versions of Get. Used by Hash.
+ template<class K>
+ const C* GetAlt(const K& key) const
+ {
+ SPInt index = findIndexAlt(key);
+ if (index >= 0)
+ return &E(index).Value;
+ return 0;
+ }
+
+ template<class K>
+ C* GetAlt(const K& key)
+ {
+ SPInt index = findIndexAlt(key);
+ if (index >= 0)
+ return &E(index).Value;
+ return 0;
+ }
+
+ template<class K>
+ bool GetAlt(const K& key, C* pval) const
+ {
+ SPInt index = findIndexAlt(key);
+ if (index >= 0)
+ {
+ if (pval)
+ *pval = E(index).Value;
+ return true;
+ }
+ return false;
+ }
+
+
+ UPInt GetSize() const
+ {
+ return pTable == NULL ? 0 : (UPInt)pTable->EntryCount;
+ }
+
+
+ // Resize the HashSet table to fit one more Entry. Often this
+ // doesn't involve any action.
+ void CheckExpand()
+ {
+ if (pTable == NULL)
+ {
+ // Initial creation of table. Make a minimum-sized table.
+ setRawCapacity(HashMinSize);
+ }
+ else if (pTable->EntryCount * 5 > (pTable->SizeMask + 1) * 4)
+ {
+ // pTable is more than 5/4 ths full. Expand.
+ setRawCapacity((pTable->SizeMask + 1) * 2);
+ }
+ }
+
+ // Hint the bucket count to >= n.
+ void Resize(UPInt n)
+ {
+ // Not really sure what this means in relation to
+ // STLport's hash_map... they say they "increase the
+ // bucket count to at least n" -- but does that mean
+ // their real capacity after Resize(n) is more like
+ // n*2 (since they do linked-list chaining within
+ // buckets?).
+ SetCapacity(n);
+ }
+
+ // Size the HashSet so that it can comfortably contain the given
+ // number of elements. If the HashSet already contains more
+ // elements than newSize, then this may be a no-op.
+ void SetCapacity(UPInt newSize)
+ {
+ UPInt newRawSize = (newSize * 5) / 4;
+ if (newRawSize <= GetSize())
+ return;
+ setRawCapacity(newRawSize);
+ }
+
+ // Disable inappropriate 'operator ->' warning on MSVC6.
+#ifdef OVR_CC_MSVC
+#if (OVR_CC_MSVC < 1300)
+# pragma warning(disable : 4284)
+#endif
+#endif
+
+ // Iterator API, like STL.
+ struct ConstIterator
+ {
+ const C& operator * () const
+ {
+ OVR_ASSERT(Index >= 0 && Index <= (SPInt)pHash->pTable->SizeMask);
+ return pHash->E(Index).Value;
+ }
+
+ const C* operator -> () const
+ {
+ OVR_ASSERT(Index >= 0 && Index <= (SPInt)pHash->pTable->SizeMask);
+ return &pHash->E(Index).Value;
+ }
+
+ void operator ++ ()
+ {
+ // Find next non-empty Entry.
+ if (Index <= (SPInt)pHash->pTable->SizeMask)
+ {
+ Index++;
+ while ((UPInt)Index <= pHash->pTable->SizeMask &&
+ pHash->E(Index).IsEmpty())
+ {
+ Index++;
+ }
+ }
+ }
+
+ bool operator == (const ConstIterator& it) const
+ {
+ if (IsEnd() && it.IsEnd())
+ {
+ return true;
+ }
+ else
+ {
+ return (pHash == it.pHash) && (Index == it.Index);
+ }
+ }
+
+ bool operator != (const ConstIterator& it) const
+ {
+ return ! (*this == it);
+ }
+
+
+ bool IsEnd() const
+ {
+ return (pHash == NULL) ||
+ (pHash->pTable == NULL) ||
+ (Index > (SPInt)pHash->pTable->SizeMask);
+ }
+
+ ConstIterator()
+ : pHash(NULL), Index(0)
+ { }
+
+ public:
+ // Constructor was intentionally made public to allow create
+ // iterator with arbitrary index.
+ ConstIterator(const SelfType* h, SPInt index)
+ : pHash(h), Index(index)
+ { }
+
+ const SelfType* GetContainer() const
+ {
+ return pHash;
+ }
+ SPInt GetIndex() const
+ {
+ return Index;
+ }
+
+ protected:
+ friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>;
+
+ const SelfType* pHash;
+ SPInt Index;
+ };
+
+ friend struct ConstIterator;
+
+
+ // Non-const Iterator; Get most of it from ConstIterator.
+ struct Iterator : public ConstIterator
+ {
+ // Allow non-const access to entries.
+ C& operator*() const
+ {
+ OVR_ASSERT(ConstIterator::Index >= 0 && ConstIterator::Index <= (SPInt)ConstIterator::pHash->pTable->SizeMask);
+ return const_cast<SelfType*>(ConstIterator::pHash)->E(ConstIterator::Index).Value;
+ }
+
+ C* operator->() const
+ {
+ return &(operator*());
+ }
+
+ Iterator()
+ : ConstIterator(NULL, 0)
+ { }
+
+ // Removes current element from Hash
+ void Remove()
+ {
+ RemoveAlt(operator*());
+ }
+
+ template <class K>
+ void RemoveAlt(const K& key)
+ {
+ SelfType* phash = const_cast<SelfType*>(ConstIterator::pHash);
+ //Entry* ee = &phash->E(ConstIterator::Index);
+ //const C& key = ee->Value;
+
+ UPInt hashValue = AltHashF()(key);
+ SPInt index = hashValue & phash->pTable->SizeMask;
+
+ Entry* e = &phash->E(index);
+
+ // If empty node or occupied by collider, we have nothing to remove.
+ if (e->IsEmpty() || (e->GetCachedHash(phash->pTable->SizeMask) != (UPInt)index))
+ return;
+
+ // Save index
+ SPInt naturalIndex = index;
+ SPInt prevIndex = -1;
+
+ while ((e->GetCachedHash(phash->pTable->SizeMask) != (UPInt)naturalIndex) || !(e->Value == key))
+ {
+ // Keep looking through the chain.
+ prevIndex = index;
+ index = e->NextInChain;
+ if (index == -1)
+ return; // End of chain, item not found
+ e = &phash->E(index);
+ }
+
+ if (index == (SPInt)ConstIterator::Index)
+ {
+ // Found it - our item is at index
+ if (naturalIndex == index)
+ {
+ // If we have a follower, move it to us
+ if (!e->IsEndOfChain())
+ {
+ Entry* enext = &phash->E(e->NextInChain);
+ e->Clear();
+ new (e) Entry(*enext);
+ // Point us to the follower's cell that will be cleared
+ e = enext;
+ --ConstIterator::Index;
+ }
+ }
+ else
+ {
+ // We are not at natural index, so deal with the prev items next index
+ phash->E(prevIndex).NextInChain = e->NextInChain;
+ }
+
+ // Clear us, of the follower cell that was moved.
+ e->Clear();
+ phash->pTable->EntryCount --;
+ }
+ else
+ OVR_ASSERT(0); //?
+ }
+
+ private:
+ friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>;
+
+ Iterator(SelfType* h, SPInt i0)
+ : ConstIterator(h, i0)
+ { }
+ };
+
+ friend struct Iterator;
+
+ Iterator Begin()
+ {
+ if (pTable == 0)
+ return Iterator(NULL, 0);
+
+ // Scan till we hit the First valid Entry.
+ UPInt i0 = 0;
+ while (i0 <= pTable->SizeMask && E(i0).IsEmpty())
+ {
+ i0++;
+ }
+ return Iterator(this, i0);
+ }
+ Iterator End() { return Iterator(NULL, 0); }
+
+ ConstIterator Begin() const { return const_cast<SelfType*>(this)->Begin(); }
+ ConstIterator End() const { return const_cast<SelfType*>(this)->End(); }
+
+ template<class K>
+ Iterator Find(const K& key)
+ {
+ SPInt index = findIndex(key);
+ if (index >= 0)
+ return Iterator(this, index);
+ return Iterator(NULL, 0);
+ }
+
+ template<class K>
+ Iterator FindAlt(const K& key)
+ {
+ SPInt index = findIndexAlt(key);
+ if (index >= 0)
+ return Iterator(this, index);
+ return Iterator(NULL, 0);
+ }
+
+ template<class K>
+ ConstIterator Find(const K& key) const { return const_cast<SelfType*>(this)->Find(key); }
+
+ template<class K>
+ ConstIterator FindAlt(const K& key) const { return const_cast<SelfType*>(this)->FindAlt(key); }
+
+private:
+ // Find the index of the matching Entry. If no match, then return -1.
+ template<class K>
+ SPInt findIndex(const K& key) const
+ {
+ if (pTable == NULL)
+ return -1;
+ UPInt hashValue = HashF()(key) & pTable->SizeMask;
+ return findIndexCore(key, hashValue);
+ }
+
+ template<class K>
+ SPInt findIndexAlt(const K& key) const
+ {
+ if (pTable == NULL)
+ return -1;
+ UPInt hashValue = AltHashF()(key) & pTable->SizeMask;
+ return findIndexCore(key, hashValue);
+ }
+
+ // Find the index of the matching Entry. If no match, then return -1.
+ template<class K>
+ SPInt findIndexCore(const K& key, UPInt hashValue) const
+ {
+ // Table must exist.
+ OVR_ASSERT(pTable != 0);
+ // Hash key must be 'and-ed' by the caller.
+ OVR_ASSERT((hashValue & ~pTable->SizeMask) == 0);
+
+ UPInt index = hashValue;
+ const Entry* e = &E(index);
+
+ // If empty or occupied by a collider, not found.
+ if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != index))
+ return -1;
+
+ while(1)
+ {
+ OVR_ASSERT(e->GetCachedHash(pTable->SizeMask) == hashValue);
+
+ if (e->GetCachedHash(pTable->SizeMask) == hashValue && e->Value == key)
+ {
+ // Found it.
+ return index;
+ }
+ // Values can not be equal at this point.
+ // That would mean that the hash key for the same value differs.
+ OVR_ASSERT(!(e->Value == key));
+
+ // Keep looking through the chain.
+ index = e->NextInChain;
+ if (index == (UPInt)-1)
+ break; // end of chain
+
+ e = &E(index);
+ OVR_ASSERT(!e->IsEmpty());
+ }
+ return -1;
+ }
+
+
+ // Add a new value to the HashSet table, under the specified key.
+ template<class CRef>
+ void add(const CRef& key, UPInt hashValue)
+ {
+ CheckExpand();
+ hashValue &= pTable->SizeMask;
+
+ pTable->EntryCount++;
+
+ SPInt index = hashValue;
+ Entry* naturalEntry = &(E(index));
+
+ if (naturalEntry->IsEmpty())
+ {
+ // Put the new Entry in.
+ new (naturalEntry) Entry(key, -1);
+ }
+ else
+ {
+ // Find a blank spot.
+ SPInt blankIndex = index;
+ do {
+ blankIndex = (blankIndex + 1) & pTable->SizeMask;
+ } while(!E(blankIndex).IsEmpty());
+
+ Entry* blankEntry = &E(blankIndex);
+
+ if (naturalEntry->GetCachedHash(pTable->SizeMask) == (UPInt)index)
+ {
+ // Collision. Link into this chain.
+
+ // Move existing list head.
+ new (blankEntry) Entry(*naturalEntry); // placement new, copy ctor
+
+ // Put the new info in the natural Entry.
+ naturalEntry->Value = key;
+ naturalEntry->NextInChain = blankIndex;
+ }
+ else
+ {
+ // Existing Entry does not naturally
+ // belong in this slot. Existing
+ // Entry must be moved.
+
+ // Find natural location of collided element (i.e. root of chain)
+ SPInt collidedIndex = naturalEntry->GetCachedHash(pTable->SizeMask);
+ OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (SPInt)pTable->SizeMask);
+ for (;;)
+ {
+ Entry* e = &E(collidedIndex);
+ if (e->NextInChain == index)
+ {
+ // Here's where we need to splice.
+ new (blankEntry) Entry(*naturalEntry);
+ e->NextInChain = blankIndex;
+ break;
+ }
+ collidedIndex = e->NextInChain;
+ OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (SPInt)pTable->SizeMask);
+ }
+
+ // Put the new data in the natural Entry.
+ naturalEntry->Value = key;
+ naturalEntry->NextInChain = -1;
+ }
+ }
+
+ // Record hash value: has effect only if cached node is used.
+ naturalEntry->SetCachedHash(hashValue);
+ }
+
+ // Index access helpers.
+ Entry& E(UPInt index)
+ {
+ // Must have pTable and access needs to be within bounds.
+ OVR_ASSERT(index <= pTable->SizeMask);
+ return *(((Entry*) (pTable + 1)) + index);
+ }
+ const Entry& E(UPInt index) const
+ {
+ OVR_ASSERT(index <= pTable->SizeMask);
+ return *(((Entry*) (pTable + 1)) + index);
+ }
+
+
+ // Resize the HashSet table to the given size (Rehash the
+ // contents of the current table). The arg is the number of
+ // HashSet table entries, not the number of elements we should
+ // actually contain (which will be less than this).
+ void setRawCapacity(UPInt newSize)
+ {
+ if (newSize == 0)
+ {
+ // Special case.
+ Clear();
+ return;
+ }
+
+ // Minimum size; don't incur rehashing cost when expanding
+ // very small tables. Not that we perform this check before
+ // 'log2f' call to avoid fp exception with newSize == 1.
+ if (newSize < HashMinSize)
+ newSize = HashMinSize;
+ else
+ {
+ // Force newSize to be a power of two.
+ int bits = Alg::UpperBit(newSize-1) + 1; // Chop( Log2f((float)(newSize-1)) + 1);
+ OVR_ASSERT((UPInt(1) << bits) >= newSize);
+ newSize = UPInt(1) << bits;
+ }
+
+ SelfType newHash;
+ newHash.pTable = (TableType*)
+ Allocator::Alloc(
+ sizeof(TableType) + sizeof(Entry) * newSize);
+ // Need to do something on alloc failure!
+ OVR_ASSERT(newHash.pTable);
+
+ newHash.pTable->EntryCount = 0;
+ newHash.pTable->SizeMask = newSize - 1;
+ UPInt i, n;
+
+ // Mark all entries as empty.
+ for (i = 0; i < newSize; i++)
+ newHash.E(i).NextInChain = -2;
+
+ // Copy stuff to newHash
+ if (pTable)
+ {
+ for (i = 0, n = pTable->SizeMask; i <= n; i++)
+ {
+ Entry* e = &E(i);
+ if (e->IsEmpty() == false)
+ {
+ // Insert old Entry into new HashSet.
+ newHash.Add(e->Value);
+ // placement delete of old element
+ e->Clear();
+ }
+ }
+
+ // Delete our old data buffer.
+ Allocator::Free(pTable);
+ }
+
+ // Steal newHash's data.
+ pTable = newHash.pTable;
+ newHash.pTable = NULL;
+ }
+
+ struct TableType
+ {
+ UPInt EntryCount;
+ UPInt SizeMask;
+ // Entry array follows this structure
+ // in memory.
+ };
+ TableType* pTable;
+};
+
+
+
+//-----------------------------------------------------------------------------------
+template<class C, class HashF = FixedSizeHash<C>,
+ class AltHashF = HashF,
+ class Allocator = ContainerAllocator<C>,
+ class Entry = HashsetCachedEntry<C, HashF> >
+class HashSet : public HashSetBase<C, HashF, AltHashF, Allocator, Entry>
+{
+public:
+ typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> BaseType;
+ typedef HashSet<C, HashF, AltHashF, Allocator, Entry> SelfType;
+
+ HashSet() { }
+ HashSet(int sizeHint) : BaseType(sizeHint) { }
+ HashSet(const SelfType& src) : BaseType(src) { }
+ ~HashSet() { }
+
+ void operator = (const SelfType& src) { BaseType::Assign(src); }
+
+ // Set a new or existing value under the key, to the value.
+ // Pass a different class of 'key' so that assignment reference object
+ // can be passed instead of the actual object.
+ template<class CRef>
+ void Set(const CRef& key)
+ {
+ BaseType::Set(key);
+ }
+
+ template<class CRef>
+ inline void Add(const CRef& key)
+ {
+ BaseType::Add(key);
+ }
+
+ // Hint the bucket count to >= n.
+ void Resize(UPInt n)
+ {
+ BaseType::SetCapacity(n);
+ }
+
+ // Size the HashSet so that it can comfortably contain the given
+ // number of elements. If the HashSet already contains more
+ // elements than newSize, then this may be a no-op.
+ void SetCapacity(UPInt newSize)
+ {
+ BaseType::SetCapacity(newSize);
+ }
+
+};
+
+// HashSet with uncached hash code; declared for convenience.
+template<class C, class HashF = FixedSizeHash<C>,
+ class AltHashF = HashF,
+ class Allocator = ContainerAllocator<C> >
+class HashSetUncached : public HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> >
+{
+public:
+
+ typedef HashSetUncached<C, HashF, AltHashF, Allocator> SelfType;
+ typedef HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> > BaseType;
+
+ // Delegated constructors.
+ HashSetUncached() { }
+ HashSetUncached(int sizeHint) : BaseType(sizeHint) { }
+ HashSetUncached(const SelfType& src) : BaseType(src) { }
+ ~HashSetUncached() { }
+
+ void operator = (const SelfType& src)
+ {
+ BaseType::operator = (src);
+ }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Hash hash table implementation
+
+// Node for Hash - necessary so that Hash can delegate its implementation
+// to HashSet.
+template<class C, class U, class HashF>
+struct HashNode
+{
+ typedef HashNode<C, U, HashF> SelfType;
+ typedef C FirstType;
+ typedef U SecondType;
+
+ C First;
+ U Second;
+
+ // NodeRef is used to allow passing of elements into HashSet
+ // without using a temporary object.
+ struct NodeRef
+ {
+ const C* pFirst;
+ const U* pSecond;
+
+ NodeRef(const C& f, const U& s) : pFirst(&f), pSecond(&s) { }
+ NodeRef(const NodeRef& src) : pFirst(src.pFirst), pSecond(src.pSecond) { }
+
+ // Enable computation of ghash_node_hashf.
+ inline UPInt GetHash() const { return HashF()(*pFirst); }
+ // Necessary conversion to allow HashNode::operator == to work.
+ operator const C& () const { return *pFirst; }
+ };
+
+ // Note: No default constructor is necessary.
+ HashNode(const HashNode& src) : First(src.First), Second(src.Second) { }
+ HashNode(const NodeRef& src) : First(*src.pFirst), Second(*src.pSecond) { }
+ void operator = (const NodeRef& src) { First = *src.pFirst; Second = *src.pSecond; }
+
+ template<class K>
+ bool operator == (const K& src) const { return (First == src); }
+
+ template<class K>
+ static UPInt CalcHash(const K& data) { return HashF()(data); }
+ inline UPInt GetHash() const { return HashF()(First); }
+
+ // Hash functors used with this node. A separate functor is used for alternative
+ // key lookup so that it does not need to access the '.First' element.
+ struct NodeHashF
+ {
+ template<class K>
+ UPInt operator()(const K& data) const { return data.GetHash(); }
+ };
+ struct NodeAltHashF
+ {
+ template<class K>
+ UPInt operator()(const K& data) const { return HashNode<C,U,HashF>::CalcHash(data); }
+ };
+};
+
+
+
+// **** Extra hashset_entry types to allow NodeRef construction.
+
+// The big difference between the below types and the ones used in hash_set is that
+// these allow initializing the node with 'typename C::NodeRef& keyRef', which
+// is critical to avoid temporary node allocation on stack when using placement new.
+
+// Compact hash table Entry type that re-computes hash keys during hash traversal.
+// Good to use if the hash function is cheap or the hash value is already cached in C.
+template<class C, class HashF>
+class HashsetNodeEntry
+{
+public:
+ // Internal chaining for collisions.
+ SPInt NextInChain;
+ C Value;
+
+ HashsetNodeEntry()
+ : NextInChain(-2) { }
+ HashsetNodeEntry(const HashsetNodeEntry& e)
+ : NextInChain(e.NextInChain), Value(e.Value) { }
+ HashsetNodeEntry(const C& key, SPInt next)
+ : NextInChain(next), Value(key) { }
+ HashsetNodeEntry(const typename C::NodeRef& keyRef, SPInt next)
+ : NextInChain(next), Value(keyRef) { }
+
+ bool IsEmpty() const { return NextInChain == -2; }
+ bool IsEndOfChain() const { return NextInChain == -1; }
+ UPInt GetCachedHash(UPInt maskValue) const { return HashF()(Value) & maskValue; }
+ void SetCachedHash(UPInt hashValue) { OVR_UNUSED(hashValue); }
+
+ void Clear()
+ {
+ Value.~C(); // placement delete
+ NextInChain = -2;
+ }
+ // Free is only used from dtor of hash; Clear is used during regular operations:
+ // assignment, hash reallocations, value reassignments, so on.
+ void Free() { Clear(); }
+};
+
+// Hash table Entry type that caches the Entry hash value for nodes, so that it
+// does not need to be re-computed during access.
+template<class C, class HashF>
+class HashsetCachedNodeEntry
+{
+public:
+ // Internal chaining for collisions.
+ SPInt NextInChain;
+ UPInt HashValue;
+ C Value;
+
+ HashsetCachedNodeEntry()
+ : NextInChain(-2) { }
+ HashsetCachedNodeEntry(const HashsetCachedNodeEntry& e)
+ : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { }
+ HashsetCachedNodeEntry(const C& key, SPInt next)
+ : NextInChain(next), Value(key) { }
+ HashsetCachedNodeEntry(const typename C::NodeRef& keyRef, SPInt next)
+ : NextInChain(next), Value(keyRef) { }
+
+ bool IsEmpty() const { return NextInChain == -2; }
+ bool IsEndOfChain() const { return NextInChain == -1; }
+ UPInt GetCachedHash(UPInt maskValue) const { OVR_UNUSED(maskValue); return HashValue; }
+ void SetCachedHash(UPInt hashValue) { HashValue = hashValue; }
+
+ void Clear()
+ {
+ Value.~C();
+ NextInChain = -2;
+ }
+ // Free is only used from dtor of hash; Clear is used during regular operations:
+ // assignment, hash reallocations, value reassignments, so on.
+ void Free() { Clear(); }
+};
+
+
+//-----------------------------------------------------------------------------------
+template<class C, class U,
+ class HashF = FixedSizeHash<C>,
+ class Allocator = ContainerAllocator<C>,
+ class HashNode = OVR::HashNode<C,U,HashF>,
+ class Entry = HashsetCachedNodeEntry<HashNode, typename HashNode::NodeHashF>,
+ class Container = HashSet<HashNode, typename HashNode::NodeHashF,
+ typename HashNode::NodeAltHashF, Allocator,
+ Entry> >
+class Hash
+{
+public:
+ OVR_MEMORY_REDEFINE_NEW(Hash)
+
+ // Types used for hash_set.
+ typedef U ValueType;
+ typedef Hash<C, U, HashF, Allocator, HashNode, Entry, Container> SelfType;
+
+ // Actual hash table itself, implemented as hash_set.
+ Container mHash;
+
+public:
+ Hash() { }
+ Hash(int sizeHint) : mHash(sizeHint) { }
+ Hash(const SelfType& src) : mHash(src.mHash) { }
+ ~Hash() { }
+
+ void operator = (const SelfType& src) { mHash = src.mHash; }
+
+ // Remove all entries from the Hash table.
+ inline void Clear() { mHash.Clear(); }
+ // Returns true if the Hash is empty.
+ inline bool IsEmpty() const { return mHash.IsEmpty(); }
+
+ // Access (set).
+ inline void Set(const C& key, const U& value)
+ {
+ typename HashNode::NodeRef e(key, value);
+ mHash.Set(e);
+ }
+ inline void Add(const C& key, const U& value)
+ {
+ typename HashNode::NodeRef e(key, value);
+ mHash.Add(e);
+ }
+
+ // Removes an element by clearing its Entry.
+ inline void Remove(const C& key)
+ {
+ mHash.RemoveAlt(key);
+ }
+ template<class K>
+ inline void RemoveAlt(const K& key)
+ {
+ mHash.RemoveAlt(key);
+ }
+
+ // Retrieve the value under the given key.
+ // - If there's no value under the key, then return false and leave *pvalue alone.
+ // - If there is a value, return true, and Set *Pvalue to the Entry's value.
+ // - If value == NULL, return true or false according to the presence of the key.
+ bool Get(const C& key, U* pvalue) const
+ {
+ const HashNode* p = mHash.GetAlt(key);
+ if (p)
+ {
+ if (pvalue)
+ *pvalue = p->Second;
+ return true;
+ }
+ return false;
+ }
+
+ template<class K>
+ bool GetAlt(const K& key, U* pvalue) const
+ {
+ const HashNode* p = mHash.GetAlt(key);
+ if (p)
+ {
+ if (pvalue)
+ *pvalue = p->Second;
+ return true;
+ }
+ return false;
+ }
+
+ // Retrieve the pointer to a value under the given key.
+ // - If there's no value under the key, then return NULL.
+ // - If there is a value, return the pointer.
+ inline U* Get(const C& key)
+ {
+ HashNode* p = mHash.GetAlt(key);
+ return p ? &p->Second : 0;
+ }
+ inline const U* Get(const C& key) const
+ {
+ const HashNode* p = mHash.GetAlt(key);
+ return p ? &p->Second : 0;
+ }
+
+ template<class K>
+ inline U* GetAlt(const K& key)
+ {
+ HashNode* p = mHash.GetAlt(key);
+ return p ? &p->Second : 0;
+ }
+ template<class K>
+ inline const U* GetAlt(const K& key) const
+ {
+ const HashNode* p = mHash.GetAlt(key);
+ return p ? &p->Second : 0;
+ }
+
+ // Sizing methods - delegate to Hash.
+ inline UPInt GetSize() const { return mHash.GetSize(); }
+ inline void Resize(UPInt n) { mHash.Resize(n); }
+ inline void SetCapacity(UPInt newSize) { mHash.SetCapacity(newSize); }
+
+ // Iterator API, like STL.
+ typedef typename Container::ConstIterator ConstIterator;
+ typedef typename Container::Iterator Iterator;
+
+ inline Iterator Begin() { return mHash.Begin(); }
+ inline Iterator End() { return mHash.End(); }
+ inline ConstIterator Begin() const { return mHash.Begin(); }
+ inline ConstIterator End() const { return mHash.End(); }
+
+ Iterator Find(const C& key) { return mHash.FindAlt(key); }
+ ConstIterator Find(const C& key) const { return mHash.FindAlt(key); }
+
+ template<class K>
+ Iterator FindAlt(const K& key) { return mHash.FindAlt(key); }
+ template<class K>
+ ConstIterator FindAlt(const K& key) const { return mHash.FindAlt(key); }
+};
+
+
+
+// Hash with uncached hash code; declared for convenience.
+template<class C, class U, class HashF = FixedSizeHash<C>, class Allocator = ContainerAllocator<C> >
+class HashUncached
+ : public Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>,
+ HashsetNodeEntry<HashNode<C,U,HashF>, typename HashNode<C,U,HashF>::NodeHashF> >
+{
+public:
+ typedef HashUncached<C, U, HashF, Allocator> SelfType;
+ typedef Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>,
+ HashsetNodeEntry<HashNode<C,U,HashF>,
+ typename HashNode<C,U,HashF>::NodeHashF> > BaseType;
+
+ // Delegated constructors.
+ HashUncached() { }
+ HashUncached(int sizeHint) : BaseType(sizeHint) { }
+ HashUncached(const SelfType& src) : BaseType(src) { }
+ ~HashUncached() { }
+ void operator = (const SelfType& src) { BaseType::operator = (src); }
+};
+
+
+
+// And identity hash in which keys serve as hash value. Can be uncached,
+// since hash computation is assumed cheap.
+template<class C, class U, class Allocator = ContainerAllocator<C>, class HashF = IdentityHash<C> >
+class HashIdentity
+ : public HashUncached<C, U, HashF, Allocator>
+{
+public:
+ typedef HashIdentity<C, U, Allocator, HashF> SelfType;
+ typedef HashUncached<C, U, HashF, Allocator> BaseType;
+
+ // Delegated constructors.
+ HashIdentity() { }
+ HashIdentity(int sizeHint) : BaseType(sizeHint) { }
+ HashIdentity(const SelfType& src) : BaseType(src) { }
+ ~HashIdentity() { }
+ void operator = (const SelfType& src) { BaseType::operator = (src); }
+};
+
+
+} // OVR
+
+
+#ifdef OVR_DEFINE_NEW
+#define new OVR_DEFINE_NEW
+#endif
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_KeyCodes.h b/LibOVR/Src/Kernel/OVR_KeyCodes.h new file mode 100644 index 0000000..647688a --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_KeyCodes.h @@ -0,0 +1,240 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_KeyCodes.h
+Content : Common keyboard constants
+Created : September 19, 2012
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_KeyCodes_h
+#define OVR_KeyCodes_h
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** KeyCode
+
+// KeyCode enumeration defines platform-independent keyboard key constants.
+// Note that Key_A through Key_Z are mapped to capital ascii constants.
+
+enum KeyCode
+{
+ // Key_None indicates that no key was specified.
+ Key_None = 0,
+
+ // A through Z and numbers 0 through 9.
+ Key_A = 65,
+ Key_B,
+ Key_C,
+ Key_D,
+ Key_E,
+ Key_F,
+ Key_G,
+ Key_H,
+ Key_I,
+ Key_J,
+ Key_K,
+ Key_L,
+ Key_M,
+ Key_N,
+ Key_O,
+ Key_P,
+ Key_Q,
+ Key_R,
+ Key_S,
+ Key_T,
+ Key_U,
+ Key_V,
+ Key_W,
+ Key_X,
+ Key_Y,
+ Key_Z,
+ Key_Num0 = 48,
+ Key_Num1,
+ Key_Num2,
+ Key_Num3,
+ Key_Num4,
+ Key_Num5,
+ Key_Num6,
+ Key_Num7,
+ Key_Num8,
+ Key_Num9,
+
+ // Numeric keypad.
+ Key_KP_0 = 0xa0,
+ Key_KP_1,
+ Key_KP_2,
+ Key_KP_3,
+ Key_KP_4,
+ Key_KP_5,
+ Key_KP_6,
+ Key_KP_7,
+ Key_KP_8,
+ Key_KP_9,
+ Key_KP_Multiply,
+ Key_KP_Add,
+ Key_KP_Enter,
+ Key_KP_Subtract,
+ Key_KP_Decimal,
+ Key_KP_Divide,
+
+ // Function keys.
+ Key_F1 = 0xb0,
+ Key_F2,
+ Key_F3,
+ Key_F4,
+ Key_F5,
+ Key_F6,
+ Key_F7,
+ Key_F8,
+ Key_F9,
+ Key_F10,
+ Key_F11,
+ Key_F12,
+ Key_F13,
+ Key_F14,
+ Key_F15,
+
+ // Other keys.
+ Key_Backspace = 8,
+ Key_Tab,
+ Key_Clear = 12,
+ Key_Return,
+ Key_Shift = 16,
+ Key_Control,
+ Key_Alt,
+ Key_Pause,
+ Key_CapsLock = 20, // Toggle
+ Key_Escape = 27,
+ Key_Space = 32,
+ Key_Quote = 39,
+ Key_PageUp = 0xc0,
+ Key_PageDown,
+ Key_End,
+ Key_Home,
+ Key_Left,
+ Key_Up,
+ Key_Right,
+ Key_Down,
+ Key_Insert,
+ Key_Delete,
+ Key_Help,
+
+ Key_Comma = 44,
+ Key_Minus,
+ Key_Slash = 47,
+ Key_Period,
+ Key_NumLock = 144, // Toggle
+ Key_ScrollLock = 145, // Toggle
+
+ Key_Semicolon = 59,
+ Key_Equal = 61,
+ Key_Bar = 192,
+ Key_BracketLeft = 91,
+ Key_Backslash,
+ Key_BracketRight,
+
+ Key_OEM_AX = 0xE1, // 'AX' key on Japanese AX keyboard
+ Key_OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key keyboard.
+ Key_ICO_HELP = 0xE3, // Help key on ICO
+ Key_ICO_00 = 0xE4, // 00 key on ICO
+
+ Key_Meta,
+
+ // Total number of keys.
+ Key_CodeCount
+};
+
+
+//-----------------------------------------------------------------------------------
+
+class KeyModifiers
+{
+public:
+ enum
+ {
+ Key_ShiftPressed = 0x01,
+ Key_CtrlPressed = 0x02,
+ Key_AltPressed = 0x04,
+ Key_MetaPressed = 0x08,
+ Key_CapsToggled = 0x10,
+ Key_NumToggled = 0x20,
+ Key_ScrollToggled = 0x40,
+
+ Initialized_Bit = 0x80,
+ Initialized_Mask = 0xFF
+ };
+ unsigned char States;
+
+ KeyModifiers() : States(0) { }
+ KeyModifiers(unsigned char st) : States((unsigned char)(st | Initialized_Bit)) { }
+
+ void Reset() { States = 0; }
+
+ bool IsShiftPressed() const { return (States & Key_ShiftPressed) != 0; }
+ bool IsCtrlPressed() const { return (States & Key_CtrlPressed) != 0; }
+ bool IsAltPressed() const { return (States & Key_AltPressed) != 0; }
+ bool IsMetaPressed() const { return (States & Key_MetaPressed) != 0; }
+ bool IsCapsToggled() const { return (States & Key_CapsToggled) != 0; }
+ bool IsNumToggled() const { return (States & Key_NumToggled) != 0; }
+ bool IsScrollToggled() const{ return (States & Key_ScrollToggled) != 0; }
+
+ void SetShiftPressed(bool v = true) { (v) ? States |= Key_ShiftPressed : States &= ~Key_ShiftPressed; }
+ void SetCtrlPressed(bool v = true) { (v) ? States |= Key_CtrlPressed : States &= ~Key_CtrlPressed; }
+ void SetAltPressed(bool v = true) { (v) ? States |= Key_AltPressed : States &= ~Key_AltPressed; }
+ void SetMetaPressed(bool v = true) { (v) ? States |= Key_MetaPressed : States &= ~Key_MetaPressed; }
+ void SetCapsToggled(bool v = true) { (v) ? States |= Key_CapsToggled : States &= ~Key_CapsToggled; }
+ void SetNumToggled(bool v = true) { (v) ? States |= Key_NumToggled : States &= ~Key_NumToggled; }
+ void SetScrollToggled(bool v = true) { (v) ? States |= Key_ScrollToggled: States &= ~Key_ScrollToggled; }
+
+ bool IsInitialized() const { return (States & Initialized_Mask) != 0; }
+};
+
+
+//-----------------------------------------------------------------------------------
+
+/*
+enum PadKeyCode
+{
+ Pad_None, // Indicates absence of key code.
+ Pad_Back,
+ Pad_Start,
+ Pad_A,
+ Pad_B,
+ Pad_X,
+ Pad_Y,
+ Pad_R1, // RightShoulder;
+ Pad_L1, // LeftShoulder;
+ Pad_R2, // RightTrigger;
+ Pad_L2, // LeftTrigger;
+ Pad_Up,
+ Pad_Down,
+ Pad_Right,
+ Pad_Left,
+ Pad_Plus,
+ Pad_Minus,
+ Pad_1,
+ Pad_2,
+ Pad_H,
+ Pad_C,
+ Pad_Z,
+ Pad_O,
+ Pad_T,
+ Pad_S,
+ Pad_Select,
+ Pad_Home,
+ Pad_RT, // RightThumb;
+ Pad_LT // LeftThumb;
+};
+*/
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_List.h b/LibOVR/Src/Kernel/OVR_List.h new file mode 100644 index 0000000..0292f51 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_List.h @@ -0,0 +1,325 @@ +/************************************************************************************
+
+PublicHeader: OVR
+Filename : OVR_List.h
+Content : Template implementation for doubly-connected linked List
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_List_h
+#define OVR_List_h
+
+#include "OVR_Types.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** ListNode
+//
+// Base class for the elements of the intrusive linked list.
+// To store elements in the List do:
+//
+// struct MyData : ListNode<MyData>
+// {
+// . . .
+// };
+
+template<class T>
+struct ListNode
+{
+ union {
+ T* pPrev;
+ void* pVoidPrev;
+ };
+ union {
+ T* pNext;
+ void* pVoidNext;
+ };
+
+ void RemoveNode()
+ {
+ pPrev->pNext = pNext;
+ pNext->pPrev = pPrev;
+ }
+
+ // Removes us from the list and inserts pnew there instead.
+ void ReplaceNodeWith(T* pnew)
+ {
+ pPrev->pNext = pnew;
+ pNext->pPrev = pnew;
+ pnew->pPrev = pPrev;
+ pnew->pNext = pNext;
+ }
+
+ // Inserts the argument linked list node after us in the list.
+ void InsertNodeAfter(T* p)
+ {
+ p->pPrev = pNext->pPrev; // this
+ p->pNext = pNext;
+ pNext->pPrev = p;
+ pNext = p;
+ }
+ // Inserts the argument linked list node before us in the list.
+ void InsertNodeBefore(T* p)
+ {
+ p->pNext = pNext->pPrev; // this
+ p->pPrev = pPrev;
+ pPrev->pNext = p;
+ pPrev = p;
+ }
+
+ void Alloc_MoveTo(ListNode<T>* pdest)
+ {
+ pdest->pNext = pNext;
+ pdest->pPrev = pPrev;
+ pPrev->pNext = (T*)pdest;
+ pNext->pPrev = (T*)pdest;
+ }
+};
+
+
+//------------------------------------------------------------------------
+// ***** List
+//
+// Doubly linked intrusive list.
+// The data type must be derived from ListNode.
+//
+// Adding: PushFront(), PushBack().
+// Removing: Remove() - the element must be in the list!
+// Moving: BringToFront(), SendToBack() - the element must be in the list!
+//
+// Iterating:
+// MyData* data = MyList.GetFirst();
+// while (!MyList.IsNull(data))
+// {
+// . . .
+// data = MyList.GetNext(data);
+// }
+//
+// Removing:
+// MyData* data = MyList.GetFirst();
+// while (!MyList.IsNull(data))
+// {
+// MyData* next = MyList.GetNext(data);
+// if (ToBeRemoved(data))
+// MyList.Remove(data);
+// data = next;
+// }
+//
+
+// List<> represents a doubly-linked list if T, where each T must derive
+// from ListNode<B>. B specifies the base class that was directly
+// derived from ListNode, and is only necessary if there is an intermediate
+// inheritance chain.
+
+template<class T, class B = T> class List
+{
+public:
+ typedef T ValueType;
+
+ List()
+ {
+ Root.pNext = Root.pPrev = (ValueType*)&Root;
+ }
+
+ void Clear()
+ {
+ Root.pNext = Root.pPrev = (ValueType*)&Root;
+ }
+
+ const ValueType* GetFirst() const { return (const ValueType*)Root.pNext; }
+ const ValueType* GetLast () const { return (const ValueType*)Root.pPrev; }
+ ValueType* GetFirst() { return (ValueType*)Root.pNext; }
+ ValueType* GetLast () { return (ValueType*)Root.pPrev; }
+
+ // Determine if list is empty (i.e.) points to itself.
+ // Go through void* access to avoid issues with strict-aliasing optimizing out the
+ // access after RemoveNode(), etc.
+ bool IsEmpty() const { return Root.pVoidNext == (const T*)(const B*)&Root; }
+ bool IsFirst(const ValueType* p) const { return p == Root.pNext; }
+ bool IsLast (const ValueType* p) const { return p == Root.pPrev; }
+ bool IsNull (const ValueType* p) const { return p == (const T*)(const B*)&Root; }
+
+ inline static const ValueType* GetPrev(const ValueType* p) { return (const ValueType*)p->pPrev; }
+ inline static const ValueType* GetNext(const ValueType* p) { return (const ValueType*)p->pNext; }
+ inline static ValueType* GetPrev( ValueType* p) { return (ValueType*)p->pPrev; }
+ inline static ValueType* GetNext( ValueType* p) { return (ValueType*)p->pNext; }
+
+ void PushFront(ValueType* p)
+ {
+ p->pNext = Root.pNext;
+ p->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = p;
+ Root.pNext = p;
+ }
+
+ void PushBack(ValueType* p)
+ {
+ p->pPrev = Root.pPrev;
+ p->pNext = (ValueType*)&Root;
+ Root.pPrev->pNext = p;
+ Root.pPrev = p;
+ }
+
+ static void Remove(ValueType* p)
+ {
+ p->pPrev->pNext = p->pNext;
+ p->pNext->pPrev = p->pPrev;
+ }
+
+ void BringToFront(ValueType* p)
+ {
+ Remove(p);
+ PushFront(p);
+ }
+
+ void SendToBack(ValueType* p)
+ {
+ Remove(p);
+ PushBack(p);
+ }
+
+ // Appends the contents of the argument list to the front of this list;
+ // items are removed from the argument list.
+ void PushListToFront(List<T>& src)
+ {
+ if (!src.IsEmpty())
+ {
+ ValueType* pfirst = src.GetFirst();
+ ValueType* plast = src.GetLast();
+ src.Clear();
+ plast->pNext = Root.pNext;
+ pfirst->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = plast;
+ Root.pNext = pfirst;
+ }
+ }
+
+ void PushListToBack(List<T>& src)
+ {
+ if (!src.IsEmpty())
+ {
+ ValueType* pfirst = src.GetFirst();
+ ValueType* plast = src.GetLast();
+ src.Clear();
+ plast->pNext = (ValueType*)&Root;
+ pfirst->pPrev = Root.pPrev;
+ Root.pPrev->pNext = pfirst;
+ Root.pPrev = plast;
+ }
+ }
+
+ // Removes all source list items after (and including) the 'pfirst' node from the
+ // source list and adds them to out list.
+ void PushFollowingListItemsToFront(List<T>& src, ValueType *pfirst)
+ {
+ if (pfirst != &src.Root)
+ {
+ ValueType *plast = src.Root.pPrev;
+
+ // Remove list remainder from source.
+ pfirst->pPrev->pNext = (ValueType*)&src.Root;
+ src.Root.pPrev = pfirst->pPrev;
+ // Add the rest of the items to list.
+ plast->pNext = Root.pNext;
+ pfirst->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = plast;
+ Root.pNext = pfirst;
+ }
+ }
+
+ // Removes all source list items up to but NOT including the 'pend' node from the
+ // source list and adds them to out list.
+ void PushPrecedingListItemsToFront(List<T>& src, ValueType *ptail)
+ {
+ if (src.GetFirst() != ptail)
+ {
+ ValueType *pfirst = src.Root.pNext;
+ ValueType *plast = ptail->pPrev;
+
+ // Remove list remainder from source.
+ ptail->pPrev = (ValueType*)&src.Root;
+ src.Root.pNext = ptail;
+
+ // Add the rest of the items to list.
+ plast->pNext = Root.pNext;
+ pfirst->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = plast;
+ Root.pNext = pfirst;
+ }
+ }
+
+
+ // Removes a range of source list items starting at 'pfirst' and up to, but not including 'pend',
+ // and adds them to out list. Note that source items MUST already be in the list.
+ void PushListItemsToFront(ValueType *pfirst, ValueType *pend)
+ {
+ if (pfirst != pend)
+ {
+ ValueType *plast = pend->pPrev;
+
+ // Remove list remainder from source.
+ pfirst->pPrev->pNext = pend;
+ pend->pPrev = pfirst->pPrev;
+ // Add the rest of the items to list.
+ plast->pNext = Root.pNext;
+ pfirst->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = plast;
+ Root.pNext = pfirst;
+ }
+ }
+
+
+ void Alloc_MoveTo(List<T>* pdest)
+ {
+ if (IsEmpty())
+ pdest->Clear();
+ else
+ {
+ pdest->Root.pNext = Root.pNext;
+ pdest->Root.pPrev = Root.pPrev;
+
+ Root.pNext->pPrev = (ValueType*)&pdest->Root;
+ Root.pPrev->pNext = (ValueType*)&pdest->Root;
+ }
+ }
+
+
+private:
+ // Copying is prohibited
+ List(const List<T>&);
+ const List<T>& operator = (const List<T>&);
+
+ ListNode<B> Root;
+};
+
+
+//------------------------------------------------------------------------
+// ***** FreeListElements
+//
+// Remove all elements in the list and free them in the allocator
+
+template<class List, class Allocator>
+void FreeListElements(List& list, Allocator& allocator)
+{
+ typename List::ValueType* self = list.GetFirst();
+ while(!list.IsNull(self))
+ {
+ typename List::ValueType* next = list.GetNext(self);
+ allocator.Free(self);
+ self = next;
+ }
+ list.Clear();
+}
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Log.cpp b/LibOVR/Src/Kernel/OVR_Log.cpp new file mode 100644 index 0000000..baede98 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Log.cpp @@ -0,0 +1,173 @@ +/************************************************************************************
+
+Filename : OVR_Log.cpp
+Content : Logging support
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Log.h"
+#include "OVR_Std.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+#if defined(OVR_OS_WIN32)
+#include <windows.h>
+#elif defined(OVR_OS_ANDROID)
+#include <android/log.h>
+#endif
+
+namespace OVR {
+
+// Global Log pointer.
+Log* volatile OVR_GlobalLog = 0;
+
+//-----------------------------------------------------------------------------------
+// ***** Log Implementation
+
+Log::~Log()
+{
+ // Clear out global log
+ if (this == OVR_GlobalLog)
+ {
+ // TBD: perhaps we should ASSERT if this happens before system shutdown?
+ OVR_GlobalLog = 0;
+ }
+}
+
+void Log::LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList)
+{
+ if ((messageType & LoggingMask) == 0)
+ return;
+#ifndef OVR_BUILD_DEBUG
+ if (IsDebugMessage(messageType))
+ return;
+#endif
+
+ char buffer[MaxLogBufferMessageSize];
+ FormatLog(buffer, MaxLogBufferMessageSize, messageType, fmt, argList);
+ DefaultLogOutput(buffer, IsDebugMessage(messageType));
+}
+
+void OVR::Log::LogMessage(LogMessageType messageType, const char* pfmt, ...)
+{
+ va_list argList;
+ va_start(argList, pfmt);
+ LogMessageVarg(messageType, pfmt, argList);
+ va_end(argList);
+}
+
+
+void Log::FormatLog(char* buffer, unsigned bufferSize, LogMessageType messageType,
+ const char* fmt, va_list argList)
+{
+ bool addNewline = true;
+
+ switch(messageType)
+ {
+ case Log_Error: OVR_strcpy(buffer, bufferSize, "Error: "); break;
+ case Log_Debug: OVR_strcpy(buffer, bufferSize, "Debug: "); break;
+ case Log_Assert: OVR_strcpy(buffer, bufferSize, "Assert: "); break;
+ case Log_Text: buffer[0] = 0; addNewline = false; break;
+ case Log_DebugText: buffer[0] = 0; addNewline = false; break;
+ default:
+ buffer[0] = 0;
+ addNewline = false;
+ break;
+ }
+
+ UPInt prefixLength = OVR_strlen(buffer);
+ char *buffer2 = buffer + prefixLength;
+ OVR_vsprintf(buffer2, bufferSize - prefixLength, fmt, argList);
+
+ if (addNewline)
+ OVR_strcat(buffer, bufferSize, "\n");
+}
+
+
+void Log::DefaultLogOutput(const char* formattedText, bool debug)
+{
+
+#if defined(OVR_OS_WIN32)
+ // Under Win32, output regular messages to console if it exists; debug window otherwise.
+ static DWORD dummyMode;
+ static bool hasConsole = (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) &&
+ (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummyMode));
+
+ if (!hasConsole || debug)
+ {
+ ::OutputDebugStringA(formattedText);
+ }
+ else
+ {
+ fputs(formattedText, stdout);
+ }
+
+#elif defined(OVR_OS_ANDROID)
+ __android_log_write(ANDROID_LOG_INFO, "OVR", formattedText);
+
+#else
+ fputs(formattedText, stdout);
+
+#endif
+
+ // Just in case.
+ OVR_UNUSED2(formattedText, debug);
+}
+
+
+//static
+void Log::SetGlobalLog(Log *log)
+{
+ OVR_GlobalLog = log;
+}
+//static
+Log* Log::GetGlobalLog()
+{
+// No global log by default?
+// if (!OVR_GlobalLog)
+// OVR_GlobalLog = GetDefaultLog();
+ return OVR_GlobalLog;
+}
+
+//static
+Log* Log::GetDefaultLog()
+{
+ // Create default log pointer statically so that it can be used
+ // even during startup.
+ static Log defaultLog;
+ return &defaultLog;
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** Global Logging functions
+
+#define OVR_LOG_FUNCTION_IMPL(Name) \
+ void Log##Name(const char* fmt, ...) \
+ { \
+ if (OVR_GlobalLog) \
+ { \
+ va_list argList; va_start(argList, fmt); \
+ OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList); \
+ va_end(argList); \
+ } \
+ }
+
+OVR_LOG_FUNCTION_IMPL(Text)
+OVR_LOG_FUNCTION_IMPL(Error)
+
+#ifdef OVR_BUILD_DEBUG
+OVR_LOG_FUNCTION_IMPL(DebugText)
+OVR_LOG_FUNCTION_IMPL(Debug)
+OVR_LOG_FUNCTION_IMPL(Assert)
+#endif
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_Log.h b/LibOVR/Src/Kernel/OVR_Log.h new file mode 100644 index 0000000..acc298d --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Log.h @@ -0,0 +1,193 @@ +/************************************************************************************
+
+PublicHeader: OVR
+Filename : OVR_Log.h
+Content : Logging support
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Log_h
+#define OVR_Log_h
+
+#include "OVR_Types.h"
+#include <stdarg.h>
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Logging Constants
+
+// LogMaskConstants defined bit mask constants that describe what log messages
+// should be displayed.
+enum LogMaskConstants
+{
+ LogMask_Regular = 0x100,
+ LogMask_Debug = 0x200,
+ LogMask_None = 0,
+ LogMask_All = LogMask_Regular|LogMask_Debug
+};
+
+
+// LogMessageType describes the type of the log message, controls when it is
+// displayed and what prefix/suffix is given to it. Messages are subdivided into
+// regular and debug logging types. Debug logging is only generated in debug builds.
+//
+// Log_Text - General output text displayed without prefix or new-line.
+// Used in OVR libraries for general log flow messages
+// such as "Device Initialized".
+//
+// Log_Error - Error message output with "Error: %s\n", intended for
+// application/sample-level use only, in cases where an expected
+// operation failed. OVR libraries should not use this internally,
+// reporting status codes instead.
+//
+// Log_DebugText - Message without prefix or new lines; output in Debug build only.
+//
+// Log_Debug - Debug-build only message, formatted with "Debug: %s\n".
+// Intended to comment on incorrect API usage that doesn't lead
+// to crashes but can be avoided with proper use.
+// There is no Debug Error on purpose, since real errors should
+// be handled by API user.
+//
+// Log_Assert - Debug-build only message, formatted with "Assert: %s\n".
+// Intended for severe unrecoverable conditions in library
+// source code. Generated though OVR_ASSERT_MSG(c, "Text").
+
+enum LogMessageType
+{
+ // General Logging
+ Log_Text = LogMask_Regular | 0,
+ Log_Error = LogMask_Regular | 1, // "Error: %s\n".
+
+ // Debug-only messages (not generated in release build)
+ Log_DebugText = LogMask_Debug | 0,
+ Log_Debug = LogMask_Debug | 1, // "Debug: %s\n".
+ Log_Assert = LogMask_Debug | 2, // "Assert: %s\n".
+};
+
+
+// LOG_VAARG_ATTRIBUTE macro, enforces printf-style fromatting for message types
+#ifdef __GNUC__
+# define OVR_LOG_VAARG_ATTRIBUTE(a,b) __attribute__((format (printf, a, b)))
+#else
+# define OVR_LOG_VAARG_ATTRIBUTE(a,b)
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** Log
+
+// Log defines a base class interface that can be implemented to catch both
+// debug and runtime messages.
+// Debug logging can be overridden by calling Log::SetGlobalLog.
+
+class Log
+{
+ friend class System;
+public:
+ Log(unsigned logMask = LogMask_Debug) : LoggingMask(logMask) { }
+ virtual ~Log();
+
+ // Log formating buffer size used by default LogMessageVarg. Longer strings are truncated.
+ enum { MaxLogBufferMessageSize = 2048 };
+
+ unsigned GetLoggingMask() const { return LoggingMask; }
+ void SetLoggingMask(unsigned logMask) { LoggingMask = logMask; }
+
+ // This virtual function receives all the messages,
+ // developers should override this function in order to do custom logging
+ virtual void LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList);
+
+ // Call the logging function with specific message type, with no type filtering.
+ void LogMessage(LogMessageType messageType,
+ const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(3,4);
+
+
+ // Helper used by LogMessageVarg to format the log message, writing the resulting
+ // string into buffer. It formats text based on fmt and appends prefix/new line
+ // based on LogMessageType.
+ static void FormatLog(char* buffer, unsigned bufferSize, LogMessageType messageType,
+ const char* fmt, va_list argList);
+
+ // Default log output implementation used by by LogMessageVarg.
+ // Debug flag may be used to re-direct output on some platforms, but doesn't
+ // necessarily disable it in release builds; that is the job of the called.
+ static void DefaultLogOutput(const char* textBuffer, bool debug);
+
+ // Determines if the specified message type is for debugging only.
+ static bool IsDebugMessage(LogMessageType messageType)
+ {
+ return (messageType & LogMask_Debug) != 0;
+ }
+
+ // *** Global APIs
+
+ // Global Log registration APIs.
+ // - Global log is used for OVR_DEBUG messages. Set global log to null (0)
+ // to disable all logging.
+ static void SetGlobalLog(Log *log);
+ static Log* GetGlobalLog();
+
+ // Returns default log singleton instance.
+ static Log* GetDefaultLog();
+
+ // Applies logMask to the default log and returns a pointer to it.
+ // By default, only Debug logging is enabled, so to avoid SDK generating console
+ // messages in user app (those are always disabled in release build,
+ // even if the flag is set). This function is useful in System constructor.
+ static Log* ConfigureDefaultLog(unsigned logMask = LogMask_Debug)
+ {
+ Log* log = GetDefaultLog();
+ log->SetLoggingMask(logMask);
+ return log;
+ }
+
+private:
+ // Logging mask described by LogMaskConstants.
+ unsigned LoggingMask;
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Global Logging Functions and Debug Macros
+
+// These functions will output text to global log with semantics described by
+// their LogMessageType.
+void LogText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+void LogError(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+
+#ifdef OVR_BUILD_DEBUG
+
+ // Debug build only logging.
+ void LogDebugText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+ void LogDebug(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+ void LogAssert(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+
+ // Macro to do debug logging, printf-style.
+ // An extra set of set of parenthesis must be used around arguments,
+ // as in: OVR_LOG_DEBUG(("Value %d", 2)).
+ #define OVR_DEBUG_LOG(args) do { OVR::LogDebug args; } while(0)
+ #define OVR_DEBUG_LOG_TEXT(args) do { OVR::LogDebugText args; } while(0)
+
+ #define OVR_ASSERT_LOG(c, args) do { if (!(c)) { OVR::LogAssert args; OVR_DEBUG_BREAK; } } while(0)
+
+#else
+
+ // If not in debug build, macros do nothing.
+ #define OVR_DEBUG_LOG(args) ((void)0)
+ #define OVR_DEBUG_LOG_TEXT(args) ((void)0)
+ #define OVR_ASSERT_LOG(c, args) ((void)0)
+
+#endif
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Math.cpp b/LibOVR/Src/Kernel/OVR_Math.cpp new file mode 100644 index 0000000..eaf23fe --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Math.cpp @@ -0,0 +1,153 @@ +/************************************************************************************
+
+Filename : OVR_Math.h
+Content : Implementation of 3D primitives such as vectors, matrices.
+Created : September 4, 2012
+Authors : Andrew Reisse, Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Math.h"
+
+#include <float.h>
+
+namespace OVR {
+
+
+//-------------------------------------------------------------------------------------
+// ***** Math
+
+
+// Single-precision Math constants class.
+const float Math<float>::Pi = 3.1415926f;
+const float Math<float>::TwoPi = 3.1415926f * 2;
+const float Math<float>::PiOver2 = 3.1415926f / 2.0f;
+const float Math<float>::PiOver4 = 3.1415926f / 4.0f;
+const float Math<float>::E = 2.7182818f;
+
+const float Math<float>::MaxValue = FLT_MAX;
+const float Math<float>::MinPositiveValue = FLT_MIN;
+
+const float Math<float>::RadToDegreeFactor = 360.0f / Math<float>::TwoPi;
+const float Math<float>::DegreeToRadFactor = Math<float>::TwoPi / 360.0f;
+
+const float Math<float>::Tolerance = 0.00001f;
+const float Math<float>::SingularityRadius = 0.0000001f; // Use for Gimbal lock numerical problems
+
+
+// Double-precision Math constants class.
+const double Math<double>::Pi = 3.14159265358979;
+const double Math<double>::TwoPi = 3.14159265358979 * 2;
+const double Math<double>::PiOver2 = 3.14159265358979 / 2.0;
+const double Math<double>::PiOver4 = 3.14159265358979 / 4.0;
+const double Math<double>::E = 2.71828182845905;
+
+const double Math<double>::MaxValue = DBL_MAX;
+const double Math<double>::MinPositiveValue = DBL_MIN;
+
+const double Math<double>::RadToDegreeFactor = 360.0 / Math<double>::TwoPi;
+const double Math<double>::DegreeToRadFactor = Math<double>::TwoPi / 360.0;
+
+const double Math<double>::Tolerance = 0.00001;
+const double Math<double>::SingularityRadius = 0.000000000001; // Use for Gimbal lock numerical problems
+
+
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix4f
+
+
+Matrix4f Matrix4f::LookAtRH(const Vector3f& eye, const Vector3f& at, const Vector3f& up)
+{
+ Vector3f z = (eye - at).Normalized(); // Forward
+ Vector3f x = up.Cross(z).Normalized(); // Right
+ Vector3f y = z.Cross(x);
+
+ Matrix4f m(x.x, x.y, x.z, -(x * eye),
+ y.x, y.y, y.z, -(y * eye),
+ z.x, z.y, z.z, -(z * eye),
+ 0, 0, 0, 1 );
+ return m;
+}
+
+Matrix4f Matrix4f::LookAtLH(const Vector3f& eye, const Vector3f& at, const Vector3f& up)
+{
+ Vector3f z = (at - eye).Normalized(); // Forward
+ Vector3f x = up.Cross(z).Normalized(); // Right
+ Vector3f y = z.Cross(x);
+
+ Matrix4f m(x.x, x.y, x.z, -(x * eye),
+ y.x, y.y, y.z, -(y * eye),
+ z.x, z.y, z.z, -(z * eye),
+ 0, 0, 0, 1 );
+ return m;
+}
+
+
+Matrix4f Matrix4f::PerspectiveLH(float yfov, float aspect, float znear, float zfar)
+{
+ Matrix4f m;
+ float tanHalfFov = tan(yfov * 0.5f);
+
+ m.M[0][0] = 1.0f / (aspect * tanHalfFov);
+ m.M[1][1] = 1.0f / tanHalfFov;
+ m.M[2][2] = zfar / (zfar - znear);
+ m.M[3][2] = 1.0f;
+ m.M[2][3] = (zfar * znear) / (znear - zfar);
+ m.M[3][3] = 0.0f;
+
+ // Note: Post-projection matrix result assumes Left-Handed coordinate system,
+ // with Y up, X right and Z forward. This supports positive z-buffer values.
+ return m;
+}
+
+
+Matrix4f Matrix4f::PerspectiveRH(float yfov, float aspect, float znear, float zfar)
+{
+ Matrix4f m;
+ float tanHalfFov = tan(yfov * 0.5f);
+
+ m.M[0][0] = 1.0f / (aspect * tanHalfFov);
+ m.M[1][1] = 1.0f / tanHalfFov;
+ m.M[2][2] = zfar / (znear - zfar);
+ // m.M[2][2] = zfar / (zfar - znear);
+ m.M[3][2] = -1.0f;
+ m.M[2][3] = (zfar * znear) / (znear - zfar);
+ m.M[3][3] = 0.0f;
+
+ // Note: Post-projection matrix result assumes Left-Handed coordinate system,
+ // with Y up, X right and Z forward. This supports positive z-buffer values.
+ // This is the case even for RHS cooridnate input.
+ return m;
+}
+
+
+/*
+OffCenterLH
+
+2*zn/(r-l) 0 0 0
+0 2*zn/(t-b) 0 0
+(l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1
+0 0 zn*zf/(zn-zf) 0
+
+*/
+
+
+Matrix4f Matrix4f::Ortho2D(float w, float h)
+{
+ Matrix4f m;
+ m.M[0][0] = 2.0f/w;
+ m.M[1][1] = -2.0f/h;
+ m.M[0][3] = -1.0;
+ m.M[1][3] = 1.0;
+ m.M[2][2] = 0;
+ return m;
+}
+
+}
diff --git a/LibOVR/Src/Kernel/OVR_Math.h b/LibOVR/Src/Kernel/OVR_Math.h new file mode 100644 index 0000000..8c5a7ba --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Math.h @@ -0,0 +1,1070 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Math.h
+Content : Implementation of 3D primitives such as vectors, matrices.
+Created : September 4, 2012
+Authors : Andrew Reisse, Michael Antonov, Steve LaValle, Anna Yershova
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Math_h
+#define OVR_Math_h
+
+#include <assert.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "OVR_Types.h"
+#include "OVR_RefCount.h"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+// Constants for 3D world/axis definitions.
+
+// Definitions of axes for coordinate and rotation conversions.
+enum Axis
+{
+ Axis_X = 0, Axis_Y = 1, Axis_Z = 2
+};
+
+// RotateDirection describes the rotation direction around an axis, interpreted as follows:
+// CW - Clockwise while looking "down" from positive axis towards the origin.
+// CCW - Counter-clockwise while looking from the positive axis towards the origin,
+// which is in the negative axis direction.
+// CCW is the default for the RHS coordinate system. Oculus standard RHS coordinate
+// system defines Y up, X right, and Z back (pointing out from the screen). In this
+// system Rotate_CCW around Z will specifies counter-clockwise rotation in XY plane.
+enum RotateDirection
+{
+ Rotate_CCW = 1,
+ Rotate_CW = -1
+};
+
+enum HandedSystem
+{
+ Handed_R = 1, Handed_L = -1
+};
+
+// AxisDirection describes which way the axis points. Used by WorldAxes.
+enum AxisDirection
+{
+ Axis_Up = 2,
+ Axis_Down = -2,
+ Axis_Right = 1,
+ Axis_Left = -1,
+ Axis_In = 3,
+ Axis_Out = -3
+};
+
+struct WorldAxes
+{
+ AxisDirection XAxis, YAxis, ZAxis;
+
+ WorldAxes(AxisDirection x, AxisDirection y, AxisDirection z)
+ : XAxis(x), YAxis(y), ZAxis(z)
+ { OVR_ASSERT(abs(x) != abs(y) && abs(y) != abs(z) && abs(z) != abs(x));}
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** Math
+
+// Math class contains constants and functions. This class is a template specialized
+// per type, with Math<float> and Math<double> being distinct.
+template<class Type>
+class Math
+{
+};
+
+// Single-precision Math constants class.
+template<>
+class Math<float>
+{
+public:
+ static const float Pi;
+ static const float TwoPi;
+ static const float PiOver2;
+ static const float PiOver4;
+ static const float E;
+
+ static const float MaxValue; // Largest positive float Value
+ static const float MinPositiveValue; // Smallest possible positive value
+
+ static const float RadToDegreeFactor;
+ static const float DegreeToRadFactor;
+
+ static const float Tolerance; // 0.00001f;
+ static const float SingularityRadius; //0.00000000001f for Gimbal lock numerical problems
+};
+
+// Double-precision Math constants class.
+template<>
+class Math<double>
+{
+public:
+ static const double Pi;
+ static const double TwoPi;
+ static const double PiOver2;
+ static const double PiOver4;
+ static const double E;
+
+ static const double MaxValue; // Largest positive double Value
+ static const double MinPositiveValue; // Smallest possible positive value
+
+ static const double RadToDegreeFactor;
+ static const double DegreeToRadFactor;
+
+ static const double Tolerance; // 0.00001f;
+ static const double SingularityRadius; //0.00000000001 for Gimbal lock numerical problems
+};
+
+typedef Math<float> Mathf;
+typedef Math<double> Mathd;
+
+// Conversion functions between degrees and radians
+template<class FT>
+FT RadToDegree(FT rads) { return rads * Math<FT>::RadToDegreeFactor; }
+template<class FT>
+FT DegreeToRad(FT rads) { return rads * Math<FT>::DegreeToRadFactor; }
+
+template<class T>
+class Quat;
+
+//-------------------------------------------------------------------------------------
+// ***** Vector2f - 2D Vector2f
+
+// Vector2f represents a 2-dimensional vector or point in space,
+// consisting of coordinates x and y,
+
+template<class T>
+class Vector2
+{
+public:
+ T x, y;
+
+ Vector2() : x(0), y(0) { }
+ Vector2(T x_, T y_) : x(x_), y(y_) { }
+ explicit Vector2(T s) : x(s), y(s) { }
+
+ bool operator== (const Vector2& b) const { return x == b.x && y == b.y; }
+ bool operator!= (const Vector2& b) const { return x != b.x || y != b.y; }
+
+ Vector2 operator+ (const Vector2& b) const { return Vector2(x + b.x, y + b.y); }
+ Vector2& operator+= (const Vector2& b) { x += b.x; y += b.y; return *this; }
+ Vector2 operator- (const Vector2& b) const { return Vector2(x - b.x, y - b.y); }
+ Vector2& operator-= (const Vector2& b) { x -= b.x; y -= b.y; return *this; }
+ Vector2 operator- () const { return Vector2(-x, -y); }
+
+ // Scalar multiplication/division scales vector.
+ Vector2 operator* (T s) const { return Vector2(x*s, y*s); }
+ Vector2& operator*= (T s) { x *= s; y *= s; return *this; }
+
+ Vector2 operator/ (T s) const { T rcp = T(1)/s;
+ return Vector2(x*rcp, y*rcp); }
+ Vector2& operator/= (T s) { T rcp = T(1)/s;
+ x *= rcp; y *= rcp;
+ return *this; }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
+ bool Compare(const Vector2&b, T tolerance = Mathf::Tolerance)
+ {
+ return (fabs(b.x-x) < tolerance) && (fabs(b.y-y) < tolerance);
+ }
+
+ // Dot product overload.
+ // Used to calculate angle q between two vectors among other things,
+ // as (A dot B) = |a||b|cos(q).
+ T operator* (const Vector2& b) const { return x*b.x + y*b.y; }
+
+ // Returns the angle from this vector to b, in radians.
+ T Angle(const Vector2& b) const { return acos((*this * b)/(Length()*b.Length())); }
+
+ // Return Length of the vector squared.
+ T LengthSq() const { return (x * x + y * y); }
+ // Return vector length.
+ T Length() const { return sqrt(LengthSq()); }
+
+ // Returns distance between two points represented by vectors.
+ T Distance(Vector2& b) const { return (*this - b).Length(); }
+
+ // Determine if this a unit vector.
+ bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance; }
+ // Normalize, convention vector length to 1.
+ void Normalize() { *this /= Length(); }
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector2 Normalized() const { return *this / Length(); }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector2 Lerp(const Vector2& b, T f) const { return *this*(T(1) - f) + b*f; }
+
+ // Projects this vector onto the argument; in other words,
+ // A.Project(B) returns projection of vector A onto B.
+ Vector2 ProjectTo(const Vector2& b) const { return b * ((*this * b) / b.LengthSq()); }
+};
+
+
+typedef Vector2<float> Vector2f;
+typedef Vector2<double> Vector2d;
+
+//-------------------------------------------------------------------------------------
+// ***** Vector3f - 3D Vector3f
+
+// Vector3f represents a 3-dimensional vector or point in space,
+// consisting of coordinates x, y and z.
+
+template<class T>
+class Vector3
+{
+public:
+ T x, y, z;
+
+ Vector3() : x(0), y(0), z(0) { }
+ Vector3(T x_, T y_, T z_ = 0) : x(x_), y(y_), z(z_) { }
+ explicit Vector3(T s) : x(s), y(s), z(s) { }
+
+ bool operator== (const Vector3& b) const { return x == b.x && y == b.y && z == b.z; }
+ bool operator!= (const Vector3& b) const { return x != b.x || y != b.y || z != b.z; }
+
+ Vector3 operator+ (const Vector3& b) const { return Vector3(x + b.x, y + b.y, z + b.z); }
+ Vector3& operator+= (const Vector3& b) { x += b.x; y += b.y; z += b.z; return *this; }
+ Vector3 operator- (const Vector3& b) const { return Vector3(x - b.x, y - b.y, z - b.z); }
+ Vector3& operator-= (const Vector3& b) { x -= b.x; y -= b.y; z -= b.z; return *this; }
+ Vector3 operator- () const { return Vector3(-x, -y, -z); }
+
+ // Scalar multiplication/division scales vector.
+ Vector3 operator* (T s) const { return Vector3(x*s, y*s, z*s); }
+ Vector3& operator*= (T s) { x *= s; y *= s; z *= s; return *this; }
+
+ Vector3 operator/ (T s) const { T rcp = T(1)/s;
+ return Vector3(x*rcp, y*rcp, z*rcp); }
+ Vector3& operator/= (T s) { T rcp = T(1)/s;
+ x *= rcp; y *= rcp; z *= rcp;
+ return *this; }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
+ bool Compare(const Vector3&b, T tolerance = Mathf::Tolerance)
+ {
+ return (fabs(b.x-x) < tolerance) && (fabs(b.y-y) < tolerance) && (fabs(b.z-z) < tolerance);
+ }
+
+ // Dot product overload.
+ // Used to calculate angle q between two vectors among other things,
+ // as (A dot B) = |a||b|cos(q).
+ T operator* (const Vector3& b) const { return x*b.x + y*b.y + z*b.z; }
+
+ // Compute cross product, which generates a normal vector.
+ // Direction vector can be determined by right-hand rule: Pointing index finder in
+ // direction a and middle finger in direction b, thumb will point in a.Cross(b).
+ Vector3 Cross(const Vector3& b) const { return Vector3(y*b.z - z*b.y,
+ z*b.x - x*b.z,
+ x*b.y - y*b.x); }
+
+ // Returns the angle from this vector to b, in radians.
+ T Angle(const Vector3& b) const { return acos((*this * b)/(Length()*b.Length())); }
+
+ // Return Length of the vector squared.
+ T LengthSq() const { return (x * x + y * y + z * z); }
+ // Return vector length.
+ T Length() const { return sqrt(LengthSq()); }
+
+ // Returns distance between two points represented by vectors.
+ T Distance(Vector3& b) const { return (*this - b).Length(); }
+
+ // Determine if this a unit vector.
+ bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance; }
+ // Normalize, convention vector length to 1.
+ void Normalize() { *this /= Length(); }
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector3 Normalized() const { return *this / Length(); }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector3 Lerp(const Vector3& b, T f) const { return *this*(T(1) - f) + b*f; }
+
+ // Projects this vector onto the argument; in other words,
+ // A.Project(B) returns projection of vector A onto B.
+ Vector3 ProjectTo(const Vector3& b) const { return b * ((*this * b) / b.LengthSq()); }
+};
+
+
+typedef Vector3<float> Vector3f;
+typedef Vector3<double> Vector3d;
+
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix4f
+
+// Matrix4f is a 4x4 matrix used for 3d transformations and projections.
+// Translation stored in the last column.
+// The matrix is stored in row-major order in memory, meaning that values
+// of the first row are stored before the next one.
+//
+// The arrangement of the matrix is chosen to be in Right-Handed
+// coordinate system and counterclockwise rotations when looking down
+// the axis
+//
+// Transformation Order:
+// - Transformations are applied from right to left, so the expression
+// M1 * M2 * M3 * V means that the vector V is transformed by M3 first,
+// followed by M2 and M1.
+//
+// Coordinate system: Right Handed
+//
+// Rotations: Counterclockwise when looking down the axis. All angles are in radians.
+//
+// | sx 01 02 tx | // First column (sx, 10, 20): Axis X basis vector.
+// | 10 sy 12 ty | // Second column (01, sy, 21): Axis Y basis vector.
+// | 20 21 sz tz | // Third columnt (02, 12, sz): Axis Z basis vector.
+// | 30 31 32 33 |
+//
+// The basis vectors are first three columns.
+
+class Matrix4f
+{
+ static Matrix4f IdentityValue;
+
+public:
+ float M[4][4];
+
+ enum NoInitType { NoInit };
+
+ // Construct with no memory initialization.
+ Matrix4f(NoInitType) { }
+
+ // By default, we construct identity matrix.
+ Matrix4f()
+ {
+ SetIdentity();
+ }
+
+ Matrix4f(float m11, float m12, float m13, float m14,
+ float m21, float m22, float m23, float m24,
+ float m31, float m32, float m33, float m34,
+ float m41, float m42, float m43, float m44)
+ {
+ M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = m14;
+ M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = m24;
+ M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = m34;
+ M[3][0] = m41; M[3][1] = m42; M[3][2] = m43; M[3][3] = m44;
+ }
+
+ Matrix4f(float m11, float m12, float m13,
+ float m21, float m22, float m23,
+ float m31, float m32, float m33)
+ {
+ M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = 0;
+ M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = 0;
+ M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = 0;
+ M[3][0] = 0; M[3][1] = 0; M[3][2] = 0; M[3][3] = 1;
+ }
+
+ static const Matrix4f& Identity() { return IdentityValue; }
+
+ void SetIdentity()
+ {
+ M[0][0] = M[1][1] = M[2][2] = M[3][3] = 1;
+ M[0][1] = M[1][0] = M[2][3] = M[3][1] = 0;
+ M[0][2] = M[1][2] = M[2][0] = M[3][2] = 0;
+ M[0][3] = M[1][3] = M[2][1] = M[3][0] = 0;
+ }
+
+ // Multiplies two matrices into destination with minimum copying.
+ static Matrix4f& Multiply(Matrix4f* d, const Matrix4f& a, const Matrix4f& b)
+ {
+ OVR_ASSERT((d != &a) && (d != &b));
+ int i = 0;
+ do {
+ d->M[i][0] = a.M[i][0] * b.M[0][0] + a.M[i][1] * b.M[1][0] + a.M[i][2] * b.M[2][0] + a.M[i][3] * b.M[3][0];
+ d->M[i][1] = a.M[i][0] * b.M[0][1] + a.M[i][1] * b.M[1][1] + a.M[i][2] * b.M[2][1] + a.M[i][3] * b.M[3][1];
+ d->M[i][2] = a.M[i][0] * b.M[0][2] + a.M[i][1] * b.M[1][2] + a.M[i][2] * b.M[2][2] + a.M[i][3] * b.M[3][2];
+ d->M[i][3] = a.M[i][0] * b.M[0][3] + a.M[i][1] * b.M[1][3] + a.M[i][2] * b.M[2][3] + a.M[i][3] * b.M[3][3];
+ } while((++i) < 4);
+
+ return *d;
+ }
+
+ Matrix4f operator* (const Matrix4f& b) const
+ {
+ Matrix4f result(Matrix4f::NoInit);
+ Multiply(&result, *this, b);
+ return result;
+ }
+
+ Matrix4f& operator*= (const Matrix4f& b)
+ {
+ return Multiply(this, Matrix4f(*this), b);
+ }
+
+ Matrix4f operator* (float s) const
+ {
+ return Matrix4f(M[0][0] * s, M[0][1] * s, M[0][2] * s, M[0][3] * s,
+ M[1][0] * s, M[1][1] * s, M[1][2] * s, M[1][3] * s,
+ M[2][0] * s, M[2][1] * s, M[2][2] * s, M[2][3] * s,
+ M[3][0] * s, M[3][1] * s, M[3][2] * s, M[3][3] * s);
+ }
+
+ Matrix4f& operator*= (float s)
+ {
+ M[0][0] *= s; M[0][1] *= s; M[0][2] *= s; M[0][3] *= s;
+ M[1][0] *= s; M[1][1] *= s; M[1][2] *= s; M[1][3] *= s;
+ M[2][0] *= s; M[2][1] *= s; M[2][2] *= s; M[2][3] *= s;
+ M[3][0] *= s; M[3][1] *= s; M[3][2] *= s; M[3][3] *= s;
+ return *this;
+ }
+
+ Vector3f Transform(const Vector3f& v) const
+ {
+ return Vector3f(M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3],
+ M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3],
+ M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3]);
+ }
+
+ Matrix4f Transposed() const
+ {
+ return Matrix4f(M[0][0], M[1][0], M[2][0], M[3][0],
+ M[0][1], M[1][1], M[2][1], M[3][1],
+ M[0][2], M[1][2], M[2][2], M[3][2],
+ M[0][3], M[1][3], M[2][3], M[3][3]);
+ }
+
+ void Transpose()
+ {
+ *this = Transposed();
+ }
+
+
+ float SubDet (const int* rows, const int* cols) const
+ {
+ return M[rows[0]][cols[0]] * (M[rows[1]][cols[1]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[1]])
+ - M[rows[0]][cols[1]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[0]])
+ + M[rows[0]][cols[2]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[1]] - M[rows[1]][cols[1]] * M[rows[2]][cols[0]]);
+ }
+
+ float Cofactor(int I, int J) const
+ {
+ const int indices[4][3] = {{1,2,3},{0,2,3},{0,1,3},{0,1,2}};
+ return ((I+J)&1) ? -SubDet(indices[I],indices[J]) : SubDet(indices[I],indices[J]);
+ }
+
+ float Determinant() const
+ {
+ return M[0][0] * Cofactor(0,0) + M[0][1] * Cofactor(0,1) + M[0][2] * Cofactor(0,2) + M[0][3] * Cofactor(0,3);
+ }
+
+ Matrix4f Adjugated() const
+ {
+ return Matrix4f(Cofactor(0,0), Cofactor(1,0), Cofactor(2,0), Cofactor(3,0),
+ Cofactor(0,1), Cofactor(1,1), Cofactor(2,1), Cofactor(3,1),
+ Cofactor(0,2), Cofactor(1,2), Cofactor(2,2), Cofactor(3,2),
+ Cofactor(0,3), Cofactor(1,3), Cofactor(2,3), Cofactor(3,3));
+ }
+
+ Matrix4f Inverted() const
+ {
+ float det = Determinant();
+ assert(det != 0);
+ return Adjugated() * (1.0f/det);
+ }
+
+ void Invert()
+ {
+ *this = Inverted();
+ }
+
+ //AnnaSteve:
+ // a,b,c, are the YawPitchRoll angles to be returned
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A3
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
+ void ToEulerAngles(float *a, float *b, float *c)
+ {
+ OVR_COMPILER_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3));
+
+ float psign = -1.0f;
+ if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3)) // Determine whether even permutation
+ psign = 1.0f;
+
+ float pm = psign*M[A1][A3];
+ if (pm < -1.0f + Math<float>::SingularityRadius)
+ { // South pole singularity
+ *a = 0.0f;
+ *b = -S*D*Math<float>::PiOver2;
+ *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
+ }
+ else if (pm > 1.0 - Math<float>::SingularityRadius)
+ { // North pole singularity
+ *a = 0.0f;
+ *b = S*D*Math<float>::PiOver2;
+ *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
+ }
+ else
+ { // Normal case (nonsingular)
+ *a = S*D*atan2( -psign*M[A2][A3], M[A3][A3] );
+ *b = S*D*asin(pm);
+ *c = S*D*atan2( -psign*M[A1][A2], M[A1][A1] );
+ }
+
+ return;
+ }
+
+ //AnnaSteve:
+ // a,b,c, are the YawPitchRoll angles to be returned
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A1
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
+ void ToEulerAnglesABA(float *a, float *b, float *c)
+ {
+ OVR_COMPILER_ASSERT(A1 != A2);
+
+ // Determine the axis that was not supplied
+ int m = 3 - A1 - A2;
+
+ float psign = -1.0f;
+ if ((A1 + 1) % 3 == A2) // Determine whether even permutation
+ psign = 1.0f;
+
+ float c2 = M[A1][A1];
+ if (c2 < -1.0 + Math<float>::SingularityRadius)
+ { // South pole singularity
+ *a = 0.0f;
+ *b = S*D*Math<float>::Pi;
+ *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
+ }
+ else if (c2 > 1.0 - Math<float>::SingularityRadius)
+ { // North pole singularity
+ *a = 0.0f;
+ *b = 0.0f;
+ *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
+ }
+ else
+ { // Normal case (nonsingular)
+ *a = S*D*atan2( M[A2][A1],-psign*M[m][A1]);
+ *b = S*D*acos(c2);
+ *c = S*D*atan2( M[A1][A2],psign*M[A1][m]);
+ }
+ return;
+ }
+
+ // Creates a matrix that converts the vertices from one coordinate system
+ // to another.
+ //
+ static Matrix4f AxisConversion(const WorldAxes& to, const WorldAxes& from)
+ {
+ // Holds axis values from the 'to' structure
+ int toArray[3] = { to.XAxis, to.YAxis, to.ZAxis };
+
+ // The inverse of the toArray
+ int inv[4];
+ inv[0] = inv[abs(to.XAxis)] = 0;
+ inv[abs(to.YAxis)] = 1;
+ inv[abs(to.ZAxis)] = 2;
+
+ Matrix4f m(0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0);
+
+ // Only three values in the matrix need to be changed to 1 or -1.
+ m.M[inv[abs(from.XAxis)]][0] = float(from.XAxis/toArray[inv[abs(from.XAxis)]]);
+ m.M[inv[abs(from.YAxis)]][1] = float(from.YAxis/toArray[inv[abs(from.YAxis)]]);
+ m.M[inv[abs(from.ZAxis)]][2] = float(from.ZAxis/toArray[inv[abs(from.ZAxis)]]);
+ return m;
+ }
+
+
+
+ static Matrix4f Translation(const Vector3f& v)
+ {
+ Matrix4f t;
+ t.M[0][3] = v.x;
+ t.M[1][3] = v.y;
+ t.M[2][3] = v.z;
+ return t;
+ }
+
+ static Matrix4f Translation(float x, float y, float z = 0.0f)
+ {
+ Matrix4f t;
+ t.M[0][3] = x;
+ t.M[1][3] = y;
+ t.M[2][3] = z;
+ return t;
+ }
+
+ static Matrix4f Scaling(const Vector3f& v)
+ {
+ Matrix4f t;
+ t.M[0][0] = v.x;
+ t.M[1][1] = v.y;
+ t.M[2][2] = v.z;
+ return t;
+ }
+
+ static Matrix4f Scaling(float x, float y, float z)
+ {
+ Matrix4f t;
+ t.M[0][0] = x;
+ t.M[1][1] = y;
+ t.M[2][2] = z;
+ return t;
+ }
+
+ static Matrix4f Scaling(float s)
+ {
+ Matrix4f t;
+ t.M[0][0] = s;
+ t.M[1][1] = s;
+ t.M[2][2] = s;
+ return t;
+ }
+
+
+
+ //AnnaSteve : Just for quick testing. Not for final API. Need to remove case.
+ static Matrix4f RotationAxis(Axis A, float angle, RotateDirection d, HandedSystem s)
+ {
+ float sina = s * d *sin(angle);
+ float cosa = cos(angle);
+
+ switch(A)
+ {
+ case Axis_X:
+ return Matrix4f(1, 0, 0,
+ 0, cosa, -sina,
+ 0, sina, cosa);
+ case Axis_Y:
+ return Matrix4f(cosa, 0, sina,
+ 0, 1, 0,
+ -sina, 0, cosa);
+ case Axis_Z:
+ return Matrix4f(cosa, -sina, 0,
+ sina, cosa, 0,
+ 0, 0, 1);
+ }
+ }
+
+
+ // Creates a rotation matrix rotating around the X axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4f RotationX(float angle)
+ {
+ float sina = sin(angle);
+ float cosa = cos(angle);
+ return Matrix4f(1, 0, 0,
+ 0, cosa, -sina,
+ 0, sina, cosa);
+ }
+
+ // Creates a rotation matrix rotating around the Y axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4f RotationY(float angle)
+ {
+ float sina = sin(angle);
+ float cosa = cos(angle);
+ return Matrix4f(cosa, 0, sina,
+ 0, 1, 0,
+ -sina, 0, cosa);
+ }
+
+ // Creates a rotation matrix rotating around the Z axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4f RotationZ(float angle)
+ {
+ float sina = sin(angle);
+ float cosa = cos(angle);
+ return Matrix4f(cosa, -sina, 0,
+ sina, cosa, 0,
+ 0, 0, 1);
+ }
+
+
+ // LookAtRH creates a View transformation matrix for right-handed coordinate system.
+ // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
+ // specifying the up vector. The resulting matrix should be used with PerspectiveRH
+ // projection.
+ static Matrix4f LookAtRH(const Vector3f& eye, const Vector3f& at, const Vector3f& up);
+
+ // LookAtLH creates a View transformation matrix for left-handed coordinate system.
+ // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
+ // specifying the up vector.
+ static Matrix4f LookAtLH(const Vector3f& eye, const Vector3f& at, const Vector3f& up);
+
+
+ // PerspectiveRH creates a right-handed perspective projection matrix that can be
+ // used with the Oculus sample renderer.
+ // yfov - Specifies vertical field of view in radians.
+ // aspect - Screen aspect ration, which is usually width/height for square pixels.
+ // Note that xfov = yfov * aspect.
+ // znear - Absolute value of near Z clipping clipping range.
+ // zfar - Absolute value of far Z clipping clipping range (larger then near).
+ // Even though RHS usually looks in the direction of negative Z, positive values
+ // are expected for znear and zfar.
+ static Matrix4f PerspectiveRH(float yfov, float aspect, float znear, float zfar);
+
+
+ // PerspectiveRH creates a left-handed perspective projection matrix that can be
+ // used with the Oculus sample renderer.
+ // yfov - Specifies vertical field of view in radians.
+ // aspect - Screen aspect ration, which is usually width/height for square pixels.
+ // Note that xfov = yfov * aspect.
+ // znear - Absolute value of near Z clipping clipping range.
+ // zfar - Absolute value of far Z clipping clipping range (larger then near).
+ static Matrix4f PerspectiveLH(float yfov, float aspect, float znear, float zfar);
+
+
+ static Matrix4f Ortho2D(float w, float h);
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** Quat
+
+// Quatf represents a quaternion class used for rotations.
+//
+// Quaternion multiplications are done in right-to-left order, to match the
+// behavior of matrices.
+
+
+template<class T>
+class Quat
+{
+public:
+ // w + Xi + Yj + Zk
+ T x, y, z, w;
+
+ Quat() : x(0), y(0), z(0), w(1) {}
+ Quat(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) {}
+
+
+ // Constructs rotation quaternion around the axis.
+ Quat(const Vector3<T>& axis, T angle)
+ {
+ Vector3<T> unitAxis = axis.Normalized();
+ T sinHalfAngle = sin(angle * T(0.5));
+
+ w = cos(angle * T(0.5));
+ x = unitAxis.x * sinHalfAngle;
+ y = unitAxis.y * sinHalfAngle;
+ z = unitAxis.z * sinHalfAngle;
+ }
+
+ //AnnaSteve:
+ void AxisAngle(Axis A, T angle, RotateDirection d, HandedSystem s)
+ {
+ T sinHalfAngle = s * d *sin(angle * (T)0.5);
+ T v[3];
+ v[0] = v[1] = v[2] = (T)0;
+ v[A] = sinHalfAngle;
+ //return Quat(v[0], v[1], v[2], cos(angle * (T)0.5));
+ w = cos(angle * (T)0.5);
+ x = v[0];
+ y = v[1];
+ z = v[2];
+ }
+
+
+ void GetAxisAngle(Vector3<T>* axis, T* angle) const
+ {
+ if (LengthSq() > Math<T>::Tolerance * Math<T>::Tolerance)
+ {
+ *axis = Vector3<T>(x, y, z).Normalized();
+ *angle = 2 * acos(w);
+ }
+ else
+ {
+ *axis = Vector3<T>(1, 0, 0);
+ *angle= 0;
+ }
+ }
+
+ bool operator== (const Quat& b) const { return x == b.x && y == b.y && z == b.z && w == b.w; }
+ bool operator!= (const Quat& b) const { return x != b.x || y != b.y || z != b.z || w != b.w; }
+
+ Quat operator+ (const Quat& b) const { return Quat(x + b.x, y + b.y, z + b.z, w + b.w); }
+ Quat& operator+= (const Quat& b) { w += b.w; x += b.x; y += b.y; z += b.z; return *this; }
+ Quat operator- (const Quat& b) const { return Quat(x - b.x, y - b.y, z - b.z, w - b.w); }
+ Quat& operator-= (const Quat& b) { w -= b.w; x -= b.x; y -= b.y; z -= b.z; return *this; }
+
+ Quat operator* (T s) const { return Quat(x * s, y * s, z * s, w * s); }
+ Quat& operator*= (T s) { w *= s; x *= s; y *= s; z *= s; return *this; }
+ Quat operator/ (T s) const { T rcp = T(1)/s; return Quat(x * rcp, y * rcp, z * rcp, w *rcp); }
+ Quat& operator/= (T s) { T rcp = T(1)/s; w *= rcp; x *= rcp; y *= rcp; z *= rcp; return *this; }
+
+ // Get Imaginary part vector
+ Vector3<T> Imag() const { return Vector3<T>(x,y,z); }
+
+ // Get quaternion length.
+ T Length() const { return sqrt(x * x + y * y + z * z + w * w); }
+ // Get quaternion length squared.
+ T LengthSq() const { return (x * x + y * y + z * z + w * w); }
+ // Simple Eulidean distance in R^4 (not SLERP distance, but at least respects Haar measure)
+ T Distance(const Quat& q) const
+ {
+ T d1 = (*this - q).Length();
+ T d2 = (*this + q).Length(); // Antipoldal point check
+ return (d1 < d2) ? d1 : d2;
+ }
+ T DistanceSq(const Quat& q) const
+ {
+ T d1 = (*this - q).LengthSq();
+ T d2 = (*this + q).LengthSq(); // Antipoldal point check
+ return (d1 < d2) ? d1 : d2;
+ }
+
+ // Normalize
+ bool IsNormalized() const { return fabs(LengthSq() - 1) < Math<T>::Tolerance; }
+ void Normalize() { *this /= Length(); }
+ Quat Normalized() const { return *this / Length(); }
+
+ // Returns conjugate of the quaternion. Produces inverse rotation if quaternion is normalized.
+ Quat Conj() const { return Quat(-x, -y, -z, w); }
+
+ // AnnaSteve fixed: order of quaternion multiplication
+ // Quaternion multiplication. Combines quaternion rotations, performing the one on the
+ // right hand side first.
+ Quat operator* (const Quat& b) const { return Quat(w * b.x + x * b.w + y * b.z - z * b.y,
+ w * b.y - x * b.z + y * b.w + z * b.x,
+ w * b.z + x * b.y - y * b.x + z * b.w,
+ w * b.w - x * b.x - y * b.y - z * b.z); }
+
+ //
+ // this^p normalized; same as rotating by this p times.
+ Quat PowNormalized(T p) const
+ {
+ Vector3<T> v;
+ T a;
+ GetAxisAngle(&v, &a);
+ return Quat(v, a * p);
+ }
+
+ // Rotate transforms vector in a manner that matches Matrix rotations (counter-clockwise,
+ // assuming negative direction of the axis). Standard formula: q(t) * V * q(t)^-1.
+ Vector3<T> Rotate(const Vector3<T>& v) const
+ {
+ return ((*this * Quat<T>(v.x, v.y, v.z, 0)) * Inverted()).Imag();
+ }
+
+
+ // Inversed quaternion rotates in the opposite direction.
+ Quat Inverted() const
+ {
+ return Quat(-x, -y, -z, w);
+ }
+
+ // Sets this quaternion to the one rotates in the opposite direction.
+ void Invert() const
+ {
+ *this = Quat(-x, -y, -z, w);
+ }
+
+ // Converting quaternion to matrix.
+ operator Matrix4f() const
+ {
+ T ww = w*w;
+ T xx = x*x;
+ T yy = y*y;
+ T zz = z*z;
+
+ return Matrix4f(float(ww + xx - yy - zz), float(T(2) * (x*y - w*z)), float(T(2) * (x*z + w*y)),
+ float(T(2) * (x*y + w*z)), float(ww - xx + yy - zz), float(T(2) * (y*z - w*x)),
+ float(T(2) * (x*z - w*y)), float(T(2) * (y*z + w*x)), float(ww - xx - yy + zz) );
+ }
+
+
+ // GetEulerAngles extracts Euler angles from the quaternion, in the specified order of
+ // axis rotations and the specified coordinate system. Right-handed coordinate system
+ // is the default, with CCW rotations while looking in the negative axis direction.
+ // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A3
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
+ void GetEulerAngles(T *a, T *b, T *c)
+ {
+ OVR_COMPILER_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3));
+
+ T Q[3] = { x, y, z }; //Quaternion components x,y,z
+
+ T ww = w*w;
+ T Q11 = Q[A1]*Q[A1];
+ T Q22 = Q[A2]*Q[A2];
+ T Q33 = Q[A3]*Q[A3];
+
+ T psign = T(-1.0);
+ // Determine whether even permutation
+ if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3))
+ psign = T(1.0);
+
+ T s2 = psign * T(2.0) * (psign*w*Q[A2] + Q[A1]*Q[A3]);
+
+ if (s2 < (T)-1.0 + Math<T>::SingularityRadius)
+ { // South pole singularity
+ *a = T(0.0);
+ *b = -S*D*Math<T>::PiOver2;
+ *c = S*D*atan2((T)2.0*(psign*Q[A1]*Q[A2] + w*Q[A3]),
+ ww + Q22 - Q11 - Q33 );
+ }
+ else if (s2 > (T)1.0 - Math<T>::SingularityRadius)
+ { // North pole singularity
+ *a = (T)0.0;
+ *b = S*D*Math<T>::PiOver2;
+ *c = S*D*atan2((T)2.0*(psign*Q[A1]*Q[A2] + w*Q[A3]),
+ ww + Q22 - Q11 - Q33);
+ }
+ else
+ {
+ *a = -S*D*atan2((T)-2.0*(w*Q[A1] - psign*Q[A2]*Q[A3]),
+ ww + Q33 - Q11 - Q22);
+ *b = S*D*asin(s2);
+ *c = S*D*atan2((T)2.0*(w*Q[A3] - psign*Q[A1]*Q[A2]),
+ ww + Q11 - Q22 - Q33);
+ }
+ return;
+ }
+
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D>
+ void GetEulerAngles(T *a, T *b, T *c)
+ { GetEulerAngles<A1, A2, A3, D, Handed_R>(a, b, c); }
+
+ template <Axis A1, Axis A2, Axis A3>
+ void GetEulerAngles(T *a, T *b, T *c)
+ { GetEulerAngles<A1, A2, A3, Rotate_CCW, Handed_R>(a, b, c); }
+
+
+ // GetEulerAnglesABA extracts Euler angles from the quaternion, in the specified order of
+ // axis rotations and the specified coordinate system. Right-handed coordinate system
+ // is the default, with CCW rotations while looking in the negative axis direction.
+ // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A1
+ // Rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
+ void GetEulerAnglesABA(T *a, T *b, T *c)
+ {
+ OVR_COMPILER_ASSERT(A1 != A2);
+
+ T Q[3] = {x, y, z}; // Quaternion components
+
+ // Determine the missing axis that was not supplied
+ int m = 3 - A1 - A2;
+
+ T ww = w*w;
+ T Q11 = Q[A1]*Q[A1];
+ T Q22 = Q[A2]*Q[A2];
+ T Qmm = Q[m]*Q[m];
+
+ T psign = T(-1.0);
+ if ((A1 + 1) % 3 == A2) // Determine whether even permutation
+ {
+ psign = (T)1.0;
+ }
+
+ T c2 = ww + Q11 - Q22 - Qmm;
+ if (c2 < (T)-1.0 + Math<T>::SingularityRadius)
+ { // South pole singularity
+ *a = (T)0.0;
+ *b = S*D*Math<T>::Pi;
+ *c = S*D*atan2( (T)2.0*(w*Q[A1] - psign*Q[A2]*Q[m]),
+ ww + Q22 - Q11 - Qmm);
+ }
+ else if (c2 > (T)1.0 - Math<T>::SingularityRadius)
+ { // North pole singularity
+ *a = (T)0.0;
+ *b = (T)0.0;
+ *c = S*D*atan2( (T)2.0*(w*Q[A1] - psign*Q[A2]*Q[m]),
+ ww + Q22 - Q11 - Qmm);
+ }
+ else
+ {
+ *a = S*D*atan2( psign*w*Q[m] + Q[A1]*Q[A2],
+ w*Q[A2] -psign*Q[A1]*Q[m]);
+ *b = S*D*acos(c2);
+ *c = S*D*atan2( -psign*w*Q[m] + Q[A1]*Q[A2],
+ w*Q[A2] + psign*Q[A1]*Q[m]);
+ }
+ return;
+ }
+};
+
+
+typedef Quat<float> Quatf;
+typedef Quat<double> Quatd;
+
+//-------------------------------------------------------------------------------------
+// ***** Plane
+
+// Consists of a normal vector and distance from the origin where the plane is located.
+
+template<class T>
+class Plane : public RefCountBase<Plane<T> >
+{
+public:
+ Vector3<T> N;
+ T D;
+
+ Plane() : D(0) {}
+
+ // Normals must already be normalized
+ Plane(const Vector3<T>& n, T d) : N(n), D(d) {}
+ Plane(T x, T y, T z, T d) : N(x,y,z), D(d) {}
+
+ // construct from a point on the plane and the normal
+ Plane(const Vector3<T>& p, const Vector3<T>& n) : N(n), D(-(p * n)) {}
+
+ // Find the point to plane distance. The sign indicates what side of the plane the point is on (0 = point on plane).
+ T TestSide(const Vector3<T>& p) const
+ {
+ return (N * p) + D;
+ }
+
+ Plane<T> Flipped() const
+ {
+ return Plane(-N, -D);
+ }
+
+ void Flip()
+ {
+ N = -N;
+ D = -D;
+ }
+
+ bool operator==(const Plane<T>& rhs) const
+ {
+ return (this->D == rhs.D && this->N == rhs.N);
+ }
+};
+
+typedef Plane<float> Planef;
+
+}
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_RefCount.cpp b/LibOVR/Src/Kernel/OVR_RefCount.cpp new file mode 100644 index 0000000..a1171fa --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_RefCount.cpp @@ -0,0 +1,100 @@ +/************************************************************************************
+
+Filename : OVR_RefCount.cpp
+Content : Reference counting implementation
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_RefCount.h"
+#include "OVR_Atomic.h"
+#include "OVR_Log.h"
+
+namespace OVR {
+
+#ifdef OVR_CC_ARM
+void* ReturnArg0(void* p)
+{
+ return p;
+}
+#endif
+
+// ***** Reference Count Base implementation
+
+RefCountImplCore::~RefCountImplCore()
+{
+ // RefCount can be either 1 or 0 here.
+ // 0 if Release() was properly called.
+ // 1 if the object was declared on stack or as an aggregate.
+ OVR_ASSERT(RefCount <= 1);
+}
+
+#ifdef OVR_BUILD_DEBUG
+void RefCountImplCore::reportInvalidDelete(void *pmem)
+{
+ OVR_DEBUG_LOG(
+ ("Invalid delete call on ref-counted object at %p. Please use Release()", pmem));
+ OVR_ASSERT(0);
+}
+#endif
+
+RefCountNTSImplCore::~RefCountNTSImplCore()
+{
+ // RefCount can be either 1 or 0 here.
+ // 0 if Release() was properly called.
+ // 1 if the object was declared on stack or as an aggregate.
+ OVR_ASSERT(RefCount <= 1);
+}
+
+#ifdef OVR_BUILD_DEBUG
+void RefCountNTSImplCore::reportInvalidDelete(void *pmem)
+{
+ OVR_DEBUG_LOG(
+ ("Invalid delete call on ref-counted object at %p. Please use Release()", pmem));
+ OVR_ASSERT(0);
+}
+#endif
+
+
+// *** Thread-Safe RefCountImpl
+
+void RefCountImpl::AddRef()
+{
+ AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1);
+}
+void RefCountImpl::Release()
+{
+ if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
+ delete this;
+}
+
+// *** Thread-Safe RefCountVImpl w/virtual AddRef/Release
+
+void RefCountVImpl::AddRef()
+{
+ AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1);
+}
+void RefCountVImpl::Release()
+{
+ if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
+ delete this;
+}
+
+// *** NON-Thread-Safe RefCountImpl
+
+void RefCountNTSImpl::Release() const
+{
+ RefCount--;
+ if (RefCount == 0)
+ delete this;
+}
+
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_RefCount.h b/LibOVR/Src/Kernel/OVR_RefCount.h new file mode 100644 index 0000000..8622050 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_RefCount.h @@ -0,0 +1,522 @@ +/************************************************************************************
+
+PublicHeader: Kernel
+Filename : OVR_RefCount.h
+Content : Reference counting implementation headers
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_RefCount_h
+#define OVR_RefCount_h
+
+#include "OVR_Types.h"
+#include "OVR_Allocator.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Reference Counting
+
+// There are three types of reference counting base classes:
+//
+// RefCountBase - Provides thread-safe reference counting (Default).
+// RefCountBaseNTS - Non Thread Safe version of reference counting.
+
+
+// ***** Declared classes
+
+template<class C>
+class RefCountBase;
+template<class C>
+class RefCountBaseNTS;
+
+class RefCountImpl;
+class RefCountNTSImpl;
+
+
+//-----------------------------------------------------------------------------------
+// ***** Implementation For Reference Counting
+
+// RefCountImplCore holds RefCount value and defines a few utility
+// functions shared by all implementations.
+
+class RefCountImplCore
+{
+protected:
+ volatile int RefCount;
+
+public:
+ // RefCountImpl constructor always initializes RefCount to 1 by default.
+ OVR_FORCE_INLINE RefCountImplCore() : RefCount(1) { }
+
+ // Need virtual destructor
+ // This: 1. Makes sure the right destructor's called.
+ // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
+ virtual ~RefCountImplCore();
+
+ // Debug method only.
+ int GetRefCount() const { return RefCount; }
+
+ // This logic is used to detect invalid 'delete' calls of reference counted
+ // objects. Direct delete calls are not allowed on them unless they come in
+ // internally from Release.
+#ifdef OVR_BUILD_DEBUG
+ static void OVR_CDECL reportInvalidDelete(void *pmem);
+ inline static void checkInvalidDelete(RefCountImplCore *pmem)
+ {
+ if (pmem->RefCount != 0)
+ reportInvalidDelete(pmem);
+ }
+#else
+ inline static void checkInvalidDelete(RefCountImplCore *) { }
+#endif
+
+ // Base class ref-count content should not be copied.
+ void operator = (const RefCountImplCore &) { }
+};
+
+class RefCountNTSImplCore
+{
+protected:
+ mutable int RefCount;
+
+public:
+ // RefCountImpl constructor always initializes RefCount to 1 by default.
+ OVR_FORCE_INLINE RefCountNTSImplCore() : RefCount(1) { }
+
+ // Need virtual destructor
+ // This: 1. Makes sure the right destructor's called.
+ // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
+ virtual ~RefCountNTSImplCore();
+
+ // Debug method only.
+ int GetRefCount() const { return RefCount; }
+
+ // This logic is used to detect invalid 'delete' calls of reference counted
+ // objects. Direct delete calls are not allowed on them unless they come in
+ // internally from Release.
+#ifdef OVR_BUILD_DEBUG
+ static void OVR_CDECL reportInvalidDelete(void *pmem);
+ OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem)
+ {
+ if (pmem->RefCount != 0)
+ reportInvalidDelete(pmem);
+ }
+#else
+ OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { }
+#endif
+
+ // Base class ref-count content should not be copied.
+ void operator = (const RefCountNTSImplCore &) { }
+};
+
+
+
+// RefCountImpl provides Thread-Safe implementation of reference counting, so
+// it should be used by default in most places.
+
+class RefCountImpl : public RefCountImplCore
+{
+public:
+ // Thread-Safe Ref-Count Implementation.
+ void AddRef();
+ void Release();
+};
+
+// RefCountVImpl provides Thread-Safe implementation of reference counting, plus,
+// virtual AddRef and Release.
+
+class RefCountVImpl : public RefCountImplCore
+{
+public:
+ // Thread-Safe Ref-Count Implementation.
+ virtual void AddRef();
+ virtual void Release();
+};
+
+
+// RefCountImplNTS provides Non-Thread-Safe implementation of reference counting,
+// which is slightly more efficient since it doesn't use atomics.
+
+class RefCountNTSImpl : public RefCountNTSImplCore
+{
+public:
+ OVR_FORCE_INLINE void AddRef() const { RefCount++; }
+ void Release() const;
+};
+
+
+
+// RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking
+// to the reference counting implementation. Base must be one of the RefCountImpl classes.
+
+template<class Base>
+class RefCountBaseStatImpl : public Base
+{
+public:
+ RefCountBaseStatImpl() { }
+
+ // *** Override New and Delete
+
+ // DOM-IGNORE-BEGIN
+ // Undef new temporarily if it is being redefined
+#ifdef OVR_DEFINE_NEW
+#undef new
+#endif
+
+#ifdef OVR_BUILD_DEBUG
+ // Custom check used to detect incorrect calls of 'delete' on ref-counted objects.
+ #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \
+ do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0)
+#else
+ #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p)
+#endif
+
+ // Redefine all new & delete operators.
+ OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE)
+
+#ifdef OVR_DEFINE_NEW
+#define new OVR_DEFINE_NEW
+#endif
+ // OVR_BUILD_DEFINE_NEW
+ // DOM-IGNORE-END
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// *** End user RefCountBase<> classes
+
+
+// RefCountBase is a base class for classes that require thread-safe reference
+// counting; it also overrides the new and delete operators to use MemoryHeap.
+//
+// Reference counted objects start out with RefCount value of 1. Further lifetime
+// management is done through the AddRef() and Release() methods, typically
+// hidden by Ptr<>.
+
+template<class C>
+class RefCountBase : public RefCountBaseStatImpl<RefCountImpl>
+{
+public:
+ // Constructor.
+ OVR_FORCE_INLINE RefCountBase() : RefCountBaseStatImpl<RefCountImpl>() { }
+};
+
+// RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release
+
+template<class C>
+class RefCountBaseV : public RefCountBaseStatImpl<RefCountVImpl>
+{
+public:
+ // Constructor.
+ OVR_FORCE_INLINE RefCountBaseV() : RefCountBaseStatImpl<RefCountVImpl>() { }
+};
+
+
+// RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference
+// counting; it also overrides the new and delete operators to use MemoryHeap.
+// This class should only be used if all pointers to it are known to be assigned,
+// destroyed and manipulated within one thread.
+//
+// Reference counted objects start out with RefCount value of 1. Further lifetime
+// management is done through the AddRef() and Release() methods, typically
+// hidden by Ptr<>.
+
+template<class C>
+class RefCountBaseNTS : public RefCountBaseStatImpl<RefCountNTSImpl>
+{
+public:
+ // Constructor.
+ OVR_FORCE_INLINE RefCountBaseNTS() : RefCountBaseStatImpl<RefCountNTSImpl>() { }
+};
+
+//-----------------------------------------------------------------------------------
+// ***** Pickable template pointer
+enum PickType { PickValue };
+
+template <typename T>
+class Pickable
+{
+public:
+ Pickable() : pV(NULL) {}
+ explicit Pickable(T* p) : pV(p) {}
+ Pickable(T* p, PickType) : pV(p)
+ {
+ OVR_ASSERT(pV);
+ if (pV)
+ pV->AddRef();
+ }
+ template <typename OT>
+ Pickable(const Pickable<OT>& other) : pV(other.GetPtr()) {}
+
+public:
+ Pickable& operator =(const Pickable& other)
+ {
+ OVR_ASSERT(pV == NULL);
+ pV = other.pV;
+ // Extra check.
+ //other.pV = NULL;
+ return *this;
+ }
+
+public:
+ T* GetPtr() const { return pV; }
+ T* operator->() const
+ {
+ return pV;
+ }
+ T& operator*() const
+ {
+ OVR_ASSERT(pV);
+ return *pV;
+ }
+
+private:
+ T* pV;
+};
+
+template <typename T>
+OVR_FORCE_INLINE
+Pickable<T> MakePickable(T* p)
+{
+ return Pickable<T>(p);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** Ref-Counted template pointer
+
+// Automatically AddRefs and Releases interfaces
+
+void* ReturnArg0(void* p);
+
+template<class C>
+class Ptr
+{
+#ifdef OVR_CC_ARM
+ static C* ReturnArg(void* p) { return (C*)ReturnArg0(p); }
+#endif
+
+protected:
+ C *pObject;
+
+public:
+
+ // Constructors
+ OVR_FORCE_INLINE Ptr() : pObject(0)
+ { }
+#ifdef OVR_CC_ARM
+ OVR_FORCE_INLINE Ptr(C &robj) : pObject(ReturnArg(&robj))
+#else
+ OVR_FORCE_INLINE Ptr(C &robj) : pObject(&robj)
+#endif
+ { }
+ OVR_FORCE_INLINE Ptr(Pickable<C> v) : pObject(v.GetPtr())
+ {
+ // No AddRef() on purpose.
+ }
+ OVR_FORCE_INLINE Ptr(Ptr<C>& other, PickType) : pObject(other.pObject)
+ {
+ other.pObject = NULL;
+ // No AddRef() on purpose.
+ }
+ OVR_FORCE_INLINE Ptr(C *pobj)
+ {
+ if (pobj) pobj->AddRef();
+ pObject = pobj;
+ }
+ OVR_FORCE_INLINE Ptr(const Ptr<C> &src)
+ {
+ if (src.pObject) src.pObject->AddRef();
+ pObject = src.pObject;
+ }
+
+ template<class R>
+ OVR_FORCE_INLINE Ptr(Ptr<R> &src)
+ {
+ if (src) src->AddRef();
+ pObject = src;
+ }
+ template<class R>
+ OVR_FORCE_INLINE Ptr(Pickable<R> v) : pObject(v.GetPtr())
+ {
+ // No AddRef() on purpose.
+ }
+
+ // Destructor
+ OVR_FORCE_INLINE ~Ptr()
+ {
+ if (pObject) pObject->Release();
+ }
+
+ // Compares
+ OVR_FORCE_INLINE bool operator == (const Ptr &other) const { return pObject == other.pObject; }
+ OVR_FORCE_INLINE bool operator != (const Ptr &other) const { return pObject != other.pObject; }
+
+ OVR_FORCE_INLINE bool operator == (C *pother) const { return pObject == pother; }
+ OVR_FORCE_INLINE bool operator != (C *pother) const { return pObject != pother; }
+
+
+ OVR_FORCE_INLINE bool operator < (const Ptr &other) const { return pObject < other.pObject; }
+
+ // Assignment
+ template<class R>
+ OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<R> &src)
+ {
+ if (src) src->AddRef();
+ if (pObject) pObject->Release();
+ pObject = src;
+ return *this;
+ }
+ // Specialization
+ OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<C> &src)
+ {
+ if (src) src->AddRef();
+ if (pObject) pObject->Release();
+ pObject = src;
+ return *this;
+ }
+
+ OVR_FORCE_INLINE const Ptr<C>& operator = (C *psrc)
+ {
+ if (psrc) psrc->AddRef();
+ if (pObject) pObject->Release();
+ pObject = psrc;
+ return *this;
+ }
+ OVR_FORCE_INLINE const Ptr<C>& operator = (C &src)
+ {
+ if (pObject) pObject->Release();
+ pObject = &src;
+ return *this;
+ }
+ OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<C> src)
+ {
+ return Pick(src);
+ }
+ template<class R>
+ OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<R> src)
+ {
+ return Pick(src);
+ }
+
+ // Set Assignment
+ template<class R>
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<R> &src)
+ {
+ if (src) src->AddRef();
+ if (pObject) pObject->Release();
+ pObject = src;
+ return *this;
+ }
+ // Specialization
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<C> &src)
+ {
+ if (src) src->AddRef();
+ if (pObject) pObject->Release();
+ pObject = src;
+ return *this;
+ }
+
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(C *psrc)
+ {
+ if (psrc) psrc->AddRef();
+ if (pObject) pObject->Release();
+ pObject = psrc;
+ return *this;
+ }
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(C &src)
+ {
+ if (pObject) pObject->Release();
+ pObject = &src;
+ return *this;
+ }
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(Pickable<C> src)
+ {
+ return Pick(src);
+ }
+
+ // Nulls ref-counted pointer without decrement
+ OVR_FORCE_INLINE void NullWithoutRelease()
+ {
+ pObject = 0;
+ }
+
+ // Clears the pointer to the object
+ OVR_FORCE_INLINE void Clear()
+ {
+ if (pObject) pObject->Release();
+ pObject = 0;
+ }
+
+ // Obtain pointer reference directly, for D3D interfaces
+ OVR_FORCE_INLINE C*& GetRawRef() { return pObject; }
+
+ // Access Operators
+ OVR_FORCE_INLINE C* GetPtr() const { return pObject; }
+ OVR_FORCE_INLINE C& operator * () const { return *pObject; }
+ OVR_FORCE_INLINE C* operator -> () const { return pObject; }
+ // Conversion
+ OVR_FORCE_INLINE operator C* () const { return pObject; }
+
+ // Pickers.
+
+ // Pick a value.
+ OVR_FORCE_INLINE Ptr<C>& Pick(Ptr<C>& other)
+ {
+ if (&other != this)
+ {
+ if (pObject) pObject->Release();
+ pObject = other.pObject;
+ other.pObject = 0;
+ }
+
+ return *this;
+ }
+
+ OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<C> v)
+ {
+ if (v.GetPtr() != pObject)
+ {
+ if (pObject) pObject->Release();
+ pObject = v.GetPtr();
+ }
+
+ return *this;
+ }
+
+ template<class R>
+ OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<R> v)
+ {
+ if (v.GetPtr() != pObject)
+ {
+ if (pObject) pObject->Release();
+ pObject = v.GetPtr();
+ }
+
+ return *this;
+ }
+
+ OVR_FORCE_INLINE Ptr<C>& Pick(C* p)
+ {
+ if (p != pObject)
+ {
+ if (pObject) pObject->Release();
+ pObject = p;
+ }
+
+ return *this;
+ }
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Std.cpp b/LibOVR/Src/Kernel/OVR_Std.cpp new file mode 100644 index 0000000..088f9e9 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Std.cpp @@ -0,0 +1,1025 @@ +/************************************************************************************
+
+Filename : OVR_Std.cpp
+Content : Standard C function implementation
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Std.h"
+#include "OVR_Alg.h"
+
+// localeconv() call in OVR_strtod()
+#include <locale.h>
+
+namespace OVR {
+
+// Source for functions not available on all platforms is included here.
+
+// Case insensitive compare implemented in platform-specific way.
+int OVR_CDECL OVR_stricmp(const char* a, const char* b)
+{
+#if defined(OVR_OS_WIN32)
+ #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ return ::_stricmp(a, b);
+ #else
+ return ::stricmp(a, b);
+ #endif
+
+#else
+ return strcasecmp(a, b);
+#endif
+}
+
+int OVR_CDECL OVR_strnicmp(const char* a, const char* b, UPInt count)
+{
+#if defined(OVR_OS_WIN32)
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ return ::_strnicmp(a, b, count);
+#else
+ return ::strnicmp(a, b, count);
+#endif
+
+#else
+ return strncasecmp(a, b, count);
+#endif
+}
+
+wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, UPInt destsize, const wchar_t* src)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ wcscpy_s(dest, destsize, src);
+ return dest;
+#elif defined(OVR_OS_WIN32)
+ OVR_UNUSED(destsize);
+ wcscpy(dest, src);
+ return dest;
+#else
+ UPInt l = OVR_wcslen(src) + 1; // incl term null
+ l = (l < destsize) ? l : destsize;
+ memcpy(dest, src, l * sizeof(wchar_t));
+ return dest;
+#endif
+}
+
+wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, UPInt destsize, const wchar_t* src, UPInt count)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ wcsncpy_s(dest, destsize, src, count);
+ return dest;
+#else
+ UPInt srclen = OVR_wcslen(src);
+ UPInt l = Alg::Min(srclen, count);
+ l = (l < destsize) ? l : destsize;
+ memcpy(dest, src, l * sizeof(wchar_t));
+ if (count > srclen)
+ {
+ UPInt remLen = Alg::Min(destsize - l, (count - srclen));
+ memset(&dest[l], 0, sizeof(wchar_t)*remLen);
+ }
+ else if (l < destsize)
+ dest[l] = 0;
+ return dest;
+#endif
+}
+
+
+wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, UPInt destsize, const wchar_t* src)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ wcscat_s(dest, destsize, src);
+ return dest;
+#elif defined(OVR_OS_WIN32)
+ OVR_UNUSED(destsize);
+ wcscat(dest, src);
+ return dest;
+#else
+ UPInt dstlen = OVR_wcslen(dest); // do not incl term null
+ UPInt srclen = OVR_wcslen(src) + 1; // incl term null
+ UPInt copylen = (dstlen + srclen < destsize) ? srclen : destsize - dstlen;
+ memcpy(dest + dstlen, src, copylen * sizeof(wchar_t));
+ return dest;
+#endif
+}
+
+UPInt OVR_CDECL OVR_wcslen(const wchar_t* str)
+{
+#if defined(OVR_OS_WIN32)
+ return wcslen(str);
+#else
+ UPInt i = 0;
+ while(str[i] != '\0')
+ ++i;
+ return i;
+#endif
+}
+
+int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b)
+{
+#if defined(OVR_OS_WIN32) || defined(OVR_OS_LINUX)
+ return wcscmp(a, b);
+#else
+ // not supported, use custom implementation
+ const wchar_t *pa = a, *pb = b;
+ while (*pa && *pb)
+ {
+ wchar_t ca = *pa;
+ wchar_t cb = *pb;
+ if (ca < cb)
+ return -1;
+ else if (ca > cb)
+ return 1;
+ pa++;
+ pb++;
+ }
+ if (*pa)
+ return 1;
+ else if (*pb)
+ return -1;
+ else
+ return 0;
+#endif
+}
+
+int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b)
+{
+#if defined(OVR_OS_WIN32)
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ return ::_wcsicmp(a, b);
+#else
+ return ::wcsicmp(a, b);
+#endif
+#elif defined(OVR_OS_MAC) || defined(__CYGWIN__) || defined(OVR_OS_ANDROID) || defined(OVR_OS_IPHONE)
+ // not supported, use custom implementation
+ const wchar_t *pa = a, *pb = b;
+ while (*pa && *pb)
+ {
+ wchar_t ca = OVR_towlower(*pa);
+ wchar_t cb = OVR_towlower(*pb);
+ if (ca < cb)
+ return -1;
+ else if (ca > cb)
+ return 1;
+ pa++;
+ pb++;
+ }
+ if (*pa)
+ return 1;
+ else if (*pb)
+ return -1;
+ else
+ return 0;
+#else
+ return wcscasecmp(a, b);
+#endif
+}
+
+// This function is not inline because of dependency on <locale.h>
+double OVR_CDECL OVR_strtod(const char* string, char** tailptr)
+{
+#if !defined(OVR_OS_ANDROID)
+ const char s = *localeconv()->decimal_point;
+
+ if (s != '.')
+ {
+ char buffer[347 + 1];
+
+ OVR_strcpy(buffer, sizeof(buffer), string);
+
+ for (char* c = buffer; *c != '\0'; ++c)
+ {
+ if (*c == '.')
+ {
+ *c = s;
+ break;
+ }
+ }
+
+ return strtod(buffer, tailptr);
+ }
+#endif
+
+ return strtod(string, tailptr);
+}
+
+
+#ifndef OVR_NO_WCTYPE
+
+//// Use this class to generate Unicode bitsets. For example:
+////
+//// UnicodeBitSet bitSet;
+//// for(unsigned i = 0; i < 65536; ++i)
+//// {
+//// if (iswalpha(i))
+//// bitSet.Set(i);
+//// }
+//// bitSet.Dump();
+////
+////---------------------------------------------------------------
+//class UnicodeBitSet
+//{
+//public:
+// UnicodeBitSet()
+// {
+// memset(Offsets, 0, sizeof(Offsets));
+// memset(Bits, 0, sizeof(Bits));
+// }
+//
+// void Set(unsigned bit) { Bits[bit >> 8][(bit >> 4) & 15] |= 1 << (bit & 15); }
+//
+// void Dump()
+// {
+// unsigned i, j;
+// unsigned offsetCount = 0;
+// for(i = 0; i < 256; ++i)
+// {
+// if (isNull(i)) Offsets[i] = 0;
+// else
+// if (isFull(i)) Offsets[i] = 1;
+// else Offsets[i] = UInt16(offsetCount++ * 16 + 256);
+// }
+// for(i = 0; i < 16; ++i)
+// {
+// for(j = 0; j < 16; ++j)
+// {
+// printf("%5u,", Offsets[i*16+j]);
+// }
+// printf("\n");
+// }
+// for(i = 0; i < 256; ++i)
+// {
+// if (Offsets[i] > 255)
+// {
+// for(j = 0; j < 16; j++)
+// {
+// printf("%5u,", Bits[i][j]);
+// }
+// printf("\n");
+// }
+// }
+// }
+//
+//private:
+// bool isNull(unsigned n) const
+// {
+// const UInt16* p = Bits[n];
+// for(unsigned i = 0; i < 16; ++i)
+// if (p[i] != 0) return false;
+// return true;
+// }
+//
+// bool isFull(unsigned n) const
+// {
+// const UInt16* p = Bits[n];
+// for(unsigned i = 0; i < 16; ++i)
+// if (p[i] != 0xFFFF) return false;
+// return true;
+// }
+//
+// UInt16 Offsets[256];
+// UInt16 Bits[256][16];
+//};
+
+
+const UInt16 UnicodeAlnumBits[] = {
+ 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
+ 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
+ 640, 656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 672, 688, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 704, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720,
+ 1, 1, 1, 1, 736, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 768, 784, 1, 800, 816, 832,
+ 0, 0, 0, 1023,65534, 2047,65534, 2047, 0, 0, 0, 524,65535,65407,65535,65407,
+65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
+ 0, 0, 0, 0, 32, 0, 0, 1024,55104,65535,65531,65535,32767,64767,65535, 15,
+65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
+ 0, 0, 0,65534,65535, 639,65534,65535, 255, 0, 0, 0, 0,65535, 2047, 7,
+ 0, 0,65534, 2047,65534, 63, 1023,65535,65535,65535,65535,65535,65535, 8175, 8702, 8191,
+ 0,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
+65518,65535,65535,58367, 8191,65281,65487, 0,40942,65529,65023,50117, 6559,45184,65487, 3,
+34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0,
+40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0,
+57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0,
+57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 12,
+65534,65535,65535, 2047,32767, 1023, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0,
+ 1, 0, 1023, 0,65279,65535, 2047,65534, 3843,65279,65535, 8191, 0, 0, 0, 0,
+65535,65535,63227, 327, 1023, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 127,
+65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
+65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
+32767,32573,65535,65535,65407, 2047,65024, 3, 0, 0,65535,65535,65535,65535,65535, 31,
+65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
+65535,65535,65535,65535,65535,65535,40959, 127,65534, 2047,65535,65535,65535,65535, 2047, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 0, 1023, 0,
+ 0, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
+65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
+ 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0,
+64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
+ 192, 0, 1022, 1792,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 2047,
+65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
+65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
+65535,65535,65535,16383, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
+ 0, 0, 0, 0, 0, 0, 0,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
+ 0, 1023,65534, 2047,65534, 2047,65472,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
+
+const UInt16 UnicodeAlphaBits[] = {
+ 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
+ 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
+ 640, 656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 672, 688, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 704, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720,
+ 1, 1, 1, 1, 736, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 768, 784, 1, 800, 816, 832,
+ 0, 0, 0, 0,65534, 2047,65534, 2047, 0, 0, 0, 0,65535,65407,65535,65407,
+65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
+ 0, 0, 0, 0, 32, 0, 0, 1024,55104,65535,65531,65535,32767,64767,65535, 15,
+65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
+ 0, 0, 0,65534,65535, 639,65534,65535, 255, 0, 0, 0, 0,65535, 2047, 7,
+ 0, 0,65534, 2047,65534, 63, 0,65535,65535,65535,65535,65535,65535, 8175, 8702, 7168,
+ 0,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
+65518,65535,65535,58367, 8191,65281, 15, 0,40942,65529,65023,50117, 6559,45184, 15, 3,
+34788,65529,65023,50029, 6535,24064, 0, 31,45038,65531,65023,58349, 7103, 1, 1, 0,
+40942,65529,65023,58317, 6543,45248, 3, 0,51180,54845,50968,50111, 7623, 128, 0, 0,
+57326,65533,65023,50159, 7647, 96, 3, 0,57324,65533,65023,50159, 7647,16480, 3, 0,
+57324,65533,65023,50175, 7631, 128, 3, 0,65516,64639,65535,12283,32895,65375, 0, 12,
+65534,65535,65535, 2047,32767, 0, 0, 0, 9622,65264,60590,15359, 8223,12288, 0, 0,
+ 1, 0, 0, 0,65279,65535, 2047,65534, 3843,65279,65535, 8191, 0, 0, 0, 0,
+65535,65535,63227, 327, 0, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 127,
+65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
+65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
+32767,32573,65535,65535,65407, 2047, 0, 0, 0, 0,65535,65535,65535,65535,65535, 31,
+65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
+65535,65535,65535,65535,65535,65535,40959, 127,65534, 2047,65535,65535,65535,65535, 2047, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 0, 0, 0,
+ 0, 0,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
+65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
+ 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0,
+64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
+ 192, 0, 1022, 1792,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 2047,
+65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
+65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
+65535,65535,65535,16383, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
+ 0, 0, 0, 0, 0, 0, 0,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
+ 0, 0,65534, 2047,65534, 2047,65472,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
+
+const UInt16 UnicodeDigitBits[] = {
+ 256, 0, 0, 0, 0, 0, 272, 0, 0, 288, 304, 320, 336, 352, 368, 384,
+ 400, 0, 0, 416, 0, 0, 0, 432, 448, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 464,
+ 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 1023,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65408, 0,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 1023, 0, 0,
+ 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,65024, 3, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1023, 0,
+ 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+const UInt16 UnicodeSpaceBits[] = {
+ 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+15872, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 4095, 0,33536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+const UInt16 UnicodeXDigitBits[] = {
+ 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272,
+ 0, 0, 0, 1023, 126, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1023, 126, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+// Uncomment if necessary
+//const UInt16 UnicodeCntrlBits[] = {
+// 256, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 0, 0,
+// 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320, 336,
+//65535,65535, 0, 0, 0, 0, 0,32768,65535,65535, 0, 0, 0, 0, 0, 0,
+//32768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//30720, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//61440, 0,31744, 0, 0, 0,64512, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,32768,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3584};
+//
+//const UInt16 UnicodeGraphBits[] = {
+// 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
+// 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
+// 640, 656, 0, 672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 688, 704, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 736,
+// 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 768, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 784, 800, 1, 816, 832, 848,
+// 0, 0,65534,65535,65535,65535,65535,32767, 0, 0,65534,65535,65535,65535,65535,65535,
+//65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
+// 0, 0, 0, 0, 32, 0, 0,17408,55232,65535,65531,65535,32767,64767,65535, 15,
+//65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
+// 0, 0, 0,65534,65535,65151,65534,65535, 1791, 0, 0,16384, 9,65535, 2047, 31,
+// 4096,34816,65534, 2047,65534, 63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191,
+//16383,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
+//65518,65535,65535,58367, 8191,65281,65535, 1,40942,65529,65023,50117, 6559,45184,65487, 3,
+//34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0,
+//40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0,
+//57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0,
+//57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 28,
+//65534,65535,65535, 2047,65535, 4095, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0,
+//65521, 7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191, 0, 0, 0, 0,
+//65535,65535,63227, 327,65535, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 2175,
+//65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
+//65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
+//32767,32573,65535,65535,65407, 2047,65534, 3, 0, 0,65535,65535,65535,65535,65535, 31,
+//65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
+//65535,65535,65535,65535,65535,65535,65535, 127,65534, 8191,65535,65535,65535,65535,16383, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 6128, 1023, 0,
+// 2047, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
+//65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
+// 0,65535, 255,65535,16239, 0, 0,57344,24576, 0, 0, 0, 0, 0, 0, 0,
+//64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//65486,65523, 1022, 1793,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 4095,
+//65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
+//65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
+//65535,65535,65535,65535, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
+// 0, 0, 0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
+//63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
+//
+//const UInt16 UnicodePrintBits[] = {
+// 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
+// 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
+// 640, 656, 0, 672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 688, 704, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 736,
+// 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 768, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 784, 800, 1, 816, 832, 848,
+// 512, 0,65535,65535,65535,65535,65535,32767, 0, 0,65535,65535,65535,65535,65535,65535,
+//65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
+// 0, 0, 0, 0, 32, 0, 0,17408,55232,65535,65531,65535,32767,64767,65535, 15,
+//65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
+// 0, 0, 0,65534,65535,65151,65534,65535, 1791, 0, 0,16384, 9,65535, 2047, 31,
+// 4096,34816,65534, 2047,65534, 63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191,
+//16383,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
+//65518,65535,65535,58367, 8191,65281,65535, 1,40942,65529,65023,50117, 6559,45184,65487, 3,
+//34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0,
+//40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0,
+//57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0,
+//57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 28,
+//65534,65535,65535, 2047,65535, 4095, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0,
+//65521, 7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191, 0, 0, 0, 0,
+//65535,65535,63227, 327,65535, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 2175,
+//65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
+//65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
+//32767,32573,65535,65535,65407, 2047,65534, 3, 0, 0,65535,65535,65535,65535,65535, 31,
+//65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
+//65535,65535,65535,65535,65535,65535,65535, 127,65534, 8191,65535,65535,65535,65535,16383, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 6128, 1023, 0,
+// 2047, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
+//65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
+// 0,65535, 255,65535,16239, 0, 0,57344,24576, 0, 0, 0, 0, 0, 0, 0,
+//64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//65487,65523, 1022, 1793,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 4095,
+//65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
+//65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
+//65535,65535,65535,65535, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
+// 0, 0, 0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535,40959,
+//63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
+//
+//const UInt16 UnicodePunctBits[] = {
+// 256, 0, 0, 272, 0, 288, 304, 320, 0, 336, 0, 0, 0, 352, 368, 384,
+// 400, 0, 0, 416, 0, 0, 432, 448, 464, 0, 0, 0, 0, 0, 0, 0,
+// 480, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 528, 544, 560,
+// 0, 0,65534,64512, 1,63488, 1,30720, 0, 0,65534,65535, 0, 128, 0, 128,
+// 0, 0, 0, 0, 0, 0, 0,16384, 128, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0,64512, 0, 0, 1536, 0, 0,16384, 9, 0, 0, 24,
+// 4096,34816, 0, 0, 0, 0,15360, 0, 0, 0, 0, 0, 0, 16, 0, 0,
+//16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16,
+// 0, 0, 0, 0,32768, 3072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//65520, 7, 0,15360, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0,64512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2048,
+// 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0,24576, 0, 0, 6144, 0, 0, 0, 0,14336, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6128, 0, 0,
+// 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0,65535, 255,65535,16239, 0, 0,24576,24576, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//65294,65523, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2048,
+// 0, 0, 0,49152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0,65535,65055,65527, 3339, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//63470,35840, 1,47104, 0,10240, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+//
+//const UInt16 UnicodeLowerBits[] = {
+// 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 368,
+// 384, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0, 0, 432,
+// 0, 0, 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0,32768,65535,65407,
+//43690,43690,43690,21930,43861,43690,43690,54442,12585,20004,11562,58961,23392,46421,43690,43565,
+//43690,43690,43688, 10, 0,65535,65535,65535,65535,65535,16383, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,61440,65535,32767,43235,43690, 15,
+// 0, 0, 0,65535,65535,65535,43690,43690,40962,43690,43690,43690, 4372,43690,43690, 554,
+// 0, 0, 0, 0, 0, 0,65534,65535, 255, 0, 0, 0, 0, 0, 0, 0,
+//43690,43690,43690,43690,43690,43690,43690,43690,43690, 4074,43690,43690,43690,43690,43690, 682,
+// 255, 63, 255, 255, 63, 255, 255,16383,65535,65535,65535,20703, 4316, 207, 255, 4316,
+// 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0,
+//50176, 8,32768, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 127, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+//
+//const UInt16 UnicodeUpperBits[] = {
+// 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 384,
+// 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416,
+// 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,32639, 0, 0,
+//21845,21845,21845,43605,21674,21845,21845,11093,52950,45531,53973, 4526,44464,19114,21845,21974,
+//21845,21845,21844, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0,55104,65534, 4091, 0, 0,21532,21845, 0,
+//65535,65535,65535, 0, 0, 0,21845,21845,20481,21845,21845,21845, 2187,21845,21845, 277,
+// 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535,65535, 63, 0, 0, 0,
+//21845,21845,21845,21845,21845,21845,21845,21845,21845, 21,21845,21845,21845,21845,21845, 341,
+//65280,16128,65280,65280,16128,43520,65280, 0,65280,65280,65280, 7936, 7936, 3840, 7936, 7936,
+//14468,15911,15696, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+
+// MA: March 19, 2010
+// Modified ToUpper and ToLower tables to match values expected by AS3 tests.
+// ToLower modifications:
+// 304 -> 105
+// 1024 -> 1104 *
+// 1037 -> 1117 *
+// UoUpper modifications:
+// 255 -> 376
+// 305 -> 73
+// 383 -> 83
+// 1104 -> 1024 *
+// 1117 -> 1037 *
+// Entries marked with a '*' don't make complete sense based on Unicode manual, although
+// they match AS3.
+
+
+static const UInt16 UnicodeToUpperBits[] = {
+ 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 368,
+ 0, 384, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416,
+ 0, 0, 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,65407,
+43690,43690,43690,21674,43349,43690,43690,54442, 4392, 516, 8490, 8785,21056,46421,43690,43048, // MA: Modified for AS3.
+43690, 170, 0, 0, 0, 2776,33545, 36, 3336, 4, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,61440,65534,32767, 0,43688, 0,
+ 0, 0, 0,65535,65535,65535,43690,43690, 2,43690,43690,43690, 4372,43690,35498, 554, // MA: Modified for AS3.
+ 0, 0, 0, 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0,
+43690,43690,43690,43690,43690,43690,43690,43690,43690, 42,43690,43690,43690,43690,43690, 682,
+ 255, 63, 255, 255, 63, 170, 255,16383, 0, 0, 0, 3, 0, 3, 35, 0,
+ 0, 0, 0, 0, 0, 0, 0,65535, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535, 1023, 0,
+ 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static const UInt16 UnicodeToLowerBits[] = {
+ 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 384,
+ 0, 400, 0, 0, 416, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432,
+ 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,32639, 0, 0,
+21845,21845,21845,43605,21674,21845,21845,11093,52950,45531,53909, 4526,42128,19114,21845,21522,// MA: Modidied for AS3.
+21845, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,55104,65534, 4091, 0, 0, 0,21844, 0,
+65535,65535,65535, 0, 0, 0,21845,21845, 1,21845,21845,21845, 2186,21845,17749, 277,
+ 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535,65535, 63, 0, 0, 0,
+21845,21845,21845,21845,21845,21845,21845,21845,21845, 21,21845,21845,21845,21845,21845, 341,
+65280,16128,65280,65280,16128,43520,65280, 0, 0, 0, 0, 3840, 3840, 3840, 7936, 3840,
+ 0, 0, 0, 0, 0, 0,65535, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65472,65535, 0, 0, 0,
+ 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+struct GUnicodePairType
+{
+ UInt16 Key, Value;
+};
+
+static inline bool CmpUnicodeKey(const GUnicodePairType& a, UInt16 key)
+{
+ return a.Key < key;
+}
+
+static const GUnicodePairType UnicodeToUpperTable[] = {
+{ 97, 65}, { 98, 66}, { 99, 67}, { 100, 68}, { 101, 69}, { 102, 70}, { 103, 71},
+{ 104, 72}, { 105, 73}, { 106, 74}, { 107, 75}, { 108, 76}, { 109, 77}, { 110, 78},
+{ 111, 79}, { 112, 80}, { 113, 81}, { 114, 82}, { 115, 83}, { 116, 84}, { 117, 85},
+{ 118, 86}, { 119, 87}, { 120, 88}, { 121, 89}, { 122, 90}, { 224, 192}, { 225, 193},
+{ 226, 194}, { 227, 195}, { 228, 196}, { 229, 197}, { 230, 198}, { 231, 199}, { 232, 200},
+{ 233, 201}, { 234, 202}, { 235, 203}, { 236, 204}, { 237, 205}, { 238, 206}, { 239, 207},
+{ 240, 208}, { 241, 209}, { 242, 210}, { 243, 211}, { 244, 212}, { 245, 213}, { 246, 214},
+{ 248, 216}, { 249, 217}, { 250, 218}, { 251, 219}, { 252, 220}, { 253, 221}, { 254, 222},
+{ 255, 376}, { 257, 256}, { 259, 258}, { 261, 260}, { 263, 262}, { 265, 264}, { 267, 266},
+{ 269, 268}, { 271, 270}, { 273, 272}, { 275, 274}, { 277, 276}, { 279, 278}, { 281, 280},
+{ 283, 282}, { 285, 284}, { 287, 286}, { 289, 288}, { 291, 290}, { 293, 292}, { 295, 294},
+{ 297, 296}, { 299, 298}, { 301, 300}, { 303, 302}, { 305, 73}, { 307, 306}, { 309, 308}, { 311, 310},
+{ 314, 313}, { 316, 315}, { 318, 317}, { 320, 319}, { 322, 321}, { 324, 323}, { 326, 325},
+{ 328, 327}, { 331, 330}, { 333, 332}, { 335, 334}, { 337, 336}, { 339, 338}, { 341, 340},
+{ 343, 342}, { 345, 344}, { 347, 346}, { 349, 348}, { 351, 350}, { 353, 352}, { 355, 354},
+{ 357, 356}, { 359, 358}, { 361, 360}, { 363, 362}, { 365, 364}, { 367, 366}, { 369, 368},
+{ 371, 370}, { 373, 372}, { 375, 374}, { 378, 377}, { 380, 379}, { 382, 381}, { 383, 83}, { 387, 386},
+{ 389, 388}, { 392, 391}, { 396, 395}, { 402, 401}, { 409, 408}, { 417, 416}, { 419, 418},
+{ 421, 420}, { 424, 423}, { 429, 428}, { 432, 431}, { 436, 435}, { 438, 437}, { 441, 440},
+{ 445, 444}, { 454, 452}, { 457, 455}, { 460, 458}, { 462, 461}, { 464, 463}, { 466, 465},
+{ 468, 467}, { 470, 469}, { 472, 471}, { 474, 473}, { 476, 475}, { 477, 398}, { 479, 478},
+{ 481, 480}, { 483, 482}, { 485, 484}, { 487, 486}, { 489, 488}, { 491, 490}, { 493, 492},
+{ 495, 494}, { 499, 497}, { 501, 500}, { 507, 506}, { 509, 508}, { 511, 510}, { 513, 512},
+{ 515, 514}, { 517, 516}, { 519, 518}, { 521, 520}, { 523, 522}, { 525, 524}, { 527, 526},
+{ 529, 528}, { 531, 530}, { 533, 532}, { 535, 534}, { 595, 385}, { 596, 390}, { 598, 393},
+{ 599, 394}, { 601, 399}, { 603, 400}, { 608, 403}, { 611, 404}, { 616, 407}, { 617, 406},
+{ 623, 412}, { 626, 413}, { 629, 415}, { 643, 425}, { 648, 430}, { 650, 433}, { 651, 434},
+{ 658, 439}, { 940, 902}, { 941, 904}, { 942, 905}, { 943, 906}, { 945, 913}, { 946, 914},
+{ 947, 915}, { 948, 916}, { 949, 917}, { 950, 918}, { 951, 919}, { 952, 920}, { 953, 921},
+{ 954, 922}, { 955, 923}, { 956, 924}, { 957, 925}, { 958, 926}, { 959, 927}, { 960, 928},
+{ 961, 929}, { 962, 931}, { 963, 931}, { 964, 932}, { 965, 933}, { 966, 934}, { 967, 935},
+{ 968, 936}, { 969, 937}, { 970, 938}, { 971, 939}, { 972, 908}, { 973, 910}, { 974, 911},
+{ 995, 994}, { 997, 996}, { 999, 998}, { 1001, 1000}, { 1003, 1002}, { 1005, 1004}, { 1007, 1006},
+{ 1072, 1040}, { 1073, 1041}, { 1074, 1042}, { 1075, 1043}, { 1076, 1044}, { 1077, 1045}, { 1078, 1046},
+{ 1079, 1047}, { 1080, 1048}, { 1081, 1049}, { 1082, 1050}, { 1083, 1051}, { 1084, 1052}, { 1085, 1053},
+{ 1086, 1054}, { 1087, 1055}, { 1088, 1056}, { 1089, 1057}, { 1090, 1058}, { 1091, 1059}, { 1092, 1060},
+{ 1093, 1061}, { 1094, 1062}, { 1095, 1063}, { 1096, 1064}, { 1097, 1065}, { 1098, 1066}, { 1099, 1067},
+{ 1100, 1068}, { 1101, 1069}, { 1102, 1070}, { 1103, 1071}, { 1104, 1024}, { 1105, 1025}, { 1106, 1026}, { 1107, 1027},
+{ 1108, 1028}, { 1109, 1029}, { 1110, 1030}, { 1111, 1031}, { 1112, 1032}, { 1113, 1033}, { 1114, 1034},
+{ 1115, 1035}, { 1116, 1036}, { 1117, 1037}, { 1118, 1038}, { 1119, 1039}, { 1121, 1120}, { 1123, 1122}, { 1125, 1124},
+{ 1127, 1126}, { 1129, 1128}, { 1131, 1130}, { 1133, 1132}, { 1135, 1134}, { 1137, 1136}, { 1139, 1138},
+{ 1141, 1140}, { 1143, 1142}, { 1145, 1144}, { 1147, 1146}, { 1149, 1148}, { 1151, 1150}, { 1153, 1152},
+{ 1169, 1168}, { 1171, 1170}, { 1173, 1172}, { 1175, 1174}, { 1177, 1176}, { 1179, 1178}, { 1181, 1180},
+{ 1183, 1182}, { 1185, 1184}, { 1187, 1186}, { 1189, 1188}, { 1191, 1190}, { 1193, 1192}, { 1195, 1194},
+{ 1197, 1196}, { 1199, 1198}, { 1201, 1200}, { 1203, 1202}, { 1205, 1204}, { 1207, 1206}, { 1209, 1208},
+{ 1211, 1210}, { 1213, 1212}, { 1215, 1214}, { 1218, 1217}, { 1220, 1219}, { 1224, 1223}, { 1228, 1227},
+{ 1233, 1232}, { 1235, 1234}, { 1237, 1236}, { 1239, 1238}, { 1241, 1240}, { 1243, 1242}, { 1245, 1244},
+{ 1247, 1246}, { 1249, 1248}, { 1251, 1250}, { 1253, 1252}, { 1255, 1254}, { 1257, 1256}, { 1259, 1258},
+{ 1263, 1262}, { 1265, 1264}, { 1267, 1266}, { 1269, 1268}, { 1273, 1272}, { 1377, 1329}, { 1378, 1330},
+{ 1379, 1331}, { 1380, 1332}, { 1381, 1333}, { 1382, 1334}, { 1383, 1335}, { 1384, 1336}, { 1385, 1337},
+{ 1386, 1338}, { 1387, 1339}, { 1388, 1340}, { 1389, 1341}, { 1390, 1342}, { 1391, 1343}, { 1392, 1344},
+{ 1393, 1345}, { 1394, 1346}, { 1395, 1347}, { 1396, 1348}, { 1397, 1349}, { 1398, 1350}, { 1399, 1351},
+{ 1400, 1352}, { 1401, 1353}, { 1402, 1354}, { 1403, 1355}, { 1404, 1356}, { 1405, 1357}, { 1406, 1358},
+{ 1407, 1359}, { 1408, 1360}, { 1409, 1361}, { 1410, 1362}, { 1411, 1363}, { 1412, 1364}, { 1413, 1365},
+{ 1414, 1366}, { 7681, 7680}, { 7683, 7682}, { 7685, 7684}, { 7687, 7686}, { 7689, 7688}, { 7691, 7690},
+{ 7693, 7692}, { 7695, 7694}, { 7697, 7696}, { 7699, 7698}, { 7701, 7700}, { 7703, 7702}, { 7705, 7704},
+{ 7707, 7706}, { 7709, 7708}, { 7711, 7710}, { 7713, 7712}, { 7715, 7714}, { 7717, 7716}, { 7719, 7718},
+{ 7721, 7720}, { 7723, 7722}, { 7725, 7724}, { 7727, 7726}, { 7729, 7728}, { 7731, 7730}, { 7733, 7732},
+{ 7735, 7734}, { 7737, 7736}, { 7739, 7738}, { 7741, 7740}, { 7743, 7742}, { 7745, 7744}, { 7747, 7746},
+{ 7749, 7748}, { 7751, 7750}, { 7753, 7752}, { 7755, 7754}, { 7757, 7756}, { 7759, 7758}, { 7761, 7760},
+{ 7763, 7762}, { 7765, 7764}, { 7767, 7766}, { 7769, 7768}, { 7771, 7770}, { 7773, 7772}, { 7775, 7774},
+{ 7777, 7776}, { 7779, 7778}, { 7781, 7780}, { 7783, 7782}, { 7785, 7784}, { 7787, 7786}, { 7789, 7788},
+{ 7791, 7790}, { 7793, 7792}, { 7795, 7794}, { 7797, 7796}, { 7799, 7798}, { 7801, 7800}, { 7803, 7802},
+{ 7805, 7804}, { 7807, 7806}, { 7809, 7808}, { 7811, 7810}, { 7813, 7812}, { 7815, 7814}, { 7817, 7816},
+{ 7819, 7818}, { 7821, 7820}, { 7823, 7822}, { 7825, 7824}, { 7827, 7826}, { 7829, 7828}, { 7841, 7840},
+{ 7843, 7842}, { 7845, 7844}, { 7847, 7846}, { 7849, 7848}, { 7851, 7850}, { 7853, 7852}, { 7855, 7854},
+{ 7857, 7856}, { 7859, 7858}, { 7861, 7860}, { 7863, 7862}, { 7865, 7864}, { 7867, 7866}, { 7869, 7868},
+{ 7871, 7870}, { 7873, 7872}, { 7875, 7874}, { 7877, 7876}, { 7879, 7878}, { 7881, 7880}, { 7883, 7882},
+{ 7885, 7884}, { 7887, 7886}, { 7889, 7888}, { 7891, 7890}, { 7893, 7892}, { 7895, 7894}, { 7897, 7896},
+{ 7899, 7898}, { 7901, 7900}, { 7903, 7902}, { 7905, 7904}, { 7907, 7906}, { 7909, 7908}, { 7911, 7910},
+{ 7913, 7912}, { 7915, 7914}, { 7917, 7916}, { 7919, 7918}, { 7921, 7920}, { 7923, 7922}, { 7925, 7924},
+{ 7927, 7926}, { 7929, 7928}, { 7936, 7944}, { 7937, 7945}, { 7938, 7946}, { 7939, 7947}, { 7940, 7948},
+{ 7941, 7949}, { 7942, 7950}, { 7943, 7951}, { 7952, 7960}, { 7953, 7961}, { 7954, 7962}, { 7955, 7963},
+{ 7956, 7964}, { 7957, 7965}, { 7968, 7976}, { 7969, 7977}, { 7970, 7978}, { 7971, 7979}, { 7972, 7980},
+{ 7973, 7981}, { 7974, 7982}, { 7975, 7983}, { 7984, 7992}, { 7985, 7993}, { 7986, 7994}, { 7987, 7995},
+{ 7988, 7996}, { 7989, 7997}, { 7990, 7998}, { 7991, 7999}, { 8000, 8008}, { 8001, 8009}, { 8002, 8010},
+{ 8003, 8011}, { 8004, 8012}, { 8005, 8013}, { 8017, 8025}, { 8019, 8027}, { 8021, 8029}, { 8023, 8031},
+{ 8032, 8040}, { 8033, 8041}, { 8034, 8042}, { 8035, 8043}, { 8036, 8044}, { 8037, 8045}, { 8038, 8046},
+{ 8039, 8047}, { 8048, 8122}, { 8049, 8123}, { 8050, 8136}, { 8051, 8137}, { 8052, 8138}, { 8053, 8139},
+{ 8054, 8154}, { 8055, 8155}, { 8056, 8184}, { 8057, 8185}, { 8058, 8170}, { 8059, 8171}, { 8060, 8186},
+{ 8061, 8187}, { 8112, 8120}, { 8113, 8121}, { 8144, 8152}, { 8145, 8153}, { 8160, 8168}, { 8161, 8169},
+{ 8165, 8172}, { 8560, 8544}, { 8561, 8545}, { 8562, 8546}, { 8563, 8547}, { 8564, 8548}, { 8565, 8549},
+{ 8566, 8550}, { 8567, 8551}, { 8568, 8552}, { 8569, 8553}, { 8570, 8554}, { 8571, 8555}, { 8572, 8556},
+{ 8573, 8557}, { 8574, 8558}, { 8575, 8559}, { 9424, 9398}, { 9425, 9399}, { 9426, 9400}, { 9427, 9401},
+{ 9428, 9402}, { 9429, 9403}, { 9430, 9404}, { 9431, 9405}, { 9432, 9406}, { 9433, 9407}, { 9434, 9408},
+{ 9435, 9409}, { 9436, 9410}, { 9437, 9411}, { 9438, 9412}, { 9439, 9413}, { 9440, 9414}, { 9441, 9415},
+{ 9442, 9416}, { 9443, 9417}, { 9444, 9418}, { 9445, 9419}, { 9446, 9420}, { 9447, 9421}, { 9448, 9422},
+{ 9449, 9423}, {65345,65313}, {65346,65314}, {65347,65315}, {65348,65316}, {65349,65317}, {65350,65318},
+{65351,65319}, {65352,65320}, {65353,65321}, {65354,65322}, {65355,65323}, {65356,65324}, {65357,65325},
+{65358,65326}, {65359,65327}, {65360,65328}, {65361,65329}, {65362,65330}, {65363,65331}, {65364,65332},
+{65365,65333}, {65366,65334}, {65367,65335}, {65368,65336}, {65369,65337}, {65370,65338}, {65535, 0}};
+
+static const GUnicodePairType UnicodeToLowerTable[] = {
+{ 65, 97}, { 66, 98}, { 67, 99}, { 68, 100}, { 69, 101}, { 70, 102}, { 71, 103},
+{ 72, 104}, { 73, 105}, { 74, 106}, { 75, 107}, { 76, 108}, { 77, 109}, { 78, 110},
+{ 79, 111}, { 80, 112}, { 81, 113}, { 82, 114}, { 83, 115}, { 84, 116}, { 85, 117},
+{ 86, 118}, { 87, 119}, { 88, 120}, { 89, 121}, { 90, 122}, { 192, 224}, { 193, 225},
+{ 194, 226}, { 195, 227}, { 196, 228}, { 197, 229}, { 198, 230}, { 199, 231}, { 200, 232},
+{ 201, 233}, { 202, 234}, { 203, 235}, { 204, 236}, { 205, 237}, { 206, 238}, { 207, 239},
+{ 208, 240}, { 209, 241}, { 210, 242}, { 211, 243}, { 212, 244}, { 213, 245}, { 214, 246},
+{ 216, 248}, { 217, 249}, { 218, 250}, { 219, 251}, { 220, 252}, { 221, 253}, { 222, 254},
+{ 256, 257}, { 258, 259}, { 260, 261}, { 262, 263}, { 264, 265}, { 266, 267}, { 268, 269},
+{ 270, 271}, { 272, 273}, { 274, 275}, { 276, 277}, { 278, 279}, { 280, 281}, { 282, 283},
+{ 284, 285}, { 286, 287}, { 288, 289}, { 290, 291}, { 292, 293}, { 294, 295}, { 296, 297},
+{ 298, 299}, { 300, 301}, { 302, 303}, { 304, 105}, { 306, 307}, { 308, 309}, { 310, 311}, { 313, 314},
+{ 315, 316}, { 317, 318}, { 319, 320}, { 321, 322}, { 323, 324}, { 325, 326}, { 327, 328},
+{ 330, 331}, { 332, 333}, { 334, 335}, { 336, 337}, { 338, 339}, { 340, 341}, { 342, 343},
+{ 344, 345}, { 346, 347}, { 348, 349}, { 350, 351}, { 352, 353}, { 354, 355}, { 356, 357},
+{ 358, 359}, { 360, 361}, { 362, 363}, { 364, 365}, { 366, 367}, { 368, 369}, { 370, 371},
+{ 372, 373}, { 374, 375}, { 376, 255}, { 377, 378}, { 379, 380}, { 381, 382}, { 385, 595},
+{ 386, 387}, { 388, 389}, { 390, 596}, { 391, 392}, { 393, 598}, { 394, 599}, { 395, 396},
+{ 398, 477}, { 399, 601}, { 400, 603}, { 401, 402}, { 403, 608}, { 404, 611}, { 406, 617},
+{ 407, 616}, { 408, 409}, { 412, 623}, { 413, 626}, { 415, 629}, { 416, 417}, { 418, 419},
+{ 420, 421}, { 423, 424}, { 425, 643}, { 428, 429}, { 430, 648}, { 431, 432}, { 433, 650},
+{ 434, 651}, { 435, 436}, { 437, 438}, { 439, 658}, { 440, 441}, { 444, 445}, { 452, 454},
+{ 455, 457}, { 458, 460}, { 461, 462}, { 463, 464}, { 465, 466}, { 467, 468}, { 469, 470},
+{ 471, 472}, { 473, 474}, { 475, 476}, { 478, 479}, { 480, 481}, { 482, 483}, { 484, 485},
+{ 486, 487}, { 488, 489}, { 490, 491}, { 492, 493}, { 494, 495}, { 497, 499}, { 500, 501},
+{ 506, 507}, { 508, 509}, { 510, 511}, { 512, 513}, { 514, 515}, { 516, 517}, { 518, 519},
+{ 520, 521}, { 522, 523}, { 524, 525}, { 526, 527}, { 528, 529}, { 530, 531}, { 532, 533},
+{ 534, 535}, { 902, 940}, { 904, 941}, { 905, 942}, { 906, 943}, { 908, 972}, { 910, 973},
+{ 911, 974}, { 913, 945}, { 914, 946}, { 915, 947}, { 916, 948}, { 917, 949}, { 918, 950},
+{ 919, 951}, { 920, 952}, { 921, 953}, { 922, 954}, { 923, 955}, { 924, 956}, { 925, 957},
+{ 926, 958}, { 927, 959}, { 928, 960}, { 929, 961}, { 931, 963}, { 932, 964}, { 933, 965},
+{ 934, 966}, { 935, 967}, { 936, 968}, { 937, 969}, { 938, 970}, { 939, 971}, { 994, 995},
+{ 996, 997}, { 998, 999}, { 1000, 1001}, { 1002, 1003}, { 1004, 1005}, { 1006, 1007}, { 1024, 1104}, { 1025, 1105},
+{ 1026, 1106}, { 1027, 1107}, { 1028, 1108}, { 1029, 1109}, { 1030, 1110}, { 1031, 1111}, { 1032, 1112},
+{ 1033, 1113}, { 1034, 1114}, { 1035, 1115}, { 1036, 1116}, { 1037, 1117}, { 1038, 1118}, { 1039, 1119}, { 1040, 1072},
+{ 1041, 1073}, { 1042, 1074}, { 1043, 1075}, { 1044, 1076}, { 1045, 1077}, { 1046, 1078}, { 1047, 1079},
+{ 1048, 1080}, { 1049, 1081}, { 1050, 1082}, { 1051, 1083}, { 1052, 1084}, { 1053, 1085}, { 1054, 1086},
+{ 1055, 1087}, { 1056, 1088}, { 1057, 1089}, { 1058, 1090}, { 1059, 1091}, { 1060, 1092}, { 1061, 1093},
+{ 1062, 1094}, { 1063, 1095}, { 1064, 1096}, { 1065, 1097}, { 1066, 1098}, { 1067, 1099}, { 1068, 1100},
+{ 1069, 1101}, { 1070, 1102}, { 1071, 1103}, { 1120, 1121}, { 1122, 1123}, { 1124, 1125}, { 1126, 1127},
+{ 1128, 1129}, { 1130, 1131}, { 1132, 1133}, { 1134, 1135}, { 1136, 1137}, { 1138, 1139}, { 1140, 1141},
+{ 1142, 1143}, { 1144, 1145}, { 1146, 1147}, { 1148, 1149}, { 1150, 1151}, { 1152, 1153}, { 1168, 1169},
+{ 1170, 1171}, { 1172, 1173}, { 1174, 1175}, { 1176, 1177}, { 1178, 1179}, { 1180, 1181}, { 1182, 1183},
+{ 1184, 1185}, { 1186, 1187}, { 1188, 1189}, { 1190, 1191}, { 1192, 1193}, { 1194, 1195}, { 1196, 1197},
+{ 1198, 1199}, { 1200, 1201}, { 1202, 1203}, { 1204, 1205}, { 1206, 1207}, { 1208, 1209}, { 1210, 1211},
+{ 1212, 1213}, { 1214, 1215}, { 1217, 1218}, { 1219, 1220}, { 1223, 1224}, { 1227, 1228}, { 1232, 1233},
+{ 1234, 1235}, { 1236, 1237}, { 1238, 1239}, { 1240, 1241}, { 1242, 1243}, { 1244, 1245}, { 1246, 1247},
+{ 1248, 1249}, { 1250, 1251}, { 1252, 1253}, { 1254, 1255}, { 1256, 1257}, { 1258, 1259}, { 1262, 1263},
+{ 1264, 1265}, { 1266, 1267}, { 1268, 1269}, { 1272, 1273}, { 1329, 1377}, { 1330, 1378}, { 1331, 1379},
+{ 1332, 1380}, { 1333, 1381}, { 1334, 1382}, { 1335, 1383}, { 1336, 1384}, { 1337, 1385}, { 1338, 1386},
+{ 1339, 1387}, { 1340, 1388}, { 1341, 1389}, { 1342, 1390}, { 1343, 1391}, { 1344, 1392}, { 1345, 1393},
+{ 1346, 1394}, { 1347, 1395}, { 1348, 1396}, { 1349, 1397}, { 1350, 1398}, { 1351, 1399}, { 1352, 1400},
+{ 1353, 1401}, { 1354, 1402}, { 1355, 1403}, { 1356, 1404}, { 1357, 1405}, { 1358, 1406}, { 1359, 1407},
+{ 1360, 1408}, { 1361, 1409}, { 1362, 1410}, { 1363, 1411}, { 1364, 1412}, { 1365, 1413}, { 1366, 1414},
+{ 4256, 4304}, { 4257, 4305}, { 4258, 4306}, { 4259, 4307}, { 4260, 4308}, { 4261, 4309}, { 4262, 4310},
+{ 4263, 4311}, { 4264, 4312}, { 4265, 4313}, { 4266, 4314}, { 4267, 4315}, { 4268, 4316}, { 4269, 4317},
+{ 4270, 4318}, { 4271, 4319}, { 4272, 4320}, { 4273, 4321}, { 4274, 4322}, { 4275, 4323}, { 4276, 4324},
+{ 4277, 4325}, { 4278, 4326}, { 4279, 4327}, { 4280, 4328}, { 4281, 4329}, { 4282, 4330}, { 4283, 4331},
+{ 4284, 4332}, { 4285, 4333}, { 4286, 4334}, { 4287, 4335}, { 4288, 4336}, { 4289, 4337}, { 4290, 4338},
+{ 4291, 4339}, { 4292, 4340}, { 4293, 4341}, { 7680, 7681}, { 7682, 7683}, { 7684, 7685}, { 7686, 7687},
+{ 7688, 7689}, { 7690, 7691}, { 7692, 7693}, { 7694, 7695}, { 7696, 7697}, { 7698, 7699}, { 7700, 7701},
+{ 7702, 7703}, { 7704, 7705}, { 7706, 7707}, { 7708, 7709}, { 7710, 7711}, { 7712, 7713}, { 7714, 7715},
+{ 7716, 7717}, { 7718, 7719}, { 7720, 7721}, { 7722, 7723}, { 7724, 7725}, { 7726, 7727}, { 7728, 7729},
+{ 7730, 7731}, { 7732, 7733}, { 7734, 7735}, { 7736, 7737}, { 7738, 7739}, { 7740, 7741}, { 7742, 7743},
+{ 7744, 7745}, { 7746, 7747}, { 7748, 7749}, { 7750, 7751}, { 7752, 7753}, { 7754, 7755}, { 7756, 7757},
+{ 7758, 7759}, { 7760, 7761}, { 7762, 7763}, { 7764, 7765}, { 7766, 7767}, { 7768, 7769}, { 7770, 7771},
+{ 7772, 7773}, { 7774, 7775}, { 7776, 7777}, { 7778, 7779}, { 7780, 7781}, { 7782, 7783}, { 7784, 7785},
+{ 7786, 7787}, { 7788, 7789}, { 7790, 7791}, { 7792, 7793}, { 7794, 7795}, { 7796, 7797}, { 7798, 7799},
+{ 7800, 7801}, { 7802, 7803}, { 7804, 7805}, { 7806, 7807}, { 7808, 7809}, { 7810, 7811}, { 7812, 7813},
+{ 7814, 7815}, { 7816, 7817}, { 7818, 7819}, { 7820, 7821}, { 7822, 7823}, { 7824, 7825}, { 7826, 7827},
+{ 7828, 7829}, { 7840, 7841}, { 7842, 7843}, { 7844, 7845}, { 7846, 7847}, { 7848, 7849}, { 7850, 7851},
+{ 7852, 7853}, { 7854, 7855}, { 7856, 7857}, { 7858, 7859}, { 7860, 7861}, { 7862, 7863}, { 7864, 7865},
+{ 7866, 7867}, { 7868, 7869}, { 7870, 7871}, { 7872, 7873}, { 7874, 7875}, { 7876, 7877}, { 7878, 7879},
+{ 7880, 7881}, { 7882, 7883}, { 7884, 7885}, { 7886, 7887}, { 7888, 7889}, { 7890, 7891}, { 7892, 7893},
+{ 7894, 7895}, { 7896, 7897}, { 7898, 7899}, { 7900, 7901}, { 7902, 7903}, { 7904, 7905}, { 7906, 7907},
+{ 7908, 7909}, { 7910, 7911}, { 7912, 7913}, { 7914, 7915}, { 7916, 7917}, { 7918, 7919}, { 7920, 7921},
+{ 7922, 7923}, { 7924, 7925}, { 7926, 7927}, { 7928, 7929}, { 7944, 7936}, { 7945, 7937}, { 7946, 7938},
+{ 7947, 7939}, { 7948, 7940}, { 7949, 7941}, { 7950, 7942}, { 7951, 7943}, { 7960, 7952}, { 7961, 7953},
+{ 7962, 7954}, { 7963, 7955}, { 7964, 7956}, { 7965, 7957}, { 7976, 7968}, { 7977, 7969}, { 7978, 7970},
+{ 7979, 7971}, { 7980, 7972}, { 7981, 7973}, { 7982, 7974}, { 7983, 7975}, { 7992, 7984}, { 7993, 7985},
+{ 7994, 7986}, { 7995, 7987}, { 7996, 7988}, { 7997, 7989}, { 7998, 7990}, { 7999, 7991}, { 8008, 8000},
+{ 8009, 8001}, { 8010, 8002}, { 8011, 8003}, { 8012, 8004}, { 8013, 8005}, { 8025, 8017}, { 8027, 8019},
+{ 8029, 8021}, { 8031, 8023}, { 8040, 8032}, { 8041, 8033}, { 8042, 8034}, { 8043, 8035}, { 8044, 8036},
+{ 8045, 8037}, { 8046, 8038}, { 8047, 8039}, { 8120, 8112}, { 8121, 8113}, { 8122, 8048}, { 8123, 8049},
+{ 8136, 8050}, { 8137, 8051}, { 8138, 8052}, { 8139, 8053}, { 8152, 8144}, { 8153, 8145}, { 8154, 8054},
+{ 8155, 8055}, { 8168, 8160}, { 8169, 8161}, { 8170, 8058}, { 8171, 8059}, { 8172, 8165}, { 8184, 8056},
+{ 8185, 8057}, { 8186, 8060}, { 8187, 8061}, { 8544, 8560}, { 8545, 8561}, { 8546, 8562}, { 8547, 8563},
+{ 8548, 8564}, { 8549, 8565}, { 8550, 8566}, { 8551, 8567}, { 8552, 8568}, { 8553, 8569}, { 8554, 8570},
+{ 8555, 8571}, { 8556, 8572}, { 8557, 8573}, { 8558, 8574}, { 8559, 8575}, { 9398, 9424}, { 9399, 9425},
+{ 9400, 9426}, { 9401, 9427}, { 9402, 9428}, { 9403, 9429}, { 9404, 9430}, { 9405, 9431}, { 9406, 9432},
+{ 9407, 9433}, { 9408, 9434}, { 9409, 9435}, { 9410, 9436}, { 9411, 9437}, { 9412, 9438}, { 9413, 9439},
+{ 9414, 9440}, { 9415, 9441}, { 9416, 9442}, { 9417, 9443}, { 9418, 9444}, { 9419, 9445}, { 9420, 9446},
+{ 9421, 9447}, { 9422, 9448}, { 9423, 9449}, {65313,65345}, {65314,65346}, {65315,65347}, {65316,65348},
+{65317,65349}, {65318,65350}, {65319,65351}, {65320,65352}, {65321,65353}, {65322,65354}, {65323,65355},
+{65324,65356}, {65325,65357}, {65326,65358}, {65327,65359}, {65328,65360}, {65329,65361}, {65330,65362},
+{65331,65363}, {65332,65364}, {65333,65365}, {65334,65366}, {65335,65367}, {65336,65368}, {65337,65369},
+{65338,65370}, {65535, 0}};
+
+int OVR_CDECL OVR_towupper(wchar_t charCode)
+{
+ // Don't use UnicodeUpperBits! It differs from UnicodeToUpperBits.
+ if (UnicodeCharIs(UnicodeToUpperBits, charCode))
+ {
+ // To protect from memory overrun in case the character is not found
+ // we use one extra fake element in the table {65536, 0}.
+ UPInt idx = Alg::LowerBoundSliced(
+ UnicodeToUpperTable,
+ 0,
+ sizeof(UnicodeToUpperTable) / sizeof(UnicodeToUpperTable[0]) - 1,
+ (UInt16)charCode,
+ CmpUnicodeKey);
+ return UnicodeToUpperTable[idx].Value;
+ }
+ return charCode;
+}
+
+int OVR_CDECL OVR_towlower(wchar_t charCode)
+{
+ // Don't use UnicodeLowerBits! It differs from UnicodeToLowerBits.
+ if (UnicodeCharIs(UnicodeToLowerBits, charCode))
+ {
+ // To protect from memory overrun in case the character is not found
+ // we use one extra fake element in the table {65536, 0}.
+ UPInt idx = Alg::LowerBoundSliced(
+ UnicodeToLowerTable,
+ 0,
+ sizeof(UnicodeToLowerTable) / sizeof(UnicodeToLowerTable[0]) - 1,
+ (UInt16)charCode,
+ CmpUnicodeKey);
+ return UnicodeToLowerTable[idx].Value;
+ }
+ return charCode;
+}
+
+#endif //OVR_NO_WCTYPE
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_Std.h b/LibOVR/Src/Kernel/OVR_Std.h new file mode 100644 index 0000000..b20a376 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Std.h @@ -0,0 +1,503 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Std.h
+Content : Standard C function interface
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Std_h
+#define OVR_Std_h
+
+#include "OVR_Types.h"
+#include <stdarg.h> // for va_list args
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if !defined(OVR_OS_WINCE) && defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+#define OVR_MSVC_SAFESTRING
+#include <errno.h>
+#endif
+
+// Wide-char funcs
+#include <wchar.h>
+#include <wctype.h>
+
+namespace OVR {
+
+#if defined(OVR_OS_WIN32)
+inline char* OVR_CDECL OVR_itoa(int val, char *dest, UPInt destsize, int radix)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ _itoa_s(val, dest, destsize, radix);
+ return dest;
+#else
+ OVR_UNUSED(destsize);
+ return itoa(val, dest, radix);
+#endif
+}
+#else // OVR_OS_WIN32
+inline char* OVR_itoa(int val, char* dest, unsigned int len, int radix)
+{
+ if (val == 0)
+ {
+ if (len > 1)
+ {
+ dest[0] = '0';
+ dest[1] = '\0';
+ }
+ return dest;
+ }
+
+ int cur = val;
+ unsigned int i = 0;
+ unsigned int sign = 0;
+
+ if (val < 0)
+ {
+ val = -val;
+ sign = 1;
+ }
+
+ while ((val != 0) && (i < (len - 1 - sign)))
+ {
+ cur = val % radix;
+ val /= radix;
+
+ if (radix == 16)
+ {
+ switch(cur)
+ {
+ case 10:
+ dest[i] = 'a';
+ break;
+ case 11:
+ dest[i] = 'b';
+ break;
+ case 12:
+ dest[i] = 'c';
+ break;
+ case 13:
+ dest[i] = 'd';
+ break;
+ case 14:
+ dest[i] = 'e';
+ break;
+ case 15:
+ dest[i] = 'f';
+ break;
+ default:
+ dest[i] = (char)('0' + cur);
+ break;
+ }
+ }
+ else
+ {
+ dest[i] = (char)('0' + cur);
+ }
+ ++i;
+ }
+
+ if (sign)
+ {
+ dest[i++] = '-';
+ }
+
+ for (unsigned int j = 0; j < i / 2; ++j)
+ {
+ char tmp = dest[j];
+ dest[j] = dest[i - 1 - j];
+ dest[i - 1 - j] = tmp;
+ }
+ dest[i] = '\0';
+
+ return dest;
+}
+
+#endif
+
+
+// String functions
+
+inline UPInt OVR_CDECL OVR_strlen(const char* str)
+{
+ return strlen(str);
+}
+
+inline char* OVR_CDECL OVR_strcpy(char* dest, UPInt destsize, const char* src)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ strcpy_s(dest, destsize, src);
+ return dest;
+#else
+ OVR_UNUSED(destsize);
+ return strcpy(dest, src);
+#endif
+}
+
+inline char* OVR_CDECL OVR_strncpy(char* dest, UPInt destsize, const char* src, UPInt count)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ strncpy_s(dest, destsize, src, count);
+ return dest;
+#else
+ OVR_UNUSED(destsize);
+ return strncpy(dest, src, count);
+#endif
+}
+
+inline char * OVR_CDECL OVR_strcat(char* dest, UPInt destsize, const char* src)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ strcat_s(dest, destsize, src);
+ return dest;
+#else
+ OVR_UNUSED(destsize);
+ return strcat(dest, src);
+#endif
+}
+
+inline int OVR_CDECL OVR_strcmp(const char* dest, const char* src)
+{
+ return strcmp(dest, src);
+}
+
+inline const char* OVR_CDECL OVR_strchr(const char* str, char c)
+{
+ return strchr(str, c);
+}
+
+inline char* OVR_CDECL OVR_strchr(char* str, char c)
+{
+ return strchr(str, c);
+}
+
+inline const char* OVR_strrchr(const char* str, char c)
+{
+ UPInt len = OVR_strlen(str);
+ for (UPInt i=len; i>0; i--)
+ if (str[i]==c)
+ return str+i;
+ return 0;
+}
+
+inline const UByte* OVR_CDECL OVR_memrchr(const UByte* str, UPInt size, UByte c)
+{
+ for (SPInt i = (SPInt)size - 1; i >= 0; i--)
+ {
+ if (str[i] == c)
+ return str + i;
+ }
+ return 0;
+}
+
+inline char* OVR_CDECL OVR_strrchr(char* str, char c)
+{
+ UPInt len = OVR_strlen(str);
+ for (UPInt i=len; i>0; i--)
+ if (str[i]==c)
+ return str+i;
+ return 0;
+}
+
+
+double OVR_CDECL OVR_strtod(const char* string, char** tailptr);
+
+inline long OVR_CDECL OVR_strtol(const char* string, char** tailptr, int radix)
+{
+ return strtol(string, tailptr, radix);
+}
+
+inline long OVR_CDECL OVR_strtoul(const char* string, char** tailptr, int radix)
+{
+ return strtoul(string, tailptr, radix);
+}
+
+inline int OVR_CDECL OVR_strncmp(const char* ws1, const char* ws2, UPInt size)
+{
+ return strncmp(ws1, ws2, size);
+}
+
+inline UInt64 OVR_CDECL OVR_strtouq(const char *nptr, char **endptr, int base)
+{
+#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
+ return _strtoui64(nptr, endptr, base);
+#else
+ return strtoull(nptr, endptr, base);
+#endif
+}
+
+inline SInt64 OVR_CDECL OVR_strtoq(const char *nptr, char **endptr, int base)
+{
+#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
+ return _strtoi64(nptr, endptr, base);
+#else
+ return strtoll(nptr, endptr, base);
+#endif
+}
+
+
+inline SInt64 OVR_CDECL OVR_atoq(const char* string)
+{
+#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
+ return _atoi64(string);
+#else
+ return atoll(string);
+#endif
+}
+
+inline UInt64 OVR_CDECL OVR_atouq(const char* string)
+{
+ return OVR_strtouq(string, NULL, 10);
+}
+
+
+// Implemented in GStd.cpp in platform-specific manner.
+int OVR_CDECL OVR_stricmp(const char* dest, const char* src);
+int OVR_CDECL OVR_strnicmp(const char* dest, const char* src, UPInt count);
+
+inline UPInt OVR_CDECL OVR_sprintf(char *dest, UPInt destsize, const char* format, ...)
+{
+ va_list argList;
+ va_start(argList,format);
+ UPInt ret;
+#if defined(OVR_CC_MSVC)
+ #if defined(OVR_MSVC_SAFESTRING)
+ ret = _vsnprintf_s(dest, destsize, _TRUNCATE, format, argList);
+ OVR_ASSERT(ret != -1);
+ #else
+ OVR_UNUSED(destsize);
+ ret = _vsnprintf(dest, destsize - 1, format, argList); // -1 for space for the null character
+ OVR_ASSERT(ret != -1);
+ dest[destsize-1] = 0;
+ #endif
+#else
+ OVR_UNUSED(destsize);
+ ret = vsprintf(dest, format, argList);
+ OVR_ASSERT(ret < destsize);
+#endif
+ va_end(argList);
+ return ret;
+}
+
+inline UPInt OVR_CDECL OVR_vsprintf(char *dest, UPInt destsize, const char * format, va_list argList)
+{
+ UPInt ret;
+#if defined(OVR_CC_MSVC)
+ #if defined(OVR_MSVC_SAFESTRING)
+ dest[0] = '\0';
+ int rv = vsnprintf_s(dest, destsize, _TRUNCATE, format, argList);
+ if (rv == -1)
+ {
+ dest[destsize - 1] = '\0';
+ ret = destsize - 1;
+ }
+ else
+ ret = (UPInt)rv;
+ #else
+ OVR_UNUSED(destsize);
+ int rv = _vsnprintf(dest, destsize - 1, format, argList);
+ OVR_ASSERT(rv != -1);
+ ret = (UPInt)rv;
+ dest[destsize-1] = 0;
+ #endif
+#else
+ OVR_UNUSED(destsize);
+ ret = (UPInt)vsprintf(dest, format, argList);
+ OVR_ASSERT(ret < destsize);
+#endif
+ return ret;
+}
+
+// Returns the number of characters in the formatted string.
+inline UPInt OVR_CDECL OVR_vscprintf(const char * format, va_list argList)
+{
+ UPInt ret;
+#if defined(OVR_CC_MSVC)
+ ret = (UPInt) _vscprintf(format, argList);
+#else
+ ret = (UPInt) vsnprintf(NULL, 0, format, argList);
+#endif
+ return ret;
+}
+
+
+wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, UPInt destsize, const wchar_t* src);
+wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, UPInt destsize, const wchar_t* src, UPInt count);
+wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, UPInt destsize, const wchar_t* src);
+UPInt OVR_CDECL OVR_wcslen(const wchar_t* str);
+int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b);
+int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b);
+
+inline int OVR_CDECL OVR_wcsicoll(const wchar_t* a, const wchar_t* b)
+{
+#if defined(OVR_OS_WIN32)
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ return ::_wcsicoll(a, b);
+#else
+ return ::wcsicoll(a, b);
+#endif
+#else
+ // not supported, use regular wcsicmp
+ return OVR_wcsicmp(a, b);
+#endif
+}
+
+inline int OVR_CDECL OVR_wcscoll(const wchar_t* a, const wchar_t* b)
+{
+#if defined(OVR_OS_WIN32) || defined(OVR_OS_LINUX)
+ return wcscoll(a, b);
+#else
+ // not supported, use regular wcscmp
+ return OVR_wcscmp(a, b);
+#endif
+}
+
+#ifndef OVR_NO_WCTYPE
+
+inline int OVR_CDECL UnicodeCharIs(const UInt16* table, wchar_t charCode)
+{
+ unsigned offset = table[charCode >> 8];
+ if (offset == 0) return 0;
+ if (offset == 1) return 1;
+ return (table[offset + ((charCode >> 4) & 15)] & (1 << (charCode & 15))) != 0;
+}
+
+extern const UInt16 UnicodeAlnumBits[];
+extern const UInt16 UnicodeAlphaBits[];
+extern const UInt16 UnicodeDigitBits[];
+extern const UInt16 UnicodeSpaceBits[];
+extern const UInt16 UnicodeXDigitBits[];
+
+// Uncomment if necessary
+//extern const UInt16 UnicodeCntrlBits[];
+//extern const UInt16 UnicodeGraphBits[];
+//extern const UInt16 UnicodeLowerBits[];
+//extern const UInt16 UnicodePrintBits[];
+//extern const UInt16 UnicodePunctBits[];
+//extern const UInt16 UnicodeUpperBits[];
+
+inline int OVR_CDECL OVR_iswalnum (wchar_t charCode) { return UnicodeCharIs(UnicodeAlnumBits, charCode); }
+inline int OVR_CDECL OVR_iswalpha (wchar_t charCode) { return UnicodeCharIs(UnicodeAlphaBits, charCode); }
+inline int OVR_CDECL OVR_iswdigit (wchar_t charCode) { return UnicodeCharIs(UnicodeDigitBits, charCode); }
+inline int OVR_CDECL OVR_iswspace (wchar_t charCode) { return UnicodeCharIs(UnicodeSpaceBits, charCode); }
+inline int OVR_CDECL OVR_iswxdigit(wchar_t charCode) { return UnicodeCharIs(UnicodeXDigitBits, charCode); }
+
+// Uncomment if necessary
+//inline int OVR_CDECL OVR_iswcntrl (wchar_t charCode) { return UnicodeCharIs(UnicodeCntrlBits, charCode); }
+//inline int OVR_CDECL OVR_iswgraph (wchar_t charCode) { return UnicodeCharIs(UnicodeGraphBits, charCode); }
+//inline int OVR_CDECL OVR_iswlower (wchar_t charCode) { return UnicodeCharIs(UnicodeLowerBits, charCode); }
+//inline int OVR_CDECL OVR_iswprint (wchar_t charCode) { return UnicodeCharIs(UnicodePrintBits, charCode); }
+//inline int OVR_CDECL OVR_iswpunct (wchar_t charCode) { return UnicodeCharIs(UnicodePunctBits, charCode); }
+//inline int OVR_CDECL OVR_iswupper (wchar_t charCode) { return UnicodeCharIs(UnicodeUpperBits, charCode); }
+
+int OVR_CDECL OVR_towupper(wchar_t charCode);
+int OVR_CDECL OVR_towlower(wchar_t charCode);
+
+#else // OVR_NO_WCTYPE
+
+inline int OVR_CDECL OVR_iswspace(wchar_t c)
+{
+ return iswspace(c);
+}
+
+inline int OVR_CDECL OVR_iswdigit(wchar_t c)
+{
+ return iswdigit(c);
+}
+
+inline int OVR_CDECL OVR_iswxdigit(wchar_t c)
+{
+ return iswxdigit(c);
+}
+
+inline int OVR_CDECL OVR_iswalpha(wchar_t c)
+{
+ return iswalpha(c);
+}
+
+inline int OVR_CDECL OVR_iswalnum(wchar_t c)
+{
+ return iswalnum(c);
+}
+
+inline wchar_t OVR_CDECL OVR_towlower(wchar_t c)
+{
+ return (wchar_t)towlower(c);
+}
+
+inline wchar_t OVR_towupper(wchar_t c)
+{
+ return (wchar_t)towupper(c);
+}
+
+#endif // OVR_NO_WCTYPE
+
+// ASCII versions of tolower and toupper. Don't use "char"
+inline int OVR_CDECL OVR_tolower(int c)
+{
+ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c;
+}
+
+inline int OVR_CDECL OVR_toupper(int c)
+{
+ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c;
+}
+
+
+
+inline double OVR_CDECL OVR_wcstod(const wchar_t* string, wchar_t** tailptr)
+{
+#if defined(OVR_OS_OTHER)
+ OVR_UNUSED(tailptr);
+ char buffer[64];
+ char* tp = NULL;
+ UPInt max = OVR_wcslen(string);
+ if (max > 63) max = 63;
+ unsigned char c = 0;
+ for (UPInt i=0; i < max; i++)
+ {
+ c = (unsigned char)string[i];
+ buffer[i] = ((c) < 128 ? (char)c : '!');
+ }
+ buffer[max] = 0;
+ return OVR_strtod(buffer, &tp);
+#else
+ return wcstod(string, tailptr);
+#endif
+}
+
+inline long OVR_CDECL OVR_wcstol(const wchar_t* string, wchar_t** tailptr, int radix)
+{
+#if defined(OVR_OS_OTHER)
+ OVR_UNUSED(tailptr);
+ char buffer[64];
+ char* tp = NULL;
+ UPInt max = OVR_wcslen(string);
+ if (max > 63) max = 63;
+ unsigned char c = 0;
+ for (UPInt i=0; i < max; i++)
+ {
+ c = (unsigned char)string[i];
+ buffer[i] = ((c) < 128 ? (char)c : '!');
+ }
+ buffer[max] = 0;
+ return strtol(buffer, &tp, radix);
+#else
+ return wcstol(string, tailptr, radix);
+#endif
+}
+
+} // OVR
+
+#endif // OVR_Std_h
diff --git a/LibOVR/Src/Kernel/OVR_String.cpp b/LibOVR/Src/Kernel/OVR_String.cpp new file mode 100644 index 0000000..b591ede --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_String.cpp @@ -0,0 +1,752 @@ +/************************************************************************************
+
+Filename : OVR_String.cpp
+Content : String UTF8 string implementation with copy-on-write semantics
+ (thread-safe for assignment but not modification).
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_String.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef OVR_OS_QNX
+# include <strings.h>
+#endif
+
+namespace OVR {
+
+#define String_LengthIsSize (UPInt(1) << String::Flag_LengthIsSizeShift)
+
+String::DataDesc String::NullData = {String_LengthIsSize, 1, {0} };
+
+
+String::String()
+{
+ pData = &NullData;
+ pData->AddRef();
+};
+
+String::String(const char* pdata)
+{
+ // Obtain length in bytes; it doesn't matter if _data is UTF8.
+ UPInt size = pdata ? OVR_strlen(pdata) : 0;
+ pData = AllocDataCopy1(size, 0, pdata, size);
+};
+
+String::String(const char* pdata1, const char* pdata2, const char* pdata3)
+{
+ // Obtain length in bytes; it doesn't matter if _data is UTF8.
+ UPInt size1 = pdata1 ? OVR_strlen(pdata1) : 0;
+ UPInt size2 = pdata2 ? OVR_strlen(pdata2) : 0;
+ UPInt size3 = pdata3 ? OVR_strlen(pdata3) : 0;
+
+ DataDesc *pdataDesc = AllocDataCopy2(size1 + size2 + size3, 0,
+ pdata1, size1, pdata2, size2);
+ memcpy(pdataDesc->Data + size1 + size2, pdata3, size3);
+ pData = pdataDesc;
+}
+
+String::String(const char* pdata, UPInt size)
+{
+ OVR_ASSERT((size == 0) || (pdata != 0));
+ pData = AllocDataCopy1(size, 0, pdata, size);
+};
+
+
+String::String(const InitStruct& src, UPInt size)
+{
+ pData = AllocData(size, 0);
+ src.InitString(GetData()->Data, size);
+}
+
+String::String(const String& src)
+{
+ pData = src.GetData();
+ pData->AddRef();
+}
+
+String::String(const StringBuffer& src)
+{
+ pData = AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize());
+}
+
+String::String(const wchar_t* data)
+{
+ pData = &NullData;
+ pData->AddRef();
+ // Simplified logic for wchar_t constructor.
+ if (data)
+ *this = data;
+}
+
+
+String::DataDesc* String::AllocData(UPInt size, UPInt lengthIsSize)
+{
+ String::DataDesc* pdesc;
+
+ if (size == 0)
+ {
+ pdesc = &NullData;
+ pdesc->AddRef();
+ return pdesc;
+ }
+
+ pdesc = (DataDesc*)OVR_ALLOC(sizeof(DataDesc)+ size);
+ pdesc->Data[size] = 0;
+ pdesc->RefCount = 1;
+ pdesc->Size = size | lengthIsSize;
+ return pdesc;
+}
+
+
+String::DataDesc* String::AllocDataCopy1(UPInt size, UPInt lengthIsSize,
+ const char* pdata, UPInt copySize)
+{
+ String::DataDesc* pdesc = AllocData(size, lengthIsSize);
+ memcpy(pdesc->Data, pdata, copySize);
+ return pdesc;
+}
+
+String::DataDesc* String::AllocDataCopy2(UPInt size, UPInt lengthIsSize,
+ const char* pdata1, UPInt copySize1,
+ const char* pdata2, UPInt copySize2)
+{
+ String::DataDesc* pdesc = AllocData(size, lengthIsSize);
+ memcpy(pdesc->Data, pdata1, copySize1);
+ memcpy(pdesc->Data + copySize1, pdata2, copySize2);
+ return pdesc;
+}
+
+
+UPInt String::GetLength() const
+{
+ // Optimize length accesses for non-UTF8 character strings.
+ DataDesc* pdata = GetData();
+ UPInt length, size = pdata->GetSize();
+
+ if (pdata->LengthIsSize())
+ return size;
+
+ length = (UPInt)UTF8Util::GetLength(pdata->Data, (UPInt)size);
+
+ if (length == size)
+ pdata->Size |= String_LengthIsSize;
+
+ return length;
+}
+
+
+//static UInt32 String_CharSearch(const char* buf, )
+
+
+UInt32 String::GetCharAt(UPInt index) const
+{
+ SPInt i = (SPInt) index;
+ DataDesc* pdata = GetData();
+ const char* buf = pdata->Data;
+ UInt32 c;
+
+ if (pdata->LengthIsSize())
+ {
+ OVR_ASSERT(index < pdata->GetSize());
+ buf += i;
+ return UTF8Util::DecodeNextChar_Advance0(&buf);
+ }
+
+ c = UTF8Util::GetCharAt(index, buf, pdata->GetSize());
+ return c;
+}
+
+UInt32 String::GetFirstCharAt(UPInt index, const char** offset) const
+{
+ DataDesc* pdata = GetData();
+ SPInt i = (SPInt) index;
+ const char* buf = pdata->Data;
+ const char* end = buf + pdata->GetSize();
+ UInt32 c;
+
+ do
+ {
+ c = UTF8Util::DecodeNextChar_Advance0(&buf);
+ i--;
+
+ if (buf >= end)
+ {
+ // We've hit the end of the string; don't go further.
+ OVR_ASSERT(i == 0);
+ return c;
+ }
+ } while (i >= 0);
+
+ *offset = buf;
+
+ return c;
+}
+
+UInt32 String::GetNextChar(const char** offset) const
+{
+ return UTF8Util::DecodeNextChar(offset);
+}
+
+
+
+void String::AppendChar(UInt32 ch)
+{
+ DataDesc* pdata = GetData();
+ UPInt size = pdata->GetSize();
+ char buff[8];
+ SPInt encodeSize = 0;
+
+ // Converts ch into UTF8 string and fills it into buff.
+ UTF8Util::EncodeChar(buff, &encodeSize, ch);
+ OVR_ASSERT(encodeSize >= 0);
+
+ SetData(AllocDataCopy2(size + (UPInt)encodeSize, 0,
+ pdata->Data, size, buff, (UPInt)encodeSize));
+ pdata->Release();
+}
+
+
+void String::AppendString(const wchar_t* pstr, SPInt len)
+{
+ if (!pstr)
+ return;
+
+ DataDesc* pdata = GetData();
+ UPInt oldSize = pdata->GetSize();
+ UPInt encodeSize = (UPInt)UTF8Util::GetEncodeStringSize(pstr, len);
+
+ DataDesc* pnewData = AllocDataCopy1(oldSize + (UPInt)encodeSize, 0,
+ pdata->Data, oldSize);
+ UTF8Util::EncodeString(pnewData->Data + oldSize, pstr, len);
+
+ SetData(pnewData);
+ pdata->Release();
+}
+
+
+void String::AppendString(const char* putf8str, SPInt utf8StrSz)
+{
+ if (!putf8str || !utf8StrSz)
+ return;
+ if (utf8StrSz == -1)
+ utf8StrSz = (SPInt)OVR_strlen(putf8str);
+
+ DataDesc* pdata = GetData();
+ UPInt oldSize = pdata->GetSize();
+
+ SetData(AllocDataCopy2(oldSize + (UPInt)utf8StrSz, 0,
+ pdata->Data, oldSize, putf8str, (UPInt)utf8StrSz));
+ pdata->Release();
+}
+
+void String::AssignString(const InitStruct& src, UPInt size)
+{
+ DataDesc* poldData = GetData();
+ DataDesc* pnewData = AllocData(size, 0);
+ src.InitString(pnewData->Data, size);
+ SetData(pnewData);
+ poldData->Release();
+}
+
+void String::AssignString(const char* putf8str, UPInt size)
+{
+ DataDesc* poldData = GetData();
+ SetData(AllocDataCopy1(size, 0, putf8str, size));
+ poldData->Release();
+}
+
+void String::operator = (const char* pstr)
+{
+ AssignString(pstr, pstr ? OVR_strlen(pstr) : 0);
+}
+
+void String::operator = (const wchar_t* pwstr)
+{
+ DataDesc* poldData = GetData();
+ UPInt size = pwstr ? (UPInt)UTF8Util::GetEncodeStringSize(pwstr) : 0;
+
+ DataDesc* pnewData = AllocData(size, 0);
+ UTF8Util::EncodeString(pnewData->Data, pwstr);
+ SetData(pnewData);
+ poldData->Release();
+}
+
+
+void String::operator = (const String& src)
+{
+ DataDesc* psdata = src.GetData();
+ DataDesc* pdata = GetData();
+
+ SetData(psdata);
+ psdata->AddRef();
+ pdata->Release();
+}
+
+
+void String::operator = (const StringBuffer& src)
+{
+ DataDesc* polddata = GetData();
+ SetData(AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize()));
+ polddata->Release();
+}
+
+void String::operator += (const String& src)
+{
+ DataDesc *pourData = GetData(),
+ *psrcData = src.GetData();
+ UPInt ourSize = pourData->GetSize(),
+ srcSize = psrcData->GetSize();
+ UPInt lflag = pourData->GetLengthFlag() & psrcData->GetLengthFlag();
+
+ SetData(AllocDataCopy2(ourSize + srcSize, lflag,
+ pourData->Data, ourSize, psrcData->Data, srcSize));
+ pourData->Release();
+}
+
+
+String String::operator + (const char* str) const
+{
+ String tmp1(*this);
+ tmp1 += (str ? str : "");
+ return tmp1;
+}
+
+String String::operator + (const String& src) const
+{
+ String tmp1(*this);
+ tmp1 += src;
+ return tmp1;
+}
+
+void String::Remove(UPInt posAt, SPInt removeLength)
+{
+ DataDesc* pdata = GetData();
+ UPInt oldSize = pdata->GetSize();
+ // Length indicates the number of characters to remove.
+ UPInt length = GetLength();
+
+ // If index is past the string, nothing to remove.
+ if (posAt >= length)
+ return;
+ // Otherwise, cap removeLength to the length of the string.
+ if ((posAt + removeLength) > length)
+ removeLength = length - posAt;
+
+ // Get the byte position of the UTF8 char at position posAt.
+ SPInt bytePos = UTF8Util::GetByteIndex(posAt, pdata->Data, oldSize);
+ SPInt removeSize = UTF8Util::GetByteIndex(removeLength, pdata->Data + bytePos, oldSize-bytePos);
+
+ SetData(AllocDataCopy2(oldSize - removeSize, pdata->GetLengthFlag(),
+ pdata->Data, bytePos,
+ pData->Data + bytePos + removeSize, (oldSize - bytePos - removeSize)));
+ pdata->Release();
+}
+
+
+String String::Substring(UPInt start, UPInt end) const
+{
+ UPInt length = GetLength();
+ if ((start >= length) || (start >= end))
+ return String();
+
+ DataDesc* pdata = GetData();
+
+ // If size matches, we know the exact index range.
+ if (pdata->LengthIsSize())
+ return String(pdata->Data + start, end - start);
+
+ // Get position of starting character.
+ SPInt byteStart = UTF8Util::GetByteIndex(start, pdata->Data, pdata->GetSize());
+ SPInt byteSize = UTF8Util::GetByteIndex(end - start, pdata->Data + byteStart, pdata->GetSize()-byteStart);
+ return String(pdata->Data + byteStart, (UPInt)byteSize);
+}
+
+void String::Clear()
+{
+ NullData.AddRef();
+ GetData()->Release();
+ SetData(&NullData);
+}
+
+
+String String::ToUpper() const
+{
+ UInt32 c;
+ const char* psource = GetData()->Data;
+ const char* pend = psource + GetData()->GetSize();
+ String str;
+ SPInt bufferOffset = 0;
+ char buffer[512];
+
+ while(psource < pend)
+ {
+ do {
+ c = UTF8Util::DecodeNextChar_Advance0(&psource);
+ UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towupper(wchar_t(c)));
+ } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
+
+ // Append string a piece at a time.
+ str.AppendString(buffer, bufferOffset);
+ bufferOffset = 0;
+ }
+
+ return str;
+}
+
+String String::ToLower() const
+{
+ UInt32 c;
+ const char* psource = GetData()->Data;
+ const char* pend = psource + GetData()->GetSize();
+ String str;
+ SPInt bufferOffset = 0;
+ char buffer[512];
+
+ while(psource < pend)
+ {
+ do {
+ c = UTF8Util::DecodeNextChar_Advance0(&psource);
+ UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towlower(wchar_t(c)));
+ } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
+
+ // Append string a piece at a time.
+ str.AppendString(buffer, bufferOffset);
+ bufferOffset = 0;
+ }
+
+ return str;
+}
+
+
+
+String& String::Insert(const char* substr, UPInt posAt, SPInt strSize)
+{
+ DataDesc* poldData = GetData();
+ UPInt oldSize = poldData->GetSize();
+ UPInt insertSize = (strSize < 0) ? OVR_strlen(substr) : (UPInt)strSize;
+ UPInt byteIndex = (poldData->LengthIsSize()) ?
+ posAt : (UPInt)UTF8Util::GetByteIndex(posAt, poldData->Data, oldSize);
+
+ OVR_ASSERT(byteIndex <= oldSize);
+
+ DataDesc* pnewData = AllocDataCopy2(oldSize + insertSize, 0,
+ poldData->Data, byteIndex, substr, insertSize);
+ memcpy(pnewData->Data + byteIndex + insertSize,
+ poldData->Data + byteIndex, oldSize - byteIndex);
+ SetData(pnewData);
+ poldData->Release();
+ return *this;
+}
+
+/*
+String& String::Insert(const UInt32* substr, UPInt posAt, SPInt len)
+{
+ for (SPInt i = 0; i < len; ++i)
+ {
+ UPInt charw = InsertCharAt(substr[i], posAt);
+ posAt += charw;
+ }
+ return *this;
+}
+*/
+
+UPInt String::InsertCharAt(UInt32 c, UPInt posAt)
+{
+ char buf[8];
+ SPInt index = 0;
+ UTF8Util::EncodeChar(buf, &index, c);
+ OVR_ASSERT(index >= 0);
+ buf[(UPInt)index] = 0;
+
+ Insert(buf, posAt, index);
+ return (UPInt)index;
+}
+
+
+int String::CompareNoCase(const char* a, const char* b)
+{
+ return OVR_stricmp(a, b);
+}
+
+int String::CompareNoCase(const char* a, const char* b, SPInt len)
+{
+ if (len)
+ {
+ SPInt f,l;
+ SPInt slen = len;
+ const char *s = b;
+ do {
+ f = (SPInt)OVR_tolower((int)(*(a++)));
+ l = (SPInt)OVR_tolower((int)(*(b++)));
+ } while (--len && f && (f == l) && *b != 0);
+
+ if (f == l && (len != 0 || *b != 0))
+ {
+ f = (SPInt)slen;
+ l = (SPInt)OVR_strlen(s);
+ return int(f - l);
+ }
+
+ return int(f - l);
+ }
+ else
+ return (0-(int)OVR_strlen(b));
+}
+
+// ***** Implement hash static functions
+
+// Hash function
+UPInt String::BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed)
+{
+ const UByte* pdata = (const UByte*) pdataIn;
+ UPInt h = seed;
+ while (size > 0)
+ {
+ size--;
+ h = ((h << 5) + h) ^ (unsigned) pdata[size];
+ }
+
+ return h;
+}
+
+// Hash function, case-insensitive
+UPInt String::BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed)
+{
+ const UByte* pdata = (const UByte*) pdataIn;
+ UPInt h = seed;
+ while (size > 0)
+ {
+ size--;
+ h = ((h << 5) + h) ^ OVR_tolower(pdata[size]);
+ }
+
+ // Alternative: "sdbm" hash function, suggested at same web page above.
+ // h = 0;
+ // for bytes { h = (h << 16) + (h << 6) - hash + *p; }
+ return h;
+}
+
+
+
+// ***** String Buffer used for Building Strings
+
+
+#define OVR_SBUFF_DEFAULT_GROW_SIZE 512
+// Constructors / Destructor.
+StringBuffer::StringBuffer()
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+}
+
+StringBuffer::StringBuffer(UPInt growSize)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ SetGrowSize(growSize);
+}
+
+StringBuffer::StringBuffer(const char* data)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ *this = data;
+}
+
+StringBuffer::StringBuffer(const char* data, UPInt dataSize)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ AppendString(data, dataSize);
+}
+
+StringBuffer::StringBuffer(const String& src)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ AppendString(src.ToCStr(), src.GetSize());
+}
+
+StringBuffer::StringBuffer(const StringBuffer& src)
+ : pData(NULL), Size(0), BufferSize(src.GetGrowSize()), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ AppendString(src.ToCStr(), src.GetSize());
+ LengthIsSize = src.LengthIsSize;
+}
+
+StringBuffer::StringBuffer(const wchar_t* data)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ *this = data;
+}
+
+StringBuffer::~StringBuffer()
+{
+ if (pData)
+ OVR_FREE(pData);
+}
+void StringBuffer::SetGrowSize(UPInt growSize)
+{
+ if (growSize <= 16)
+ GrowSize = 16;
+ else
+ {
+ UByte bits = Alg::UpperBit(UInt32(growSize-1));
+ UPInt size = 1<<bits;
+ GrowSize = size == growSize ? growSize : size;
+ }
+}
+
+UPInt StringBuffer::GetLength() const
+{
+ UPInt length, size = GetSize();
+ if (LengthIsSize)
+ return size;
+
+ length = (UPInt)UTF8Util::GetLength(pData, (UPInt)GetSize());
+
+ if (length == GetSize())
+ LengthIsSize = true;
+ return length;
+}
+
+void StringBuffer::Reserve(UPInt _size)
+{
+ if (_size >= BufferSize) // >= because of trailing zero! (!AB)
+ {
+ BufferSize = (_size + 1 + GrowSize - 1)& ~(GrowSize-1);
+ if (!pData)
+ pData = (char*)OVR_ALLOC(BufferSize);
+ else
+ pData = (char*)OVR_REALLOC(pData, BufferSize);
+ }
+}
+void StringBuffer::Resize(UPInt _size)
+{
+ Reserve(_size);
+ LengthIsSize = false;
+ Size = _size;
+ if (pData)
+ pData[Size] = 0;
+}
+
+void StringBuffer::Clear()
+{
+ Resize(0);
+ /*
+ if (pData != pEmptyNullData)
+ {
+ OVR_FREE(pHeap, pData);
+ pData = pEmptyNullData;
+ Size = BufferSize = 0;
+ LengthIsSize = false;
+ }
+ */
+}
+// Appends a character
+void StringBuffer::AppendChar(UInt32 ch)
+{
+ char buff[8];
+ UPInt origSize = GetSize();
+
+ // Converts ch into UTF8 string and fills it into buff. Also increments index according to the number of bytes
+ // in the UTF8 string.
+ SPInt srcSize = 0;
+ UTF8Util::EncodeChar(buff, &srcSize, ch);
+ OVR_ASSERT(srcSize >= 0);
+
+ UPInt size = origSize + srcSize;
+ Resize(size);
+ memcpy(pData + origSize, buff, srcSize);
+}
+
+// Append a string
+void StringBuffer::AppendString(const wchar_t* pstr, SPInt len)
+{
+ if (!pstr)
+ return;
+
+ SPInt srcSize = UTF8Util::GetEncodeStringSize(pstr, len);
+ UPInt origSize = GetSize();
+ UPInt size = srcSize + origSize;
+
+ Resize(size);
+ UTF8Util::EncodeString(pData + origSize, pstr, len);
+}
+
+void StringBuffer::AppendString(const char* putf8str, SPInt utf8StrSz)
+{
+ if (!putf8str || !utf8StrSz)
+ return;
+ if (utf8StrSz == -1)
+ utf8StrSz = (SPInt)OVR_strlen(putf8str);
+
+ UPInt origSize = GetSize();
+ UPInt size = utf8StrSz + origSize;
+
+ Resize(size);
+ memcpy(pData + origSize, putf8str, utf8StrSz);
+}
+
+
+void StringBuffer::operator = (const char* pstr)
+{
+ pstr = pstr ? pstr : "";
+ UPInt size = OVR_strlen(pstr);
+ Resize(size);
+ memcpy(pData, pstr, size);
+}
+
+void StringBuffer::operator = (const wchar_t* pstr)
+{
+ pstr = pstr ? pstr : L"";
+ UPInt size = (UPInt)UTF8Util::GetEncodeStringSize(pstr);
+ Resize(size);
+ UTF8Util::EncodeString(pData, pstr);
+}
+
+void StringBuffer::operator = (const String& src)
+{
+ Resize(src.GetSize());
+ memcpy(pData, src.ToCStr(), src.GetSize());
+}
+
+
+// Inserts substr at posAt
+void StringBuffer::Insert(const char* substr, UPInt posAt, SPInt len)
+{
+ UPInt oldSize = Size;
+ UPInt insertSize = (len < 0) ? OVR_strlen(substr) : (UPInt)len;
+ UPInt byteIndex = LengthIsSize ? posAt :
+ (UPInt)UTF8Util::GetByteIndex(posAt, pData, (SPInt)Size);
+
+ OVR_ASSERT(byteIndex <= oldSize);
+ Reserve(oldSize + insertSize);
+
+ memmove(pData + byteIndex + insertSize, pData + byteIndex, oldSize - byteIndex + 1);
+ memcpy (pData + byteIndex, substr, insertSize);
+ LengthIsSize = false;
+ Size = oldSize + insertSize;
+ pData[Size] = 0;
+}
+
+// Inserts character at posAt
+UPInt StringBuffer::InsertCharAt(UInt32 c, UPInt posAt)
+{
+ char buf[8];
+ SPInt len = 0;
+ UTF8Util::EncodeChar(buf, &len, c);
+ OVR_ASSERT(len >= 0);
+ buf[(UPInt)len] = 0;
+
+ Insert(buf, posAt, len);
+ return (UPInt)len;
+}
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_String.h b/LibOVR/Src/Kernel/OVR_String.h new file mode 100644 index 0000000..112878c --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_String.h @@ -0,0 +1,645 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_String.h
+Content : String UTF8 string implementation with copy-on-write semantics
+ (thread-safe for assignment but not modification).
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_String_h
+#define OVR_String_h
+
+#include "OVR_Types.h"
+#include "OVR_Allocator.h"
+#include "OVR_UTF8Util.h"
+#include "OVR_Atomic.h"
+#include "OVR_Std.h"
+#include "OVR_Alg.h"
+
+namespace OVR {
+
+// ***** Classes
+
+class String;
+class StringBuffer;
+
+
+//-----------------------------------------------------------------------------------
+// ***** String Class
+
+// String is UTF8 based string class with copy-on-write implementation
+// for assignment.
+
+class String
+{
+protected:
+
+ enum FlagConstants
+ {
+ //Flag_GetLength = 0x7FFFFFFF,
+ // This flag is set if GetLength() == GetSize() for a string.
+ // Avoid extra scanning is Substring and indexing logic.
+ Flag_LengthIsSizeShift = (sizeof(UPInt)*8 - 1)
+ };
+
+
+ // Internal structure to hold string data
+ struct DataDesc
+ {
+ // Number of bytes. Will be the same as the number of chars if the characters
+ // are ascii, may not be equal to number of chars in case string data is UTF8.
+ UPInt Size;
+ volatile SInt32 RefCount;
+ char Data[1];
+
+ void AddRef()
+ {
+ AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, 1);
+ }
+ // Decrement ref count. This needs to be thread-safe, since
+ // a different thread could have also decremented the ref count.
+ // For example, if u start off with a ref count = 2. Now if u
+ // decrement the ref count and check against 0 in different
+ // statements, a different thread can also decrement the ref count
+ // in between our decrement and checking against 0 and will find
+ // the ref count = 0 and delete the object. This will lead to a crash
+ // when context switches to our thread and we'll be trying to delete
+ // an already deleted object. Hence decrementing the ref count and
+ // checking against 0 needs to made an atomic operation.
+ void Release()
+ {
+ if ((AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
+ OVR_FREE(this);
+ }
+
+ static UPInt GetLengthFlagBit() { return UPInt(1) << Flag_LengthIsSizeShift; }
+ UPInt GetSize() const { return Size & ~GetLengthFlagBit() ; }
+ UPInt GetLengthFlag() const { return Size & GetLengthFlagBit(); }
+ bool LengthIsSize() const { return GetLengthFlag() != 0; }
+ };
+
+ // Heap type of the string is encoded in the lower bits.
+ enum HeapType
+ {
+ HT_Global = 0, // Heap is global.
+ HT_Local = 1, // SF::String_loc: Heap is determined based on string's address.
+ HT_Dynamic = 2, // SF::String_temp: Heap is stored as a part of the class.
+ HT_Mask = 3
+ };
+
+ union {
+ DataDesc* pData;
+ UPInt HeapTypeBits;
+ };
+ typedef union {
+ DataDesc* pData;
+ UPInt HeapTypeBits;
+ } DataDescUnion;
+
+ inline HeapType GetHeapType() const { return (HeapType) (HeapTypeBits & HT_Mask); }
+
+ inline DataDesc* GetData() const
+ {
+ DataDescUnion u;
+ u.pData = pData;
+ u.HeapTypeBits = (u.HeapTypeBits & ~(UPInt)HT_Mask);
+ return u.pData;
+ }
+
+ inline void SetData(DataDesc* pdesc)
+ {
+ HeapType ht = GetHeapType();
+ pData = pdesc;
+ OVR_ASSERT((HeapTypeBits & HT_Mask) == 0);
+ HeapTypeBits |= ht;
+ }
+
+
+ DataDesc* AllocData(UPInt size, UPInt lengthIsSize);
+ DataDesc* AllocDataCopy1(UPInt size, UPInt lengthIsSize,
+ const char* pdata, UPInt copySize);
+ DataDesc* AllocDataCopy2(UPInt size, UPInt lengthIsSize,
+ const char* pdata1, UPInt copySize1,
+ const char* pdata2, UPInt copySize2);
+
+ // Special constructor to avoid data initalization when used in derived class.
+ struct NoConstructor { };
+ String(const NoConstructor&) { }
+
+public:
+
+ // For initializing string with dynamic buffer
+ struct InitStruct
+ {
+ virtual ~InitStruct() { }
+ virtual void InitString(char* pbuffer, UPInt size) const = 0;
+ };
+
+
+ // Constructors / Destructors.
+ String();
+ String(const char* data);
+ String(const char* data1, const char* pdata2, const char* pdata3 = 0);
+ String(const char* data, UPInt buflen);
+ String(const String& src);
+ String(const StringBuffer& src);
+ String(const InitStruct& src, UPInt size);
+ explicit String(const wchar_t* data);
+
+ // Destructor (Captain Obvious guarantees!)
+ ~String()
+ {
+ GetData()->Release();
+ }
+
+ // Declaration of NullString
+ static DataDesc NullData;
+
+
+ // *** General Functions
+
+ void Clear();
+
+ // For casting to a pointer to char.
+ operator const char*() const { return GetData()->Data; }
+ // Pointer to raw buffer.
+ const char* ToCStr() const { return GetData()->Data; }
+
+ // Returns number of bytes
+ UPInt GetSize() const { return GetData()->GetSize() ; }
+ // Tells whether or not the string is empty
+ bool IsEmpty() const { return GetSize() == 0; }
+
+ // Returns number of characters
+ UPInt GetLength() const;
+
+ // Returns character at the specified index
+ UInt32 GetCharAt(UPInt index) const;
+ UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
+ UInt32 GetNextChar(const char** offset) const;
+
+ // Appends a character
+ void AppendChar(UInt32 ch);
+
+ // Append a string
+ void AppendString(const wchar_t* pstr, SPInt len = -1);
+ void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
+
+ // Assigned a string with dynamic data (copied through initializer).
+ void AssignString(const InitStruct& src, UPInt size);
+ // Assigns string with known size.
+ void AssignString(const char* putf8str, UPInt size);
+
+ // Resize the string to the new size
+// void Resize(UPInt _size);
+
+ // Removes the character at posAt
+ void Remove(UPInt posAt, SPInt len = 1);
+
+ // Returns a String that's a substring of this.
+ // -start is the index of the first UTF8 character you want to include.
+ // -end is the index one past the last UTF8 character you want to include.
+ String Substring(UPInt start, UPInt end) const;
+
+ // Case-conversion
+ String ToUpper() const;
+ String ToLower() const;
+
+ // Inserts substr at posAt
+ String& Insert (const char* substr, UPInt posAt, SPInt len = -1);
+
+ // Inserts character at posAt
+ UPInt InsertCharAt(UInt32 c, UPInt posAt);
+
+ // Inserts substr at posAt, which is an index of a character (not byte).
+ // Of size is specified, it is in bytes.
+// String& Insert(const UInt32* substr, UPInt posAt, SPInt size = -1);
+
+ // Get Byte index of the character at position = index
+ UPInt GetByteIndex(UPInt index) const { return (UPInt)UTF8Util::GetByteIndex(index, GetData()->Data); }
+
+ // Utility: case-insensitive string compare. stricmp() & strnicmp() are not
+ // ANSI or POSIX, do not seem to appear in Linux.
+ static int OVR_STDCALL CompareNoCase(const char* a, const char* b);
+ static int OVR_STDCALL CompareNoCase(const char* a, const char* b, SPInt len);
+
+ // Hash function, case-insensitive
+ static UPInt OVR_STDCALL BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed = 5381);
+
+ // Hash function, case-sensitive
+ static UPInt OVR_STDCALL BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed = 5381);
+
+
+ // ***** File path parsing helper functions.
+ // Implemented in OVR_String_FilePath.cpp.
+
+ // Absolute paths can star with:
+ // - protocols: 'file://', 'http://'
+ // - windows drive: 'c:\'
+ // - UNC share name: '\\share'
+ // - unix root '/'
+ static bool HasAbsolutePath(const char* path);
+ static bool HasExtension(const char* path);
+ static bool HasProtocol(const char* path);
+
+ bool HasAbsolutePath() const { return HasAbsolutePath(ToCStr()); }
+ bool HasExtension() const { return HasExtension(ToCStr()); }
+ bool HasProtocol() const { return HasProtocol(ToCStr()); }
+
+ String GetProtocol() const; // Returns protocol, if any, with trailing '://'.
+ String GetPath() const; // Returns path with trailing '/'.
+ String GetFilename() const; // Returns filename, including extension.
+ String GetExtension() const; // Returns extension with a dot.
+
+ void StripProtocol(); // Strips front protocol, if any, from the string.
+ void StripExtension(); // Strips off trailing extension.
+
+
+ // Operators
+ // Assignment
+ void operator = (const char* str);
+ void operator = (const wchar_t* str);
+ void operator = (const String& src);
+ void operator = (const StringBuffer& src);
+
+ // Addition
+ void operator += (const String& src);
+ void operator += (const char* psrc) { AppendString(psrc); }
+ void operator += (const wchar_t* psrc) { AppendString(psrc); }
+ void operator += (char ch) { AppendChar(ch); }
+ String operator + (const char* str) const;
+ String operator + (const String& src) const;
+
+ // Comparison
+ bool operator == (const String& str) const
+ {
+ return (OVR_strcmp(GetData()->Data, str.GetData()->Data)== 0);
+ }
+
+ bool operator != (const String& str) const
+ {
+ return !operator == (str);
+ }
+
+ bool operator == (const char* str) const
+ {
+ return OVR_strcmp(GetData()->Data, str) == 0;
+ }
+
+ bool operator != (const char* str) const
+ {
+ return !operator == (str);
+ }
+
+ bool operator < (const char* pstr) const
+ {
+ return OVR_strcmp(GetData()->Data, pstr) < 0;
+ }
+
+ bool operator < (const String& str) const
+ {
+ return *this < str.GetData()->Data;
+ }
+
+ bool operator > (const char* pstr) const
+ {
+ return OVR_strcmp(GetData()->Data, pstr) > 0;
+ }
+
+ bool operator > (const String& str) const
+ {
+ return *this > str.GetData()->Data;
+ }
+
+ int CompareNoCase(const char* pstr) const
+ {
+ return CompareNoCase(GetData()->Data, pstr);
+ }
+ int CompareNoCase(const String& str) const
+ {
+ return CompareNoCase(GetData()->Data, str.ToCStr());
+ }
+
+ // Accesses raw bytes
+ const char& operator [] (int index) const
+ {
+ OVR_ASSERT(index >= 0 && (UPInt)index < GetSize());
+ return GetData()->Data[index];
+ }
+ const char& operator [] (UPInt index) const
+ {
+ OVR_ASSERT(index < GetSize());
+ return GetData()->Data[index];
+ }
+
+
+ // Case insensitive keys are used to look up insensitive string in hash tables
+ // for SWF files with version before SWF 7.
+ struct NoCaseKey
+ {
+ const String* pStr;
+ NoCaseKey(const String &str) : pStr(&str){};
+ };
+
+ bool operator == (const NoCaseKey& strKey) const
+ {
+ return (CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
+ }
+ bool operator != (const NoCaseKey& strKey) const
+ {
+ return !(CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
+ }
+
+ // Hash functor used for strings.
+ struct HashFunctor
+ {
+ UPInt operator()(const String& data) const
+ {
+ UPInt size = data.GetSize();
+ return String::BernsteinHashFunction((const char*)data, size);
+ }
+ };
+ // Case-insensitive hash functor used for strings. Supports additional
+ // lookup based on NoCaseKey.
+ struct NoCaseHashFunctor
+ {
+ UPInt operator()(const String& data) const
+ {
+ UPInt size = data.GetSize();
+ return String::BernsteinHashFunctionCIS((const char*)data, size);
+ }
+ UPInt operator()(const NoCaseKey& data) const
+ {
+ UPInt size = data.pStr->GetSize();
+ return String::BernsteinHashFunctionCIS((const char*)data.pStr->ToCStr(), size);
+ }
+ };
+
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** String Buffer used for Building Strings
+
+class StringBuffer
+{
+ char* pData;
+ UPInt Size;
+ UPInt BufferSize;
+ UPInt GrowSize;
+ mutable bool LengthIsSize;
+
+public:
+
+ // Constructors / Destructor.
+ StringBuffer();
+ explicit StringBuffer(UPInt growSize);
+ StringBuffer(const char* data);
+ StringBuffer(const char* data, UPInt buflen);
+ StringBuffer(const String& src);
+ StringBuffer(const StringBuffer& src);
+ explicit StringBuffer(const wchar_t* data);
+ ~StringBuffer();
+
+
+ // Modify grow size used for growing/shrinking the buffer.
+ UPInt GetGrowSize() const { return GrowSize; }
+ void SetGrowSize(UPInt growSize);
+
+
+ // *** General Functions
+ // Does not release memory, just sets Size to 0
+ void Clear();
+
+ // For casting to a pointer to char.
+ operator const char*() const { return (pData) ? pData : ""; }
+ // Pointer to raw buffer.
+ const char* ToCStr() const { return (pData) ? pData : ""; }
+
+ // Returns number of bytes.
+ UPInt GetSize() const { return Size ; }
+ // Tells whether or not the string is empty.
+ bool IsEmpty() const { return GetSize() == 0; }
+
+ // Returns number of characters
+ UPInt GetLength() const;
+
+ // Returns character at the specified index
+ UInt32 GetCharAt(UPInt index) const;
+ UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
+ UInt32 GetNextChar(const char** offset) const;
+
+
+ // Resize the string to the new size
+ void Resize(UPInt _size);
+ void Reserve(UPInt _size);
+
+ // Appends a character
+ void AppendChar(UInt32 ch);
+
+ // Append a string
+ void AppendString(const wchar_t* pstr, SPInt len = -1);
+ void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
+ void AppendFormat(const char* format, ...);
+
+ // Assigned a string with dynamic data (copied through initializer).
+ //void AssignString(const InitStruct& src, UPInt size);
+
+ // Inserts substr at posAt
+ void Insert (const char* substr, UPInt posAt, SPInt len = -1);
+ // Inserts character at posAt
+ UPInt InsertCharAt(UInt32 c, UPInt posAt);
+
+ // Assignment
+ void operator = (const char* str);
+ void operator = (const wchar_t* str);
+ void operator = (const String& src);
+
+ // Addition
+ void operator += (const String& src) { AppendString(src.ToCStr(),src.GetSize()); }
+ void operator += (const char* psrc) { AppendString(psrc); }
+ void operator += (const wchar_t* psrc) { AppendString(psrc); }
+ void operator += (char ch) { AppendChar(ch); }
+ //String operator + (const char* str) const ;
+ //String operator + (const String& src) const ;
+
+ // Accesses raw bytes
+ char& operator [] (int index)
+ {
+ OVR_ASSERT(((UPInt)index) < GetSize());
+ return pData[index];
+ }
+ char& operator [] (UPInt index)
+ {
+ OVR_ASSERT(index < GetSize());
+ return pData[index];
+ }
+
+ const char& operator [] (int index) const
+ {
+ OVR_ASSERT(((UPInt)index) < GetSize());
+ return pData[index];
+ }
+ const char& operator [] (UPInt index) const
+ {
+ OVR_ASSERT(index < GetSize());
+ return pData[index];
+ }
+};
+
+
+//
+// Wrapper for string data. The data must have a guaranteed
+// lifespan throughout the usage of the wrapper. Not intended for
+// cached usage. Not thread safe.
+//
+class StringDataPtr
+{
+public:
+ StringDataPtr() : pStr(NULL), Size(0) {}
+ StringDataPtr(const StringDataPtr& p)
+ : pStr(p.pStr), Size(p.Size) {}
+ StringDataPtr(const char* pstr, UPInt sz)
+ : pStr(pstr), Size(sz) {}
+ StringDataPtr(const char* pstr)
+ : pStr(pstr), Size((pstr != NULL) ? OVR_strlen(pstr) : 0) {}
+ explicit StringDataPtr(const String& str)
+ : pStr(str.ToCStr()), Size(str.GetSize()) {}
+ template <typename T, int N>
+ StringDataPtr(const T (&v)[N])
+ : pStr(v), Size(N) {}
+
+public:
+ const char* ToCStr() const { return pStr; }
+ UPInt GetSize() const { return Size; }
+ bool IsEmpty() const { return GetSize() == 0; }
+
+ // value is a prefix of this string
+ // Character's values are not compared.
+ bool IsPrefix(const StringDataPtr& value) const
+ {
+ return ToCStr() == value.ToCStr() && GetSize() >= value.GetSize();
+ }
+ // value is a suffix of this string
+ // Character's values are not compared.
+ bool IsSuffix(const StringDataPtr& value) const
+ {
+ return ToCStr() <= value.ToCStr() && (End()) == (value.End());
+ }
+
+ // Find first character.
+ // init_ind - initial index.
+ SPInt FindChar(char c, UPInt init_ind = 0) const
+ {
+ for (UPInt i = init_ind; i < GetSize(); ++i)
+ if (pStr[i] == c)
+ return static_cast<SPInt>(i);
+
+ return -1;
+ }
+
+ // Find last character.
+ // init_ind - initial index.
+ SPInt FindLastChar(char c, UPInt init_ind = ~0) const
+ {
+ if (init_ind == (UPInt)~0 || init_ind > GetSize())
+ init_ind = GetSize();
+ else
+ ++init_ind;
+
+ for (UPInt i = init_ind; i > 0; --i)
+ if (pStr[i - 1] == c)
+ return static_cast<SPInt>(i - 1);
+
+ return -1;
+ }
+
+ // Create new object and trim size bytes from the left.
+ StringDataPtr GetTrimLeft(UPInt size) const
+ {
+ // Limit trim size to the size of the string.
+ size = Alg::PMin(GetSize(), size);
+
+ return StringDataPtr(ToCStr() + size, GetSize() - size);
+ }
+ // Create new object and trim size bytes from the right.
+ StringDataPtr GetTrimRight(UPInt size) const
+ {
+ // Limit trim to the size of the string.
+ size = Alg::PMin(GetSize(), size);
+
+ return StringDataPtr(ToCStr(), GetSize() - size);
+ }
+
+ // Create new object, which contains next token.
+ // Useful for parsing.
+ StringDataPtr GetNextToken(char separator = ':') const
+ {
+ UPInt cur_pos = 0;
+ const char* cur_str = ToCStr();
+
+ for (; cur_pos < GetSize() && cur_str[cur_pos]; ++cur_pos)
+ {
+ if (cur_str[cur_pos] == separator)
+ {
+ break;
+ }
+ }
+
+ return StringDataPtr(ToCStr(), cur_pos);
+ }
+
+ // Trim size bytes from the left.
+ StringDataPtr& TrimLeft(UPInt size)
+ {
+ // Limit trim size to the size of the string.
+ size = Alg::PMin(GetSize(), size);
+ pStr += size;
+ Size -= size;
+
+ return *this;
+ }
+ // Trim size bytes from the right.
+ StringDataPtr& TrimRight(UPInt size)
+ {
+ // Limit trim to the size of the string.
+ size = Alg::PMin(GetSize(), size);
+ Size -= size;
+
+ return *this;
+ }
+
+ const char* Begin() const { return ToCStr(); }
+ const char* End() const { return ToCStr() + GetSize(); }
+
+ // Hash functor used string data pointers
+ struct HashFunctor
+ {
+ UPInt operator()(const StringDataPtr& data) const
+ {
+ return String::BernsteinHashFunction(data.ToCStr(), data.GetSize());
+ }
+ };
+
+ bool operator== (const StringDataPtr& data) const
+ {
+ return (OVR_strncmp(pStr, data.pStr, data.Size) == 0);
+ }
+
+protected:
+ const char* pStr;
+ UPInt Size;
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_StringHash.h b/LibOVR/Src/Kernel/OVR_StringHash.h new file mode 100644 index 0000000..237dc7e --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_StringHash.h @@ -0,0 +1,89 @@ +/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_StringHash.h
+Content : String hash table used when optional case-insensitive
+ lookup is required.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_StringHash_h
+#define OVR_StringHash_h
+
+#include "OVR_String.h"
+#include "OVR_Hash.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// *** StringHash
+
+// This is a custom string hash table that supports case-insensitive
+// searches through special functions such as GetCaseInsensitive, etc.
+// This class is used for Flash labels, exports and other case-insensitive tables.
+
+template<class U, class Allocator = ContainerAllocator<U> >
+class StringHash : public Hash<String, U, String::NoCaseHashFunctor, Allocator>
+{
+public:
+ typedef U ValueType;
+ typedef StringHash<U, Allocator> SelfType;
+ typedef Hash<String, U, String::NoCaseHashFunctor, Allocator> BaseType;
+
+public:
+
+ void operator = (const SelfType& src) { BaseType::operator = (src); }
+
+ bool GetCaseInsensitive(const String& key, U* pvalue) const
+ {
+ String::NoCaseKey ikey(key);
+ return BaseType::GetAlt(ikey, pvalue);
+ }
+ // Pointer-returning get variety.
+ const U* GetCaseInsensitive(const String& key) const
+ {
+ String::NoCaseKey ikey(key);
+ return BaseType::GetAlt(ikey);
+ }
+ U* GetCaseInsensitive(const String& key)
+ {
+ String::NoCaseKey ikey(key);
+ return BaseType::GetAlt(ikey);
+ }
+
+
+ typedef typename BaseType::Iterator base_iterator;
+
+ base_iterator FindCaseInsensitive(const String& key)
+ {
+ String::NoCaseKey ikey(key);
+ return BaseType::FindAlt(ikey);
+ }
+
+ // Set just uses a find and assigns value if found. The key is not modified;
+ // this behavior is identical to Flash string variable assignment.
+ void SetCaseInsensitive(const String& key, const U& value)
+ {
+ base_iterator it = FindCaseInsensitive(key);
+ if (it != BaseType::End())
+ {
+ it->Second = value;
+ }
+ else
+ {
+ BaseType::Add(key, value);
+ }
+ }
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_String_FormatUtil.cpp b/LibOVR/Src/Kernel/OVR_String_FormatUtil.cpp new file mode 100644 index 0000000..a6ceb3a --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_String_FormatUtil.cpp @@ -0,0 +1,42 @@ +/************************************************************************************
+
+Filename : OVR_String_FormatUtil.cpp
+Content : String format functions.
+Created : February 27, 2013
+Notes :
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_String.h"
+#include "OVR_Log.h"
+
+namespace OVR {
+
+void StringBuffer::AppendFormat(const char* format, ...)
+{
+ va_list argList;
+
+ va_start(argList, format);
+ UPInt size = OVR_vscprintf(format, argList);
+ va_end(argList);
+
+ char* buffer = (char*) OVR_ALLOC(sizeof(char) * (size+1));
+
+ va_start(argList, format);
+ UPInt result = OVR_vsprintf(buffer, size+1, format, argList);
+ OVR_UNUSED1(result);
+ va_end(argList);
+ OVR_ASSERT_LOG(result == size, ("Error in OVR_vsprintf"));
+
+ AppendString(buffer);
+
+ OVR_FREE(buffer);
+}
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_String_PathUtil.cpp b/LibOVR/Src/Kernel/OVR_String_PathUtil.cpp new file mode 100644 index 0000000..27e79c6 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_String_PathUtil.cpp @@ -0,0 +1,200 @@ +/************************************************************************************
+
+Filename : OVR_String_PathUtil.cpp
+Content : String filename/url helper function
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_String.h"
+#include "OVR_UTF8Util.h"
+
+namespace OVR {
+
+//--------------------------------------------------------------------
+// ***** Path-Scanner helper function
+
+// Scans file path finding filename start and extension start, fills in their addess.
+void ScanFilePath(const char* url, const char** pfilename, const char** pext)
+{
+ const char* urlStart = url;
+ const char *filename = 0;
+ const char *lastDot = 0;
+
+ UInt32 charVal = UTF8Util::DecodeNextChar(&url);
+
+ while (charVal != 0)
+ {
+ if ((charVal == '/') || (charVal == '\\'))
+ {
+ filename = url;
+ lastDot = 0;
+ }
+ else if (charVal == '.')
+ {
+ lastDot = url - 1;
+ }
+
+ charVal = UTF8Util::DecodeNextChar(&url);
+ }
+
+ if (pfilename)
+ {
+ // It was a naked filename
+ if (urlStart && (*urlStart != '.') && *urlStart)
+ *pfilename = urlStart;
+ else
+ *pfilename = filename;
+ }
+
+ if (pext)
+ {
+ *pext = lastDot;
+ }
+}
+
+// Scans till the end of protocol. Returns first character past protocol,
+// 0 if not found.
+// - protocol: 'file://', 'http://'
+const char* ScanPathProtocol(const char* url)
+{
+ UInt32 charVal = UTF8Util::DecodeNextChar(&url);
+ UInt32 charVal2;
+
+ while (charVal != 0)
+ {
+ // Treat a colon followed by a slash as absolute.
+ if (charVal == ':')
+ {
+ charVal2 = UTF8Util::DecodeNextChar(&url);
+ charVal = UTF8Util::DecodeNextChar(&url);
+ if ((charVal == '/') && (charVal2 == '\\'))
+ return url;
+ }
+ charVal = UTF8Util::DecodeNextChar(&url);
+ }
+ return 0;
+}
+
+
+//--------------------------------------------------------------------
+// ***** String Path API implementation
+
+bool String::HasAbsolutePath(const char* url)
+{
+ // Absolute paths can star with:
+ // - protocols: 'file://', 'http://'
+ // - windows drive: 'c:\'
+ // - UNC share name: '\\share'
+ // - unix root '/'
+
+ // On the other hand, relative paths are:
+ // - directory: 'directory/file'
+ // - this directory: './file'
+ // - parent directory: '../file'
+ //
+ // For now, we don't parse '.' or '..' out, but instead let it be concatenated
+ // to string and let the OS figure it out. This, however, is not good for file
+ // name matching in library/etc, so it should be improved.
+
+ if (!url || !*url)
+ return true; // Treat empty strings as absolute.
+
+ UInt32 charVal = UTF8Util::DecodeNextChar(&url);
+
+ // Fist character of '/' or '\\' means absolute url.
+ if ((charVal == '/') || (charVal == '\\'))
+ return true;
+
+ while (charVal != 0)
+ {
+ // Treat a colon followed by a slash as absolute.
+ if (charVal == ':')
+ {
+ charVal = UTF8Util::DecodeNextChar(&url);
+ // Protocol or windows drive. Absolute.
+ if ((charVal == '/') || (charVal == '\\'))
+ return true;
+ }
+ else if ((charVal == '/') || (charVal == '\\'))
+ {
+ // Not a first character (else 'if' above the loop would have caught it).
+ // Must be a relative url.
+ break;
+ }
+
+ charVal = UTF8Util::DecodeNextChar(&url);
+ }
+
+ // We get here for relative paths.
+ return false;
+}
+
+
+bool String::HasExtension(const char* path)
+{
+ const char* ext = 0;
+ ScanFilePath(path, 0, &ext);
+ return ext != 0;
+}
+bool String::HasProtocol(const char* path)
+{
+ return ScanPathProtocol(path) != 0;
+}
+
+
+String String::GetPath() const
+{
+ const char* filename = 0;
+ ScanFilePath(ToCStr(), &filename, 0);
+
+ // Technically we can have extra logic somewhere for paths,
+ // such as enforcing protocol and '/' only based on flags,
+ // but we keep it simple for now.
+ return String(ToCStr(), filename ? (filename-ToCStr()) : GetSize());
+}
+
+String String::GetProtocol() const
+{
+ const char* protocolEnd = ScanPathProtocol(ToCStr());
+ return String(ToCStr(), protocolEnd ? (protocolEnd-ToCStr()) : 0);
+}
+
+String String::GetFilename() const
+{
+ const char* filename = 0;
+ ScanFilePath(ToCStr(), &filename, 0);
+ return String(filename);
+}
+String String::GetExtension() const
+{
+ const char* ext = 0;
+ ScanFilePath(ToCStr(), 0, &ext);
+ return String(ext);
+}
+
+void String::StripExtension()
+{
+ const char* ext = 0;
+ ScanFilePath(ToCStr(), 0, &ext);
+ if (ext)
+ {
+ *this = String(ToCStr(), ext-ToCStr());
+ }
+}
+
+void String::StripProtocol()
+{
+ const char* protocol = ScanPathProtocol(ToCStr());
+ if (protocol)
+ AssignString(protocol, OVR_strlen(protocol));
+}
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_SysFile.cpp b/LibOVR/Src/Kernel/OVR_SysFile.cpp new file mode 100644 index 0000000..f72a8d2 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_SysFile.cpp @@ -0,0 +1,125 @@ +/**************************************************************************
+
+Filename : OVR_SysFile.cpp
+Content : File wrapper class implementation (Win32)
+
+Created : April 5, 1999
+Authors : Michael Antonov
+
+Copyright : Copyright 2011 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+**************************************************************************/
+
+#define GFILE_CXX
+
+// Standard C library (Captain Obvious guarantees!)
+#include <stdio.h>
+
+#include "OVR_SysFile.h"
+
+namespace OVR {
+
+// This is - a dummy file that fails on all calls.
+
+class UnopenedFile : public File
+{
+public:
+ UnopenedFile() { }
+ ~UnopenedFile() { }
+
+ virtual const char* GetFilePath() { return 0; }
+
+ // ** File Information
+ virtual bool IsValid() { return 0; }
+ virtual bool IsWritable() { return 0; }
+
+ // Return position / file size
+ virtual int Tell() { return 0; }
+ virtual SInt64 LTell() { return 0; }
+ virtual int GetLength() { return 0; }
+ virtual SInt64 LGetLength() { return 0; }
+
+// virtual bool Stat(FileStats *pfs) { return 0; }
+ virtual int GetErrorCode() { return Error_FileNotFound; }
+
+ // ** Stream implementation & I/O
+ virtual int Write(const UByte *pbuffer, int numBytes) { return -1; OVR_UNUSED2(pbuffer, numBytes); }
+ virtual int Read(UByte *pbuffer, int numBytes) { return -1; OVR_UNUSED2(pbuffer, numBytes); }
+ virtual int SkipBytes(int numBytes) { return 0; OVR_UNUSED(numBytes); }
+ virtual int BytesAvailable() { return 0; }
+ virtual bool Flush() { return 0; }
+ virtual int Seek(int offset, int origin) { return -1; OVR_UNUSED2(offset, origin); }
+ virtual SInt64 LSeek(SInt64 offset, int origin) { return -1; OVR_UNUSED2(offset, origin); }
+
+ virtual int CopyFromStream(File *pstream, int byteSize) { return -1; OVR_UNUSED2(pstream, byteSize); }
+ virtual bool Close() { return 0; }
+};
+
+
+
+// ***** System File
+
+// System file is created to access objects on file system directly
+// This file can refer directly to path
+
+// ** Constructor
+SysFile::SysFile() : DelegatedFile(0)
+{
+ pFile = *new UnopenedFile;
+}
+
+File* FileFILEOpen(const String& path, int flags, int mode);
+
+// Opens a file
+SysFile::SysFile(const String& path, int flags, int mode) : DelegatedFile(0)
+{
+ Open(path, flags, mode);
+}
+
+
+// ** Open & management
+// Will fail if file's already open
+bool SysFile::Open(const String& path, int flags, int mode)
+{
+ pFile = *FileFILEOpen(path, flags, mode);
+ if ((!pFile) || (!pFile->IsValid()))
+ {
+ pFile = *new UnopenedFile;
+ return 0;
+ }
+ //pFile = *OVR_NEW DelegatedFile(pFile); // MA Testing
+ if (flags & Open_Buffered)
+ pFile = *new BufferedFile(pFile);
+ return 1;
+}
+
+
+// ** Overrides
+
+int SysFile::GetErrorCode()
+{
+ return pFile ? pFile->GetErrorCode() : Error_FileNotFound;
+}
+
+
+// Overrides to provide re-open support
+bool SysFile::IsValid()
+{
+ return pFile && pFile->IsValid();
+}
+bool SysFile::Close()
+{
+ if (IsValid())
+ {
+ DelegatedFile::Close();
+ pFile = *new UnopenedFile;
+ return 1;
+ }
+ return 0;
+}
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_SysFile.h b/LibOVR/Src/Kernel/OVR_SysFile.h new file mode 100644 index 0000000..a9bb0a0 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_SysFile.h @@ -0,0 +1,93 @@ +/************************************************************************************
+
+PublicHeader: Kernel
+Filename : OVR_SysFile.h
+Content : Header for all internal file management - functions and structures
+ to be inherited by OS specific subclasses.
+Created : September 19, 2012
+Notes :
+
+Notes : errno may not be preserved across use of GBaseFile member functions
+ : Directories cannot be deleted while files opened from them are in use
+ (For the GetFullName function)
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_SysFile_h
+#define OVR_SysFile_h
+
+#include "OVR_File.h"
+
+namespace OVR {
+
+// ***** Declared classes
+class SysFile;
+
+//-----------------------------------------------------------------------------------
+// *** File Statistics
+
+// This class contents are similar to _stat, providing
+// creation, modify and other information about the file.
+struct FileStat
+{
+ // No change or create time because they are not available on most systems
+ SInt64 ModifyTime;
+ SInt64 AccessTime;
+ SInt64 FileSize;
+
+ bool operator== (const FileStat& stat) const
+ {
+ return ( (ModifyTime == stat.ModifyTime) &&
+ (AccessTime == stat.AccessTime) &&
+ (FileSize == stat.FileSize) );
+ }
+};
+
+//-----------------------------------------------------------------------------------
+// *** System File
+
+// System file is created to access objects on file system directly
+// This file can refer directly to path.
+// System file can be open & closed several times; however, such use is not recommended
+// This class is realy a wrapper around an implementation of File interface for a
+// particular platform.
+
+class SysFile : public DelegatedFile
+{
+protected:
+ SysFile(const SysFile &source) : DelegatedFile () { OVR_UNUSED(source); }
+public:
+
+ // ** Constructor
+ SysFile();
+ // Opens a file
+ SysFile(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite);
+
+ // ** Open & management
+ bool Open(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite);
+
+ OVR_FORCE_INLINE bool Create(const String& path, int mode = Mode_ReadWrite)
+ { return Open(path, Open_ReadWrite|Open_Create, mode); }
+
+ // Helper function: obtain file statistics information. In GFx, this is used to detect file changes.
+ // Return 0 if function failed, most likely because the file doesn't exist.
+ static bool OVR_CDECL GetFileStat(FileStat* pfileStats, const String& path);
+
+ // ** Overrides
+ // Overridden to provide re-open support
+ virtual int GetErrorCode();
+
+ virtual bool IsValid();
+
+ virtual bool Close();
+};
+
+} // Scaleform
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_System.cpp b/LibOVR/Src/Kernel/OVR_System.cpp new file mode 100644 index 0000000..8eba8e2 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_System.cpp @@ -0,0 +1,70 @@ +/************************************************************************************
+
+Filename : OVR_System.cpp
+Content : General kernel initialization/cleanup, including that
+ of the memory allocator.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_System.h"
+#include "OVR_Threads.h"
+#include "OVR_Timer.h"
+
+namespace OVR {
+
+// ***** OVR::System Implementation
+
+// Initializes System core, installing allocator.
+void System::Init(Log* log, Allocator *palloc)
+{
+ if (!Allocator::GetInstance())
+ {
+ Log::SetGlobalLog(log);
+ Timer::initializeTimerSystem();
+ Allocator::setInstance(palloc);
+ }
+ else
+ {
+ OVR_DEBUG_LOG(("System::Init failed - duplicate call."));
+ }
+}
+
+void System::Destroy()
+{
+ if (Allocator::GetInstance())
+ {
+ // Wait for all threads to finish; this must be done so that memory
+ // allocator and all destructors finalize correctly.
+#ifdef OVR_ENABLE_THREADS
+ Thread::FinishAllThreads();
+#endif
+
+ // Shutdown heap and destroy SysAlloc singleton, if any.
+ Allocator::GetInstance()->onSystemShutdown();
+ Allocator::setInstance(0);
+
+ Timer::shutdownTimerSystem();
+ Log::SetGlobalLog(Log::GetDefaultLog());
+ }
+ else
+ {
+ OVR_DEBUG_LOG(("System::Destroy failed - System not initialized."));
+ }
+}
+
+// Returns 'true' if system was properly initialized.
+bool System::IsInitialized()
+{
+ return Allocator::GetInstance() != 0;
+}
+
+} // OVR
+
diff --git a/LibOVR/Src/Kernel/OVR_System.h b/LibOVR/Src/Kernel/OVR_System.h new file mode 100644 index 0000000..e53b4c8 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_System.h @@ -0,0 +1,67 @@ +/************************************************************************************
+
+PublicHeader: OVR
+Filename : OVR_System.h
+Content : General kernel initialization/cleanup, including that
+ of the memory allocator.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_System_h
+#define OVR_System_h
+
+#include "OVR_Allocator.h"
+#include "OVR_Log.h"
+
+namespace OVR {
+
+// ***** System Core Initialization class
+
+// System initialization must take place before any other OVR_Kernel objects are used;
+// this is done my calling System::Init(). Among other things, this is necessary to
+// initialize the memory allocator. Similarly, System::Destroy must be
+// called before program exist for proper cleanup. Both of these tasks can be achieved by
+// simply creating System object first, allowing its constructor/destructor do the work.
+
+// TBD: Require additional System class for Oculus Rift API?
+
+class System
+{
+public:
+
+ // System constructor expects allocator to be specified, if it is being substituted.
+ System(Log* log = Log::ConfigureDefaultLog(LogMask_Debug),
+ Allocator* palloc = DefaultAllocator::InitSystemSingleton())
+ {
+ Init(log, palloc);
+ }
+
+ ~System()
+ {
+ Destroy();
+ }
+
+ // Returns 'true' if system was properly initialized.
+ static bool OVR_CDECL IsInitialized();
+
+ // Initializes System core. Users can override memory implementation by passing
+ // a different Allocator here.
+ static void OVR_CDECL Init(Log* log = Log::ConfigureDefaultLog(LogMask_Debug),
+ Allocator *palloc = DefaultAllocator::InitSystemSingleton());
+
+ // De-initializes System more, finalizing the threading system and destroying
+ // the global memory allocator.
+ static void OVR_CDECL Destroy();
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Threads.h b/LibOVR/Src/Kernel/OVR_Threads.h new file mode 100644 index 0000000..9c29fe0 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Threads.h @@ -0,0 +1,396 @@ +/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_Threads.h
+Content : Contains thread-related (safe) functionality
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+#ifndef OVR_Threads_h
+#define OVR_Threads_h
+
+#include "OVR_Types.h"
+#include "OVR_Atomic.h"
+#include "OVR_RefCount.h"
+#include "OVR_Array.h"
+
+// Defines the infinite wait delay timeout
+#define OVR_WAIT_INFINITE 0xFFFFFFFF
+
+// To be defined in the project configuration options
+#ifdef OVR_ENABLE_THREADS
+
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ****** Declared classes
+
+// Declared with thread support only
+class Mutex;
+class WaitCondition;
+class Event;
+// Implementation forward declarations
+class MutexImpl;
+class WaitConditionImpl;
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Mutex
+
+// Mutex class represents a system Mutex synchronization object that provides access
+// serialization between different threads, allowing one thread mutually exclusive access
+// to a resource. Mutex is more heavy-weight then Lock, but supports WaitCondition.
+
+class Mutex
+{
+ friend class WaitConditionImpl;
+ friend class MutexImpl;
+
+ MutexImpl *pImpl;
+
+public:
+ // Constructor/destructor
+ Mutex(bool recursive = 1);
+ ~Mutex();
+
+ // Locking functions
+ void DoLock();
+ bool TryLock();
+ void Unlock();
+
+ // Returns 1 if the mutes is currently locked by another thread
+ // Returns 0 if the mutex is not locked by another thread, and can therefore be acquired.
+ bool IsLockedByAnotherThread();
+
+ // Locker class; Used for automatic locking of a mutex withing scope
+ class Locker
+ {
+ public:
+ Mutex *pMutex;
+ Locker(Mutex *pmutex)
+ { pMutex = pmutex; pMutex->DoLock(); }
+ ~Locker()
+ { pMutex->Unlock(); }
+ };
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** WaitCondition
+
+/*
+ WaitCondition is a synchronization primitive that can be used to implement what is known as a monitor.
+ Dependent threads wait on a wait condition by calling Wait(), and get woken up by other threads that
+ call Notify() or NotifyAll().
+
+ The unique feature of this class is that it provides an atomic way of first releasing a Mutex, and then
+ starting a wait on a wait condition. If both the mutex and the wait condition are associated with the same
+ resource, this ensures that any condition checked for while the mutex was locked does not change before
+ the wait on the condition is actually initiated.
+*/
+
+class WaitCondition
+{
+ friend class WaitConditionImpl;
+ // Internal implementation structure
+ WaitConditionImpl *pImpl;
+
+public:
+ // Constructor/destructor
+ WaitCondition();
+ ~WaitCondition();
+
+ // Release mutex and wait for condition. The mutex is re-aquired after the wait.
+ // Delay is specified in milliseconds (1/1000 of a second).
+ bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
+
+ // Notify a condition, releasing at one object waiting
+ void Notify();
+ // Notify a condition, releasing all objects waiting
+ void NotifyAll();
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Event
+
+// Event is a wait-able synchronization object similar to Windows event.
+// Event can be waited on until it's signaled by another thread calling
+// either SetEvent or PulseEvent.
+
+class Event
+{
+ // Event state, its mutex and the wait condition
+ volatile bool State;
+ volatile bool Temporary;
+ mutable Mutex StateMutex;
+ WaitCondition StateWaitCondition;
+
+ void updateState(bool newState, bool newTemp, bool mustNotify);
+
+public:
+ Event(bool setInitially = 0) : State(setInitially), Temporary(false) { }
+ ~Event() { }
+
+ // Wait on an event condition until it is set
+ // Delay is specified in milliseconds (1/1000 of a second).
+ bool Wait(unsigned delay = OVR_WAIT_INFINITE);
+
+ // Set an event, releasing objects waiting on it
+ void SetEvent()
+ { updateState(true, false, true); }
+
+ // Reset an event, un-signaling it
+ void ResetEvent()
+ { updateState(false, false, false); }
+
+ // Set and then reset an event once a waiter is released.
+ // If threads are already waiting, they will be notified and released
+ // If threads are not waiting, the event is set until the first thread comes in
+ void PulseEvent()
+ { updateState(true, true, true); }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Thread class
+
+// ThreadId uniquely identifies a thread; returned by GetCurrentThreadId() and
+// Thread::GetThreadId.
+typedef void* ThreadId;
+
+
+// *** Thread flags
+
+// Indicates that the thread is has been started, i.e. Start method has been called, and threads
+// OnExit() method has not yet been called/returned.
+#define OVR_THREAD_STARTED 0x01
+// This flag is set once the thread has ran, and finished.
+#define OVR_THREAD_FINISHED 0x02
+// This flag is set temporarily if this thread was started suspended. It is used internally.
+#define OVR_THREAD_START_SUSPENDED 0x08
+// This flag is used to ask a thread to exit. Message driven threads will usually check this flag
+// and finish once it is set.
+#define OVR_THREAD_EXIT 0x10
+
+
+class Thread : public RefCountBase<Thread>
+{ // NOTE: Waitable must be the first base since it implements RefCountImpl.
+
+public:
+
+ // *** Callback functions, can be used instead of overriding Run
+
+ // Run function prototypes.
+ // Thread function and user handle passed to it, executed by the default
+ // Thread::Run implementation if not null.
+ typedef int (*ThreadFn)(Thread *pthread, void* h);
+
+ // Thread ThreadFunction1 is executed if not 0, otherwise ThreadFunction2 is tried
+ ThreadFn ThreadFunction;
+ // User handle passes to a thread
+ void* UserHandle;
+
+ // Thread state to start a thread with
+ enum ThreadState
+ {
+ NotRunning = 0,
+ Running = 1,
+ Suspended = 2
+ };
+
+ // Thread priority
+ enum ThreadPriority
+ {
+ CriticalPriority,
+ HighestPriority,
+ AboveNormalPriority,
+ NormalPriority,
+ BelowNormalPriority,
+ LowestPriority,
+ IdlePriority,
+ };
+
+ // Thread constructor parameters
+ struct CreateParams
+ {
+ CreateParams(ThreadFn func = 0, void* hand = 0, UPInt ssize = 128 * 1024,
+ int proc = -1, ThreadState state = NotRunning, ThreadPriority prior = NormalPriority)
+ : threadFunction(func), userHandle(hand), stackSize(ssize),
+ processor(proc), initialState(state), priority(prior) {}
+ ThreadFn threadFunction; // Thread function
+ void* userHandle; // User handle passes to a thread
+ UPInt stackSize; // Thread stack size
+ int processor; // Thread hardware processor
+ ThreadState initialState; //
+ ThreadPriority priority; // Thread priority
+ };
+
+ // *** Constructors
+
+ // A default constructor always creates a thread in NotRunning state, because
+ // the derived class has not yet been initialized. The derived class can call Start explicitly.
+ // "processor" parameter specifies which hardware processor this thread will be run on.
+ // -1 means OS decides this. Implemented only on Win32
+ Thread(UPInt stackSize = 128 * 1024, int processor = -1);
+ // Constructors that initialize the thread with a pointer to function.
+ // An option to start a thread is available, but it should not be used if classes are derived from Thread.
+ // "processor" parameter specifies which hardware processor this thread will be run on.
+ // -1 means OS decides this. Implemented only on Win32
+ Thread(ThreadFn threadFunction, void* userHandle = 0, UPInt stackSize = 128 * 1024,
+ int processor = -1, ThreadState initialState = NotRunning);
+ // Constructors that initialize the thread with a create parameters structure.
+ explicit Thread(const CreateParams& params);
+
+ // Destructor.
+ virtual ~Thread();
+
+ // Waits for all Threads to finish; should be called only from the root
+ // application thread. Once this function returns, we know that all other
+ // thread's references to Thread object have been released.
+ static void OVR_CDECL FinishAllThreads();
+
+
+ // *** Overridable Run function for thread processing
+
+ // - returning from this method will end the execution of the thread
+ // - return value is usually 0 for success
+ virtual int Run();
+ // Called after return/exit function
+ virtual void OnExit();
+
+
+ // *** Thread management
+
+ // Starts the thread if its not already running
+ // - internally sets up the threading and calls Run()
+ // - initial state can either be Running or Suspended, NotRunning will just fail and do nothing
+ // - returns the exit code
+ virtual bool Start(ThreadState initialState = Running);
+
+ // Quits with an exit code
+ virtual void Exit(int exitCode=0);
+
+ // Suspend the thread until resumed
+ // Returns 1 for success, 0 for failure.
+ bool Suspend();
+ // Resumes currently suspended thread
+ // Returns 1 for success, 0 for failure.
+ bool Resume();
+
+ // Static function to return a pointer to the current thread
+ //static Thread* GetThread();
+
+
+ // *** Thread status query functions
+
+ bool GetExitFlag() const;
+ void SetExitFlag(bool exitFlag);
+
+ // Determines whether the thread was running and is now finished
+ bool IsFinished() const;
+ // Determines if the thread is currently suspended
+ bool IsSuspended() const;
+ // Returns current thread state
+ ThreadState GetThreadState() const;
+
+ // Returns the number of available CPUs on the system
+ static int GetCPUCount();
+
+ // Returns the thread exit code. Exit code is initialized to 0,
+ // and set to the return value if Run function after the thread is finished.
+ inline int GetExitCode() const { return ExitCode; }
+ // Returns an OS handle
+#if defined(OVR_OS_WIN32)
+ void* GetOSHandle() const { return ThreadHandle; }
+#else
+ pthread_t GetOSHandle() const { return ThreadHandle; }
+#endif
+
+#if defined(OVR_OS_WIN32)
+ ThreadId GetThreadId() const { return IdValue; }
+#else
+ ThreadId GetThreadId() const { return (ThreadId)GetOSHandle(); }
+#endif
+
+ static int GetOSPriority(ThreadPriority);
+ // *** Sleep
+
+ // Sleep secs seconds
+ static bool Sleep(unsigned secs);
+ // Sleep msecs milliseconds
+ static bool MSleep(unsigned msecs);
+
+
+ // *** Debugging functionality
+#if defined(OVR_OS_WIN32)
+ virtual void SetThreadName( const char* name );
+#else
+ virtual void SetThreadName( const char* name ) { OVR_UNUSED(name); }
+#endif
+
+private:
+#if defined(OVR_OS_WIN32)
+ friend unsigned WINAPI Thread_Win32StartFn(void *pthread);
+
+#else
+ friend void *Thread_PthreadStartFn(void * phandle);
+
+ static int InitAttr;
+ static pthread_attr_t Attr;
+#endif
+
+protected:
+ // Thread state flags
+ AtomicInt<UInt32> ThreadFlags;
+ AtomicInt<SInt32> SuspendCount;
+ UPInt StackSize;
+
+ // Hardware processor which this thread is running on.
+ int Processor;
+ ThreadPriority Priority;
+
+#if defined(OVR_OS_WIN32)
+ void* ThreadHandle;
+ volatile ThreadId IdValue;
+
+ // System-specific cleanup function called from destructor
+ void CleanupSystemThread();
+
+#else
+ pthread_t ThreadHandle;
+#endif
+
+ // Exit code of the thread, as returned by Run.
+ int ExitCode;
+
+ // Internal run function.
+ int PRun();
+ // Finishes the thread and releases internal reference to it.
+ void FinishAndRelease();
+
+ void Init(const CreateParams& params);
+
+ // Protected copy constructor
+ Thread(const Thread &source) { OVR_UNUSED(source); }
+
+};
+
+// Returns the unique Id of a thread it is called on, intended for
+// comparison purposes.
+ThreadId GetCurrentThreadId();
+
+
+} // OVR
+
+#endif // OVR_ENABLE_THREADS
+#endif // OVR_Threads_h
diff --git a/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp b/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp new file mode 100644 index 0000000..c40d9d8 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp @@ -0,0 +1,795 @@ +
+#include "OVR_Threads.h"
+#include "OVR_Hash.h"
+
+#ifdef OVR_ENABLE_THREADS
+
+#include "OVR_Timer.h"
+#include "OVR_Log.h"
+
+#include <pthread.h>
+#include <time.h>
+
+#ifdef OVR_OS_PS3
+#include <sys/sys_time.h>
+#include <sys/timer.h>
+#include <sys/synchronization.h>
+#define sleep(x) sys_timer_sleep(x)
+#define usleep(x) sys_timer_usleep(x)
+using std::timespec;
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#include <errno.h>
+#endif
+
+namespace OVR {
+
+// ***** Mutex implementation
+
+
+// *** Internal Mutex implementation structure
+
+class MutexImpl : public NewOverrideBase
+{
+ // System mutex or semaphore
+ pthread_mutex_t SMutex;
+ bool Recursive;
+ unsigned LockCount;
+ pthread_t LockedBy;
+
+ friend class WaitConditionImpl;
+
+public:
+ // Constructor/destructor
+ MutexImpl(Mutex* pmutex, bool recursive = 1);
+ ~MutexImpl();
+
+ // Locking functions
+ void DoLock();
+ bool TryLock();
+ void Unlock(Mutex* pmutex);
+ // Returns 1 if the mutes is currently locked
+ bool IsLockedByAnotherThread(Mutex* pmutex);
+ bool IsSignaled() const;
+};
+
+pthread_mutexattr_t Lock::RecursiveAttr;
+bool Lock::RecursiveAttrInit = 0;
+
+// *** Constructor/destructor
+MutexImpl::MutexImpl(Mutex* pmutex, bool recursive)
+{
+ Recursive = recursive;
+ LockCount = 0;
+
+ if (Recursive)
+ {
+ if (!Lock::RecursiveAttrInit)
+ {
+ pthread_mutexattr_init(&Lock::RecursiveAttr);
+ pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
+ Lock::RecursiveAttrInit = 1;
+ }
+
+ pthread_mutex_init(&SMutex, &Lock::RecursiveAttr);
+ }
+ else
+ pthread_mutex_init(&SMutex, 0);
+}
+
+MutexImpl::~MutexImpl()
+{
+ pthread_mutex_destroy(&SMutex);
+}
+
+
+// Lock and try lock
+void MutexImpl::DoLock()
+{
+ while (pthread_mutex_lock(&SMutex));
+ LockCount++;
+ LockedBy = pthread_self();
+}
+
+bool MutexImpl::TryLock()
+{
+ if (!pthread_mutex_trylock(&SMutex))
+ {
+ LockCount++;
+ LockedBy = pthread_self();
+ return 1;
+ }
+
+ return 0;
+}
+
+void MutexImpl::Unlock(Mutex* pmutex)
+{
+ OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0);
+
+ unsigned lockCount;
+ LockCount--;
+ lockCount = LockCount;
+
+ pthread_mutex_unlock(&SMutex);
+}
+
+bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
+{
+ // There could be multiple interpretations of IsLocked with respect to current thread
+ if (LockCount == 0)
+ return 0;
+ if (pthread_self() != LockedBy)
+ return 1;
+ return 0;
+}
+
+bool MutexImpl::IsSignaled() const
+{
+ // An mutex is signaled if it is not locked ANYWHERE
+ // Note that this is different from IsLockedByAnotherThread function,
+ // that takes current thread into account
+ return LockCount == 0;
+}
+
+
+// *** Actual Mutex class implementation
+
+Mutex::Mutex(bool recursive)
+{
+ // NOTE: RefCount mode already thread-safe for all waitables.
+ pImpl = new MutexImpl(this, recursive);
+}
+
+Mutex::~Mutex()
+{
+ delete pImpl;
+}
+
+// Lock and try lock
+void Mutex::DoLock()
+{
+ pImpl->DoLock();
+}
+bool Mutex::TryLock()
+{
+ return pImpl->TryLock();
+}
+void Mutex::Unlock()
+{
+ pImpl->Unlock(this);
+}
+bool Mutex::IsLockedByAnotherThread()
+{
+ return pImpl->IsLockedByAnotherThread(this);
+}
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Event
+
+bool Event::Wait(unsigned delay)
+{
+ Mutex::Locker lock(&StateMutex);
+
+ // Do the correct amount of waiting
+ if (delay == OVR_WAIT_INFINITE)
+ {
+ while(!State)
+ StateWaitCondition.Wait(&StateMutex);
+ }
+ else if (delay)
+ {
+ if (!State)
+ StateWaitCondition.Wait(&StateMutex, delay);
+ }
+
+ bool state = State;
+ // Take care of temporary 'pulsing' of a state
+ if (Temporary)
+ {
+ Temporary = false;
+ State = false;
+ }
+ return state;
+}
+
+void Event::updateState(bool newState, bool newTemp, bool mustNotify)
+{
+ Mutex::Locker lock(&StateMutex);
+ State = newState;
+ Temporary = newTemp;
+ if (mustNotify)
+ StateWaitCondition.NotifyAll();
+}
+
+
+
+// ***** Wait Condition Implementation
+
+// Internal implementation class
+class WaitConditionImpl : public NewOverrideBase
+{
+ pthread_mutex_t SMutex;
+ pthread_cond_t Condv;
+
+public:
+
+ // Constructor/destructor
+ WaitConditionImpl();
+ ~WaitConditionImpl();
+
+ // Release mutex and wait for condition. The mutex is re-aqured after the wait.
+ bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
+
+ // Notify a condition, releasing at one object waiting
+ void Notify();
+ // Notify a condition, releasing all objects waiting
+ void NotifyAll();
+};
+
+
+WaitConditionImpl::WaitConditionImpl()
+{
+ pthread_mutex_init(&SMutex, 0);
+ pthread_cond_init(&Condv, 0);
+}
+
+WaitConditionImpl::~WaitConditionImpl()
+{
+ pthread_mutex_destroy(&SMutex);
+ pthread_cond_destroy(&Condv);
+}
+
+bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
+{
+ bool result = 1;
+ unsigned lockCount = pmutex->pImpl->LockCount;
+
+ // Mutex must have been locked
+ if (lockCount == 0)
+ return 0;
+
+ pthread_mutex_lock(&SMutex);
+
+ // Finally, release a mutex or semaphore
+ if (pmutex->pImpl->Recursive)
+ {
+ // Release the recursive mutex N times
+ pmutex->pImpl->LockCount = 0;
+ for(unsigned i=0; i<lockCount; i++)
+ pthread_mutex_unlock(&pmutex->pImpl->SMutex);
+ }
+ else
+ {
+ pmutex->pImpl->LockCount = 0;
+ pthread_mutex_unlock(&pmutex->pImpl->SMutex);
+ }
+
+ // Note that there is a gap here between mutex.Unlock() and Wait().
+ // The other mutex protects this gap.
+
+ if (delay == OVR_WAIT_INFINITE)
+ pthread_cond_wait(&Condv,&SMutex);
+ else
+ {
+ timespec ts;
+#ifdef OVR_OS_PS3
+ sys_time_sec_t s;
+ sys_time_nsec_t ns;
+ sys_time_get_current_time(&s, &ns);
+
+ ts.tv_sec = s + (delay / 1000);
+ ts.tv_nsec = ns + (delay % 1000) * 1000000;
+
+#else
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+
+ ts.tv_sec = tv.tv_sec + (delay / 1000);
+ ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000;
+#endif
+ if (ts.tv_nsec > 999999999)
+ {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000;
+ }
+ int r = pthread_cond_timedwait(&Condv,&SMutex, &ts);
+ OVR_ASSERT(r == 0 || r == ETIMEDOUT);
+ if (r)
+ result = 0;
+ }
+
+ pthread_mutex_unlock(&SMutex);
+
+ // Re-aquire the mutex
+ for(unsigned i=0; i<lockCount; i++)
+ pmutex->DoLock();
+
+ // Return the result
+ return result;
+}
+
+// Notify a condition, releasing the least object in a queue
+void WaitConditionImpl::Notify()
+{
+ pthread_mutex_lock(&SMutex);
+ pthread_cond_signal(&Condv);
+ pthread_mutex_unlock(&SMutex);
+}
+
+// Notify a condition, releasing all objects waiting
+void WaitConditionImpl::NotifyAll()
+{
+ pthread_mutex_lock(&SMutex);
+ pthread_cond_broadcast(&Condv);
+ pthread_mutex_unlock(&SMutex);
+}
+
+
+
+// *** Actual implementation of WaitCondition
+
+WaitCondition::WaitCondition()
+{
+ pImpl = new WaitConditionImpl;
+}
+WaitCondition::~WaitCondition()
+{
+ delete pImpl;
+}
+
+bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
+{
+ return pImpl->Wait(pmutex, delay);
+}
+// Notification
+void WaitCondition::Notify()
+{
+ pImpl->Notify();
+}
+void WaitCondition::NotifyAll()
+{
+ pImpl->NotifyAll();
+}
+
+
+// ***** Current thread
+
+// Per-thread variable
+/*
+static __thread Thread* pCurrentThread = 0;
+
+// Static function to return a pointer to the current thread
+void Thread::InitCurrentThread(Thread *pthread)
+{
+ pCurrentThread = pthread;
+}
+
+// Static function to return a pointer to the current thread
+Thread* Thread::GetThread()
+{
+ return pCurrentThread;
+}
+*/
+
+
+// *** Thread constructors.
+
+Thread::Thread(UPInt stackSize, int processor)
+{
+ // NOTE: RefCount mode already thread-safe for all Waitable objects.
+ CreateParams params;
+ params.stackSize = stackSize;
+ params.processor = processor;
+ Init(params);
+}
+
+Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
+ int processor, Thread::ThreadState initialState)
+{
+ CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
+ Init(params);
+}
+
+Thread::Thread(const CreateParams& params)
+{
+ Init(params);
+}
+
+void Thread::Init(const CreateParams& params)
+{
+ // Clear the variables
+ ThreadFlags = 0;
+ ThreadHandle = 0;
+ ExitCode = 0;
+ SuspendCount = 0;
+ StackSize = params.stackSize;
+ Processor = params.processor;
+ Priority = params.priority;
+
+ // Clear Function pointers
+ ThreadFunction = params.threadFunction;
+ UserHandle = params.userHandle;
+ if (params.initialState != NotRunning)
+ Start(params.initialState);
+}
+
+Thread::~Thread()
+{
+ // Thread should not running while object is being destroyed,
+ // this would indicate ref-counting issue.
+ //OVR_ASSERT(IsRunning() == 0);
+
+ // Clean up thread.
+ ThreadHandle = 0;
+}
+
+
+
+// *** Overridable User functions.
+
+// Default Run implementation
+int Thread::Run()
+{
+ // Call pointer to function, if available.
+ return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
+}
+void Thread::OnExit()
+{
+}
+
+
+// Finishes the thread and releases internal reference to it.
+void Thread::FinishAndRelease()
+{
+ // Note: thread must be US.
+ ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
+ ThreadFlags |= OVR_THREAD_FINISHED;
+
+ // Release our reference; this is equivalent to 'delete this'
+ // from the point of view of our thread.
+ Release();
+}
+
+
+
+// *** ThreadList - used to track all created threads
+
+class ThreadList : public NewOverrideBase
+{
+ //------------------------------------------------------------------------
+ struct ThreadHashOp
+ {
+ size_t operator()(const Thread* ptr)
+ {
+ return (((size_t)ptr) >> 6) ^ (size_t)ptr;
+ }
+ };
+
+ HashSet<Thread*, ThreadHashOp> ThreadSet;
+ Mutex ThreadMutex;
+ WaitCondition ThreadsEmpty;
+ // Track the root thread that created us.
+ pthread_t RootThreadId;
+
+ static ThreadList* volatile pRunningThreads;
+
+ void addThread(Thread *pthread)
+ {
+ Mutex::Locker lock(&ThreadMutex);
+ ThreadSet.Add(pthread);
+ }
+
+ void removeThread(Thread *pthread)
+ {
+ Mutex::Locker lock(&ThreadMutex);
+ ThreadSet.Remove(pthread);
+ if (ThreadSet.GetSize() == 0)
+ ThreadsEmpty.Notify();
+ }
+
+ void finishAllThreads()
+ {
+ // Only original root thread can call this.
+ OVR_ASSERT(pthread_self() == RootThreadId);
+
+ Mutex::Locker lock(&ThreadMutex);
+ while (ThreadSet.GetSize() != 0)
+ ThreadsEmpty.Wait(&ThreadMutex);
+ }
+
+public:
+
+ ThreadList()
+ {
+ RootThreadId = pthread_self();
+ }
+ ~ThreadList() { }
+
+
+ static void AddRunningThread(Thread *pthread)
+ {
+ // Non-atomic creation ok since only the root thread
+ if (!pRunningThreads)
+ {
+ pRunningThreads = new ThreadList;
+ OVR_ASSERT(pRunningThreads);
+ }
+ pRunningThreads->addThread(pthread);
+ }
+
+ // NOTE: 'pthread' might be a dead pointer when this is
+ // called so it should not be accessed; it is only used
+ // for removal.
+ static void RemoveRunningThread(Thread *pthread)
+ {
+ OVR_ASSERT(pRunningThreads);
+ pRunningThreads->removeThread(pthread);
+ }
+
+ static void FinishAllThreads()
+ {
+ // This is ok because only root thread can wait for other thread finish.
+ if (pRunningThreads)
+ {
+ pRunningThreads->finishAllThreads();
+ delete pRunningThreads;
+ pRunningThreads = 0;
+ }
+ }
+};
+
+// By default, we have no thread list.
+ThreadList* volatile ThreadList::pRunningThreads = 0;
+
+
+// FinishAllThreads - exposed publicly in Thread.
+void Thread::FinishAllThreads()
+{
+ ThreadList::FinishAllThreads();
+}
+
+// *** Run override
+
+int Thread::PRun()
+{
+ // Suspend us on start, if requested
+ if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
+ {
+ Suspend();
+ ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
+ }
+
+ // Call the virtual run function
+ ExitCode = Run();
+ return ExitCode;
+}
+
+
+
+
+// *** User overridables
+
+bool Thread::GetExitFlag() const
+{
+ return (ThreadFlags & OVR_THREAD_EXIT) != 0;
+}
+
+void Thread::SetExitFlag(bool exitFlag)
+{
+ // The below is atomic since ThreadFlags is AtomicInt.
+ if (exitFlag)
+ ThreadFlags |= OVR_THREAD_EXIT;
+ else
+ ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
+}
+
+
+// Determines whether the thread was running and is now finished
+bool Thread::IsFinished() const
+{
+ return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
+}
+// Determines whether the thread is suspended
+bool Thread::IsSuspended() const
+{
+ return SuspendCount > 0;
+}
+// Returns current thread state
+Thread::ThreadState Thread::GetThreadState() const
+{
+ if (IsSuspended())
+ return Suspended;
+ if (ThreadFlags & OVR_THREAD_STARTED)
+ return Running;
+ return NotRunning;
+}
+/*
+static const char* mapsched_policy(int policy)
+{
+ switch(policy)
+ {
+ case SCHED_OTHER:
+ return "SCHED_OTHER";
+ case SCHED_RR:
+ return "SCHED_RR";
+ case SCHED_FIFO:
+ return "SCHED_FIFO";
+
+ }
+ return "UNKNOWN";
+}
+ int policy;
+ sched_param sparam;
+ pthread_getschedparam(pthread_self(), &policy, &sparam);
+ int max_prior = sched_get_priority_max(policy);
+ int min_prior = sched_get_priority_min(policy);
+ printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior);
+#include <stdio.h>
+*/
+// ***** Thread management
+
+// The actual first function called on thread start
+void* Thread_PthreadStartFn(void* phandle)
+{
+ Thread* pthread = (Thread*)phandle;
+ int result = pthread->PRun();
+ // Signal the thread as done and release it atomically.
+ pthread->FinishAndRelease();
+ // At this point Thread object might be dead; however we can still pass
+ // it to RemoveRunningThread since it is only used as a key there.
+ ThreadList::RemoveRunningThread(pthread);
+ return (void*) result;
+}
+
+int Thread::InitAttr = 0;
+pthread_attr_t Thread::Attr;
+
+/* static */
+int Thread::GetOSPriority(ThreadPriority p)
+//static inline int MapToSystemPrority(Thread::ThreadPriority p)
+{
+#ifdef OVR_OS_PS3
+ switch(p)
+ {
+ case Thread::CriticalPriority: return 0;
+ case Thread::HighestPriority: return 300;
+ case Thread::AboveNormalPriority: return 600;
+ case Thread::NormalPriority: return 1000;
+ case Thread::BelowNormalPriority: return 1500;
+ case Thread::LowestPriority: return 2500;
+ case Thread::IdlePriority: return 3071;
+ } return 1000;
+#else
+ OVR_UNUSED(p);
+ return -1;
+#endif
+}
+
+bool Thread::Start(ThreadState initialState)
+{
+ if (initialState == NotRunning)
+ return 0;
+ if (GetThreadState() != NotRunning)
+ {
+ OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
+ return 0;
+ }
+
+ if (!InitAttr)
+ {
+ pthread_attr_init(&Attr);
+ pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&Attr, 128 * 1024);
+ sched_param sparam;
+ sparam.sched_priority = Thread::GetOSPriority(NormalPriority);
+ pthread_attr_setschedparam(&Attr, &sparam);
+ InitAttr = 1;
+ }
+
+ ExitCode = 0;
+ SuspendCount = 0;
+ ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
+
+ // AddRef to us until the thread is finished
+ AddRef();
+ ThreadList::AddRunningThread(this);
+
+ int result;
+ if (StackSize != 128 * 1024 || Priority != NormalPriority)
+ {
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&attr, StackSize);
+ sched_param sparam;
+ sparam.sched_priority = Thread::GetOSPriority(Priority);
+ pthread_attr_setschedparam(&attr, &sparam);
+ result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this);
+ pthread_attr_destroy(&attr);
+ }
+ else
+ result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this);
+
+ if (result)
+ {
+ ThreadFlags = 0;
+ Release();
+ ThreadList::RemoveRunningThread(this);
+ return 0;
+ }
+ return 1;
+}
+
+
+// Suspend the thread until resumed
+bool Thread::Suspend()
+{
+ OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system"));
+ return 0;
+}
+
+// Resumes currently suspended thread
+bool Thread::Resume()
+{
+ return 0;
+}
+
+
+// Quits with an exit code
+void Thread::Exit(int exitCode)
+{
+ // Can only exist the current thread
+ // if (GetThread() != this)
+ // return;
+
+ // Call the virtual OnExit function
+ OnExit();
+
+ // Signal this thread object as done and release it's references.
+ FinishAndRelease();
+ ThreadList::RemoveRunningThread(this);
+
+ pthread_exit((void *) exitCode);
+}
+
+ThreadId GetCurrentThreadId()
+{
+ return (void*)pthread_self();
+}
+
+// *** Sleep functions
+
+/* static */
+bool Thread::Sleep(unsigned secs)
+{
+ sleep(secs);
+ return 1;
+}
+/* static */
+bool Thread::MSleep(unsigned msecs)
+{
+ usleep(msecs*1000);
+ return 1;
+}
+
+/* static */
+int Thread::GetCPUCount()
+{
+ return 1;
+}
+
+
+#ifdef OVR_OS_PS3
+
+sys_lwmutex_attribute_t Lock::LockAttr = { SYS_SYNC_PRIORITY, SYS_SYNC_RECURSIVE };
+
+#endif
+
+}
+
+#endif // OVR_ENABLE_THREADS
diff --git a/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp b/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp new file mode 100644 index 0000000..fa3962e --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp @@ -0,0 +1,994 @@ +/************************************************************************************
+
+Filename : OVR_ThreadsWinAPI.cpp
+Platform : WinAPI
+Content : Windows specific thread-related (safe) functionality
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Threads.h"
+#include "OVR_Hash.h"
+#include "OVR_Log.h"
+
+#ifdef OVR_ENABLE_THREADS
+
+// For _beginthreadex / _endtheadex
+#include <process.h>
+
+namespace OVR {
+
+
+//-----------------------------------------------------------------------------------
+// *** Internal Mutex implementation class
+
+class MutexImpl : public NewOverrideBase
+{
+ // System mutex or semaphore
+ HANDLE hMutexOrSemaphore;
+ bool Recursive;
+ volatile unsigned LockCount;
+
+ friend class WaitConditionImpl;
+
+public:
+ // Constructor/destructor
+ MutexImpl(bool recursive = 1);
+ ~MutexImpl();
+
+ // Locking functions
+ void DoLock();
+ bool TryLock();
+ void Unlock(Mutex* pmutex);
+ // Returns 1 if the mutes is currently locked
+ bool IsLockedByAnotherThread(Mutex* pmutex);
+};
+
+// *** Constructor/destructor
+MutexImpl::MutexImpl(bool recursive)
+{
+ Recursive = recursive;
+ LockCount = 0;
+ hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphore(NULL, 1, 1, NULL);
+}
+MutexImpl::~MutexImpl()
+{
+ CloseHandle(hMutexOrSemaphore);
+}
+
+
+// Lock and try lock
+void MutexImpl::DoLock()
+{
+ if (::WaitForSingleObject(hMutexOrSemaphore, INFINITE) != WAIT_OBJECT_0)
+ return;
+ LockCount++;
+}
+
+bool MutexImpl::TryLock()
+{
+ DWORD ret;
+ if ((ret=::WaitForSingleObject(hMutexOrSemaphore, 0)) != WAIT_OBJECT_0)
+ return 0;
+ LockCount++;
+ return 1;
+}
+
+void MutexImpl::Unlock(Mutex* pmutex)
+{
+ OVR_UNUSED(pmutex);
+
+ unsigned lockCount;
+ LockCount--;
+ lockCount = LockCount;
+
+ // Release mutex
+ if ((Recursive ? ReleaseMutex(hMutexOrSemaphore) :
+ ReleaseSemaphore(hMutexOrSemaphore, 1, NULL)) != 0)
+ {
+ // This used to call Wait handlers if lockCount == 0.
+ }
+}
+
+bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
+{
+ // There could be multiple interpretations of IsLocked with respect to current thread
+ if (LockCount == 0)
+ return 0;
+ if (!TryLock())
+ return 1;
+ Unlock(pmutex);
+ return 0;
+}
+
+/*
+bool MutexImpl::IsSignaled() const
+{
+ // An mutex is signaled if it is not locked ANYWHERE
+ // Note that this is different from IsLockedByAnotherThread function,
+ // that takes current thread into account
+ return LockCount == 0;
+}
+*/
+
+
+// *** Actual Mutex class implementation
+
+Mutex::Mutex(bool recursive)
+{
+ pImpl = new MutexImpl(recursive);
+}
+Mutex::~Mutex()
+{
+ delete pImpl;
+}
+
+// Lock and try lock
+void Mutex::DoLock()
+{
+ pImpl->DoLock();
+}
+bool Mutex::TryLock()
+{
+ return pImpl->TryLock();
+}
+void Mutex::Unlock()
+{
+ pImpl->Unlock(this);
+}
+bool Mutex::IsLockedByAnotherThread()
+{
+ return pImpl->IsLockedByAnotherThread(this);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** Event
+
+bool Event::Wait(unsigned delay)
+{
+ Mutex::Locker lock(&StateMutex);
+
+ // Do the correct amount of waiting
+ if (delay == OVR_WAIT_INFINITE)
+ {
+ while(!State)
+ StateWaitCondition.Wait(&StateMutex);
+ }
+ else if (delay)
+ {
+ if (!State)
+ StateWaitCondition.Wait(&StateMutex, delay);
+ }
+
+ bool state = State;
+ // Take care of temporary 'pulsing' of a state
+ if (Temporary)
+ {
+ Temporary = false;
+ State = false;
+ }
+ return state;
+}
+
+void Event::updateState(bool newState, bool newTemp, bool mustNotify)
+{
+ Mutex::Locker lock(&StateMutex);
+ State = newState;
+ Temporary = newTemp;
+ if (mustNotify)
+ StateWaitCondition.NotifyAll();
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** Win32 Wait Condition Implementation
+
+// Internal implementation class
+class WaitConditionImpl : public NewOverrideBase
+{
+ // Event pool entries for extra events
+ struct EventPoolEntry : public NewOverrideBase
+ {
+ HANDLE hEvent;
+ EventPoolEntry *pNext;
+ EventPoolEntry *pPrev;
+ };
+
+ Lock WaitQueueLoc;
+ // Stores free events that can be used later
+ EventPoolEntry * pFreeEventList;
+
+ // A queue of waiting objects to be signaled
+ EventPoolEntry* pQueueHead;
+ EventPoolEntry* pQueueTail;
+
+ // Allocation functions for free events
+ EventPoolEntry* GetNewEvent();
+ void ReleaseEvent(EventPoolEntry* pevent);
+
+ // Queue operations
+ void QueuePush(EventPoolEntry* pentry);
+ EventPoolEntry* QueuePop();
+ void QueueFindAndRemove(EventPoolEntry* pentry);
+
+public:
+
+ // Constructor/destructor
+ WaitConditionImpl();
+ ~WaitConditionImpl();
+
+ // Release mutex and wait for condition. The mutex is re-acqured after the wait.
+ bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
+
+ // Notify a condition, releasing at one object waiting
+ void Notify();
+ // Notify a condition, releasing all objects waiting
+ void NotifyAll();
+};
+
+
+
+WaitConditionImpl::WaitConditionImpl()
+{
+ pFreeEventList = 0;
+ pQueueHead =
+ pQueueTail = 0;
+}
+
+WaitConditionImpl::~WaitConditionImpl()
+{
+ // Free all the resources
+ EventPoolEntry* p = pFreeEventList;
+ EventPoolEntry* pentry;
+
+ while(p)
+ {
+ // Move to next
+ pentry = p;
+ p = p->pNext;
+ // Delete old
+ ::CloseHandle(pentry->hEvent);
+ delete pentry;
+ }
+ // Shouldn't we also consider the queue?
+
+ // To be safe
+ pFreeEventList = 0;
+ pQueueHead =
+ pQueueTail = 0;
+}
+
+
+// Allocation functions for free events
+WaitConditionImpl::EventPoolEntry* WaitConditionImpl::GetNewEvent()
+{
+ EventPoolEntry* pentry;
+
+ // If there are any free nodes, use them
+ if (pFreeEventList)
+ {
+ pentry = pFreeEventList;
+ pFreeEventList = pFreeEventList->pNext;
+ }
+ else
+ {
+ // Allocate a new node
+ pentry = new EventPoolEntry;
+ pentry->pNext = 0;
+ pentry->pPrev = 0;
+ // Non-signaled manual event
+ pentry->hEvent = ::CreateEvent(NULL, TRUE, 0, NULL);
+ }
+
+ return pentry;
+}
+
+void WaitConditionImpl::ReleaseEvent(EventPoolEntry* pevent)
+{
+ // Mark event as non-signaled
+ ::ResetEvent(pevent->hEvent);
+ // And add it to free pool
+ pevent->pNext = pFreeEventList;
+ pevent->pPrev = 0;
+ pFreeEventList = pevent;
+}
+
+// Queue operations
+void WaitConditionImpl::QueuePush(EventPoolEntry* pentry)
+{
+ // Items already exist? Just add to tail
+ if (pQueueTail)
+ {
+ pentry->pPrev = pQueueTail;
+ pQueueTail->pNext = pentry;
+ pentry->pNext = 0;
+ pQueueTail = pentry;
+ }
+ else
+ {
+ // No items in queue
+ pentry->pNext =
+ pentry->pPrev = 0;
+ pQueueHead =
+ pQueueTail = pentry;
+ }
+}
+
+WaitConditionImpl::EventPoolEntry* WaitConditionImpl::QueuePop()
+{
+ EventPoolEntry* pentry = pQueueHead;
+
+ // No items, null pointer
+ if (pentry)
+ {
+ // More items after this one? just grab the first item
+ if (pQueueHead->pNext)
+ {
+ pQueueHead = pentry->pNext;
+ pQueueHead->pPrev = 0;
+ }
+ else
+ {
+ // Last item left
+ pQueueTail =
+ pQueueHead = 0;
+ }
+ }
+ return pentry;
+}
+
+void WaitConditionImpl::QueueFindAndRemove(EventPoolEntry* pentry)
+{
+ // Do an exhaustive search looking for an entry
+ EventPoolEntry* p = pQueueHead;
+
+ while(p)
+ {
+ // Entry found? Remove.
+ if (p == pentry)
+ {
+
+ // Remove the node form the list
+ // Prev link
+ if (pentry->pPrev)
+ pentry->pPrev->pNext = pentry->pNext;
+ else
+ pQueueHead = pentry->pNext;
+ // Next link
+ if (pentry->pNext)
+ pentry->pNext->pPrev = pentry->pPrev;
+ else
+ pQueueTail = pentry->pPrev;
+ // Done
+ return;
+ }
+
+ // Move to next item
+ p = p->pNext;
+ }
+}
+
+
+bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
+{
+ bool result = 0;
+ unsigned i;
+ unsigned lockCount = pmutex->pImpl->LockCount;
+ EventPoolEntry* pentry;
+
+ // Mutex must have been locked
+ if (lockCount == 0)
+ return 0;
+
+ // Add an object to the wait queue
+ WaitQueueLoc.DoLock();
+ QueuePush(pentry = GetNewEvent());
+ WaitQueueLoc.Unlock();
+
+ // Finally, release a mutex or semaphore
+ if (pmutex->pImpl->Recursive)
+ {
+ // Release the recursive mutex N times
+ pmutex->pImpl->LockCount = 0;
+ for(i=0; i<lockCount; i++)
+ ::ReleaseMutex(pmutex->pImpl->hMutexOrSemaphore);
+ }
+ else
+ {
+ pmutex->pImpl->LockCount = 0;
+ ::ReleaseSemaphore(pmutex->pImpl->hMutexOrSemaphore, 1, NULL);
+ }
+
+ // Note that there is a gap here between mutex.Unlock() and Wait(). However,
+ // if notify() comes in at this point in the other thread it will set our
+ // corresponding event so wait will just fall through, as expected.
+
+ // Block and wait on the event
+ DWORD waitResult = ::WaitForSingleObject(pentry->hEvent,
+ (delay == OVR_WAIT_INFINITE) ? INFINITE : delay);
+ /*
+repeat_wait:
+ DWORD waitResult =
+
+ ::MsgWaitForMultipleObjects(1, &pentry->hEvent, FALSE,
+ (delay == OVR_WAIT_INFINITE) ? INFINITE : delay,
+ QS_ALLINPUT);
+ */
+
+ WaitQueueLoc.DoLock();
+ switch(waitResult)
+ {
+ case WAIT_ABANDONED:
+ case WAIT_OBJECT_0:
+ result = 1;
+ // Wait was successful, therefore the event entry should already be removed
+ // So just add entry back to a free list
+ ReleaseEvent(pentry);
+ break;
+ /*
+ case WAIT_OBJECT_0 + 1:
+ // Messages in WINDOWS queue
+ {
+ MSG msg;
+ PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
+ WaitQueueLoc.Unlock();
+ goto repeat_wait;
+ }
+ break; */
+ default:
+ // Timeout, our entry should still be in a queue
+ QueueFindAndRemove(pentry);
+ ReleaseEvent(pentry);
+ }
+ WaitQueueLoc.Unlock();
+
+ // Re-aquire the mutex
+ for(i=0; i<lockCount; i++)
+ pmutex->DoLock();
+
+ // Return the result
+ return result;
+}
+
+// Notify a condition, releasing the least object in a queue
+void WaitConditionImpl::Notify()
+{
+ Lock::Locker lock(&WaitQueueLoc);
+
+ // Pop last entry & signal it
+ EventPoolEntry* pentry = QueuePop();
+ if (pentry)
+ ::SetEvent(pentry->hEvent);
+}
+
+// Notify a condition, releasing all objects waiting
+void WaitConditionImpl::NotifyAll()
+{
+ Lock::Locker lock(&WaitQueueLoc);
+
+ // Pop and signal all events
+ // NOTE : There is no need to release the events, it's the waiters job to do so
+ EventPoolEntry* pentry = QueuePop();
+ while (pentry)
+ {
+ ::SetEvent(pentry->hEvent);
+ pentry = QueuePop();
+ }
+}
+
+
+
+// *** Actual implementation of WaitCondition
+
+WaitCondition::WaitCondition()
+{
+ pImpl = new WaitConditionImpl;
+}
+WaitCondition::~WaitCondition()
+{
+ delete pImpl;
+}
+
+// Wait without a mutex
+bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
+{
+ return pImpl->Wait(pmutex, delay);
+}
+// Notification
+void WaitCondition::Notify()
+{
+ pImpl->Notify();
+}
+void WaitCondition::NotifyAll()
+{
+ pImpl->NotifyAll();
+}
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Thread Class
+
+// Per-thread variable
+// MA: Don't use TLS for now - portability issues with DLLs, etc.
+/*
+#if !defined(OVR_CC_MSVC) || (OVR_CC_MSVC < 1300)
+__declspec(thread) Thread* pCurrentThread = 0;
+#else
+#pragma data_seg(".tls$")
+__declspec(thread) Thread* pCurrentThread = 0;
+#pragma data_seg(".rwdata")
+#endif
+*/
+
+// *** Thread constructors.
+
+Thread::Thread(UPInt stackSize, int processor)
+{
+ CreateParams params;
+ params.stackSize = stackSize;
+ params.processor = processor;
+ Init(params);
+}
+
+Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
+ int processor, Thread::ThreadState initialState)
+{
+ CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
+ Init(params);
+}
+
+Thread::Thread(const CreateParams& params)
+{
+ Init(params);
+}
+void Thread::Init(const CreateParams& params)
+{
+ // Clear the variables
+ ThreadFlags = 0;
+ ThreadHandle = 0;
+ IdValue = 0;
+ ExitCode = 0;
+ SuspendCount = 0;
+ StackSize = params.stackSize;
+ Processor = params.processor;
+ Priority = params.priority;
+
+ // Clear Function pointers
+ ThreadFunction = params.threadFunction;
+ UserHandle = params.userHandle;
+ if (params.initialState != NotRunning)
+ Start(params.initialState);
+
+}
+
+Thread::~Thread()
+{
+ // Thread should not running while object is being destroyed,
+ // this would indicate ref-counting issue.
+ //OVR_ASSERT(IsRunning() == 0);
+
+ // Clean up thread.
+ CleanupSystemThread();
+ ThreadHandle = 0;
+}
+
+
+// *** Overridable User functions.
+
+// Default Run implementation
+int Thread::Run()
+{
+ // Call pointer to function, if available.
+ return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
+}
+void Thread::OnExit()
+{
+}
+
+// Finishes the thread and releases internal reference to it.
+void Thread::FinishAndRelease()
+{
+ // Note: thread must be US.
+ ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
+ ThreadFlags |= OVR_THREAD_FINISHED;
+
+ // Release our reference; this is equivalent to 'delete this'
+ // from the point of view of our thread.
+ Release();
+}
+
+
+// *** ThreadList - used to tack all created threads
+
+class ThreadList : public NewOverrideBase
+{
+ //------------------------------------------------------------------------
+ struct ThreadHashOp
+ {
+ UPInt operator()(const Thread* ptr)
+ {
+ return (((UPInt)ptr) >> 6) ^ (UPInt)ptr;
+ }
+ };
+
+ HashSet<Thread*, ThreadHashOp> ThreadSet;
+ Mutex ThreadMutex;
+ WaitCondition ThreadsEmpty;
+ // Track the root thread that created us.
+ ThreadId RootThreadId;
+
+ static ThreadList* volatile pRunningThreads;
+
+ void addThread(Thread *pthread)
+ {
+ Mutex::Locker lock(&ThreadMutex);
+ ThreadSet.Add(pthread);
+ }
+
+ void removeThread(Thread *pthread)
+ {
+ Mutex::Locker lock(&ThreadMutex);
+ ThreadSet.Remove(pthread);
+ if (ThreadSet.GetSize() == 0)
+ ThreadsEmpty.Notify();
+ }
+
+ void finishAllThreads()
+ {
+ // Only original root thread can call this.
+ OVR_ASSERT(GetCurrentThreadId() == RootThreadId);
+
+ Mutex::Locker lock(&ThreadMutex);
+ while (ThreadSet.GetSize() != 0)
+ ThreadsEmpty.Wait(&ThreadMutex);
+ }
+
+public:
+
+ ThreadList()
+ {
+ RootThreadId = GetCurrentThreadId();
+ }
+ ~ThreadList() { }
+
+
+ static void AddRunningThread(Thread *pthread)
+ {
+ // Non-atomic creation ok since only the root thread
+ if (!pRunningThreads)
+ {
+ pRunningThreads = new ThreadList;
+ OVR_ASSERT(pRunningThreads);
+ }
+ pRunningThreads->addThread(pthread);
+ }
+
+ // NOTE: 'pthread' might be a dead pointer when this is
+ // called so it should not be accessed; it is only used
+ // for removal.
+ static void RemoveRunningThread(Thread *pthread)
+ {
+ OVR_ASSERT(pRunningThreads);
+ pRunningThreads->removeThread(pthread);
+ }
+
+ static void FinishAllThreads()
+ {
+ // This is ok because only root thread can wait for other thread finish.
+ if (pRunningThreads)
+ {
+ pRunningThreads->finishAllThreads();
+ delete pRunningThreads;
+ pRunningThreads = 0;
+ }
+ }
+};
+
+// By default, we have no thread list.
+ThreadList* volatile ThreadList::pRunningThreads = 0;
+
+
+// FinishAllThreads - exposed publicly in Thread.
+void Thread::FinishAllThreads()
+{
+ ThreadList::FinishAllThreads();
+}
+
+
+// *** Run override
+
+int Thread::PRun()
+{
+ // Suspend us on start, if requested
+ if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
+ {
+ Suspend();
+ ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
+ }
+
+ // Call the virtual run function
+ ExitCode = Run();
+ return ExitCode;
+}
+
+
+
+/* MA: Don't use TLS for now.
+
+// Static function to return a pointer to the current thread
+void Thread::InitCurrentThread(Thread *pthread)
+{
+ pCurrentThread = pthread;
+}
+
+// Static function to return a pointer to the current thread
+Thread* Thread::GetThread()
+{
+ return pCurrentThread;
+}
+*/
+
+
+// *** User overridables
+
+bool Thread::GetExitFlag() const
+{
+ return (ThreadFlags & OVR_THREAD_EXIT) != 0;
+}
+
+void Thread::SetExitFlag(bool exitFlag)
+{
+ // The below is atomic since ThreadFlags is AtomicInt.
+ if (exitFlag)
+ ThreadFlags |= OVR_THREAD_EXIT;
+ else
+ ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
+}
+
+
+// Determines whether the thread was running and is now finished
+bool Thread::IsFinished() const
+{
+ return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
+}
+// Determines whether the thread is suspended
+bool Thread::IsSuspended() const
+{
+ return SuspendCount > 0;
+}
+// Returns current thread state
+Thread::ThreadState Thread::GetThreadState() const
+{
+ if (IsSuspended())
+ return Suspended;
+ if (ThreadFlags & OVR_THREAD_STARTED)
+ return Running;
+ return NotRunning;
+}
+
+
+
+// ***** Thread management
+/* static */
+int Thread::GetOSPriority(ThreadPriority p)
+{
+ switch(p)
+ {
+ case Thread::CriticalPriority: return THREAD_PRIORITY_TIME_CRITICAL;
+ case Thread::HighestPriority: return THREAD_PRIORITY_HIGHEST;
+ case Thread::AboveNormalPriority: return THREAD_PRIORITY_ABOVE_NORMAL;
+ case Thread::NormalPriority: return THREAD_PRIORITY_NORMAL;
+ case Thread::BelowNormalPriority: return THREAD_PRIORITY_BELOW_NORMAL;
+ case Thread::LowestPriority: return THREAD_PRIORITY_LOWEST;
+ case Thread::IdlePriority: return THREAD_PRIORITY_IDLE;
+ }
+ return THREAD_PRIORITY_NORMAL;
+}
+
+// The actual first function called on thread start
+unsigned WINAPI Thread_Win32StartFn(void * phandle)
+{
+ Thread * pthread = (Thread*)phandle;
+ if (pthread->Processor != -1)
+ {
+ DWORD_PTR ret = SetThreadAffinityMask(GetCurrentThread(), (DWORD)pthread->Processor);
+ if (ret == 0)
+ OVR_DEBUG_LOG(("Could not set hardware processor for the thread"));
+ }
+ BOOL ret = ::SetThreadPriority(GetCurrentThread(), Thread::GetOSPriority(pthread->Priority));
+ if (ret == 0)
+ OVR_DEBUG_LOG(("Could not set thread priority"));
+ OVR_UNUSED(ret);
+
+ // Ensure that ThreadId is assigned once thread is running, in case
+ // beginthread hasn't filled it in yet.
+ pthread->IdValue = (ThreadId)::GetCurrentThreadId();
+
+ DWORD result = pthread->PRun();
+ // Signal the thread as done and release it atomically.
+ pthread->FinishAndRelease();
+ // At this point Thread object might be dead; however we can still pass
+ // it to RemoveRunningThread since it is only used as a key there.
+ ThreadList::RemoveRunningThread(pthread);
+ return (unsigned) result;
+}
+
+bool Thread::Start(ThreadState initialState)
+{
+ if (initialState == NotRunning)
+ return 0;
+ if (GetThreadState() != NotRunning)
+ {
+ OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
+ return 0;
+ }
+
+ // Free old thread handle before creating the new one
+ CleanupSystemThread();
+
+ // AddRef to us until the thread is finished.
+ AddRef();
+ ThreadList::AddRunningThread(this);
+
+ ExitCode = 0;
+ SuspendCount = 0;
+ ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
+ ThreadHandle = (HANDLE) _beginthreadex(0, (unsigned)StackSize,
+ Thread_Win32StartFn, this, 0, (unsigned*)&IdValue);
+
+ // Failed? Fail the function
+ if (ThreadHandle == 0)
+ {
+ ThreadFlags = 0;
+ Release();
+ ThreadList::RemoveRunningThread(this);
+ return 0;
+ }
+ return 1;
+}
+
+
+// Suspend the thread until resumed
+bool Thread::Suspend()
+{
+ // Can't suspend a thread that wasn't started
+ if (!(ThreadFlags & OVR_THREAD_STARTED))
+ return 0;
+
+ if (::SuspendThread(ThreadHandle) != 0xFFFFFFFF)
+ {
+ SuspendCount++;
+ return 1;
+ }
+ return 0;
+}
+
+// Resumes currently suspended thread
+bool Thread::Resume()
+{
+ // Can't suspend a thread that wasn't started
+ if (!(ThreadFlags & OVR_THREAD_STARTED))
+ return 0;
+
+ // Decrement count, and resume thread if it is 0
+ SInt32 oldCount = SuspendCount.ExchangeAdd_Acquire(-1);
+ if (oldCount >= 1)
+ {
+ if (oldCount == 1)
+ {
+ if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF)
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+// Quits with an exit code
+void Thread::Exit(int exitCode)
+{
+ // Can only exist the current thread.
+ // MA: Don't use TLS for now.
+ //if (GetThread() != this)
+ // return;
+
+ // Call the virtual OnExit function.
+ OnExit();
+
+ // Signal this thread object as done and release it's references.
+ FinishAndRelease();
+ ThreadList::RemoveRunningThread(this);
+
+ // Call the exit function.
+ _endthreadex((unsigned)exitCode);
+}
+
+
+void Thread::CleanupSystemThread()
+{
+ if (ThreadHandle != 0)
+ {
+ ::CloseHandle(ThreadHandle);
+ ThreadHandle = 0;
+ }
+}
+
+// *** Sleep functions
+// static
+bool Thread::Sleep(unsigned secs)
+{
+ ::Sleep(secs*1000);
+ return 1;
+}
+
+// static
+bool Thread::MSleep(unsigned msecs)
+{
+ ::Sleep(msecs);
+ return 1;
+}
+
+void Thread::SetThreadName( const char* name )
+{
+#if !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING)
+ // Looks ugly, but it is the recommended way to name a thread.
+ typedef struct tagTHREADNAME_INFO {
+ DWORD dwType; // Must be 0x1000
+ LPCSTR szName; // Pointer to name (in user address space)
+ DWORD dwThreadID; // Thread ID (-1 for caller thread)
+ DWORD dwFlags; // Reserved for future use; must be zero
+ } THREADNAME_INFO;
+
+ THREADNAME_INFO info;
+
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = reinterpret_cast<DWORD>(GetThreadId());
+ info.dwFlags = 0;
+
+ __try
+ {
+#ifdef _WIN64
+ RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR *)&info );
+#else
+ RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD *)&info );
+#endif
+ }
+ __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER )
+ {
+ }
+#endif // OVR_BUILD_SHIPPING
+}
+
+// static
+int Thread::GetCPUCount()
+{
+ SYSTEM_INFO sysInfo;
+ GetSystemInfo(&sysInfo);
+ return (int) sysInfo.dwNumberOfProcessors;
+}
+
+// Returns the unique Id of a thread it is called on, intended for
+// comparison purposes.
+ThreadId GetCurrentThreadId()
+{
+ return (ThreadId)::GetCurrentThreadId();
+}
+
+} // OVR
+
+#endif
+
+
diff --git a/LibOVR/Src/Kernel/OVR_Timer.cpp b/LibOVR/Src/Kernel/OVR_Timer.cpp new file mode 100644 index 0000000..db25b8f --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Timer.cpp @@ -0,0 +1,156 @@ +/************************************************************************************
+
+Filename : OVR_Timer.cpp
+Content : Provides static functions for precise timing
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Timer.h"
+
+#if defined (OVR_OS_WIN32)
+#include <windows.h>
+
+#else
+#include <sys/time.h>
+#endif
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Timer Class
+
+UInt64 Timer::GetProfileTicks()
+{
+ return (GetRawTicks() * MksPerSecond) / GetRawFrequency();
+}
+double Timer::GetProfileSeconds()
+{
+ static UInt64 StartTime = GetProfileTicks();
+ return TicksToSeconds(GetProfileTicks()-StartTime);
+}
+
+
+//------------------------------------------------------------------------
+// *** Win32 Specific Timer
+
+#if (defined (OVR_OS_WIN32))
+
+CRITICAL_SECTION WinAPI_GetTimeCS;
+volatile UInt32 WinAPI_OldTime = 0;
+volatile UInt32 WinAPI_WrapCounter = 0;
+
+
+UInt32 Timer::GetTicksMs()
+{
+ return timeGetTime();
+}
+
+UInt64 Timer::GetTicks()
+{
+ DWORD ticks = timeGetTime();
+ UInt64 result;
+
+ // On Win32 QueryPerformanceFrequency is unreliable due to SMP and
+ // performance levels, so use this logic to detect wrapping and track
+ // high bits.
+ ::EnterCriticalSection(&WinAPI_GetTimeCS);
+
+ if (WinAPI_OldTime > ticks)
+ WinAPI_WrapCounter++;
+ WinAPI_OldTime = ticks;
+
+ result = (UInt64(WinAPI_WrapCounter) << 32) | ticks;
+ ::LeaveCriticalSection(&WinAPI_GetTimeCS);
+
+ return result * MksPerMs;
+}
+
+UInt64 Timer::GetRawTicks()
+{
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ return li.QuadPart;
+}
+
+UInt64 Timer::GetRawFrequency()
+{
+ static UInt64 perfFreq = 0;
+ if (perfFreq == 0)
+ {
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+ perfFreq = freq.QuadPart;
+ }
+ return perfFreq;
+}
+
+void Timer::initializeTimerSystem()
+{
+ timeBeginPeriod(1);
+ InitializeCriticalSection(&WinAPI_GetTimeCS);
+
+}
+void Timer::shutdownTimerSystem()
+{
+ DeleteCriticalSection(&WinAPI_GetTimeCS);
+ timeEndPeriod(1);
+}
+
+#else // !OVR_OS_WIN32
+
+
+//------------------------------------------------------------------------
+// *** Standard OS Timer
+
+UInt32 Timer::GetTicksMs()
+{
+ return (UInt32)(GetProfileTicks() / 1000);
+}
+// The profile ticks implementation is just fine for a normal timer.
+UInt64 Timer::GetTicks()
+{
+ return GetProfileTicks();
+}
+
+void Timer::initializeTimerSystem()
+{
+}
+void Timer::shutdownTimerSystem()
+{
+}
+
+UInt64 Timer::GetRawTicks()
+{
+ // TODO: prefer rdtsc when available?
+
+ // Return microseconds.
+ struct timeval tv;
+ UInt64 result;
+
+ gettimeofday(&tv, 0);
+
+ result = (UInt64)tv.tv_sec * 1000000;
+ result += tv.tv_usec;
+
+ return result;
+}
+
+UInt64 Timer::GetRawFrequency()
+{
+ return MksPerSecond;
+}
+
+#endif // !OVR_OS_WIN32
+
+
+
+} // OVR
+
diff --git a/LibOVR/Src/Kernel/OVR_Timer.h b/LibOVR/Src/Kernel/OVR_Timer.h new file mode 100644 index 0000000..0b71912 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Timer.h @@ -0,0 +1,100 @@ +/************************************************************************************
+
+PublicHeader: OVR
+Filename : OVR_Timer.h
+Content : Provides static functions for precise timing
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Timer_h
+#define OVR_Timer_h
+
+#include "OVR_Types.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Timer
+
+// Timer class defines a family of static functions used for application
+// timing and profiling.
+
+class Timer
+{
+public:
+ enum {
+ MsPerSecond = 1000, // Milliseconds in one second.
+ MksPerMs = 1000, // Microseconds in one millisecond.
+ MksPerSecond = MsPerSecond * MksPerMs
+ };
+
+
+ // ***** Timing APIs for Application
+ // These APIs should be used to guide animation and other program functions
+ // that require precision.
+
+ // Returns ticks in milliseconds, as a 32-bit number. May wrap around every
+ // 49.2 days. Use either time difference of two values of GetTicks to avoid
+ // wrap-around. GetTicksMs may perform better then GetTicks.
+ static UInt32 OVR_STDCALL GetTicksMs();
+
+ // GetTicks returns general-purpose high resolution application timer value,
+ // measured in microseconds (mks, or 1/1000000 of a second). The actual precision
+ // is system-specific and may be much lower, such as 1 ms.
+ static UInt64 OVR_STDCALL GetTicks();
+
+
+ // ***** Profiling APIs.
+ // These functions should be used for profiling, but may have system specific
+ // artifacts that make them less appropriate for general system use.
+ // On Win32, for example these rely on QueryPerformanceConter may have
+ // problems with thread-core switching and power modes.
+
+ // Return a hi-res timer value in mks (1/1000000 of a sec).
+ // Generally you want to call this at the start and end of an
+ // operation, and pass the difference to
+ // TicksToSeconds() to find out how long the operation took.
+ static UInt64 OVR_STDCALL GetProfileTicks();
+
+ // More convenient zero-based profile timer in seconds. First call initializes
+ // the "zero" value; future calls return the difference. Not thread safe for first call.
+ // Due to low precision of Double, may malfunction after long runtime.
+ static double OVR_STDCALL GetProfileSeconds();
+
+ // Get the raw cycle counter value, providing the maximum possible timer resolution.
+ static UInt64 OVR_STDCALL GetRawTicks();
+ static UInt64 OVR_STDCALL GetRawFrequency();
+
+
+ // ***** Tick and time unit conversion.
+
+ // Convert micro-second ticks value into seconds value.
+ static inline double TicksToSeconds(UInt64 ticks)
+ {
+ return static_cast<double>(ticks) * (1.0 / (double)MksPerSecond);
+ }
+ // Convert Raw or frequency-unit ticks to seconds based on specified frequency.
+ static inline double RawTicksToSeconds(UInt64 rawTicks, UInt64 rawFrequency)
+ {
+ return static_cast<double>(rawTicks) * rawFrequency;
+ }
+
+private:
+ friend class System;
+ // System called during program startup/shutdown.
+ static void initializeTimerSystem();
+ static void shutdownTimerSystem();
+};
+
+
+} // Scaleform::Timer
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Types.h b/LibOVR/Src/Kernel/OVR_Types.h new file mode 100644 index 0000000..40eb156 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_Types.h @@ -0,0 +1,456 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Types.h
+Content : Standard library defines and simple types
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Types_H
+#define OVR_Types_H
+
+//-----------------------------------------------------------------------------------
+// ****** Operating System
+//
+// Type definitions exist for the following operating systems: (OVR_OS_x)
+//
+// WIN32 - Win32 (Windows 95/98/ME and Windows NT/2000/XP)
+// DARWIN - Darwin OS (Mac OS X)
+// LINUX - Linux
+// ANDROID - Android
+// IPHONE - iPhone
+
+#if (defined(__APPLE__) && (defined(__GNUC__) ||\
+ defined(__xlC__) || defined(__xlc__))) || defined(__MACOS__)
+# if (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) || defined(__IPHONE_OS_VERSION_MIN_REQUIRED))
+# define OVR_OS_IPHONE
+# else
+# define OVR_OS_DARWIN
+# define OVR_OS_MAC
+# endif
+#elif (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))
+# define OVR_OS_WIN32
+#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
+# define OVR_OS_WIN32
+#elif defined(__linux__) || defined(__linux)
+# define OVR_OS_LINUX
+#else
+# define OVR_OS_OTHER
+#endif
+
+#if defined(ANDROID)
+# define OVR_OS_ANDROID
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** CPU Architecture
+//
+// The following CPUs are defined: (OVR_CPU_x)
+//
+// X86 - x86 (IA-32)
+// X86_64 - x86_64 (amd64)
+// PPC - PowerPC
+// PPC64 - PowerPC64
+// MIPS - MIPS
+// OTHER - CPU for which no special support is present or needed
+
+
+#if defined(__x86_64__) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
+# define OVR_CPU_X86_64
+# define OVR_64BIT_POINTERS
+#elif defined(__i386__) || defined(OVR_OS_WIN32)
+# define OVR_CPU_X86
+#elif defined(__powerpc64__)
+# define OVR_CPU_PPC64
+#elif defined(__ppc__)
+# define OVR_CPU_PPC
+#elif defined(__mips__) || defined(__MIPSEL__)
+# define OVR_CPU_MIPS
+#elif defined(__arm__)
+# define OVR_CPU_ARM
+#else
+# define OVR_CPU_OTHER
+#endif
+
+//-----------------------------------------------------------------------------------
+// ***** Co-Processor Architecture
+//
+// The following co-processors are defined: (OVR_CPU_x)
+//
+// SSE - Available on all modern x86 processors.
+// Altivec - Available on all modern ppc processors.
+// Neon - Available on some armv7+ processors.
+
+#if defined(__SSE__) || defined(OVR_OS_WIN32)
+# define OVR_CPU_SSE
+#endif // __SSE__
+
+#if defined( __ALTIVEC__ )
+# define OVR_CPU_ALTIVEC
+#endif // __ALTIVEC__
+
+#if defined(__ARM_NEON__)
+# define OVR_CPU_ARM_NEON
+#endif // __ARM_NEON__
+
+
+//-----------------------------------------------------------------------------------
+// ***** Compiler
+//
+// The following compilers are defined: (OVR_CC_x)
+//
+// MSVC - Microsoft Visual C/C++
+// INTEL - Intel C++ for Linux / Windows
+// GNU - GNU C++
+// ARM - ARM C/C++
+
+#if defined(__INTEL_COMPILER)
+// Intel 4.0 = 400
+// Intel 5.0 = 500
+// Intel 6.0 = 600
+// Intel 8.0 = 800
+// Intel 9.0 = 900
+# define OVR_CC_INTEL __INTEL_COMPILER
+
+#elif defined(_MSC_VER)
+// MSVC 5.0 = 1100
+// MSVC 6.0 = 1200
+// MSVC 7.0 (VC2002) = 1300
+// MSVC 7.1 (VC2003) = 1310
+// MSVC 8.0 (VC2005) = 1400
+// MSVC 9.0 (VC2008) = 1500
+// MSVC 10.0 (VC2010) = 1600
+# define OVR_CC_MSVC _MSC_VER
+
+#elif defined(__GNUC__)
+# define OVR_CC_GNU
+
+#elif defined(__CC_ARM)
+# define OVR_CC_ARM
+
+#else
+# error "Oculus does not support this Compiler"
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** Compiler Warnings
+
+// Disable MSVC warnings
+#if defined(OVR_CC_MSVC)
+# pragma warning(disable : 4127) // Inconsistent dll linkage
+# pragma warning(disable : 4530) // Exception handling
+# if (OVR_CC_MSVC<1300)
+# pragma warning(disable : 4514) // Unreferenced inline function has been removed
+# pragma warning(disable : 4710) // Function not inlined
+# pragma warning(disable : 4714) // _force_inline not inlined
+# pragma warning(disable : 4786) // Debug variable name longer than 255 chars
+# endif // (OVR_CC_MSVC<1300)
+#endif // (OVR_CC_MSVC)
+
+
+
+// *** Linux Unicode - must come before Standard Includes
+
+#ifdef OVR_OS_LINUX
+// Use glibc unicode functions on linux.
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+#endif
+
+//-----------------------------------------------------------------------------------
+// ***** Standard Includes
+//
+#include <stddef.h>
+#include <limits.h>
+#include <float.h>
+
+
+// MSVC Based Memory Leak checking - for now
+#if defined(OVR_CC_MSVC) && defined(OVR_BUILD_DEBUG)
+# define _CRTDBG_MAP_ALLOC
+# include <stdlib.h>
+# include <crtdbg.h>
+
+// Uncomment this to help debug memory leaks under Visual Studio in OVR apps only.
+// This shouldn't be defined in customer releases.
+# ifndef OVR_DEFINE_NEW
+# define OVR_DEFINE_NEW new(__FILE__, __LINE__)
+# define new OVR_DEFINE_NEW
+# endif
+
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** Type definitions for Common Systems
+
+namespace OVR {
+
+typedef char Char;
+
+// Pointer-sized integer
+typedef size_t UPInt;
+typedef ptrdiff_t SPInt;
+
+
+#if defined(OVR_OS_WIN32)
+
+typedef char SByte; // 8 bit Integer (Byte)
+typedef unsigned char UByte;
+typedef short SInt16; // 16 bit Integer (Word)
+typedef unsigned short UInt16;
+typedef long SInt32; // 32 bit Integer
+typedef unsigned long UInt32;
+typedef __int64 SInt64; // 64 bit Integer (QWord)
+typedef unsigned __int64 UInt64;
+
+
+#elif defined(OVR_OS_MAC) || defined(OVR_OS_IPHONE) || defined(OVR_CC_GNU)
+
+typedef int SByte __attribute__((__mode__ (__QI__)));
+typedef unsigned int UByte __attribute__((__mode__ (__QI__)));
+typedef int SInt16 __attribute__((__mode__ (__HI__)));
+typedef unsigned int UInt16 __attribute__((__mode__ (__HI__)));
+typedef int SInt32 __attribute__((__mode__ (__SI__)));
+typedef unsigned int UInt32 __attribute__((__mode__ (__SI__)));
+typedef int SInt64 __attribute__((__mode__ (__DI__)));
+typedef unsigned int UInt64 __attribute__((__mode__ (__DI__)));
+
+#else
+
+#include <sys/types.h>
+typedef int8_t SByte;
+typedef uint8_t UByte;
+typedef int16_t SInt16;
+typedef uint16_t UInt16;
+typedef int32_t SInt32;
+typedef uint32_t UInt32;
+typedef int64_t SInt64;
+typedef uint64_t UInt64;
+
+#endif
+
+
+// ***** BaseTypes Namespace
+
+// BaseTypes namespace is explicitly declared to allow base types to be used
+// by customers directly without other contents of OVR namespace.
+//
+// Its is expected that GFx samples will declare 'using namespace OVR::BaseTypes'
+// to allow using these directly without polluting the target scope with other
+// OVR declarations, such as Ptr<>, String or Mutex.
+namespace BaseTypes
+{
+ using OVR::UPInt;
+ using OVR::SPInt;
+ using OVR::UByte;
+ using OVR::SByte;
+ using OVR::UInt16;
+ using OVR::SInt16;
+ using OVR::UInt32;
+ using OVR::SInt32;
+ using OVR::UInt64;
+ using OVR::SInt64;
+} // OVR::BaseTypes
+
+} // OVR
+
+
+//-----------------------------------------------------------------------------------
+// ***** Macro Definitions
+//
+// We define the following:
+//
+// OVR_BYTE_ORDER - Defined to either OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN
+// OVR_FORCE_INLINE - Forces inline expansion of function
+// OVR_ASM - Assembly language prefix
+// OVR_STR - Prefixes string with L"" if building unicode
+//
+// OVR_STDCALL - Use stdcall calling convention (Pascal arg order)
+// OVR_CDECL - Use cdecl calling convention (C argument order)
+// OVR_FASTCALL - Use fastcall calling convention (registers)
+//
+
+// Byte order constants, OVR_BYTE_ORDER is defined to be one of these.
+#define OVR_LITTLE_ENDIAN 1
+#define OVR_BIG_ENDIAN 2
+
+
+// Force inline substitute - goes before function declaration
+#if defined(OVR_CC_MSVC)
+# define OVR_FORCE_INLINE __forceinline
+#elif defined(OVR_CC_GNU)
+# define OVR_FORCE_INLINE __attribute__((always_inline))
+#else
+# define OVR_FORCE_INLINE inline
+#endif // OVR_CC_MSVC
+
+
+#if defined(OVR_OS_WIN32)
+
+ // ***** Win32
+
+ // Byte order
+ #define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN
+
+ // Calling convention - goes after function return type but before function name
+ #ifdef __cplusplus_cli
+ # define OVR_FASTCALL __stdcall
+ #else
+ # define OVR_FASTCALL __fastcall
+ #endif
+
+ #define OVR_STDCALL __stdcall
+ #define OVR_CDECL __cdecl
+
+
+ // Assembly macros
+ #if defined(OVR_CC_MSVC)
+ # define OVR_ASM _asm
+ #else
+ # define OVR_ASM asm
+ #endif // (OVR_CC_MSVC)
+
+ #ifdef UNICODE
+ # define OVR_STR(str) L##str
+ #else
+ # define OVR_STR(str) str
+ #endif // UNICODE
+
+#else
+
+ // **** Standard systems
+
+ #if (defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN))|| \
+ (defined(_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN))
+ # define OVR_BYTE_ORDER OVR_BIG_ENDIAN
+ #elif (defined(__ARMEB__) || defined(OVR_CPU_PPC) || defined(OVR_CPU_PPC64))
+ # define OVR_BYTE_ORDER OVR_BIG_ENDIAN
+ #else
+ # define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN
+ #endif
+
+ // Assembly macros
+ #define OVR_ASM __asm__
+ #define OVR_ASM_PROC(procname) OVR_ASM
+ #define OVR_ASM_END OVR_ASM
+
+ // Calling convention - goes after function return type but before function name
+ #define OVR_FASTCALL
+ #define OVR_STDCALL
+ #define OVR_CDECL
+
+#endif // defined(OVR_OS_WIN32)
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_DEBUG_BREAK, OVR_ASSERT
+//
+// If not in debug build, macros do nothing
+#ifndef OVR_BUILD_DEBUG
+
+# define OVR_DEBUG_BREAK ((void)0)
+# define OVR_ASSERT(p) ((void)0)
+
+#else
+
+// Microsoft Win32 specific debugging support
+#if defined(OVR_OS_WIN32)
+# ifdef OVR_CPU_X86
+# if defined(__cplusplus_cli)
+# define OVR_DEBUG_BREAK do { __debugbreak(); } while(0)
+# elif defined(OVR_CC_GNU)
+# define OVR_DEBUG_BREAK do { OVR_ASM("int $3\n\t"); } while(0)
+# else
+# define OVR_DEBUG_BREAK do { OVR_ASM int 3 } while (0)
+# endif
+# else
+# define OVR_DEBUG_BREAK do { __debugbreak(); } while(0)
+# endif
+// Unix specific debugging support
+#elif defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64)
+# define OVR_DEBUG_BREAK do { OVR_ASM("int $3\n\t"); } while(0)
+#else
+# define OVR_DEBUG_BREAK do { *((int *) 0) = 1; } while(0)
+#endif
+
+// This will cause compiler breakpoint
+#define OVR_ASSERT(p) do { if (!(p)) { OVR_DEBUG_BREAK; } } while(0)
+
+#endif // OVR_BUILD_DEBUG
+
+
+// Compile-time assert; produces compiler error if condition is false
+#define OVR_COMPILER_ASSERT(x) { int zero = 0; switch(zero) {case 0: case x:;} }
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_UNUSED - Unused Argument handling
+
+// Macro to quiet compiler warnings about unused parameters/variables.
+#if defined(OVR_CC_GNU)
+# define OVR_UNUSED(a) do {__typeof__ (&a) __attribute__ ((unused)) __tmp = &a; } while(0)
+#else
+# define OVR_UNUSED(a) (a)
+#endif
+
+#define OVR_UNUSED1(a1) OVR_UNUSED(a1)
+#define OVR_UNUSED2(a1,a2) OVR_UNUSED(a1); OVR_UNUSED(a2)
+#define OVR_UNUSED3(a1,a2,a3) OVR_UNUSED2(a1,a2); OVR_UNUSED(a3)
+#define OVR_UNUSED4(a1,a2,a3,a4) OVR_UNUSED3(a1,a2,a3); OVR_UNUSED(a4)
+#define OVR_UNUSED5(a1,a2,a3,a4,a5) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED(a5)
+#define OVR_UNUSED6(a1,a2,a3,a4,a5,a6) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED2(a5,a6)
+#define OVR_UNUSED7(a1,a2,a3,a4,a5,a6,a7) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED3(a5,a6,a7)
+#define OVR_UNUSED8(a1,a2,a3,a4,a5,a6,a7,a8) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED4(a5,a6,a7,a8)
+#define OVR_UNUSED9(a1,a2,a3,a4,a5,a6,a7,a8,a9) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED5(a5,a6,a7,a8,a9)
+
+
+//-----------------------------------------------------------------------------------
+// ***** Configuration Macros
+
+// SF Build type
+#ifdef OVR_BUILD_DEBUG
+# define OVR_BUILD_STRING "Debug"
+#else
+# define OVR_BUILD_STRING "Release"
+#endif
+
+
+//// Enables SF Debugging information
+//# define OVR_BUILD_DEBUG
+
+// OVR_DEBUG_STATEMENT injects a statement only in debug builds.
+// OVR_DEBUG_SELECT injects first argument in debug builds, second argument otherwise.
+#ifdef OVR_BUILD_DEBUG
+#define OVR_DEBUG_STATEMENT(s) s
+#define OVR_DEBUG_SELECT(d, nd) d
+#else
+#define OVR_DEBUG_STATEMENT(s)
+#define OVR_DEBUG_SELECT(d, nd) nd
+#endif
+
+
+#define OVR_ENABLE_THREADS
+//
+// Prevents OVR from defining new within
+// type macros, so developers can override
+// new using the #define new new(...) trick
+// - used with OVR_DEFINE_NEW macro
+//# define OVR_BUILD_DEFINE_NEW
+//
+
+
+#endif // OVR_Types_h
diff --git a/LibOVR/Src/Kernel/OVR_UTF8Util.cpp b/LibOVR/Src/Kernel/OVR_UTF8Util.cpp new file mode 100644 index 0000000..21485df --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_UTF8Util.cpp @@ -0,0 +1,545 @@ +/**************************************************************************
+
+Filename : OVR_UTF8Util.cpp
+Content : UTF8 Unicode character encoding/decoding support
+Created : September 19, 2012
+Notes :
+Notes : Much useful info at "UTF-8 and Unicode FAQ"
+ http://www.cl.cam.ac.uk/~mgk25/unicode.html
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_UTF8Util.h"
+
+namespace OVR { namespace UTF8Util {
+
+SPInt OVR_STDCALL GetLength(const char* buf, SPInt buflen)
+{
+ const char* p = buf;
+ SPInt length = 0;
+
+ if (buflen != -1)
+ {
+ while (p - buf < buflen)
+ {
+ // We should be able to have ASStrings with 0 in the middle.
+ UTF8Util::DecodeNextChar_Advance0(&p);
+ length++;
+ }
+ }
+ else
+ {
+ while (UTF8Util::DecodeNextChar_Advance0(&p))
+ length++;
+ }
+
+ return length;
+}
+
+UInt32 OVR_STDCALL GetCharAt(SPInt index, const char* putf8str, SPInt length)
+{
+ const char* buf = putf8str;
+ UInt32 c = 0;
+
+ if (length != -1)
+ {
+ while (buf - putf8str < length)
+ {
+ c = UTF8Util::DecodeNextChar_Advance0(&buf);
+ if (index == 0)
+ return c;
+ index--;
+ }
+
+ return c;
+ }
+
+ do
+ {
+ c = UTF8Util::DecodeNextChar_Advance0(&buf);
+ index--;
+
+ if (c == 0)
+ {
+ // We've hit the end of the string; don't go further.
+ OVR_ASSERT(index == 0);
+ return c;
+ }
+ } while (index >= 0);
+
+ return c;
+}
+
+SPInt OVR_STDCALL GetByteIndex(SPInt index, const char *putf8str, SPInt length)
+{
+ const char* buf = putf8str;
+
+ if (length != -1)
+ {
+ while ((buf - putf8str) < length && index > 0)
+ {
+ UTF8Util::DecodeNextChar_Advance0(&buf);
+ index--;
+ }
+
+ return buf-putf8str;
+ }
+
+ while (index > 0)
+ {
+ UInt32 c = UTF8Util::DecodeNextChar_Advance0(&buf);
+ index--;
+
+ if (c == 0)
+ return buf-putf8str;
+ };
+
+ return buf-putf8str;
+}
+
+int OVR_STDCALL GetEncodeCharSize(UInt32 ucs_character)
+{
+ if (ucs_character <= 0x7F)
+ return 1;
+ else if (ucs_character <= 0x7FF)
+ return 2;
+ else if (ucs_character <= 0xFFFF)
+ return 3;
+ else if (ucs_character <= 0x1FFFFF)
+ return 4;
+ else if (ucs_character <= 0x3FFFFFF)
+ return 5;
+ else if (ucs_character <= 0x7FFFFFFF)
+ return 6;
+ else
+ return 0;
+}
+
+UInt32 OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer)
+{
+ UInt32 uc;
+ char c;
+
+ // Security considerations:
+ //
+ // Changed, this is now only the case for DecodeNextChar:
+ // - If we hit a zero byte, we want to return 0 without stepping
+ // the buffer pointer past the 0. th
+ //
+ // If we hit an "overlong sequence"; i.e. a character encoded
+ // in a longer multibyte string than is necessary, then we
+ // need to discard the character. This is so attackers can't
+ // disguise dangerous characters or character sequences --
+ // there is only one valid encoding for each character.
+ //
+ // If we decode characters { 0xD800 .. 0xDFFF } or { 0xFFFE,
+ // 0xFFFF } then we ignore them; they are not valid in UTF-8.
+
+ // This isn't actually an invalid character; it's a valid char that
+ // looks like an inverted question mark.
+#define INVALID_CHAR 0x0FFFD
+
+#define FIRST_BYTE(mask, shift) \
+ uc = (c & (mask)) << (shift);
+
+#define NEXT_BYTE(shift) \
+ c = **putf8Buffer; \
+ if (c == 0) return 0; /* end of buffer, do not advance */ \
+ if ((c & 0xC0) != 0x80) return INVALID_CHAR; /* standard check */ \
+ (*putf8Buffer)++; \
+ uc |= (c & 0x3F) << shift;
+
+ c = **putf8Buffer;
+ (*putf8Buffer)++;
+ if (c == 0)
+ return 0; // End of buffer.
+
+ if ((c & 0x80) == 0) return (UInt32) c; // Conventional 7-bit ASCII.
+
+ // Multi-byte sequences.
+ if ((c & 0xE0) == 0xC0)
+ {
+ // Two-byte sequence.
+ FIRST_BYTE(0x1F, 6);
+ NEXT_BYTE(0);
+ if (uc < 0x80) return INVALID_CHAR; // overlong
+ return uc;
+ }
+ else if ((c & 0xF0) == 0xE0)
+ {
+ // Three-byte sequence.
+ FIRST_BYTE(0x0F, 12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x800) return INVALID_CHAR; // overlong
+ // Not valid ISO 10646, but Flash requires these to work
+ // see AS3 test e15_5_3_2_3 for String.fromCharCode().charCodeAt(0)
+ // if (uc >= 0x0D800 && uc <= 0x0DFFF) return INVALID_CHAR;
+ // if (uc == 0x0FFFE || uc == 0x0FFFF) return INVALID_CHAR; // not valid ISO 10646
+ return uc;
+ }
+ else if ((c & 0xF8) == 0xF0)
+ {
+ // Four-byte sequence.
+ FIRST_BYTE(0x07, 18);
+ NEXT_BYTE(12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x010000) return INVALID_CHAR; // overlong
+ return uc;
+ }
+ else if ((c & 0xFC) == 0xF8)
+ {
+ // Five-byte sequence.
+ FIRST_BYTE(0x03, 24);
+ NEXT_BYTE(18);
+ NEXT_BYTE(12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x0200000) return INVALID_CHAR; // overlong
+ return uc;
+ }
+ else if ((c & 0xFE) == 0xFC)
+ {
+ // Six-byte sequence.
+ FIRST_BYTE(0x01, 30);
+ NEXT_BYTE(24);
+ NEXT_BYTE(18);
+ NEXT_BYTE(12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x04000000) return INVALID_CHAR; // overlong
+ return uc;
+ }
+ else
+ {
+ // Invalid.
+ return INVALID_CHAR;
+ }
+}
+
+
+void OVR_STDCALL EncodeChar(char* pbuffer, SPInt* pindex, UInt32 ucs_character)
+{
+ if (ucs_character <= 0x7F)
+ {
+ // Plain single-byte ASCII.
+ pbuffer[(*pindex)++] = (char) ucs_character;
+ }
+ else if (ucs_character <= 0x7FF)
+ {
+ // Two bytes.
+ pbuffer[(*pindex)++] = 0xC0 | (char)(ucs_character >> 6);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0xFFFF)
+ {
+ // Three bytes.
+ pbuffer[(*pindex)++] = 0xE0 | (char)(ucs_character >> 12);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0x1FFFFF)
+ {
+ // Four bytes.
+ pbuffer[(*pindex)++] = 0xF0 | (char)(ucs_character >> 18);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0x3FFFFFF)
+ {
+ // Five bytes.
+ pbuffer[(*pindex)++] = 0xF8 | (char)(ucs_character >> 24);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0x7FFFFFFF)
+ {
+ // Six bytes.
+ pbuffer[(*pindex)++] = 0xFC | (char)(ucs_character >> 30);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 24) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else
+ {
+ // Invalid char; don't encode anything.
+ }
+}
+
+SPInt OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, SPInt length)
+{
+ SPInt len = 0;
+ if (length != -1)
+ for (int i = 0; i < length; i++)
+ {
+ len += GetEncodeCharSize(pchar[i]);
+ }
+ else
+ for (int i = 0;; i++)
+ {
+ if (pchar[i] == 0)
+ return len;
+ len += GetEncodeCharSize(pchar[i]);
+ }
+ return len;
+}
+
+void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, SPInt length)
+{
+ SPInt ofs = 0;
+ if (length != -1)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ EncodeChar(pbuff, &ofs, pchar[i]);
+ }
+ }
+ else
+ {
+ for (int i = 0;; i++)
+ {
+ if (pchar[i] == 0)
+ break;
+ EncodeChar(pbuff, &ofs, pchar[i]);
+ }
+ }
+ pbuff[ofs] = 0;
+}
+
+UPInt OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, SPInt bytesLen)
+{
+ wchar_t *pbegin = pbuff;
+ if (bytesLen == -1)
+ {
+ while (1)
+ {
+ UInt32 ch = DecodeNextChar_Advance0(&putf8str);
+ if (ch == 0)
+ break;
+ else if (ch >= 0xFFFF)
+ ch = 0xFFFD;
+ *pbuff++ = wchar_t(ch);
+ }
+ }
+ else
+ {
+ const char* p = putf8str;
+ while ((p - putf8str) < bytesLen)
+ {
+ UInt32 ch = DecodeNextChar_Advance0(&p);
+ if (ch >= 0xFFFF)
+ ch = 0xFFFD;
+ *pbuff++ = wchar_t(ch);
+ }
+ }
+
+ *pbuff = 0;
+ return pbuff - pbegin;
+}
+
+
+#ifdef UTF8_UNIT_TEST
+
+// Compile this test case with something like:
+//
+// gcc utf8.cpp -g -I.. -DUTF8_UNIT_TEST -lstdc++ -o utf8_test
+//
+// or
+//
+// cl utf8.cpp -Zi -Od -DUTF8_UNIT_TEST -I..
+//
+// If possible, try running the test program with the first arg
+// pointing at the file:
+//
+// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+//
+// and examine the results by eye to make sure they are acceptable to
+// you.
+
+
+#include "base/utility.h"
+#include <stdio.h>
+
+
+bool check_equal(const char* utf8_in, const UInt32* ucs_in)
+{
+ for (;;)
+ {
+ UInt32 next_ucs = *ucs_in++;
+ UInt32 next_ucs_from_utf8 = utf8::decode_next_unicode_character(&utf8_in);
+ if (next_ucs != next_ucs_from_utf8)
+ {
+ return false;
+ }
+ if (next_ucs == 0)
+ {
+ OVR_ASSERT(next_ucs_from_utf8 == 0);
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+void log_ascii(const char* line)
+{
+ for (;;)
+ {
+ unsigned char c = (unsigned char) *line++;
+ if (c == 0)
+ {
+ // End of line.
+ return;
+ }
+ else if (c != '\n'
+ && (c < 32 || c > 127))
+ {
+ // Non-printable as plain ASCII.
+ printf("<0x%02X>", (int) c);
+ }
+ else
+ {
+ printf("%c", c);
+ }
+ }
+}
+
+
+void log_ucs(const UInt32* line)
+{
+ for (;;)
+ {
+ UInt32 uc = *line++;
+ if (uc == 0)
+ {
+ // End of line.
+ return;
+ }
+ else if (uc != '\n'
+ && (uc < 32 || uc > 127))
+ {
+ // Non-printable as plain ASCII.
+ printf("<U-%04X>", uc);
+ }
+ else
+ {
+ printf("%c", (char) uc);
+ }
+ }
+}
+
+
+// Simple canned test.
+int main(int argc, const char* argv[])
+{
+ {
+ const char* test8 = "Ignacio CastaƱo";
+ const UInt32 test32[] =
+ {
+ 0x49, 0x67, 0x6E, 0x61, 0x63,
+ 0x69, 0x6F, 0x20, 0x43, 0x61,
+ 0x73, 0x74, 0x61, 0xF1, 0x6F,
+ 0x00
+ };
+
+ OVR_ASSERT(check_equal(test8, test32));
+ }
+
+ // If user passed an arg, try reading the file as UTF-8 encoded text.
+ if (argc > 1)
+ {
+ const char* filename = argv[1];
+ FILE* fp = fopen(filename, "rb");
+ if (fp == NULL)
+ {
+ printf("Can't open file '%s'\n", filename);
+ return 1;
+ }
+
+ // Read lines from the file, encode/decode them, and highlight discrepancies.
+ const int LINE_SIZE = 200; // max line size
+ char line_buffer_utf8[LINE_SIZE];
+ char reencoded_utf8[6 * LINE_SIZE];
+ UInt32 line_buffer_ucs[LINE_SIZE];
+
+ int byte_counter = 0;
+ for (;;)
+ {
+ int c = fgetc(fp);
+ if (c == EOF)
+ {
+ // Done.
+ break;
+ }
+ line_buffer_utf8[byte_counter++] = c;
+ if (c == '\n' || byte_counter >= LINE_SIZE - 2)
+ {
+ // End of line. Process the line.
+ line_buffer_utf8[byte_counter++] = 0; // terminate.
+
+ // Decode into UCS.
+ const char* p = line_buffer_utf8;
+ UInt32* q = line_buffer_ucs;
+ for (;;)
+ {
+ UInt32 uc = UTF8Util::DecodeNextChar(&p);
+ *q++ = uc;
+
+ OVR_ASSERT(q < line_buffer_ucs + LINE_SIZE);
+ OVR_ASSERT(p < line_buffer_utf8 + LINE_SIZE);
+
+ if (uc == 0) break;
+ }
+
+ // Encode back into UTF-8.
+ q = line_buffer_ucs;
+ int index = 0;
+ for (;;)
+ {
+ UInt32 uc = *q++;
+ OVR_ASSERT(index < LINE_SIZE * 6 - 6);
+ int last_index = index;
+ UTF8Util::EncodeChar(reencoded_utf8, &index, uc);
+ OVR_ASSERT(index <= last_index + 6);
+ if (uc == 0) break;
+ }
+
+ // This can be useful for debugging.
+#if 0
+ // Show the UCS and the re-encoded UTF-8.
+ log_ucs(line_buffer_ucs);
+ log_ascii(reencoded_utf8);
+#endif // 0
+
+ OVR_ASSERT(check_equal(line_buffer_utf8, line_buffer_ucs));
+ OVR_ASSERT(check_equal(reencoded_utf8, line_buffer_ucs));
+
+ // Start next line.
+ byte_counter = 0;
+ }
+ }
+
+ fclose(fp);
+ }
+
+ return 0;
+}
+
+
+#endif // UTF8_UNIT_TEST
+
+}} // namespace UTF8Util::OVR
+
diff --git a/LibOVR/Src/Kernel/OVR_UTF8Util.h b/LibOVR/Src/Kernel/OVR_UTF8Util.h new file mode 100644 index 0000000..bf5af46 --- /dev/null +++ b/LibOVR/Src/Kernel/OVR_UTF8Util.h @@ -0,0 +1,88 @@ +/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_UTF8Util.h
+Content : UTF8 Unicode character encoding/decoding support
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_UTF8Util_h
+#define OVR_UTF8Util_h
+
+#include "OVR_Types.h"
+
+namespace OVR { namespace UTF8Util {
+
+//-----------------------------------------------------------------------------------
+
+// *** UTF8 string length and indexing.
+
+// Determines the length of UTF8 string in characters.
+// If source length is specified (in bytes), null 0 character is counted properly.
+SPInt OVR_STDCALL GetLength(const char* putf8str, SPInt length = -1);
+
+// Gets a decoded UTF8 character at index; you can access up to the index returned
+// by GetLength. 0 will be returned for out of bounds access.
+UInt32 OVR_STDCALL GetCharAt(SPInt index, const char* putf8str, SPInt length = -1);
+
+// Converts UTF8 character index into byte offset.
+// -1 is returned if index was out of bounds.
+SPInt OVR_STDCALL GetByteIndex(SPInt index, const char* putf8str, SPInt length = -1);
+
+
+// *** 16-bit Unicode string Encoding/Decoding routines.
+
+// Determines the number of bytes necessary to encode a string.
+// Does not count the terminating 0 (null) character.
+SPInt OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, SPInt length = -1);
+
+// Encodes a unicode (UCS-2 only) string into a buffer. The size of buffer must be at
+// least GetEncodeStringSize() + 1.
+void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, SPInt length = -1);
+
+// Decode UTF8 into a wchar_t buffer. Must have GetLength()+1 characters available.
+// Characters over 0xFFFF are replaced with 0xFFFD.
+// Returns the length of resulting string (number of characters)
+UPInt OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, SPInt bytesLen = -1);
+
+
+// *** Individual character Encoding/Decoding.
+
+// Determined the number of bytes necessary to encode a UCS character.
+int OVR_STDCALL GetEncodeCharSize(UInt32 ucsCharacter);
+
+// Encodes the given UCS character into the given UTF-8 buffer.
+// Writes the data starting at buffer[offset], and
+// increments offset by the number of bytes written.
+// May write up to 6 bytes, so make sure there's room in the buffer
+void OVR_STDCALL EncodeChar(char* pbuffer, SPInt* poffset, UInt32 ucsCharacter);
+
+// Return the next Unicode character in the UTF-8 encoded buffer.
+// Invalid UTF-8 sequences produce a U+FFFD character as output.
+// Advances *utf8_buffer past the character returned. Pointer advance
+// occurs even if the terminating 0 character is hit, since that allows
+// strings with middle '\0' characters to be supported.
+UInt32 OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer);
+
+// Safer version of DecodeNextChar, which doesn't advance pointer if
+// null character is hit.
+inline UInt32 DecodeNextChar(const char** putf8Buffer)
+{
+ UInt32 ch = DecodeNextChar_Advance0(putf8Buffer);
+ if (ch == 0)
+ (*putf8Buffer)--;
+ return ch;
+}
+
+
+}} // OVR::UTF8Util
+
+#endif
|