Sync AMTL.
This commit is contained in:
		| @@ -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; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user