406 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			406 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// vim: set sts=8 ts=2 sw=2 tw=99 et:
 | 
						|
//
 | 
						|
// Copyright (C) 2013, David Anderson and AlliedModders LLC
 | 
						|
// All rights reserved.
 | 
						|
// 
 | 
						|
// Redistribution and use in source and binary forms, with or without
 | 
						|
// modification, are permitted provided that the following conditions are met:
 | 
						|
// 
 | 
						|
//  * Redistributions of source code must retain the above copyright notice, this
 | 
						|
//    list of conditions and the following disclaimer.
 | 
						|
//  * Redistributions in binary form must reproduce the above copyright notice,
 | 
						|
//    this list of conditions and the following disclaimer in the documentation
 | 
						|
//    and/or other materials provided with the distribution.
 | 
						|
//  * Neither the name of AlliedModders LLC nor the names of its contributors
 | 
						|
//    may be used to endorse or promote products derived from this software
 | 
						|
//    without specific prior written permission.
 | 
						|
//
 | 
						|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
						|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
						|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
						|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
						|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
						|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
						|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
						|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
						|
// POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
#ifndef _include_amtl_utility_h_
 | 
						|
#define _include_amtl_utility_h_
 | 
						|
 | 
						|
#include <assert.h>
 | 
						|
#include <stddef.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdint.h>
 | 
						|
#if defined(_MSC_VER)
 | 
						|
# include <intrin.h>
 | 
						|
#endif
 | 
						|
#include <am-moveable.h>
 | 
						|
 | 
						|
#define KE_32BIT
 | 
						|
 | 
						|
#if defined(_MSC_VER)
 | 
						|
# pragma warning(disable:4355)
 | 
						|
#endif
 | 
						|
 | 
						|
