Sync AMTL.
This commit is contained in:
parent
006e6e967a
commit
de73007922
|
@ -93,7 +93,7 @@
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<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>
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
<StructMemberAlignment>4Bytes</StructMemberAlignment>
|
<StructMemberAlignment>4Bytes</StructMemberAlignment>
|
||||||
|
@ -144,7 +144,7 @@
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
<OmitFramePointers>true</OmitFramePointers>
|
<OmitFramePointers>true</OmitFramePointers>
|
||||||
<AdditionalIncludeDirectories>..\;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<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>
|
<IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
|
||||||
<StringPooling>true</StringPooling>
|
<StringPooling>true</StringPooling>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
|
|
@ -3,6 +3,10 @@ import os.path
|
||||||
|
|
||||||
binary = AMXX.MetaModule(builder, 'hamsandwich')
|
binary = AMXX.MetaModule(builder, 'hamsandwich')
|
||||||
|
|
||||||
|
binary.compiler.defines += [
|
||||||
|
'HAVE_STDINT_H',
|
||||||
|
]
|
||||||
|
|
||||||
binary.sources = [
|
binary.sources = [
|
||||||
'sdk/amxxmodule.cpp',
|
'sdk/amxxmodule.cpp',
|
||||||
'amxx_api.cpp',
|
'amxx_api.cpp',
|
||||||
|
|
99
public/amtl/am-fixedarray.h
Normal file
99
public/amtl/am-fixedarray.h
Normal 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_
|
|
@ -138,19 +138,24 @@ class HashMap : public AllocPolicy
|
||||||
// The map must not have been mutated in between findForAdd() and add().
|
// The map must not have been mutated in between findForAdd() and add().
|
||||||
// The Insert object is still valid after add() returns, however.
|
// The Insert object is still valid after add() returns, however.
|
||||||
bool add(Insert &i, const K &key, const V &value) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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
|
// This can be used to avoid compiler constructed temporaries, since AMTL
|
||||||
|
|
|
@ -35,12 +35,15 @@
|
||||||
|
|
||||||
namespace ke {
|
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>
|
template <typename T>
|
||||||
class RefcountedThreadsafe
|
class RefcountedThreadsafe
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RefcountedThreadsafe()
|
RefcountedThreadsafe()
|
||||||
: refcount_(1)
|
: refcount_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,18 +37,28 @@ namespace ke {
|
||||||
|
|
||||||
template <typename T> class Ref;
|
template <typename T> class Ref;
|
||||||
|
|
||||||
// Holds a refcounted T without addrefing it. This is similar to PassRef<>
|
// Objects in AMTL inheriting from Refcounted will have an initial refcount
|
||||||
// below, but is intended only for freshly allocated objects which start
|
// of 0. However, in some systems (such as COM), the initial refcount is 1,
|
||||||
// with reference count 1, and we don't want to add an extra ref just by
|
// or functions may return raw pointers that have been AddRef'd. In these
|
||||||
// assigning to PassRef<> or Ref<>.
|
// 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>
|
template <typename T>
|
||||||
class Newborn
|
class AlreadyRefed
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Newborn(T *t)
|
AlreadyRefed(T *t)
|
||||||
: thing_(t)
|
: thing_(t)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
~AlreadyRefed() {
|
||||||
|
if (thing_)
|
||||||
|
thing_->Release();
|
||||||
|
}
|
||||||
|
|
||||||
T *release() const {
|
T *release() const {
|
||||||
return ReturnAndVoid(thing_);
|
return ReturnAndVoid(thing_);
|
||||||
|
@ -59,10 +69,10 @@ class Newborn
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline Newborn<T>
|
static inline AlreadyRefed<T>
|
||||||
NoAddRef(T *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,
|
// 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())
|
: thing_(other.release())
|
||||||
{
|
{
|
||||||
// Don't addref, newborn means already addref'd.
|
// Don't addref, newborn means already addref'd.
|
||||||
|
@ -134,7 +151,7 @@ class PassRef
|
||||||
private:
|
private:
|
||||||
// Disallowed operators.
|
// Disallowed operators.
|
||||||
PassRef &operator =(T *other);
|
PassRef &operator =(T *other);
|
||||||
PassRef &operator =(Newborn<T> &other);
|
PassRef &operator =(AlreadyRefed<T> &other);
|
||||||
|
|
||||||
void AddRef() {
|
void AddRef() {
|
||||||
if (thing_)
|
if (thing_)
|
||||||
|
@ -149,13 +166,18 @@ class PassRef
|
||||||
mutable T *thing_;
|
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>
|
template <typename T>
|
||||||
class Refcounted
|
class Refcounted
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Refcounted()
|
Refcounted()
|
||||||
: refcount_(1)
|
: refcount_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +239,12 @@ class Ref
|
||||||
: thing_(other.release())
|
: 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())
|
: thing_(other.release())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -255,7 +282,7 @@ class Ref
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
Ref &operator =(const Newborn<S> &other) {
|
Ref &operator =(const AlreadyRefed<S> &other) {
|
||||||
Release();
|
Release();
|
||||||
thing_ = other.release();
|
thing_ = other.release();
|
||||||
return *this;
|
return *this;
|
||||||
|
|
|
@ -56,7 +56,7 @@ class AString
|
||||||
if (other.length_)
|
if (other.length_)
|
||||||
set(other.chars_, other.length_);
|
set(other.chars_, other.length_);
|
||||||
else
|
else
|
||||||
length_ = 0;
|
length_ = 0;
|
||||||
}
|
}
|
||||||
AString(Moveable<AString> other)
|
AString(Moveable<AString> other)
|
||||||
: chars_(other->chars_.take()),
|
: chars_(other->chars_.take()),
|
||||||
|
@ -106,17 +106,29 @@ class AString
|
||||||
return chars()[index];
|
return chars()[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setVoid() {
|
||||||
|
chars_ = NULL;
|
||||||
|
length_ = kInvalidLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isVoid() const {
|
||||||
|
return length_ == kInvalidLength;
|
||||||
|
}
|
||||||
|
|
||||||
size_t length() const {
|
size_t length() const {
|
||||||
|
assert(!isVoid());
|
||||||
return length_;
|
return length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *chars() const {
|
const char *chars() const {
|
||||||
if (!chars_)
|
if (!chars_)
|
||||||
return "";
|
return isVoid() ? NULL : "";
|
||||||
return chars_;
|
return chars_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const size_t kInvalidLength = (size_t)-1;
|
||||||
|
|
||||||
void set(const char *str, size_t length) {
|
void set(const char *str, size_t length) {
|
||||||
chars_ = new char[length + 1];
|
chars_ = new char[length + 1];
|
||||||
length_ = length;
|
length_ = length;
|
||||||
|
|
175
public/amtl/am-threadlocal.h
Normal file
175
public/amtl/am-threadlocal.h
Normal 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_
|
|
@ -33,11 +33,10 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
//#include <stdint.h>
|
#include <stdint.h>
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# include <intrin.h>
|
# include <intrin.h>
|
||||||
#endif
|
#endif
|
||||||
#include <am-moveable.h>
|
|
||||||
|
|
||||||
#define KE_32BIT
|
#define KE_32BIT
|
||||||
|
|
||||||
|
@ -53,7 +52,7 @@ static const size_t kKB = 1024;
|
||||||
static const size_t kMB = 1024 * kKB;
|
static const size_t kMB = 1024 * kKB;
|
||||||
static const size_t kGB = 1024 * kMB;
|
static const size_t kGB = 1024 * kMB;
|
||||||
|
|
||||||
typedef unsigned char * Address;
|
typedef uint8_t * Address;
|
||||||
|
|
||||||
template <typename T> T
|
template <typename T> T
|
||||||
ReturnAndVoid(T &t)
|
ReturnAndVoid(T &t)
|
||||||
|
@ -63,18 +62,6 @@ ReturnAndVoid(T &t)
|
||||||
return saved;
|
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
|
// Wrapper that automatically deletes its contents. The pointer can be taken
|
||||||
// to avoid destruction.
|
// to avoid destruction.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -87,15 +74,10 @@ class AutoPtr
|
||||||
: t_(NULL)
|
: t_(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
AutoPtr(T *t)
|
explicit AutoPtr(T *t)
|
||||||
: t_(t)
|
: t_(t)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
AutoPtr(Moveable<AutoPtr<T> > other)
|
|
||||||
{
|
|
||||||
t_ = other->t_;
|
|
||||||
other->t_ = NULL;
|
|
||||||
}
|
|
||||||
~AutoPtr() {
|
~AutoPtr() {
|
||||||
delete t_;
|
delete t_;
|
||||||
}
|
}
|
||||||
|
@ -111,24 +93,13 @@ class AutoPtr
|
||||||
operator T *() const {
|
operator T *() const {
|
||||||
return t_;
|
return t_;
|
||||||
}
|
}
|
||||||
T *operator =(T *t) {
|
void operator =(T *t) {
|
||||||
delete t_;
|
delete t_;
|
||||||
t_ = t;
|
t_ = t;
|
||||||
return t_;
|
|
||||||
}
|
|
||||||
T *operator =(Moveable<AutoPtr<T> > other) {
|
|
||||||
delete t_;
|
|
||||||
t_ = other->t_;
|
|
||||||
other->t_ = NULL;
|
|
||||||
return t_;
|
|
||||||
}
|
}
|
||||||
bool operator !() const {
|
bool operator !() const {
|
||||||
return !t_;
|
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
|
// 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)
|
#if defined(_MSC_VER)
|
||||||
# define KE_SIZET_FMT "%Iu"
|
# define KE_SIZET_FMT "%Iu"
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
|
|
|
@ -86,22 +86,14 @@ class Vector : public AllocPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift all elements including |at| up by one, and insert |item| at the
|
// 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,
|
// given position. This is a linear-time operation.
|
||||||
// i.e. |at == length()|, then this is the same as append(). No other
|
|
||||||
// invalid indexes are allowed.
|
|
||||||
//
|
|
||||||
// This is a linear-time operation.
|
|
||||||
bool insert(size_t at, const T &item) {
|
bool insert(size_t at, const T &item) {
|
||||||
if (at == length())
|
|
||||||
return append(item);
|
|
||||||
if (!moveUp(at))
|
if (!moveUp(at))
|
||||||
return false;
|
return false;
|
||||||
new (&data_[at]) T(item);
|
new (&data_[at]) T(item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool insert(size_t at, Moveable<T> item) {
|
bool insert(size_t at, Moveable<T> item) {
|
||||||
if (at == length())
|
|
||||||
return append(item);
|
|
||||||
if (!moveUp(at))
|
if (!moveUp(at))
|
||||||
return false;
|
return false;
|
||||||
new (&data_[at]) T(item);
|
new (&data_[at]) T(item);
|
||||||
|
@ -112,7 +104,7 @@ class Vector : public AllocPolicy
|
||||||
// element. This is a linear-time operation.
|
// element. This is a linear-time operation.
|
||||||
void remove(size_t at) {
|
void remove(size_t at) {
|
||||||
for (size_t i = at; i < length() - 1; i++)
|
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();
|
pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +159,14 @@ class Vector : public AllocPolicy
|
||||||
return growIfNeeded(desired - length());
|
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:
|
private:
|
||||||
// These are disallowed because they basically violate the failure handling
|
// These are disallowed because they basically violate the failure handling
|
||||||
// model for AllocPolicies and are also likely to have abysmal performance.
|
// model for AllocPolicies and are also likely to have abysmal performance.
|
||||||
|
@ -186,10 +186,15 @@ class Vector : public AllocPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
bool moveUp(size_t at) {
|
bool moveUp(size_t at) {
|
||||||
assert(at < nitems_);
|
// Note: we don't use append() here. Passing an element as a Moveable into
|
||||||
if (!append(Moveable<T>(data_[nitems_ - 1])))
|
// 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;
|
return false;
|
||||||
|
new (&data_[nitems_]) T(Moveable<T>(data_[nitems_ - 1]));
|
||||||
|
nitems_++;
|
||||||
for (size_t i = nitems_ - 2; i > at; i--)
|
for (size_t i = nitems_ - 2; i > at; i--)
|
||||||
data_[i] = Moveable<T>(data_[i - 1]);
|
data_[i] = Moveable<T>(data_[i - 1]);
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user