This patch uses SmxBuilder from spcomp2 to replace the old assemble() pipeline. Instead of generating into an old AMX structure, and then decoding that into SMX, we now directly generate into SMX. This greatly simplifies code generation and smx building.
378 lines
7.8 KiB
C++
378 lines
7.8 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>
|
|
#include <math.h>
|
|
#include <float.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)
|
|
{
|
|
}
|
|
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);
|
|
|
|
#ifdef _MSC_VER
|
|
unsigned long rval;
|
|
# ifdef _M_IX86
|
|
_BitScanReverse(&rval, number);
|
|
# elif _M_X64
|
|
_BitScanReverse64(&rval, number);
|
|
# endif
|
|
return rval;
|
|
#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);
|
|
|
|
#ifdef _MSC_VER
|
|
unsigned long rval;
|
|
# ifdef _M_IX86
|
|
_BitScanForward(&rval, number);
|
|
# elif _M_X64
|
|
_BitScanForward64(&rval, number);
|
|
# endif
|
|
return rval;
|
|
#else
|
|
size_t bit;
|
|
asm("bsf %1, %0\n"
|
|
: "=r" (bit)
|
|
: "rm" (number));
|
|
return bit;
|
|
#endif
|
|
}
|
|
|
|
static inline bool
|
|
IsNaN(double v)
|
|
{
|
|
#ifdef _MSC_VER
|
|
return !!_isnan(v);
|
|
#else
|
|
return isnan(v);
|
|
#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_;
|
|
};
|
|
|
|
#if defined(_MSC_VER)
|
|
# define KE_SIZET_FMT "%Iu"
|
|
#elif defined(__GNUC__)
|
|
# define KE_SIZET_FMT "%zu"
|
|
#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_
|