Sync AMTL.

This commit is contained in:
Arkshine 2014-07-03 11:26:50 +02:00
parent 006e6e967a
commit de73007922
10 changed files with 403 additions and 71 deletions

View File

@ -93,7 +93,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;PAWN_CELL_SIZE=32;ASM32;JIT;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;PAWN_CELL_SIZE=32;ASM32;JIT;_CRT_SECURE_NO_DEPRECATE;HAVE_STDINT_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
@ -144,7 +144,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;JIT;ASM32;PAWN_CELL_SIZE=32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;JIT;ASM32;PAWN_CELL_SIZE=32;_CRT_SECURE_NO_DEPRECATE;HAVE_STDINT_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>

View File

@ -3,6 +3,10 @@ import os.path
binary = AMXX.MetaModule(builder, 'hamsandwich')
binary.compiler.defines += [
'HAVE_STDINT_H',
]
binary.sources = [
'sdk/amxxmodule.cpp',
'amxx_api.cpp',

View File

@ -0,0 +1,99 @@
// vim: set sts=8 ts=2 sw=2 tw=99 et:
//
// Copyright (C) 2013-2014, 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_fixedarray_h_
#define _include_amtl_fixedarray_h_
#include <am-utility.h>
#include <am-allocator-policies.h>
#include <am-moveable.h>
namespace ke {
template <typename T, typename AllocPolicy = SystemAllocatorPolicy>
class FixedArray : public AllocPolicy
{
public:
FixedArray(size_t length, AllocPolicy = AllocPolicy()) {
length_ = length;
data_ = (T *)this->malloc(sizeof(T) * length_);
if (!data_)
return;
for (size_t i = 0; i < length_; i++)
new (&data_[i]) T();
}
~FixedArray() {
for (size_t i = 0; i < length_; i++)
data_[i].~T();
this->free(data_);
}
// This call may be skipped if the allocator policy is infallible.
bool initialize() {
return length_ == 0 || !!data_;
}
size_t length() const {
return length_;
}
T &operator [](size_t index) {
return at(index);
}
const T &operator [](size_t index) const {
return at(index);
}
T &at(size_t index) {
assert(index < length());
return data_[index];
}
const T &at(size_t index) const {
assert(index < length());
return data_[index];
}
void set(size_t index, const T &t) {
assert(index < length());
data_[index] = t;
}
void set(size_t index, ke::Moveable<T> t) {
assert(index < length());
data_[index] = t;
}
private:
FixedArray(const FixedArray &other) KE_DELETE;
FixedArray &operator =(const FixedArray &other) KE_DELETE;
private:
size_t length_;
T *data_;
};
} // namespace ke
#endif // _include_amtl_fixedarray_h_

View File

@ -138,19 +138,24 @@ class HashMap : public AllocPolicy
// The map must not have been mutated in between findForAdd() and add().
// The Insert object is still valid after add() returns, however.
bool add(Insert &i, const K &key, const V &value) {
return table_.add(i, Entry(key, value));
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, Moveable<K> key, const V &value) {
return table_.add(i, Entry(key, value));
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, const K &key, Moveable<V> value) {
return table_.add(i, Entry(key, value));
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, Moveable<K> key, Moveable<V> value) {
return table_.add(i, Entry(key, value));
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, Moveable<K> key) {
return table_.add(i, Entry(key, V()));
Entry entry(key, V());
return table_.add(i, ke::Move(entry));
}
// This can be used to avoid compiler constructed temporaries, since AMTL

View File

@ -35,12 +35,15 @@
namespace ke {
// See the comment above Refcounted<T> for more information. This class is
// identical, except changing the reference count is guaranteed to be atomic
// with respect to other threads changing the reference count.
template <typename T>
class RefcountedThreadsafe
{
public:
RefcountedThreadsafe()
: refcount_(1)
: refcount_(0)
{
}

View File

@ -37,18 +37,28 @@ namespace ke {
template <typename T> class Ref;
// Holds a refcounted T without addrefing it. This is similar to PassRef<>
// below, but is intended only for freshly allocated objects which start
// with reference count 1, and we don't want to add an extra ref just by
// assigning to PassRef<> or Ref<>.
// Objects in AMTL inheriting from Refcounted will have an initial refcount
// of 0. However, in some systems (such as COM), the initial refcount is 1,
// or functions may return raw pointers that have been AddRef'd. In these
// cases it would be a mistake to use Ref<> or PassRef<>, since the object
// would leak an extra reference.
//
// This container holds a refcounted object without addrefing it. This is
// intended only for interacting with functions which return an object that
// has been manually AddRef'd. Note that this will perform a Release(), so
// so it is necessary to assign it to retain the object.
template <typename T>
class Newborn
class AlreadyRefed
{
public:
Newborn(T *t)
AlreadyRefed(T *t)
: thing_(t)
{
}
~AlreadyRefed() {
if (thing_)
thing_->Release();
}
T *release() const {
return ReturnAndVoid(thing_);
@ -59,10 +69,10 @@ class Newborn
};
template <typename T>
static inline Newborn<T>
NoAddRef(T *t)
static inline AlreadyRefed<T>
AdoptRef(T *t)
{
return Newborn<T>(t);
return AlreadyRefed<T>(t);
}
// When returning a value, we'd rather not be needlessly changing the refcount,
@ -81,7 +91,14 @@ class PassRef
{
}
PassRef(const Newborn<T *> &other)
PassRef(const AlreadyRefed<T *> &other)
: thing_(other.release())
{
// Don't addref, newborn means already addref'd.
}
template <typename S>
PassRef(const AlreadyRefed<S *> &other)
: thing_(other.release())
{
// Don't addref, newborn means already addref'd.
@ -134,7 +151,7 @@ class PassRef
private:
// Disallowed operators.
PassRef &operator =(T *other);
PassRef &operator =(Newborn<T> &other);
PassRef &operator =(AlreadyRefed<T> &other);
void AddRef() {
if (thing_)
@ -149,13 +166,18 @@ class PassRef
mutable T *thing_;
};
// Classes which are refcounted should inherit from this.
// Classes which are refcounted should inherit from this. Note that reference
// counts start at 0 in AMTL, rather than 1. This avoids the complexity of
// having to adopt the initial ref upon allocation. However, this also means
// invoking Release() on a newly allocated object is illegal. Newborn objects
// must either be assigned to a Ref or PassRef (NOT an AdoptRef/AlreadyRefed),
// or must be deleted using |delete|.
template <typename T>
class Refcounted
{
public:
Refcounted()
: refcount_(1)
: refcount_(0)
{
}
@ -217,7 +239,12 @@ class Ref
: thing_(other.release())
{
}
Ref(const Newborn<T> &other)
Ref(const AlreadyRefed<T> &other)
: thing_(other.release())
{
}
template <typename S>
Ref(const AlreadyRefed<S> &other)
: thing_(other.release())
{
}
@ -255,7 +282,7 @@ class Ref
}
template <typename S>
Ref &operator =(const Newborn<S> &other) {
Ref &operator =(const AlreadyRefed<S> &other) {
Release();
thing_ = other.release();
return *this;

View File

@ -56,7 +56,7 @@ class AString
if (other.length_)
set(other.chars_, other.length_);
else
length_ = 0;
length_ = 0;
}
AString(Moveable<AString> other)
: chars_(other->chars_.take()),
@ -106,17 +106,29 @@ class AString
return chars()[index];
}
void setVoid() {
chars_ = NULL;
length_ = kInvalidLength;
}
bool isVoid() const {
return length_ == kInvalidLength;
}
size_t length() const {
assert(!isVoid());
return length_;
}
const char *chars() const {
if (!chars_)
return "";
return isVoid() ? NULL : "";
return chars_;
}
private:
static const size_t kInvalidLength = (size_t)-1;
void set(const char *str, size_t length) {
chars_ = new char[length + 1];
length_ = length;

View File

@ -0,0 +1,175 @@
// vim: set sts=2 ts=8 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_thread_local_h_
#define _include_amtl_thread_local_h_
#include <am-thread-utils.h>
namespace ke {
// Stores a per-thread value. In single-threaded mode (KE_SINGLE_THREADED),
// this is a no-op container wrapper.
//
// T must be castable to uintptr_t.
//
// When assigning to a ThreadLocal<T>, the assigment will automatically attempt
// to allocate thread-local storage from the operating system. If it fails, it
// will abort the program. If this is undesirable, you may call allocate()
// up-front and handle the error case manually.
//
// The number of thread local slots available to processes is limited (on
// Linux, it is generally 1024). It is best to use ThreadLocal sparingly to
// play nicely with other libraries.
//
// ThreadLocal will free the underlying thread-local storage slot in its
// destructor, but it is not an AutoPtr. It does not delete pointers. Since
// one thread's value is only observable from that thread, make sure to free
// the contained resource (if necessary) before the thread exits.
template <typename T>
class ThreadLocal
{
public:
void operator =(const T &other) {
set(other);
}
T operator *() const {
return get();
}
T operator ->() const {
return get();
}
bool operator !() const {
return !get();
}
bool operator ==(const T &other) const {
return get() == other;
}
bool operator !=(const T &other) const {
return get() != other;
}
private:
ThreadLocal(const ThreadLocal &other) KE_DELETE;
ThreadLocal &operator =(const ThreadLocal &other) KE_DELETE;
#if !defined(KE_SINGLE_THREADED)
private:
int allocated_;
public:
ThreadLocal() {
allocated_ = 0;
}
T get() const {
if (!allocated_)
return T();
return internalGet();
}
void set(const T &t) {
if (!allocated_ && !allocate()) {
fprintf(stderr, "could not allocate thread-local storage\n");
abort();
}
internalSet(t);
}
# if defined(_MSC_VER)
~ThreadLocal() {
if (allocated_)
TlsFree(key_);
}
private:
T internalGet() const {
return reinterpret_cast<T>(TlsGetValue(key_));
}
void internalSet(const T &t) {
TlsSetValue(key_, reinterpret_cast<LPVOID>(t));
}
bool allocate() {
if (InterlockedCompareExchange(&allocated_, 1, 0) == 1)
return true;
key_ = TlsAlloc();
return key_ != TLS_OUT_OF_INDEXES;
}
DWORD key_;
# else
public:
~ThreadLocal() {
if (allocated_)
pthread_key_delete(key_);
}
bool allocate() {
if (!__sync_bool_compare_and_swap(&allocated_, 0, 1))
return true;
return pthread_key_create(&key_, NULL) == 0;
}
private:
T internalGet() const {
return (T)reinterpret_cast<uintptr_t>(pthread_getspecific(key_));
}
void internalSet(const T &t) {
pthread_setspecific(key_, reinterpret_cast<void *>(t));
}
pthread_key_t key_;
# endif // !_MSC_VER
#else // KE_SINGLE_THREADED
public:
ThreadLocal() {
t_ = T();
}
bool allocate() {
return true;
}
T get() const {
return t_;
}
void set(const T &t) {
t_ = t;
}
private:
T t_;
#endif
};
} // namespace ke
#endif // _include_amtl_thread_local_h_

View File

@ -33,11 +33,10 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
//#include <stdint.h>
#include <stdint.h>
#if defined(_MSC_VER)
# include <intrin.h>
#endif
#include <am-moveable.h>
#define KE_32BIT
@ -53,7 +52,7 @@ static const size_t kKB = 1024;
static const size_t kMB = 1024 * kKB;
static const size_t kGB = 1024 * kMB;
typedef unsigned char * Address;
typedef uint8_t * Address;
template <typename T> T
ReturnAndVoid(T &t)
@ -63,18 +62,6 @@ ReturnAndVoid(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>
@ -87,15 +74,10 @@ class AutoPtr
: t_(NULL)
{
}
AutoPtr(T *t)
explicit AutoPtr(T *t)
: t_(t)
{
}
AutoPtr(Moveable<AutoPtr<T> > other)
{
t_ = other->t_;
other->t_ = NULL;
}
~AutoPtr() {
delete t_;
}
@ -111,24 +93,13 @@ class AutoPtr
operator T *() const {
return t_;
}
T *operator =(T *t) {
void 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
@ -327,6 +298,37 @@ class StorageBuffer
};
};
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 __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"
#elif defined(__GNUC__)

View File

@ -86,22 +86,14 @@ class Vector : public AllocPolicy
}
// Shift all elements including |at| up by one, and insert |item| at the
// given position. If |at| is one greater than the last usable index,
// i.e. |at == length()|, then this is the same as append(). No other
// invalid indexes are allowed.
//
// This is a linear-time operation.
// given position. This is a linear-time operation.
bool insert(size_t at, const T &item) {
if (at == length())
return append(item);
if (!moveUp(at))
return false;
new (&data_[at]) T(item);
return true;
}
bool insert(size_t at, Moveable<T> item) {
if (at == length())
return append(item);
if (!moveUp(at))
return false;
new (&data_[at]) T(item);
@ -112,7 +104,7 @@ class Vector : public AllocPolicy
// element. This is a linear-time operation.
void remove(size_t at) {
for (size_t i = at; i < length() - 1; i++)
data_[i] = Moveable<T>(data_[i + 1]);
data_[i] = T(Moveable<T>(data_[i + 1]));
pop();
}
@ -167,6 +159,14 @@ class Vector : public AllocPolicy
return growIfNeeded(desired - length());
}
Vector &operator =(Moveable<Vector<T, AllocPolicy> > other) {
data_ = other->data_;
nitems_ = other->nitems_;
maxsize_ = other->maxsize_;
other->reset();
return *this;
}
private:
// These are disallowed because they basically violate the failure handling
// model for AllocPolicies and are also likely to have abysmal performance.
@ -186,10 +186,15 @@ class Vector : public AllocPolicy
}
bool moveUp(size_t at) {
assert(at < nitems_);
if (!append(Moveable<T>(data_[nitems_ - 1])))
// Note: we don't use append() here. Passing an element as a Moveable into
// insert() or append() can break, since the underlying storage could be
// reallocated, invalidating the Moveable reference. Instead, we inline
// the logic to append() to ensure growIfNeeded occurs before any
// references are taken.
if (!growIfNeeded(1))
return false;
new (&data_[nitems_]) T(Moveable<T>(data_[nitems_ - 1]));
nitems_++;
for (size_t i = nitems_ - 2; i > at; i--)
data_[i] = Moveable<T>(data_[i - 1]);
return true;