ovr_sdk

diff LibOVR/Src/Kernel/OVR_Alg.h @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/LibOVR/Src/Kernel/OVR_Alg.h	Wed Jan 14 06:51:16 2015 +0200
     1.3 @@ -0,0 +1,1062 @@
     1.4 +/************************************************************************************
     1.5 +
     1.6 +PublicHeader:   OVR_Kernel.h
     1.7 +Filename    :   OVR_Alg.h
     1.8 +Content     :   Simple general purpose algorithms: Sort, Binary Search, etc.
     1.9 +Created     :   September 19, 2012
    1.10 +Notes       : 
    1.11 +
    1.12 +Copyright   :   Copyright 2014 Oculus VR, LLC All Rights reserved.
    1.13 +
    1.14 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 
    1.15 +you may not use the Oculus VR Rift SDK except in compliance with the License, 
    1.16 +which is provided at the time of installation or download, or which 
    1.17 +otherwise accompanies this software in either electronic or hard copy form.
    1.18 +
    1.19 +You may obtain a copy of the License at
    1.20 +
    1.21 +http://www.oculusvr.com/licenses/LICENSE-3.2 
    1.22 +
    1.23 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 
    1.24 +distributed under the License is distributed on an "AS IS" BASIS,
    1.25 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.26 +See the License for the specific language governing permissions and
    1.27 +limitations under the License.
    1.28 +
    1.29 +************************************************************************************/
    1.30 +
    1.31 +#ifndef OVR_Alg_h
    1.32 +#define OVR_Alg_h
    1.33 +
    1.34 +#include "OVR_Types.h"
    1.35 +#include <string.h>
    1.36 +
    1.37 +namespace OVR { namespace Alg {
    1.38 +
    1.39 +
    1.40 +//-----------------------------------------------------------------------------------
    1.41 +// ***** Operator extensions
    1.42 +
    1.43 +template <typename T> OVR_FORCE_INLINE void Swap(T &a, T &b) 
    1.44 +{  T temp(a); a = b; b = temp; }
    1.45 +
    1.46 +
    1.47 +// ***** min/max are not implemented in Visual Studio 6 standard STL
    1.48 +
    1.49 +template <typename T> OVR_FORCE_INLINE const T Min(const T a, const T b)
    1.50 +{ return (a < b) ? a : b; }
    1.51 +
    1.52 +template <typename T> OVR_FORCE_INLINE const T Max(const T a, const T b)
    1.53 +{ return (b < a) ? a : b; }
    1.54 +
    1.55 +template <typename T> OVR_FORCE_INLINE const T Clamp(const T v, const T minVal, const T maxVal)
    1.56 +{ return Max<T>(minVal, Min<T>(v, maxVal)); }
    1.57 +
    1.58 +template <typename T> OVR_FORCE_INLINE int     Chop(T f)
    1.59 +{ return (int)f; }
    1.60 +
    1.61 +template <typename T> OVR_FORCE_INLINE T       Lerp(T a, T b, T f) 
    1.62 +{ return (b - a) * f + a; }
    1.63 +
    1.64 +
    1.65 +// These functions stand to fix a stupid VC++ warning (with /Wp64 on):
    1.66 +// "warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned', possible loss of data"
    1.67 +// Use these functions instead of gmin/gmax if the argument has size
    1.68 +// of the pointer to avoid the warning. Though, functionally they are
    1.69 +// absolutelly the same as regular gmin/gmax.
    1.70 +template <typename T>   OVR_FORCE_INLINE const T PMin(const T a, const T b)
    1.71 +{
    1.72 +    OVR_COMPILER_ASSERT(sizeof(T) == sizeof(size_t));
    1.73 +    return (a < b) ? a : b;
    1.74 +}
    1.75 +template <typename T>   OVR_FORCE_INLINE const T PMax(const T a, const T b)
    1.76 +{
    1.77 +    OVR_COMPILER_ASSERT(sizeof(T) == sizeof(size_t));
    1.78 +    return (b < a) ? a : b;
    1.79 +}
    1.80 +
    1.81 +
    1.82 +template <typename T>   OVR_FORCE_INLINE const T Abs(const T v)
    1.83 +{ return (v>=0) ? v : -v; }
    1.84 +
    1.85 +
    1.86 +//-----------------------------------------------------------------------------------
    1.87 +// ***** OperatorLess
    1.88 +//
    1.89 +template<class T> struct OperatorLess
    1.90 +{
    1.91 +    static bool Compare(const T& a, const T& b)
    1.92 +    {
    1.93 +        return a < b;
    1.94 +    }
    1.95 +};
    1.96 +
    1.97 +
    1.98 +//-----------------------------------------------------------------------------------
    1.99 +// ***** QuickSortSliced
   1.100 +//
   1.101 +// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
   1.102 +// The range is specified with start, end, where "end" is exclusive!
   1.103 +// The comparison predicate must be specified.
   1.104 +template<class Array, class Less> 
   1.105 +void QuickSortSliced(Array& arr, size_t start, size_t end, Less less)
   1.106 +{
   1.107 +    enum 
   1.108 +    {
   1.109 +        Threshold = 9
   1.110 +    };
   1.111 +
   1.112 +    if(end - start <  2) return;
   1.113 +
   1.114 +    intptr_t  stack[80];
   1.115 +    intptr_t* top   = stack; 
   1.116 +    intptr_t  base  = (intptr_t)start;
   1.117 +    intptr_t  limit = (intptr_t)end;
   1.118 +
   1.119 +    for(;;)
   1.120 +    {
   1.121 +        intptr_t len = limit - base;
   1.122 +        intptr_t i, j, pivot;
   1.123 +
   1.124 +        if(len > Threshold)
   1.125 +        {
   1.126 +            // we use base + len/2 as the pivot
   1.127 +            pivot = base + len / 2;
   1.128 +            Swap(arr[base], arr[pivot]);
   1.129 +
   1.130 +            i = base + 1;
   1.131 +            j = limit - 1;
   1.132 +
   1.133 +            // now ensure that *i <= *base <= *j 
   1.134 +            if(less(arr[j],    arr[i])) Swap(arr[j],    arr[i]);
   1.135 +            if(less(arr[base], arr[i])) Swap(arr[base], arr[i]);
   1.136 +            if(less(arr[j], arr[base])) Swap(arr[j], arr[base]);
   1.137 +
   1.138 +            for(;;)
   1.139 +            {
   1.140 +                do i++; while( less(arr[i], arr[base]) );
   1.141 +                do j--; while( less(arr[base], arr[j]) );
   1.142 +
   1.143 +                if( i > j )
   1.144 +                {
   1.145 +                    break;
   1.146 +                }
   1.147 +
   1.148 +                Swap(arr[i], arr[j]);
   1.149 +            }
   1.150 +
   1.151 +            Swap(arr[base], arr[j]);
   1.152 +
   1.153 +            // now, push the largest sub-array
   1.154 +            if(j - base > limit - i)
   1.155 +            {
   1.156 +                top[0] = base;
   1.157 +                top[1] = j;
   1.158 +                base   = i;
   1.159 +            }
   1.160 +            else
   1.161 +            {
   1.162 +                top[0] = i;
   1.163 +                top[1] = limit;
   1.164 +                limit  = j;
   1.165 +            }
   1.166 +            top += 2;
   1.167 +        }
   1.168 +        else
   1.169 +        {
   1.170 +            // the sub-array is small, perform insertion sort
   1.171 +            j = base;
   1.172 +            i = j + 1;
   1.173 +
   1.174 +            for(; i < limit; j = i, i++)
   1.175 +            {
   1.176 +                for(; less(arr[j + 1], arr[j]); j--)
   1.177 +                {
   1.178 +                    Swap(arr[j + 1], arr[j]);
   1.179 +                    if(j == base)
   1.180 +                    {
   1.181 +                        break;
   1.182 +                    }
   1.183 +                }
   1.184 +            }
   1.185 +            if(top > stack)
   1.186 +            {
   1.187 +                top  -= 2;
   1.188 +                base  = top[0];
   1.189 +                limit = top[1];
   1.190 +            }
   1.191 +            else
   1.192 +            {
   1.193 +                break;
   1.194 +            }
   1.195 +        }
   1.196 +    }
   1.197 +}
   1.198 +
   1.199 +
   1.200 +//-----------------------------------------------------------------------------------
   1.201 +// ***** QuickSortSliced
   1.202 +//
   1.203 +// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
   1.204 +// The range is specified with start, end, where "end" is exclusive!
   1.205 +// The data type must have a defined "<" operator.
   1.206 +template<class Array> 
   1.207 +void QuickSortSliced(Array& arr, size_t start, size_t end)
   1.208 +{
   1.209 +    typedef typename Array::ValueType ValueType;
   1.210 +    QuickSortSliced(arr, start, end, OperatorLess<ValueType>::Compare);
   1.211 +}
   1.212 +
   1.213 +// Same as corresponding G_QuickSortSliced but with checking array limits to avoid
   1.214 +// crash in the case of wrong comparator functor.
   1.215 +template<class Array, class Less> 
   1.216 +bool QuickSortSlicedSafe(Array& arr, size_t start, size_t end, Less less)
   1.217 +{
   1.218 +    enum 
   1.219 +    {
   1.220 +        Threshold = 9
   1.221 +    };
   1.222 +
   1.223 +    if(end - start <  2) return true;
   1.224 +
   1.225 +    intptr_t  stack[80];
   1.226 +    intptr_t* top   = stack; 
   1.227 +    intptr_t  base  = (intptr_t)start;
   1.228 +    intptr_t  limit = (intptr_t)end;
   1.229 +
   1.230 +    for(;;)
   1.231 +    {
   1.232 +        intptr_t len = limit - base;
   1.233 +        intptr_t i, j, pivot;
   1.234 +
   1.235 +        if(len > Threshold)
   1.236 +        {
   1.237 +            // we use base + len/2 as the pivot
   1.238 +            pivot = base + len / 2;
   1.239 +            Swap(arr[base], arr[pivot]);
   1.240 +
   1.241 +            i = base + 1;
   1.242 +            j = limit - 1;
   1.243 +
   1.244 +            // now ensure that *i <= *base <= *j 
   1.245 +            if(less(arr[j],    arr[i])) Swap(arr[j],    arr[i]);
   1.246 +            if(less(arr[base], arr[i])) Swap(arr[base], arr[i]);
   1.247 +            if(less(arr[j], arr[base])) Swap(arr[j], arr[base]);
   1.248 +
   1.249 +            for(;;)
   1.250 +            {
   1.251 +                do 
   1.252 +                {   
   1.253 +                    i++; 
   1.254 +                    if (i >= limit)
   1.255 +                        return false;
   1.256 +                } while( less(arr[i], arr[base]) );
   1.257 +                do 
   1.258 +                {
   1.259 +                    j--; 
   1.260 +                    if (j < 0)
   1.261 +                        return false;
   1.262 +                } while( less(arr[base], arr[j]) );
   1.263 +
   1.264 +                if( i > j )
   1.265 +                {
   1.266 +                    break;
   1.267 +                }
   1.268 +
   1.269 +                Swap(arr[i], arr[j]);
   1.270 +            }
   1.271 +
   1.272 +            Swap(arr[base], arr[j]);
   1.273 +
   1.274 +            // now, push the largest sub-array
   1.275 +            if(j - base > limit - i)
   1.276 +            {
   1.277 +                top[0] = base;
   1.278 +                top[1] = j;
   1.279 +                base   = i;
   1.280 +            }
   1.281 +            else
   1.282 +            {
   1.283 +                top[0] = i;
   1.284 +                top[1] = limit;
   1.285 +                limit  = j;
   1.286 +            }
   1.287 +            top += 2;
   1.288 +        }
   1.289 +        else
   1.290 +        {
   1.291 +            // the sub-array is small, perform insertion sort
   1.292 +            j = base;
   1.293 +            i = j + 1;
   1.294 +
   1.295 +            for(; i < limit; j = i, i++)
   1.296 +            {
   1.297 +                for(; less(arr[j + 1], arr[j]); j--)
   1.298 +                {
   1.299 +                    Swap(arr[j + 1], arr[j]);
   1.300 +                    if(j == base)
   1.301 +                    {
   1.302 +                        break;
   1.303 +                    }
   1.304 +                }
   1.305 +            }
   1.306 +            if(top > stack)
   1.307 +            {
   1.308 +                top  -= 2;
   1.309 +                base  = top[0];
   1.310 +                limit = top[1];
   1.311 +            }
   1.312 +            else
   1.313 +            {
   1.314 +                break;
   1.315 +            }
   1.316 +        }
   1.317 +    }
   1.318 +    return true;
   1.319 +}
   1.320 +
   1.321 +template<class Array> 
   1.322 +bool QuickSortSlicedSafe(Array& arr, size_t start, size_t end)
   1.323 +{
   1.324 +    typedef typename Array::ValueType ValueType;
   1.325 +    return QuickSortSlicedSafe(arr, start, end, OperatorLess<ValueType>::Compare);
   1.326 +}
   1.327 +
   1.328 +//-----------------------------------------------------------------------------------
   1.329 +// ***** QuickSort
   1.330 +//
   1.331 +// Sort an array Array, ArrayPaged, ArrayUnsafe.
   1.332 +// The array must have GetSize() function.
   1.333 +// The comparison predicate must be specified.
   1.334 +template<class Array, class Less> 
   1.335 +void QuickSort(Array& arr, Less less)
   1.336 +{
   1.337 +    QuickSortSliced(arr, 0, arr.GetSize(), less);
   1.338 +}
   1.339 +
   1.340 +// checks for boundaries
   1.341 +template<class Array, class Less> 
   1.342 +bool QuickSortSafe(Array& arr, Less less)
   1.343 +{
   1.344 +    return QuickSortSlicedSafe(arr, 0, arr.GetSize(), less);
   1.345 +}
   1.346 +
   1.347 +
   1.348 +//-----------------------------------------------------------------------------------
   1.349 +// ***** QuickSort
   1.350 +//
   1.351 +// Sort an array Array, ArrayPaged, ArrayUnsafe.
   1.352 +// The array must have GetSize() function.
   1.353 +// The data type must have a defined "<" operator.
   1.354 +template<class Array> 
   1.355 +void QuickSort(Array& arr)
   1.356 +{
   1.357 +    typedef typename Array::ValueType ValueType;
   1.358 +    QuickSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
   1.359 +}
   1.360 +
   1.361 +template<class Array> 
   1.362 +bool QuickSortSafe(Array& arr)
   1.363 +{
   1.364 +    typedef typename Array::ValueType ValueType;
   1.365 +    return QuickSortSlicedSafe(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
   1.366 +}
   1.367 +
   1.368 +//-----------------------------------------------------------------------------------
   1.369 +// ***** InsertionSortSliced
   1.370 +//
   1.371 +// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
   1.372 +// The range is specified with start, end, where "end" is exclusive!
   1.373 +// The comparison predicate must be specified.
   1.374 +// Unlike Quick Sort, the Insertion Sort works much slower in average, 
   1.375 +// but may be much faster on almost sorted arrays. Besides, it guarantees
   1.376 +// that the elements will not be swapped if not necessary. For example, 
   1.377 +// an array with all equal elements will remain "untouched", while 
   1.378 +// Quick Sort will considerably shuffle the elements in this case.
   1.379 +template<class Array, class Less> 
   1.380 +void InsertionSortSliced(Array& arr, size_t start, size_t end, Less less)
   1.381 +{
   1.382 +    size_t j = start;
   1.383 +    size_t i = j + 1;
   1.384 +    size_t limit = end;
   1.385 +
   1.386 +    for(; i < limit; j = i, i++)
   1.387 +    {
   1.388 +        for(; less(arr[j + 1], arr[j]); j--)
   1.389 +        {
   1.390 +            Swap(arr[j + 1], arr[j]);
   1.391 +            if(j <= start)
   1.392 +            {
   1.393 +                break;
   1.394 +            }
   1.395 +        }
   1.396 +    }
   1.397 +}
   1.398 +
   1.399 +
   1.400 +//-----------------------------------------------------------------------------------
   1.401 +// ***** InsertionSortSliced
   1.402 +//
   1.403 +// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
   1.404 +// The range is specified with start, end, where "end" is exclusive!
   1.405 +// The data type must have a defined "<" operator.
   1.406 +template<class Array> 
   1.407 +void InsertionSortSliced(Array& arr, size_t start, size_t end)
   1.408 +{
   1.409 +    typedef typename Array::ValueType ValueType;
   1.410 +    InsertionSortSliced(arr, start, end, OperatorLess<ValueType>::Compare);
   1.411 +}
   1.412 +
   1.413 +//-----------------------------------------------------------------------------------
   1.414 +// ***** InsertionSort
   1.415 +//
   1.416 +// Sort an array Array, ArrayPaged, ArrayUnsafe.
   1.417 +// The array must have GetSize() function.
   1.418 +// The comparison predicate must be specified.
   1.419 +
   1.420 +template<class Array, class Less> 
   1.421 +void InsertionSort(Array& arr, Less less)
   1.422 +{
   1.423 +    InsertionSortSliced(arr, 0, arr.GetSize(), less);
   1.424 +}
   1.425 +
   1.426 +//-----------------------------------------------------------------------------------
   1.427 +// ***** InsertionSort
   1.428 +//
   1.429 +// Sort an array Array, ArrayPaged, ArrayUnsafe.
   1.430 +// The array must have GetSize() function.
   1.431 +// The data type must have a defined "<" operator.
   1.432 +template<class Array> 
   1.433 +void InsertionSort(Array& arr)
   1.434 +{
   1.435 +    typedef typename Array::ValueType ValueType;
   1.436 +    InsertionSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
   1.437 +}
   1.438 +
   1.439 +//-----------------------------------------------------------------------------------
   1.440 +// ***** Median
   1.441 +// Returns a median value of the input array.
   1.442 +// Caveats: partially sorts the array, returns a reference to the array element
   1.443 +// TBD: This needs to be optimized and generalized
   1.444 +//
   1.445 +template<class Array> 
   1.446 +typename Array::ValueType& Median(Array& arr)
   1.447 +{
   1.448 +    size_t count = arr.GetSize();
   1.449 +    size_t mid = (count - 1) / 2;
   1.450 +    OVR_ASSERT(count > 0);
   1.451 +
   1.452 +	for (size_t j = 0; j <= mid; j++)
   1.453 +    {
   1.454 +		size_t min = j;
   1.455 +		for (size_t k = j + 1; k < count; k++)
   1.456 +            if (arr[k] < arr[min]) 
   1.457 +                min = k;
   1.458 +        Swap(arr[j], arr[min]);
   1.459 +    }
   1.460 +    return arr[mid];
   1.461 +}
   1.462 +
   1.463 +//-----------------------------------------------------------------------------------
   1.464 +// ***** LowerBoundSliced
   1.465 +//
   1.466 +template<class Array, class Value, class Less>
   1.467 +size_t LowerBoundSliced(const Array& arr, size_t start, size_t end, const Value& val, Less less)
   1.468 +{
   1.469 +    intptr_t first = (intptr_t)start;
   1.470 +    intptr_t len   = (intptr_t)(end - start);
   1.471 +    intptr_t half;
   1.472 +    intptr_t middle;
   1.473 +    
   1.474 +    while(len > 0) 
   1.475 +    {
   1.476 +        half = len >> 1;
   1.477 +        middle = first + half;
   1.478 +        if(less(arr[middle], val)) 
   1.479 +        {
   1.480 +            first = middle + 1;
   1.481 +            len   = len - half - 1;
   1.482 +        }
   1.483 +        else
   1.484 +        {
   1.485 +            len = half;
   1.486 +        }
   1.487 +    }
   1.488 +    return (size_t)first;
   1.489 +}
   1.490 +
   1.491 +
   1.492 +//-----------------------------------------------------------------------------------
   1.493 +// ***** LowerBoundSliced
   1.494 +//
   1.495 +template<class Array, class Value>
   1.496 +size_t LowerBoundSliced(const Array& arr, size_t start, size_t end, const Value& val)
   1.497 +{
   1.498 +    return LowerBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare);
   1.499 +}
   1.500 +
   1.501 +//-----------------------------------------------------------------------------------
   1.502 +// ***** LowerBoundSized
   1.503 +//
   1.504 +template<class Array, class Value>
   1.505 +size_t LowerBoundSized(const Array& arr, size_t size, const Value& val)
   1.506 +{
   1.507 +    return LowerBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare);
   1.508 +}
   1.509 +
   1.510 +//-----------------------------------------------------------------------------------
   1.511 +// ***** LowerBound
   1.512 +//
   1.513 +template<class Array, class Value, class Less>
   1.514 +size_t LowerBound(const Array& arr, const Value& val, Less less)
   1.515 +{
   1.516 +    return LowerBoundSliced(arr, 0, arr.GetSize(), val, less);
   1.517 +}
   1.518 +
   1.519 +
   1.520 +//-----------------------------------------------------------------------------------
   1.521 +// ***** LowerBound
   1.522 +//
   1.523 +template<class Array, class Value>
   1.524 +size_t LowerBound(const Array& arr, const Value& val)
   1.525 +{
   1.526 +    return LowerBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare);
   1.527 +}
   1.528 +
   1.529 +
   1.530 +
   1.531 +//-----------------------------------------------------------------------------------
   1.532 +// ***** UpperBoundSliced
   1.533 +//
   1.534 +template<class Array, class Value, class Less>
   1.535 +size_t UpperBoundSliced(const Array& arr, size_t start, size_t end, const Value& val, Less less)
   1.536 +{
   1.537 +    intptr_t first = (intptr_t)start;
   1.538 +    intptr_t len   = (intptr_t)(end - start);
   1.539 +    intptr_t half;
   1.540 +    intptr_t middle;
   1.541 +    
   1.542 +    while(len > 0) 
   1.543 +    {
   1.544 +        half = len >> 1;
   1.545 +        middle = first + half;
   1.546 +        if(less(val, arr[middle]))
   1.547 +        {
   1.548 +            len = half;
   1.549 +        }
   1.550 +        else 
   1.551 +        {
   1.552 +            first = middle + 1;
   1.553 +            len   = len - half - 1;
   1.554 +        }
   1.555 +    }
   1.556 +    return (size_t)first;
   1.557 +}
   1.558 +
   1.559 +
   1.560 +//-----------------------------------------------------------------------------------
   1.561 +// ***** UpperBoundSliced
   1.562 +//
   1.563 +template<class Array, class Value>
   1.564 +size_t UpperBoundSliced(const Array& arr, size_t start, size_t end, const Value& val)
   1.565 +{
   1.566 +    return UpperBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare);
   1.567 +}
   1.568 +
   1.569 +
   1.570 +//-----------------------------------------------------------------------------------
   1.571 +// ***** UpperBoundSized
   1.572 +//
   1.573 +template<class Array, class Value>
   1.574 +size_t UpperBoundSized(const Array& arr, size_t size, const Value& val)
   1.575 +{
   1.576 +    return UpperBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare);
   1.577 +}
   1.578 +
   1.579 +
   1.580 +//-----------------------------------------------------------------------------------
   1.581 +// ***** UpperBound
   1.582 +//
   1.583 +template<class Array, class Value, class Less>
   1.584 +size_t UpperBound(const Array& arr, const Value& val, Less less)
   1.585 +{
   1.586 +    return UpperBoundSliced(arr, 0, arr.GetSize(), val, less);
   1.587 +}
   1.588 +
   1.589 +
   1.590 +//-----------------------------------------------------------------------------------
   1.591 +// ***** UpperBound
   1.592 +//
   1.593 +template<class Array, class Value>
   1.594 +size_t UpperBound(const Array& arr, const Value& val)
   1.595 +{
   1.596 +    return UpperBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare);
   1.597 +}
   1.598 +
   1.599 +
   1.600 +//-----------------------------------------------------------------------------------
   1.601 +// ***** ReverseArray
   1.602 +//
   1.603 +template<class Array> void ReverseArray(Array& arr)
   1.604 +{
   1.605 +    intptr_t from = 0;
   1.606 +    intptr_t to   = arr.GetSize() - 1;
   1.607 +    while(from < to)
   1.608 +    {
   1.609 +        Swap(arr[from], arr[to]);
   1.610 +        ++from;
   1.611 +        --to;
   1.612 +    }
   1.613 +}
   1.614 +
   1.615 +
   1.616 +// ***** AppendArray
   1.617 +//
   1.618 +template<class CDst, class CSrc> 
   1.619 +void AppendArray(CDst& dst, const CSrc& src)
   1.620 +{
   1.621 +    size_t i;
   1.622 +    for(i = 0; i < src.GetSize(); i++) 
   1.623 +        dst.PushBack(src[i]);
   1.624 +}
   1.625 +
   1.626 +//-----------------------------------------------------------------------------------
   1.627 +// ***** ArrayAdaptor
   1.628 +//
   1.629 +// A simple adapter that provides the GetSize() method and overloads 
   1.630 +// operator []. Used to wrap plain arrays in QuickSort and such.
   1.631 +template<class T> class ArrayAdaptor
   1.632 +{
   1.633 +public:
   1.634 +    typedef T ValueType;
   1.635 +    ArrayAdaptor() : Data(0), Size(0) {}
   1.636 +    ArrayAdaptor(T* ptr, size_t size) : Data(ptr), Size(size) {}
   1.637 +    size_t GetSize() const { return Size; }
   1.638 +	int GetSizeI() const { return (int)GetSize(); }
   1.639 +    const T& operator [] (size_t i) const { return Data[i]; }
   1.640 +          T& operator [] (size_t i)       { return Data[i]; }
   1.641 +private:
   1.642 +    T*      Data;
   1.643 +    size_t  Size;
   1.644 +};
   1.645 +
   1.646 +
   1.647 +//-----------------------------------------------------------------------------------
   1.648 +// ***** GConstArrayAdaptor
   1.649 +//
   1.650 +// A simple const adapter that provides the GetSize() method and overloads 
   1.651 +// operator []. Used to wrap plain arrays in LowerBound and such.
   1.652 +template<class T> class ConstArrayAdaptor
   1.653 +{
   1.654 +public:
   1.655 +    typedef T ValueType;
   1.656 +    ConstArrayAdaptor() : Data(0), Size(0) {}
   1.657 +    ConstArrayAdaptor(const T* ptr, size_t size) : Data(ptr), Size(size) {}
   1.658 +    size_t GetSize() const { return Size; }
   1.659 +	int GetSizeI() const { return (int)GetSize(); }
   1.660 +	const T& operator [] (size_t i) const { return Data[i]; }
   1.661 +private:
   1.662 +    const T* Data;
   1.663 +    size_t   Size;
   1.664 +};
   1.665 +
   1.666 +
   1.667 +
   1.668 +//-----------------------------------------------------------------------------------
   1.669 +extern const uint8_t UpperBitTable[256];
   1.670 +extern const uint8_t LowerBitTable[256];
   1.671 +
   1.672 +
   1.673 +
   1.674 +//-----------------------------------------------------------------------------------
   1.675 +inline uint8_t UpperBit(size_t val)
   1.676 +{
   1.677 +#ifndef OVR_64BIT_POINTERS
   1.678 +
   1.679 +    if (val & 0xFFFF0000)
   1.680 +    {
   1.681 +        return (val & 0xFF000000) ? 
   1.682 +            UpperBitTable[(val >> 24)       ] + 24: 
   1.683 +            UpperBitTable[(val >> 16) & 0xFF] + 16;
   1.684 +    }
   1.685 +    return (val & 0xFF00) ?
   1.686 +        UpperBitTable[(val >> 8) & 0xFF] + 8:
   1.687 +        UpperBitTable[(val     ) & 0xFF];
   1.688 +
   1.689 +#else
   1.690 +
   1.691 +    if (val & 0xFFFFFFFF00000000)
   1.692 +    {
   1.693 +        if (val & 0xFFFF000000000000)
   1.694 +        {
   1.695 +            return (val & 0xFF00000000000000) ?
   1.696 +                UpperBitTable[(val >> 56)       ] + 56: 
   1.697 +                UpperBitTable[(val >> 48) & 0xFF] + 48;
   1.698 +        }
   1.699 +        return (val & 0xFF0000000000) ?
   1.700 +            UpperBitTable[(val >> 40) & 0xFF] + 40:
   1.701 +            UpperBitTable[(val >> 32) & 0xFF] + 32;
   1.702 +    }
   1.703 +    else
   1.704 +    {
   1.705 +        if (val & 0xFFFF0000)
   1.706 +        {
   1.707 +            return (val & 0xFF000000) ? 
   1.708 +                UpperBitTable[(val >> 24)       ] + 24: 
   1.709 +                UpperBitTable[(val >> 16) & 0xFF] + 16;
   1.710 +        }
   1.711 +        return (val & 0xFF00) ?
   1.712 +            UpperBitTable[(val >> 8) & 0xFF] + 8:
   1.713 +            UpperBitTable[(val     ) & 0xFF];
   1.714 +    }
   1.715 +
   1.716 +#endif
   1.717 +}
   1.718 +
   1.719 +//-----------------------------------------------------------------------------------
   1.720 +inline uint8_t LowerBit(size_t val)
   1.721 +{
   1.722 +#ifndef OVR_64BIT_POINTERS
   1.723 +
   1.724 +    if (val & 0xFFFF)
   1.725 +    {
   1.726 +        return (val & 0xFF) ?
   1.727 +            LowerBitTable[ val & 0xFF]:
   1.728 +            LowerBitTable[(val >> 8) & 0xFF] + 8;
   1.729 +    }
   1.730 +    return (val & 0xFF0000) ?
   1.731 +            LowerBitTable[(val >> 16) & 0xFF] + 16:
   1.732 +            LowerBitTable[(val >> 24) & 0xFF] + 24;
   1.733 +
   1.734 +#else
   1.735 +
   1.736 +    if (val & 0xFFFFFFFF)
   1.737 +    {
   1.738 +        if (val & 0xFFFF)
   1.739 +        {
   1.740 +            return (val & 0xFF) ?
   1.741 +                LowerBitTable[ val & 0xFF]:
   1.742 +                LowerBitTable[(val >> 8) & 0xFF] + 8;
   1.743 +        }
   1.744 +        return (val & 0xFF0000) ?
   1.745 +                LowerBitTable[(val >> 16) & 0xFF] + 16:
   1.746 +                LowerBitTable[(val >> 24) & 0xFF] + 24;
   1.747 +    }
   1.748 +    else
   1.749 +    {
   1.750 +        if (val & 0xFFFF00000000)
   1.751 +        {
   1.752 +             return (val & 0xFF00000000) ?
   1.753 +                LowerBitTable[(val >> 32) & 0xFF] + 32:
   1.754 +                LowerBitTable[(val >> 40) & 0xFF] + 40;
   1.755 +        }
   1.756 +        return (val & 0xFF000000000000) ?
   1.757 +            LowerBitTable[(val >> 48) & 0xFF] + 48:
   1.758 +            LowerBitTable[(val >> 56) & 0xFF] + 56;
   1.759 +    }
   1.760 +
   1.761 +#endif
   1.762 +}
   1.763 +
   1.764 +
   1.765 +
   1.766 +// ******* Special (optimized) memory routines
   1.767 +// Note: null (bad) pointer is not tested
   1.768 +class MemUtil
   1.769 +{
   1.770 +public:
   1.771 +                                    
   1.772 +    // Memory compare
   1.773 +    static int      Cmp  (const void* p1, const void* p2, size_t byteCount)      { return memcmp(p1, p2, byteCount); }
   1.774 +    static int      Cmp16(const void* p1, const void* p2, size_t int16Count);
   1.775 +    static int      Cmp32(const void* p1, const void* p2, size_t int32Count);
   1.776 +    static int      Cmp64(const void* p1, const void* p2, size_t int64Count); 
   1.777 +};
   1.778 +
   1.779 +// ** Inline Implementation
   1.780 +
   1.781 +inline int MemUtil::Cmp16(const void* p1, const void* p2, size_t int16Count)
   1.782 +{
   1.783 +    int16_t*  pa  = (int16_t*)p1; 
   1.784 +    int16_t*  pb  = (int16_t*)p2;
   1.785 +    unsigned ic  = 0;
   1.786 +    if (int16Count == 0)
   1.787 +        return 0;
   1.788 +    while (pa[ic] == pb[ic])
   1.789 +        if (++ic==int16Count)
   1.790 +            return 0;
   1.791 +    return pa[ic] > pb[ic] ? 1 : -1;
   1.792 +}
   1.793 +inline int MemUtil::Cmp32(const void* p1, const void* p2, size_t int32Count)
   1.794 +{
   1.795 +    int32_t*  pa  = (int32_t*)p1;
   1.796 +    int32_t*  pb  = (int32_t*)p2;
   1.797 +    unsigned ic  = 0;
   1.798 +    if (int32Count == 0)
   1.799 +        return 0;
   1.800 +    while (pa[ic] == pb[ic])
   1.801 +        if (++ic==int32Count)
   1.802 +            return 0;
   1.803 +    return pa[ic] > pb[ic] ? 1 : -1;
   1.804 +}
   1.805 +inline int MemUtil::Cmp64(const void* p1, const void* p2, size_t int64Count)
   1.806 +{
   1.807 +    int64_t*  pa  = (int64_t*)p1;
   1.808 +    int64_t*  pb  = (int64_t*)p2;
   1.809 +    unsigned ic  = 0;
   1.810 +    if (int64Count == 0)
   1.811 +        return 0;
   1.812 +    while (pa[ic] == pb[ic])
   1.813 +        if (++ic==int64Count)
   1.814 +            return 0;
   1.815 +    return pa[ic] > pb[ic] ? 1 : -1;
   1.816 +}
   1.817 +
   1.818 +// ** End Inline Implementation
   1.819 +
   1.820 +
   1.821 +//-----------------------------------------------------------------------------------
   1.822 +// ******* Byte Order Conversions
   1.823 +namespace ByteUtil {
   1.824 +
   1.825 +    // *** Swap Byte Order
   1.826 +
   1.827 +    // Swap the byte order of a byte array
   1.828 +    inline void     SwapOrder(void* pv, int size)
   1.829 +    {
   1.830 +        uint8_t*  pb = (uint8_t*)pv;
   1.831 +        uint8_t temp;
   1.832 +        for (int i = 0; i < size>>1; i++)
   1.833 +        { 
   1.834 +            temp            = pb[size-1-i];
   1.835 +            pb[size-1-i]    = pb[i];
   1.836 +            pb[i]           = temp; 
   1.837 +        }
   1.838 +    }
   1.839 +
   1.840 +    // Swap the byte order of primitive types
   1.841 +    inline uint8_t  SwapOrder(uint8_t v)    { return v; }
   1.842 +    inline int8_t   SwapOrder(int8_t v)     { return v; }
   1.843 +    inline uint16_t SwapOrder(uint16_t v)   { return uint16_t(v>>8)|uint16_t(v<<8); }
   1.844 +    inline int16_t  SwapOrder(int16_t v)    { return int16_t((uint16_t(v)>>8)|(v<<8)); }
   1.845 +    inline uint32_t SwapOrder(uint32_t v)   { return (v>>24)|((v&0x00FF0000)>>8)|((v&0x0000FF00)<<8)|(v<<24); }
   1.846 +    inline int32_t  SwapOrder(int32_t p)    { return (int32_t)SwapOrder(uint32_t(p)); }
   1.847 +    inline uint64_t SwapOrder(uint64_t v)
   1.848 +    { 
   1.849 +        return   (v>>56) |
   1.850 +                 ((v&uint64_t(0x00FF000000000000ULL))>>40) |
   1.851 +                 ((v&uint64_t(0x0000FF0000000000ULL))>>24) |
   1.852 +                 ((v&uint64_t(0x000000FF00000000ULL))>>8)  |
   1.853 +                 ((v&uint64_t(0x00000000FF000000ULL))<<8)  |
   1.854 +                 ((v&uint64_t(0x0000000000FF0000ULL))<<24) |
   1.855 +                 ((v&uint64_t(0x000000000000FF00ULL))<<40) |
   1.856 +                 (v<<56); 
   1.857 +    }
   1.858 +    inline int64_t  SwapOrder(int64_t v)     { return (int64_t)SwapOrder(uint64_t(v)); }
   1.859 +    inline float    SwapOrder(float p)      
   1.860 +    { 
   1.861 +        union {
   1.862 +            float p;
   1.863 +            uint32_t v;
   1.864 +        } u;
   1.865 +        u.p = p;
   1.866 +        u.v = SwapOrder(u.v);
   1.867 +        return u.p;
   1.868 +    }
   1.869 +
   1.870 +    inline double   SwapOrder(double p)
   1.871 +    { 
   1.872 +        union {
   1.873 +            double p;
   1.874 +            uint64_t v;
   1.875 +        } u;
   1.876 +        u.p = p;
   1.877 +        u.v = SwapOrder(u.v);
   1.878 +        return u.p;
   1.879 +    }
   1.880 +    
   1.881 +    // *** Byte-order conversion
   1.882 +
   1.883 +#if (OVR_BYTE_ORDER == OVR_LITTLE_ENDIAN)
   1.884 +    // Little Endian to System (LE)
   1.885 +    inline uint8_t  LEToSystem(uint8_t v)   { return v; }
   1.886 +    inline int8_t   LEToSystem(int8_t v)    { return v; }
   1.887 +    inline uint16_t LEToSystem(uint16_t v)  { return v; }
   1.888 +    inline int16_t  LEToSystem(int16_t v)   { return v; }
   1.889 +    inline uint32_t LEToSystem(uint32_t v)  { return v; }
   1.890 +    inline int32_t  LEToSystem(int32_t v)   { return v; }
   1.891 +    inline uint64_t LEToSystem(uint64_t v)  { return v; }
   1.892 +    inline int64_t  LEToSystem(int64_t v)    { return v; }
   1.893 +    inline float    LEToSystem(float  v)    { return v; }
   1.894 +    inline double   LEToSystem(double v)    { return v; }
   1.895 +
   1.896 +    // Big Endian to System (LE)
   1.897 +    inline uint8_t  BEToSystem(uint8_t v)   { return SwapOrder(v); }
   1.898 +    inline int8_t   BEToSystem(int8_t v)    { return SwapOrder(v); }
   1.899 +    inline uint16_t BEToSystem(uint16_t v)  { return SwapOrder(v); }
   1.900 +    inline int16_t  BEToSystem(int16_t v)   { return SwapOrder(v); }
   1.901 +    inline uint32_t BEToSystem(uint32_t v)  { return SwapOrder(v); }
   1.902 +    inline int32_t  BEToSystem(int32_t v)   { return SwapOrder(v); }
   1.903 +    inline uint64_t BEToSystem(uint64_t v)  { return SwapOrder(v); }
   1.904 +    inline int64_t  BEToSystem(int64_t v)    { return SwapOrder(v); }
   1.905 +    inline float    BEToSystem(float  v)    { return SwapOrder(v); }
   1.906 +    inline double   BEToSystem(double v)    { return SwapOrder(v); }
   1.907 +
   1.908 +    // System (LE) to Little Endian
   1.909 +    inline uint8_t  SystemToLE(uint8_t v)   { return v; }
   1.910 +    inline int8_t   SystemToLE(int8_t v)    { return v; }
   1.911 +    inline uint16_t SystemToLE(uint16_t v)  { return v; }
   1.912 +    inline int16_t  SystemToLE(int16_t v)   { return v; }
   1.913 +    inline uint32_t SystemToLE(uint32_t v)  { return v; }
   1.914 +    inline int32_t  SystemToLE(int32_t v)   { return v; }
   1.915 +    inline uint64_t SystemToLE(uint64_t v)  { return v; }
   1.916 +    inline int64_t  SystemToLE(int64_t v)    { return v; }
   1.917 +    inline float    SystemToLE(float  v)    { return v; }
   1.918 +    inline double   SystemToLE(double v)    { return v; }   
   1.919 +
   1.920 +    // System (LE) to Big Endian
   1.921 +    inline uint8_t  SystemToBE(uint8_t v)   { return SwapOrder(v); }
   1.922 +    inline int8_t   SystemToBE(int8_t v)    { return SwapOrder(v); }
   1.923 +    inline uint16_t SystemToBE(uint16_t v)  { return SwapOrder(v); }
   1.924 +    inline int16_t  SystemToBE(int16_t v)   { return SwapOrder(v); }
   1.925 +    inline uint32_t SystemToBE(uint32_t v)  { return SwapOrder(v); }
   1.926 +    inline int32_t  SystemToBE(int32_t v)   { return SwapOrder(v); }
   1.927 +    inline uint64_t SystemToBE(uint64_t v)  { return SwapOrder(v); }
   1.928 +    inline int64_t  SystemToBE(int64_t v)    { return SwapOrder(v); }
   1.929 +    inline float    SystemToBE(float  v)    { return SwapOrder(v); }
   1.930 +    inline double   SystemToBE(double v)    { return SwapOrder(v); }
   1.931 +
   1.932 +#elif (OVR_BYTE_ORDER == OVR_BIG_ENDIAN)
   1.933 +    // Little Endian to System (BE)
   1.934 +    inline uint8_t  LEToSystem(uint8_t  v)  { return SwapOrder(v); }
   1.935 +    inline int8_t   LEToSystem(int8_t v)    { return SwapOrder(v); }
   1.936 +    inline uint16_t LEToSystem(uint16_t v)  { return SwapOrder(v); }
   1.937 +    inline int16_t  LEToSystem(int16_t v)   { return SwapOrder(v); }
   1.938 +    inline uint32_t LEToSystem(uint32_t v)  { return SwapOrder(v); }
   1.939 +    inline int32_t  LEToSystem(int32_t v)   { return SwapOrder(v); }
   1.940 +    inline uint64_t LEToSystem(uint64_t v)  { return SwapOrder(v); }
   1.941 +    inline int64_t  LEToSystem(int64_t v)    { return SwapOrder(v); }
   1.942 +    inline float    LEToSystem(float  v)    { return SwapOrder(v); }
   1.943 +    inline double   LEToSystem(double v)    { return SwapOrder(v); }
   1.944 +
   1.945 +    // Big Endian to System (BE)
   1.946 +    inline uint8_t  BEToSystem(uint8_t v)   { return v; }
   1.947 +    inline int8_t   BEToSystem(int8_t v)    { return v; }
   1.948 +    inline uint16_t BEToSystem(uint16_t v)  { return v; }
   1.949 +    inline int16_t  BEToSystem(int16_t v)   { return v; }
   1.950 +    inline uint32_t BEToSystem(uint32_t v)  { return v; }
   1.951 +    inline int32_t  BEToSystem(int32_t v)   { return v; }
   1.952 +    inline uint64_t BEToSystem(uint64_t v)  { return v; }
   1.953 +    inline int64_t  BEToSystem(int64_t v)    { return v; }
   1.954 +    inline float    BEToSystem(float  v)    { return v; }
   1.955 +    inline double   BEToSystem(double v)    { return v; }
   1.956 +
   1.957 +    // System (BE) to Little Endian
   1.958 +    inline uint8_t  SystemToLE(uint8_t v)   { return SwapOrder(v); }
   1.959 +    inline int8_t   SystemToLE(int8_t v)    { return SwapOrder(v); }
   1.960 +    inline uint16_t SystemToLE(uint16_t v)  { return SwapOrder(v); }
   1.961 +    inline int16_t  SystemToLE(int16_t v)   { return SwapOrder(v); }
   1.962 +    inline uint32_t SystemToLE(uint32_t v)  { return SwapOrder(v); }
   1.963 +    inline int32_t  SystemToLE(int32_t v)   { return SwapOrder(v); }
   1.964 +    inline uint64_t SystemToLE(uint64_t v)  { return SwapOrder(v); }
   1.965 +    inline int64_t  SystemToLE(int64_t v)    { return SwapOrder(v); }
   1.966 +    inline float    SystemToLE(float  v)    { return SwapOrder(v); }
   1.967 +    inline double   SystemToLE(double v)    { return SwapOrder(v); }
   1.968 +
   1.969 +    // System (BE) to Big Endian
   1.970 +    inline uint8_t  SystemToBE(uint8_t v)   { return v; }
   1.971 +    inline int8_t   SystemToBE(int8_t v)    { return v; }
   1.972 +    inline uint16_t SystemToBE(uint16_t v)  { return v; }
   1.973 +    inline int16_t  SystemToBE(int16_t v)   { return v; }
   1.974 +    inline uint32_t SystemToBE(uint32_t v)  { return v; }
   1.975 +    inline int32_t  SystemToBE(int32_t v)   { return v; }
   1.976 +    inline uint64_t SystemToBE(uint64_t v)  { return v; }
   1.977 +    inline int64_t  SystemToBE(int64_t v)    { return v; }
   1.978 +    inline float    SystemToBE(float  v)    { return v; }
   1.979 +    inline double   SystemToBE(double v)    { return v; }
   1.980 +
   1.981 +#else
   1.982 +    #error "OVR_BYTE_ORDER must be defined to OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN"
   1.983 +#endif
   1.984 +
   1.985 +} // namespace ByteUtil
   1.986 +
   1.987 +
   1.988 +
   1.989 +// Used primarily for hardware interfacing such as sensor reports, firmware, etc.
   1.990 +// Reported data is all little-endian.
   1.991 +inline uint16_t DecodeUInt16(const uint8_t* buffer)
   1.992 +{
   1.993 +    return ByteUtil::LEToSystem ( *(const uint16_t*)buffer );
   1.994 +}
   1.995 +
   1.996 +inline int16_t DecodeSInt16(const uint8_t* buffer)
   1.997 +{
   1.998 +    return ByteUtil::LEToSystem ( *(const int16_t*)buffer );
   1.999 +}
  1.1000 +
  1.1001 +inline uint32_t DecodeUInt32(const uint8_t* buffer)
  1.1002 +{    
  1.1003 +    return ByteUtil::LEToSystem ( *(const uint32_t*)buffer );
  1.1004 +}
  1.1005 +
  1.1006 +inline int32_t DecodeSInt32(const uint8_t* buffer)
  1.1007 +{    
  1.1008 +    return ByteUtil::LEToSystem ( *(const int32_t*)buffer );
  1.1009 +}
  1.1010 +
  1.1011 +inline float DecodeFloat(const uint8_t* buffer)
  1.1012 +{
  1.1013 +    union {
  1.1014 +        uint32_t U;
  1.1015 +        float  F;
  1.1016 +    };
  1.1017 +
  1.1018 +    U = DecodeUInt32(buffer);
  1.1019 +    return F;
  1.1020 +}
  1.1021 +
  1.1022 +inline void EncodeUInt16(uint8_t* buffer, uint16_t val)
  1.1023 +{
  1.1024 +    *(uint16_t*)buffer = ByteUtil::SystemToLE ( val );
  1.1025 +}
  1.1026 +
  1.1027 +inline void EncodeSInt16(uint8_t* buffer, int16_t val)
  1.1028 +{
  1.1029 +    *(int16_t*)buffer = ByteUtil::SystemToLE ( val );
  1.1030 +}
  1.1031 +
  1.1032 +inline void EncodeUInt32(uint8_t* buffer, uint32_t val)
  1.1033 +{
  1.1034 +    *(uint32_t*)buffer = ByteUtil::SystemToLE ( val );
  1.1035 +}
  1.1036 +
  1.1037 +inline void EncodeSInt32(uint8_t* buffer, int32_t val)
  1.1038 +{
  1.1039 +    *(int32_t*)buffer = ByteUtil::SystemToLE ( val );
  1.1040 +}
  1.1041 +
  1.1042 +inline void EncodeFloat(uint8_t* buffer, float val)
  1.1043 +{
  1.1044 +    union {
  1.1045 +        uint32_t U;
  1.1046 +        float  F;
  1.1047 +    };
  1.1048 +
  1.1049 +    F = val;
  1.1050 +    EncodeUInt32(buffer, U);
  1.1051 +}
  1.1052 +
  1.1053 +// Converts an 8-bit binary-coded decimal
  1.1054 +inline int8_t DecodeBCD(uint8_t byte)
  1.1055 +{
  1.1056 +    uint8_t digit1 = (byte >> 4) & 0x0f;
  1.1057 +    uint8_t digit2 = byte & 0x0f;
  1.1058 +    int decimal = digit1 * 10 + digit2;   // maximum value = 99
  1.1059 +    return (int8_t)decimal;
  1.1060 +}
  1.1061 +
  1.1062 +
  1.1063 +}} // OVR::Alg
  1.1064 +
  1.1065 +#endif