namespace ke {
 | 
						|
 | 
						|
static const size_t kMallocAlignment = sizeof(void *) * 2;
 | 
						|
 | 
						|
static const size_t kKB = 1024;
 | 
						|
static const size_t kMB = 1024 * kKB;
 | 
						|
static const size_t kGB = 1024 * kMB;
 | 
						|
 | 
						|
typedef uint8_t * Address;
 | 
						|
 | 
						|
template <typename T> T
 | 
						|
ReturnAndVoid(T &t)
 | 
						|
{
 | 
						|
    T saved = t;
 | 
						|
    t = T();
 | 
						|
    return saved;
 | 
						|
}
 | 
						|
 | 
						|
#if __cplusplus >= 201103L
 | 
						|
# define KE_CXX11
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(KE_CXX11)
 | 
						|
# define KE_DELETE = delete
 | 
						|
# define KE_OVERRIDE override
 | 
						|
#else
 | 
						|
# define KE_DELETE
 | 
						|
# define KE_OVERRIDE
 | 
						|
#endif
 | 
						|
 | 
						|
// Wrapper that automatically deletes its contents. The pointer can be taken
 | 
						|
// to avoid destruction.
 | 
						|
template <typename T>
 | 
						|
class AutoPtr
 | 
						|
{
 | 
						|
    T *t_;
 | 
						|
 | 
						|
  public:
 | 
						|
    AutoPtr()
 | 
						|
      : t_(NULL)
 | 
						|
    {
 | 
						|
    }
 | 
						|
    explicit AutoPtr(T *t)
 | 
						|
      : t_(t)
 | 
						|
    {
 | 
						|
    }
 | 
						|
    AutoPtr(Moveable<AutoPtr<T> > other)
 | 
						|
    {
 | 
						|
        t_ = other->t_;
 | 
						|
        other->t_ = NULL;
 | 
						|
    }
 | 
						|
    ~AutoPtr() {
 | 
						|
        delete t_;
 | 
						|
    }
 | 
						|
    T *take() {
 | 
						|
        return ReturnAndVoid(t_);
 | 
						|
    }
 | 
						|
    T *operator *() const {
 | 
						|
        return t_;
 | 
						|
    }
 | 
						|
    T *operator ->() const {
 | 
						|
        return t_;
 | 
						|
    }
 | 
						|
    operator T *() const {
 | 
						|
        return t_;
 | 
						|
    }
 | 
						|
    T *operator =(T *t) {
 | 
						|
        delete t_;
 | 
						|
        t_ = t;
 | 
						|
        return t_;
 | 
						|
    }
 | 
						|
    T *operator =(Moveable<AutoPtr<T> > other) {
 | 
						|
        delete t_;
 | 
						|
        t_ = other->t_;
 | 
						|
        other->t_ = NULL;
 | 
						|
        return t_;
 | 
						|
    }
 | 
						|
    bool operator !() const {
 | 
						|
        return !t_;
 | 
						|
    }
 | 
						|
 | 
						|
  private:
 | 
						|
    AutoPtr(const AutoPtr &other) KE_DELETE;
 | 
						|
    AutoPtr &operator =(const AutoPtr &other) KE_DELETE;
 | 
						|
};
 | 
						|
 | 
						|
// Wrapper that automatically deletes its contents. The pointer can be taken
 | 
						|
// to avoid destruction.
 | 
						|
template <typename T>
 | 
						|
class AutoArray
 | 
						|
{
 | 
						|
    T *t_;
 | 
						|
 | 
						|
  public:
 | 
						|
    AutoArray()
 | 
						|
      : t_(NULL)
 | 
						|
    {
 | 
						|
    }
 | 
						|
    explicit AutoArray(T *t)
 | 
						|
      : t_(t)
 | 
						|
    {
 | 
						|
    }
 | 
						|
    ~AutoArray() {
 | 
						|
        delete [] t_;
 | 
						|
    }
 | 
						|
    T *take() {
 | 
						|
        return ReturnAndVoid(t_);
 | 
						|
    }
 | 
						|
    T *operator *() const {
 | 
						|
        return t_;
 | 
						|
    }
 | 
						|
    T &operator [](size_t index) {
 | 
						|
      return t_[index];
 | 
						|
    }
 | 
						|
    const T &operator [](size_t index) const {
 | 
						|
      return t_[index];
 | 
						|
    }
 | 
						|
    operator T *() const {
 | 
						|
        return t_;
 | 
						|
    }
 | 
						|
    void operator =(T *t) {
 | 
						|
        delete [] t_;
 | 
						|
        t_ = t;
 | 
						|
    }
 | 
						|
    bool operator !() const {
 | 
						|
        return !t_;
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
static inline size_t
 | 
						|
Log2(size_t number)
 | 
						|
{
 | 
						|
    assert(number != 0);
 | 
						|
 | 
						|
#if defined _MSC_VER
 | 
						|
    unsigned long rval;
 | 
						|
# ifdef _M_IX86
 | 
						|
    _BitScanReverse(&rval, number);
 | 
						|
# elif _M_X64
 | 
						|
    _BitScanReverse64(&rval, number);
 | 
						|
# endif
 | 
						|
    return rval;
 | 
						|
#elif defined __GNUC__
 | 
						|
    return 31 - __builtin_clz(number);
 | 
						|
#else
 | 
						|
    size_t bit;
 | 
						|
    asm("bsr %1, %0\n"
 | 
						|
        : "=r" (bit)
 | 
						|
        : "rm" (number));
 | 
						|
    return bit;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
static inline size_t
 | 
						|
FindRightmostBit(size_t number)
 | 
						|
{
 | 
						|
    assert(number != 0);
 | 
						|
 | 
						|
#if defined _MSC_VER
 | 
						|
    unsigned long rval;
 | 
						|
# ifdef _M_IX86
 | 
						|
    _BitScanForward(&rval, number);
 | 
						|
# elif _M_X64
 | 
						|
    _BitScanForward64(&rval, number);
 | 
						|
# endif
 | 
						|
    return rval;
 | 
						|
#elif defined __GNUC__
 | 
						|
    return __builtin_ctz(number);
 | 
						|
#else
 | 
						|
    size_t bit;
 | 
						|
    asm("bsf %1, %0\n"
 | 
						|
        : "=r" (bit)
 | 
						|
        : "rm" (number));
 | 
						|
    return bit;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
static inline bool
 | 
						|
IsPowerOfTwo(size_t value)
 | 
						|
{
 | 
						|
    if (value == 0)
 | 
						|
        return false;
 | 
						|
    return !(value & (value - 1));
 | 
						|
}
 | 
						|
 | 
						|
static inline size_t
 | 
						|
Align(size_t count, size_t alignment)
 | 
						|
{
 | 
						|
    assert(IsPowerOfTwo(alignment));
 | 
						|
    return count + (alignment - (count % alignment)) % alignment;
 | 
						|
}
 | 
						|
 | 
						|
static inline bool
 | 
						|
IsUint32AddSafe(unsigned a, unsigned b)
 | 
						|
{
 | 
						|
    if (!a || !b)
 | 
						|
        return true;
 | 
						|
    size_t log2_a = Log2(a);
 | 
						|
    size_t log2_b = Log2(b);
 | 
						|
    return (log2_a < sizeof(unsigned) * 8) &&
 | 
						|
           (log2_b < sizeof(unsigned) * 8);
 | 
						|
}
 | 
						|
 | 
						|
static inline bool
 | 
						|
IsUintPtrAddSafe(size_t a, size_t b)
 | 
						|
{
 | 
						|
    if (!a || !b)
 | 
						|
        return true;
 | 
						|
    size_t log2_a = Log2(a);
 | 
						|
    size_t log2_b = Log2(b);
 | 
						|
    return (log2_a < sizeof(size_t) * 8) &&
 | 
						|
           (log2_b < sizeof(size_t) * 8);
 | 
						|
}
 | 
						|
 | 
						|
static inline bool
 | 
						|
IsUint32MultiplySafe(unsigned a, unsigned b)
 | 
						|
{
 | 
						|
    if (a <= 1 || b <= 1)
 | 
						|
        return true;
 | 
						|
 | 
						|
    size_t log2_a = Log2(a);
 | 
						|
    size_t log2_b = Log2(b);
 | 
						|
    return log2_a + log2_b <= sizeof(unsigned) * 8;
 | 
						|
}
 | 
						|
 | 
						|
static inline bool
 | 
						|
IsUintPtrMultiplySafe(size_t a, size_t b)
 | 
						|
{
 | 
						|
    if (a <= 1 || b <= 1)
 | 
						|
        return true;
 | 
						|
 | 
						|
    size_t log2_a = Log2(a);
 | 
						|
    size_t log2_b = Log2(b);
 | 
						|
    return log2_a + log2_b <= sizeof(size_t) * 8;
 | 
						|
}
 | 
						|
 | 
						|
#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
 | 
						|
#define STATIC_ASSERT(cond) extern int static_assert_f(int a[(cond) ? 1 : -1])
 | 
						|
 | 
						|
#define IS_ALIGNED(addr, alignment)    (!(uintptr_t(addr) & ((alignment) - 1)))
 | 
						|
 | 
						|
template <typename T>
 | 
						|
static inline bool
 | 
						|
IsAligned(T addr, size_t alignment)
 | 
						|
{
 | 
						|
    assert(IsPowerOfTwo(alignment));
 | 
						|
    return !(uintptr_t(addr) & (alignment - 1));
 | 
						|
}
 | 
						|
 | 
						|
static inline Address
 | 
						|
AlignedBase(Address addr, size_t alignment)
 | 
						|
{
 | 
						|
    assert(IsPowerOfTwo(alignment));
 | 
						|
    return Address(uintptr_t(addr) & ~(alignment - 1));
 | 
						|
}
 | 
						|
 | 
						|
template <typename T> static inline T
 | 
						|
Min(const T &t1, const T &t2)
 | 
						|
{
 | 
						|
    return t1 < t2 ? t1 : t2;
 | 
						|
}
 | 
						|
 | 
						|
template <typename T> static inline T
 | 
						|
Max(const T &t1, const T &t2)
 | 
						|
{
 | 
						|
    return t1 > t2 ? t1 : t2;
 | 
						|
}
 | 
						|
 | 
						|
template <typename T>
 | 
						|
class StorageBuffer
 | 
						|
{
 | 
						|
 public:
 | 
						|
  T *address() {
 | 
						|
    return reinterpret_cast<T *>(buffer_);
 | 
						|
  }
 | 
						|
  const T *address() const {
 | 
						|
    return reinterpret_cast<const T *>(buffer_);
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  union {
 | 
						|
    char buffer_[sizeof(T)];
 | 
						|
    uint64_t aligned_;
 | 
						|
  };
 | 
						|
};
 | 
						|
 | 
						|
template <typename T>
 | 
						|
class SaveAndSet
 | 
						|
{
 | 
						|
 public:
 | 
						|
  SaveAndSet(T *location, const T &value)
 | 
						|
   : location_(location),
 | 
						|
     old_(*location)
 | 
						|
  {
 | 
						|
    *location_ = value;
 | 
						|
  }
 | 
						|
  ~SaveAndSet() {
 | 
						|
    *location_ = old_;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  T *location_;
 | 
						|
  T old_;
 | 
						|
};
 | 
						|
 | 
						|
template <typename T>
 | 
						|
class StackLinked
 | 
						|
{
 | 
						|
 public:
 | 
						|
  StackLinked<T>(T **prevp)
 | 
						|
   : prevp_(prevp),
 | 
						|
     prev_(*prevp)
 | 
						|
  {
 | 
						|
    *prevp_ = static_cast<T *>(this);
 | 
						|
  }
 | 
						|
  virtual ~StackLinked() {
 | 
						|
    assert(*prevp_ == this);
 | 
						|
    *prevp_ = prev_;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  T **prevp_;
 | 
						|
  T *prev_;
 | 
						|
};
 | 
						|
 | 
						|
#if __cplusplus >= 201103L
 | 
						|
# define KE_CXX11
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(KE_CXX11)
 | 
						|
# define KE_DELETE = delete
 | 
						|
# define KE_OVERRIDE override
 | 
						|
#else
 | 
						|
# define KE_DELETE
 | 
						|
# define KE_OVERRIDE
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(_MSC_VER)
 | 
						|
# define KE_SIZET_FMT           "%Iu"
 | 
						|
# define KE_I64_FMT             "%I64d"
 | 
						|
# define KE_U64_FMT             "%I64u"
 | 
						|
#elif defined(__GNUC__)
 | 
						|
# define KE_SIZET_FMT           "%zu"
 | 
						|
# define KE_I64_FMT             "%lld"
 | 
						|
# define KE_U64_FMT             "%llu"
 | 
						|
#else
 | 
						|
# error "Implement format specifier string"
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(__GNUC__)
 | 
						|
# define KE_CRITICAL_LIKELY(x)  __builtin_expect(!!(x), 1)
 | 
						|
#else
 | 
						|
# define KE_CRITICAL_LIKELY(x)  x
 | 
						|
#endif
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#endif // _include_amtl_utility_h_
 |