commit
6d283a1599
|
@ -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>
|
||||
|
|
|
@ -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',
|
||||
|
|
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 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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
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 <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__)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user