C++11: Sync AMTL libraries from upstream

This commit is contained in:
Arkshine 2014-12-06 12:21:14 +01:00
parent 2bba5ce69a
commit 590e6b1258
24 changed files with 1464 additions and 363 deletions

View File

@ -0,0 +1,58 @@
// 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_algorithm_h_
#define _include_amtl_algorithm_h_
#include <am-moveable.h>
namespace ke {
template <typename T> static inline T
Min(const T &t1, const T &t2)
{
return t1 < t2 ? t1 : t2;
}
template <typename T> static inline T
Max(const T &t1, const T &t2)
{
return t1 > t2 ? t1 : t2;
}
template <typename T> static inline void
Swap(T &left, T &right)
{
T tmp(Move(left));
left = Move(right);
right = Move(tmp);
}
} // namespace ke
#endif // _include_amtl_algorithm_h_

View File

@ -0,0 +1,67 @@
// 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_bits_h_
#define _include_amtl_bits_h_
#include <am-algorithm.h>
namespace ke {
static inline bool
TryUint64Multiply(uint64_t left, uint64_t right, uint64_t *out)
{
uint64_t r = left * right;
if (r != 0 && ((r / left) != right))
return false;
*out = r;
return true;
}
static inline bool
TryUint32Add(uint32_t left, uint32_t right, uint32_t *out)
{
if (left + right < Max(left, right))
return false;
*out = left + right;
return true;
}
static inline bool
TryUint64Add(uint64_t left, uint64_t right, uint64_t *out)
{
if (left + right < Max(left, right))
return false;
*out = left + right;
return true;
}
} // namespace ke
#endif // _include_amtl_bits_h_

View File

@ -38,13 +38,69 @@ namespace ke {
extern "C" {
long __cdecl _InterlockedIncrement(long volatile *dest);
long __cdecl _InterlockedDecrement(long volatile *dest);
long __cdecl _InterlockedIncrement64(long long volatile *dest);
long __cdecl _InterlockedDecrement64(long long volatile *dest);
long long __cdecl _InterlockedIncrement64(long long volatile *dest);
long long __cdecl _InterlockedDecrement64(long long volatile *dest);
long __cdecl _InterlockedCompareExchange(long volatile *dest, long exchange, long comparand);
# if _MSC_VER > 1600 || (_MSC_VER == 1600 && !defined(_M_IX86))
void * __cdecl _InterlockedCompareExchangePointer(
void * volatile *Destination,
void * Exchange,
void * Comparand
);
#else
static inline void * _InterlockedCompareExchangePointer(
void * volatile *Destination,
void * Exchange,
void * Comparand)
{
return (void *)_InterlockedCompareExchange((long volatile *)Destination, (long)Exchange, (long)Comparand);
}
#endif
}
# pragma intrinsic(_InterlockedIncrement)
# pragma intrinsic(_InterlockedDecrement)
# pragma intrinsic(_InterlockedCompareExchange)
# if _MSC_VER > 1600 || (_MSC_VER == 1600 && !defined(_M_IX86))
# pragma intrinsic(_InterlockedCompareExchangePointer)
# endif
# if defined(_WIN64)
# pragma intrinsic(_InterlockedIncrement64)
# pragma intrinsic(_InterlockedDecrement64)
# endif
#endif
#if defined(__GNUC__)
# if defined(i386) || defined(__x86_64__)
# if defined(__clang__)
static inline void YieldProcessor() { asm("pause"); }
# else
# if KE_GCC_AT_LEAST(4, 7)
# define YieldProcessor() __builtin_ia32_pause()
# else
static inline void YieldProcessor() { asm("pause"); }
# endif
# endif
# else
# define YieldProcessor()
# endif
#elif defined(_MSC_VER)
# if !defined(YieldProcessor)
# define YieldProcessor _mm_pause
# endif
#endif
#if defined(_MSC_VER)
static inline void *
CompareAndSwapPtr(void *volatile *Destination, void *Exchange, void *Comparand)
{
return _InterlockedCompareExchangePointer(Destination, Exchange, Comparand);
}
#else
static inline void *
CompareAndSwapPtr(void *volatile *dest, void *newval, void *oldval)
{
return __sync_val_compare_and_swap(dest, oldval, newval);
}
#endif
template <size_t Width>
@ -104,13 +160,12 @@ struct AtomicOps<8>
#endif
};
class AtomicRefCount
class KE_LINK AtomicRefcount
{
typedef AtomicOps<sizeof(uintptr_t)> Ops;
public:
AtomicRefCount(uintptr_t value)
AtomicRefcount(uintptr_t value)
: value_(value)
{
}

213
public/amtl/am-cxx.h Normal file
View File

@ -0,0 +1,213 @@
// vim: set sts=8 ts=2 sw=2 tw=99 et:
//
// Copyright (C) 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_cxx_support_h_
#define _include_amtl_cxx_support_h_
#if defined(__clang__)
# if !(defined(__clang_major__) && defined(__clang_minor__))
# define KE_CLANG_MAJOR 1
# define KE_CLANG_MINOR __GNUC_MINOR__
# else
# if defined(__apple_build_version__) && clang_major__ > 3
// 4.0 => 3.1, 4.1 => 3.2
# if __clang_major__ == 4
# define KE_CLANG_MAJOR 3
# if __clang_minor__ == 0
# define KE_CLANG_MINOR 1
# else
# define KE_CLANG_MINOR 2
# endif
// 5.0 => 3.3, 5.1 => 3.4
# elif __clang_major__ == 5
# define KE_CLANG_MAJOR 3
# if __clang_minor__ == 0
# define KE_CLANG_MINOR 3
# else
# define KE_CLANG_MINOR 4
# endif
# elif __clang_major__ == 6
# define KE_CLANG_MAJOR 3
# define KE_CLANG_MINOR 5
# endif
# endif
# if !defined(KE_CLANG_MAJOR)
# define KE_CLANG_MAJOR __clang_major__
# endif
# if !defined(KE_CLANG_MINOR)
# define KE_CLANG_MINOR __clang_minor__
# endif
# endif
// Done with horrible clang version detection.
# define KE_CLANG_AT_LEAST(x, y) \
((__clang_major__ > (x)) || (__clang_major__ == x && __clang_minor__ >= y))
# if KE_CLANG_AT_LEAST(2, 9)
# define KE_CXX_HAS_RVAL_REFS 30
# define KE_CXX_HAS_DELETE
# define KE_CXX_HAS_STATIC_ASSERT
# define KE_CXX_HAS_DOUBLE_GT
# define KE_CXX_HAS_ENUM_CLASS
# endif
# if KE_CLANG_AT_LEAST(3, 0)
# define KE_CXX_HAS_OVERRIDE
# define KE_CXX_HAS_EXPLICIT_BOOL
# define KE_CXX_HAS_NULLPTR
# define KE_CXX_HAS_NOEXCEPT
# endif
# if KE_CLANG_AT_LEAST(3, 1)
# define KE_CXX_HAS_CONSTEXPR
# endif
#elif defined(__GNUC__)
# define KE_GCC_AT_LEAST(x, y) ((__GNUC__ > (x)) || (__GNUC__ == x && __GNUC_MINOR__ >= y))
# if KE_GCC_AT_LEAST(4, 3)
# define KE_CXX_HAS_RVAL_REFS 10
# define KE_CXX_HAS_STATIC_ASSERT
# define KE_CXX_HAS_DOUBLE_GT
# endif
# if KE_GCC_AT_LEAST(4, 4)
# define KE_CXX_HAS_DELETE
# define KE_CXX_HAS_ENUM_CLASS
# endif
# if KE_GCC_AT_LEAST(4, 5)
# define KE_CXX_HAS_EXPLICIT_BOOL
# undef KE_CXX_HAS_RVAL_REFS
# define KE_CXX_HAS_RVAL_REFS 21
# endif
# if KE_GCC_AT_LEAST(4, 6)
# define KE_CXX_HAS_NULLPTR
# define KE_CXX_HAS_NOEXCEPT
# define KE_CXX_HAS_CONSTEXPR
# undef KE_CXX_HAS_RVAL_REFS
# define KE_CXX_HAS_RVAL_REFS 30
# endif
# if KE_GCC_AT_LEAST(4, 7)
# define KE_CXX_HAS_OVERRIDE
# endif
#elif defined(_MSC_VER)
# if _MSC_VER >= 1600
# define KE_CXX_HAS_RVAL_REFS 20
# define KE_CXX_HAS_STATIC_ASSERT
# define KE_CXX_HAS_DOUBLE_GT
# define KE_CXX_HAS_NULLPTR
# endif
# if _MSC_VER >= 1700
# undef KE_CXX_HAS_RVAL_REFS
# define KE_CXX_HAS_RVAL_REFS 21
# define KE_CXX_HAS_OVERRIDE
# define KE_CXX_HAS_ENUM_CLASS
# endif
# if _MSC_VER >= 1800
# define KE_CXX_HAS_DELETE
# define KE_CXX_HAS_EXPLICIT_BOOL
# endif
# if _MSC_VER == 1800 && _MSC_FULL_VER == 180021114
# define KE_CXX_HAS_CONSTEXPR
# endif
#else
# error Unrecognized compiler.
#endif
// Done with compiler feature detection.
#if defined(KE_CXX_HAS_OVERRIDE)
# define KE_OVERRIDE override
#else
# define KE_OVERRIDE
#endif
#if defined(KE_CXX_HAS_DELETE)
# define KE_DELETE = delete
#else
# define KE_DELETE
#endif
#if defined(KE_CXX_HAS_NOEXCEPT)
# define KE_NOEXCEPT noexcept
#else
# define KE_NOEXCEPT
#endif
#if defined(KE_CXX_HAS_CONSTEXPR)
# define KE_CONSTEXPR constexpr
#else
# define KE_CONSTEXPR
#endif
#if defined(KE_CXX_HAS_STATIC_ASSERT)
# define KE_STATIC_ASSERT(cond) static_assert(cond, #cond)
#else
# define KE_STATIC_ASSERT(cond) extern int static_assert_f(int a[(cond) ? 1 : -1])
#endif
#if !defined(KE_CXX_HAS_RVAL_REFS) || KE_CXX_HAS_RVAL_REFS < 21
//# error AMTL requires rvalue reference 2.1 support (N2844+)
#endif
#if !defined(KE_CXX_HAS_DOUBLE_GT)
# error AMTL requires support for >> in template names
#endif
#if !defined(KE_CXX_HAS_NULLPTR)
# if defined(__GNUC__) && !defined(__clang__)
# define nullptr __null
# define KE_CXX_HAS_NULLPTR
# else
# error AMTL requires nullptr support
# endif
#endif
#define KE_DEFINE_ENUM_OPERATORS(EnumName) \
static inline EnumName operator |(const EnumName &left, const EnumName &right) { \
return EnumName(uint32_t(left) | uint32_t(right)); \
} \
static inline EnumName operator &(const EnumName &left, const EnumName &right) { \
return EnumName(uint32_t(left) & uint32_t(right)); \
} \
static inline EnumName operator ^(const EnumName &left, const EnumName &right) { \
return EnumName(uint32_t(left) ^ uint32_t(right)); \
} \
static inline EnumName operator ~(const EnumName &flags) { \
return EnumName(~uint32_t(flags)); \
} \
static inline EnumName & operator |=(EnumName &left, const EnumName &right) { \
return left = left | right; \
} \
static inline EnumName & operator &=(EnumName &left, const EnumName &right) { \
return left = left & right; \
} \
static inline EnumName & operator ^=(EnumName &left, const EnumName &right) { \
return left = left ^ right; \
} \
static inline bool operator !(const EnumName &obj) { \
return uint32_t(obj) == 0; \
}
#endif // _include_amtl_cxx_support_h_

260
public/amtl/am-deque.h Normal file
View File

@ -0,0 +1,260 @@
// vim: set sts=8 ts=2 sw=2 tw=99 et:
//
// Copyright (C) 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_KEIMA_TPL_CPP_DEQUE_H_
#define _INCLUDE_KEIMA_TPL_CPP_DEQUE_H_
#include <new>
#include <stdlib.h>
#include <assert.h>
#include <am-cxx.h>
#include <am-allocator-policies.h>
#include <am-utility.h>
#include <am-moveable.h>
namespace ke {
template <typename T, typename AllocPolicy = SystemAllocatorPolicy>
class Deque : public AllocPolicy
{
static const size_t kInvalidIndex = ~size_t(0);
public:
Deque(AllocPolicy = AllocPolicy())
: buffer_(NULL),
maxlength_(0),
first_(0),
last_(0)
{
}
Deque(Deque &&other)
: buffer_(other.buffer_),
maxlength_(other.maxlength_),
first_(other.first_),
last_(other.last_)
{
other.reset();
}
~Deque() {
zap();
}
Deque &operator =(Deque &&other) {
zap();
buffer_ = other.buffer_;
maxlength_ = other.maxlength_;
first_ = other.first_;
last_ = other.last_;
other.reset();
}
bool empty() const {
return first_ == last_;
}
template <typename U>
bool append(U &&other) {
size_t next = ensureCanAppend();
if (next == kInvalidIndex)
return false;
new (&buffer_[last_]) T(ke::Forward<U>(other));
last_ = next;
return true;
}
template <typename U>
bool prepend(U &&other) {
size_t prev = ensureCanPrepend();
if (prev == kInvalidIndex)
return false;
first_ = prev;
new (&buffer_[first_]) T(ke::Forward<U>(other));
return true;
}
void popFront() {
assert(!empty());
buffer_[first_].~T();
if (first_ == maxlength_ - 1)
first_ = 0;
else
first_++;
}
void popBack() {
assert(!empty());
if (last_ == 0)
last_ = maxlength_ - 1;
else
last_--;
buffer_[last_].~T();
}
T popFrontCopy() {
T t = front();
popFront();
return t;
}
T popBackCopy() {
T t = back();
popBack();
return t;
}
const T &front() const {
assert(!empty());
return buffer_[first_];
}
T &front() {
assert(!empty());
return buffer_[first_];
}
const T &back() const {
assert(!empty());
if (last_ == 0)
return buffer_[maxlength_ - 1];
return buffer_[last_ - 1];
}
T &back() {
assert(!empty());
if (last_ == 0)
return buffer_[maxlength_ - 1];
return buffer_[last_ - 1];
}
size_t length() const {
if (first_ == last_)
return 0;
return first_ < last_
? (last_ - first_)
: (last_ + (maxlength_ - first_));
}
size_t capacity() const {
return maxlength_;
}
private:
Deque(const Deque<T> &other) KE_DELETE;
Deque &operator =(const Deque<T> &other) KE_DELETE;
// Return the next value of first_.
size_t ensureCanPrepend() {
if (first_ == 0) {
if (maxlength_ && (last_ != maxlength_ - 1))
return maxlength_ - 1;
} else if (first_ - 1 != last_) {
return first_ - 1;
}
// The ring is full.
if (!growByOne())
return kInvalidIndex;
return maxlength_ - 1;
}
// Return the next value of last_.
size_t ensureCanAppend() {
if (last_ < first_) {
if (last_ + 1 != first_)
return last_ + 1;
} else{
if (last_ + 1 < maxlength_)
return last_ + 1;
if (first_ != 0)
return 0;
}
// The ring is full.
if (!growByOne())
return kInvalidIndex;
return last_ + 1;
}
bool growByOne() {
if (!IsUintPtrMultiplySafe(maxlength_, 2)) {
this->reportAllocationOverflow();
return false;
}
size_t new_maxlength = maxlength_ ? maxlength_ * 2 : 8;
T *new_buffer = (T *)this->malloc(sizeof(T) * new_maxlength);
if (!new_buffer)
return false;
// Move everything to the bottom of the new buffer, and reset our indices
// so that first is at 0.
if (first_ < last_) {
MoveRange(new_buffer, buffer_ + first_, last_ - first_);
last_ = last_ - first_;
first_ = 0;
} else {
MoveRange(new_buffer, buffer_ + first_, maxlength_ - first_);
MoveRange(new_buffer + (maxlength_ - first_), buffer_, last_);
last_ = last_ + (maxlength_ - first_);
first_ = 0;
}
this->free(buffer_);
buffer_ = new_buffer;
maxlength_ = new_maxlength;
return true;
}
void reset() {
buffer_ = NULL;
maxlength_ = 0;
first_ = 0;
last_ = 0;
}
void zap() {
if (first_ < last_) {
for (size_t i = first_; i < last_; i++)
buffer_[i].~T();
} else {
for (size_t i = first_; i < maxlength_; i++)
buffer_[i].~T();
for (size_t i = 0; i < last_; i++)
buffer_[i].~T();
}
this->free(buffer_);
}
private:
T *buffer_;
size_t maxlength_;
// Always points to the first readable item.
size_t first_;
// Always points to where the next item can be appended.
size_t last_;
};
}
#endif // _INCLUDE_KEIMA_TPL_CPP_DEQUE_H_

View File

@ -76,13 +76,17 @@ class FixedArray : public AllocPolicy
assert(index < length());
return data_[index];
}
void set(size_t index, const T &t) {
assert(index < length());
data_[index] = t;
T &back() {
assert(length() > 0);
return data_[length() - 1];
}
void set(size_t index, ke::Moveable<T> t) {
assert(index < length());
data_[index] = t;
const T &back() const {
assert(length() > 0);
return data_[length() - 1];
}
T *buffer() const {
return data_;
}
private:

View File

@ -35,8 +35,55 @@
namespace ke {
static const uint32_t kFloat32ExponentMask = 0x7F800000;
static const uint64_t kFloat64ExponentMask = 0x7FFF000000000000ULL;
struct float32_bits
{
static const uint32_t kExponentMask = kFloat32ExponentMask;
typedef uint32_t Bits;
union layout {
uint32_t bits;
float value;
};
static layout to_layout(float value) {
layout impl;
impl.value = value;
return impl;
}
};
struct float64_bits
{
static const uint64_t kExponentMask = kFloat64ExponentMask;
typedef uint64_t Bits;
union layout {
uint64_t bits;
float value;
};
static layout to_layout(float value) {
layout impl;
impl.value = value;
return impl;
}
};
template <typename T>
struct float_bits;
template <>
struct float_bits<float> : public float32_bits {};
template <>
struct float_bits<double> : public float64_bits {};
template <typename T>
static inline bool
IsNaN(double v)
IsNaN(T v)
{
#ifdef _MSC_VER
return !!_isnan(v);
@ -45,6 +92,48 @@ IsNaN(double v)
#endif
}
template <typename T> static inline bool
IsInfinite(T value)
{
typedef float_bits<T> Properties;
typedef typename Properties::Bits Bits;
Bits bits = Properties::to_layout(value).bits;
return (bits & Properties::kExponentMask) == Properties::kExponentMask;
};
// Performs the operation (x % y) where x and y are floating-point values.
//
// To compute a floating point modulus, this function returns "r", where r
// satisfies the following equation:
//
// x = (I * y) + r
//
// Where I is an integer <= x, and r is a value less than y. If no such
// integer I exists, the result is NaN.
//
// If x or y are NaN, the result is NaN.
// If x is +/-Infinity, the result is NaN.
// If y is 0, the result is NaN (as a divide by zero is implied).
//
// If y is Infinity, then r = x (and I = 0).
// If x is +/-0, then r = +/-0.
template <typename T> static inline T
FloatModulo(T left, T right)
{
#if defined(KE_WINDOWS)
// Windows fmod() does not follow the contract above, in that:
// 42 % Infinity => NaN, instead of 42, and
// -0 % -N => 0, instead of -0.
if ((!IsInfinite(left) && IsInfinite(right)) ||
(left == 0 && !IsInfinite(right)))
{
return left;
}
#endif
return fmod(left, right);
}
} // namespace ke
#endif // _include_amtl_float_h_

View File

@ -58,29 +58,20 @@ class HashMap : public AllocPolicy
V value;
Entry()
{
}
Entry(Moveable<Entry> other)
: key(Moveable<K>(other->key)),
value(Moveable<V>(other->value))
{
}
{}
Entry(const Entry &other)
: key(other.key),
value(other.value)
{}
Entry(Entry &&other)
: key(ke::Move(other.key)),
value(ke::Move(other.value))
{}
Entry(const K &aKey, const V &aValue)
: key(aKey),
value(aValue)
{ }
Entry(const K &aKey, Moveable<V> aValue)
: key(aKey),
value(aValue)
{ }
Entry(Moveable<K> aKey, const V &aValue)
: key(aKey),
value(aValue)
{ }
Entry(Moveable<K> aKey, Moveable<V> aValue)
: key(aKey),
value(aValue)
template <typename UK, typename UV>
Entry(UK &&aKey, UV &&aValue)
: key(ke::Forward<UK>(aKey)),
value(ke::Forward<UV>(aValue))
{ }
};
@ -137,24 +128,14 @@ 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) {
Entry entry(key, value);
template <typename UK, typename UV>
bool add(Insert &i, UK &&key, UV &&value) {
Entry entry(ke::Forward<UK>(key), ke::Forward<UV>(value));
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, Moveable<K> key, const V &value) {
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, const K &key, Moveable<V> value) {
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, Moveable<K> key, Moveable<V> value) {
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, Moveable<K> key) {
Entry entry(key, V());
template <typename UK>
bool add(Insert &i, UK &&key) {
Entry entry(ke::Forward<UK>(key), V());
return table_.add(i, ke::Move(entry));
}

View File

@ -27,8 +27,8 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef _include_amtl_hashmap_h_
#define _include_amtl_hashmap_h_
#ifndef _include_amtl_hashset_h_
#define _include_amtl_hashset_h_
#include <am-hashtable.h>
@ -76,6 +76,7 @@ class HashSet : public AllocPolicy
typedef typename Internal::Result Result;
typedef typename Internal::Insert Insert;
typedef typename Internal::iterator iterator;
template <typename Lookup>
Result find(const Lookup &key) {
@ -98,11 +99,9 @@ class HashSet : 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) {
return table_.add(i, key);
}
bool add(Insert &i, Moveable<K> key) {
return table_.add(i, key);
template <typename UK>
bool add(Insert &i, UK &&key) {
return table_.add(i, ke::Forward<UK>(key));
}
// This can be used to avoid compiler constructed temporaries, since AMTL
@ -112,6 +111,9 @@ class HashSet : public AllocPolicy
return table_.add(i);
}
iterator iter() {
return iterator(&table_);
}
void clear() {
table_.clear();
}

View File

@ -54,14 +54,9 @@ namespace detail {
void setHash(uint32_t hash) {
hash_ = hash;
}
void construct() {
new (&t_) T();
}
void construct(const T &t) {
new (&t_) T(t);
}
void construct(Moveable<T> t) {
new (&t_) T(t);
template <typename U>
void construct(U &&u) {
new (&t_) T(ke::Forward<U>(u));
}
uint32_t hash() const {
return hash_;
@ -151,7 +146,7 @@ class HashTable : public AllocPolicy
Entry *table = (Entry *)this->malloc(capacity * sizeof(Entry));
if (!table)
return NULL;
return nullptr;
for (size_t i = 0; i < capacity; i++)
table[i].initialize();
@ -267,7 +262,7 @@ class HashTable : public AllocPolicy
if (oldEntry.isLive()) {
Insert p = insertUnique(oldEntry.hash());
p.entry().setHash(p.hash());
p.entry().construct(Moveable<Payload>(oldEntry.payload()));
p.entry().construct(ke::Move(oldEntry.payload()));
}
oldEntry.destruct();
}
@ -373,7 +368,7 @@ class HashTable : public AllocPolicy
capacity_(0),
nelements_(0),
ndeleted_(0),
table_(NULL),
table_(nullptr),
minCapacity_(kMinCapacity)
{
}
@ -385,7 +380,7 @@ class HashTable : public AllocPolicy
this->free(table_);
}
bool init(uint32_t capacity = 0) {
bool init(size_t capacity = 0) {
if (capacity < kMinCapacity) {
capacity = kMinCapacity;
} else if (capacity > kMaxCapacity) {
@ -393,10 +388,10 @@ class HashTable : public AllocPolicy
return false;
}
minCapacity_ = capacity;
minCapacity_ = uint32_t(capacity);
assert(IsPowerOfTwo(capacity));
capacity_ = capacity;
capacity_ = uint32_t(capacity);
table_ = createTable(capacity_);
if (!table_)
@ -432,16 +427,11 @@ class HashTable : public AllocPolicy
// The table 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 Payload &payload) {
template <typename U>
bool add(Insert &i, U &&payload) {
if (!internalAdd(i))
return false;
i.entry().construct(payload);
return true;
}
bool add(Insert &i, Moveable<Payload> payload) {
if (!internalAdd(i))
return false;
i.entry().construct(payload);
i.entry().construct(ke::Forward<U>(payload));
return true;
}
bool add(Insert &i) {
@ -610,7 +600,7 @@ template <>
inline uint32_t
HashInteger<4>(uintptr_t value)
{
return HashInt32(value);
return HashInt32(uint32_t(value));
}
template <>

View File

@ -32,6 +32,7 @@
#include <stddef.h>
#include <assert.h>
#include <am-cxx.h>
namespace ke {
@ -46,8 +47,8 @@ class InlineListNode
public:
InlineListNode()
: next_(NULL),
prev_(NULL)
: next_(nullptr),
prev_(nullptr)
{
}
@ -147,7 +148,7 @@ class InlineList
remove(at.iter_);
// Iterator is no longer valid.
at.iter_ = NULL;
at.iter_ = nullptr;
return next;
}
@ -161,8 +162,8 @@ class InlineList
t->next_->prev_ = t->prev_;
#if !defined(NDEBUG)
t->next_ = NULL;
t->prev_ = NULL;
t->next_ = nullptr;
t->prev_ = nullptr;
#endif
}

View File

@ -52,18 +52,8 @@ class LinkedList : public AllocPolicy
public:
friend class iterator;
class Node
struct Node
{
public:
Node(const T &o)
: obj(o)
{
}
Node(Moveable<T> o)
: obj(o)
{
}
T obj;
Node *next;
Node *prev;
@ -80,18 +70,14 @@ public:
clear();
}
bool append(const T &obj) {
return insertBefore(end(), obj) != end();
}
bool append(Moveable<T> obj) {
return insertBefore(end(), obj) != end();
template <typename U>
bool append(U &&obj) {
return insertBefore(end(), ke::Forward<U>(obj)) != end();
}
bool prepend(const T &obj) {
return insertBefore(begin(), obj) != begin();
}
bool prepend(Moveable<T> obj) {
return insertBefore(begin(), obj) != begin();
template <typename U>
bool prepend(U &&obj) {
return insertBefore(begin(), ke::Forward<U>(obj)) != begin();
}
size_t length() const {
@ -134,18 +120,12 @@ public:
return sentinel_.address();
}
Node *allocNode(const T &obj) {
template <typename U>
Node *allocNode(U &&obj) {
Node *node = (Node *)this->malloc(sizeof(Node));
if (!node)
return NULL;
new (node) Node(obj);
return node;
}
Node *allocNode(Moveable<T> obj) {
Node *node = (Node *)this->malloc(sizeof(Node));
if (!node)
return NULL;
new (node) Node(obj);
return nullptr;
new (&node->obj) T(ke::Forward<U>(obj));
return node;
}
@ -165,7 +145,7 @@ public:
public:
iterator()
: this_(NULL)
: this_(nullptr)
{
}
iterator(const LinkedList &src)
@ -269,11 +249,9 @@ public:
return iter;
}
iterator insertBefore(iterator where, const T &obj) {
return insert(where, allocNode(obj));
}
iterator insertBefore(iterator where, Moveable<T> obj) {
return insert(where, allocNode(obj));
template <typename U>
iterator insertBefore(iterator where, U &&obj) {
return insert(where, allocNode(ke::Forward<U>(obj)));
}
public:

View File

@ -30,42 +30,44 @@
#ifndef _include_amtl_moveable_h_
#define _include_amtl_moveable_h_
#include <am-type-traits.h>
namespace ke {
// This is a feature in C++11, but since AM projects do not have access to
// C++11 yet, we provide templates to implement move semantics. A class can
// provide a constructor for (ke::Moveable<T> t) which containers will try
// to use.
//
// When implementing a constructor that takes a Moveable, the object being
// moved should be left in a state that is safe, since its destructor will
// be called even though it has been moved.
// Previously, we implemented Move semantics without C++11. Now that we use
// C++11, we implement this as STL does for std::move.
template <typename T>
static inline typename remove_reference<T>::type &&
Move(T &&t)
{
return static_cast<typename remove_reference<T>::type &&>(t);
}
// std::forward replacement. See:
// http://thbecker.net/articles/rvalue_references/section_07.html and
// http://thbecker.net/articles/rvalue_references/section_08.html
template <typename T>
static KE_CONSTEXPR inline T &&
Forward(typename remove_reference<T>::type &t) KE_NOEXCEPT
{
return static_cast<T &&>(t);
}
template <typename T>
struct Moveable
static KE_CONSTEXPR inline T &&
Forward(typename remove_reference<T>::type &&t) KE_NOEXCEPT
{
public:
explicit Moveable(T &t)
: t_(t)
{
}
T *operator ->() {
return &t_;
}
operator T &() {
return t_;
}
private:
T &t_;
};
return static_cast<T &&>(t);
}
template <typename T>
static inline Moveable<T>
Move(T &t)
static inline void
MoveRange(T *dest, T *src, size_t length)
{
return Moveable<T>(t);
for (size_t i = 0; i < length; i++) {
new (&dest[i]) T(ke::Move(src[i]));
src[i].~T();
}
}
} // namespace ke

66
public/amtl/am-platform.h Normal file
View File

@ -0,0 +1,66 @@
// vim: set sts=8 ts=2 sw=2 tw=99 et:
//
// Copyright (C) 2013, David Anderson and AlliedModders LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of AlliedModders LLC nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef _include_amtl_platform_h_
#define _include_amtl_platform_h_
namespace ke {
#if defined(__NetBSD__)
# define KE_NETBSD
# define KE_BSD
#elif defined(__FreeBSD__)
# define KE_FREEBSD
# define KE_BSD
#elif defined(__OpenBSD__)
# define KE_OPENBSD
# define KE_BSD
#elif defined(__APPLE__)
# define KE_MACOSX
# define KE_MACH
# define KE_BSD
#elif defined(__MACH__)
# define KE_MACH
# define KE_BSD
#elif defined(_WIN32)
# define KE_WINDOWS
#elif defined(__linux__)
# define KE_LINUX
# define KE_POSIX
#elif defined(__sun__)
# define KE_SOLARIS
# define KE_POSIX
#endif
#if defined(KE_BSD)
# define KE_POSIX
#endif
} // ke
#endif // _include_amtl_platform_h_

View File

@ -39,7 +39,7 @@ namespace ke {
// 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
class KE_LINK RefcountedThreadsafe
{
public:
RefcountedThreadsafe()
@ -63,7 +63,132 @@ class RefcountedThreadsafe
}
private:
AtomicRefCount refcount_;
AtomicRefcount refcount_;
};
// Use this to forward to ke::Refcounted<X>, when implementing IRefcounted.
#define KE_IMPL_REFCOUNTING_TS(classname) \
void AddRef() { \
ke::RefcountedThreadsafe<classname>::AddRef(); \
} \
void Release() { \
ke::RefcountedThreadsafe<classname>::Release(); \
}
// Classes may be multiply-inherited may wish to derive from this Refcounted
// instead.
class VirtualRefcountedThreadsafe : public IRefcounted
{
public:
VirtualRefcountedThreadsafe() : refcount_(0)
{
#if !defined(NDEBUG)
destroying_ = false;
#endif
}
virtual ~VirtualRefcountedThreadsafe()
{}
void AddRef() KE_OVERRIDE {
assert(!destroying_);
refcount_.increment();
}
void Release() KE_OVERRIDE {
if (!refcount_.decrement()) {
#if !defined(NDEBUG)
destroying_ = true;
#endif
delete this;
}
}
private:
AtomicRefcount refcount_;
#if !defined(NDEBUG)
bool destroying_;
#endif
};
// This is a specialized version of Ref<> that is safe to read and write from
// multiple threads. It is not recommended for general use, since it imposes
// a CAS spin-lock on every read/write.
//
// Normally, assigning Ref<> to Ref<> has a race condition where in between
// the read and incref, another thread can assign, decref, and ultimately
// destroy the left-hand side. This prevents such a scenario by making reads
// atomic with respect to the incref operation.
//
// Pointers stored in an AtomicRef<> must be at least sizeof(void *) aligned.
template <typename T>
class AtomicRef
{
public:
AtomicRef()
: thing_(nullptr)
{}
AtomicRef(T *thing)
: thing_(thing)
{
assert(IsAligned(thing, sizeof(void *)));
if (thing)
thing->AddRef();
}
~AtomicRef() {
assert(thing_ == untagged(thing_));
if (thing_)
reinterpret_cast<T *>(thing_)->Release();
}
// Atomically retrieve and add a reference to the contained value.
AlreadyRefed<T> get() {
T *value = lock();
if (value)
value->AddRef();
unlock(value);
return AdoptRef(value);
}
// Atomically incref the new value and replace the old value.
void operator =(T *other) {
T *value = lock();
if (other)
other->AddRef();
unlock(other);
if (value)
value->Release();
}
private:
AtomicRef(const AtomicRef &other) KE_DELETE;
void operator =(const AtomicRef &other) KE_DELETE;
private:
// We represent a locked state with a tag bit.
void *tagged(void *ptr) {
return reinterpret_cast<void *>(uintptr_t(ptr) | 1);
}
void *untagged(void *ptr) {
return reinterpret_cast<void *>(uintptr_t(ptr) & ~uintptr_t(1));
}
T *lock() {
// Spin until we can replace an untagged ptr with the tagged version.
void *oldval = untagged(thing_);
while (CompareAndSwapPtr(&thing_, tagged(oldval), oldval) != oldval) {
YieldProcessor();
oldval = untagged(thing_);
}
return reinterpret_cast<T *>(oldval);
}
void unlock(T *ptr) {
// Nothing should have mutated the value, and the new value should be
// untagged.
assert(thing_ == tagged(thing_));
assert(ptr == untagged(ptr));
thing_ = ptr;
}
private:
void * volatile thing_;
};
} // namespace ke

View File

@ -60,13 +60,26 @@ class AlreadyRefed
{
// If copy elision for some reason doesn't happen (for example, when
// returning from AdoptRef), just null out the source ref.
other.thing_ = NULL;
other.thing_ = nullptr;
}
~AlreadyRefed() {
if (thing_)
thing_->Release();
}
bool operator !() const {
return !thing_;
}
T *operator ->() const {
return thing_;
}
bool operator ==(T *other) const {
return thing_ == other;
}
bool operator !=(T *other) const {
return thing_ != other;
}
T *release() const {
return ReturnAndVoid(thing_);
}
@ -94,18 +107,18 @@ class PassRef
AddRef();
}
PassRef()
: thing_(NULL)
: thing_(nullptr)
{
}
PassRef(const AlreadyRefed<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)
PassRef(const AlreadyRefed<S> &other)
: thing_(other.release())
{
// Don't addref, newborn means already addref'd.
@ -185,7 +198,7 @@ class PassRef
// must either be assigned to a Ref or PassRef (NOT an AdoptRef/AlreadyRefed),
// or must be deleted using |delete|.
template <typename T>
class Refcounted
class KE_LINK Refcounted
{
public:
Refcounted()
@ -210,6 +223,58 @@ class Refcounted
uintptr_t refcount_;
};
// Use this to forward to ke::Refcounted<X>, when implementing IRefcounted.
#define KE_IMPL_REFCOUNTING(classname) \
void AddRef() { \
ke::Refcounted<classname>::AddRef(); \
} \
void Release() { \
ke::Refcounted<classname>::Release(); \
}
// This can be used for classes which will inherit from VirtualRefcounted.
class KE_LINK IRefcounted
{
public:
virtual ~IRefcounted() {}
virtual void AddRef() = 0;
virtual void Release() = 0;
};
// Classes may be multiply-inherited may wish to derive from this Refcounted
// instead.
class KE_LINK VirtualRefcounted : public IRefcounted
{
public:
VirtualRefcounted() : refcount_(0)
{
#if !defined(NDEBUG)
destroying_ = false;
#endif
}
virtual ~VirtualRefcounted()
{}
void AddRef() KE_OVERRIDE {
assert(!destroying_);
refcount_++;
}
void Release() KE_OVERRIDE {
assert(refcount_ > 0);
if (--refcount_ == 0) {
#if !defined(NDEBUG)
destroying_ = true;
#endif
delete this;
}
}
private:
uintptr_t refcount_;
#if !defined(NDEBUG)
bool destroying_;
#endif
};
// Simple class for automatic refcounting.
template <typename T>
class Ref
@ -222,7 +287,7 @@ class Ref
}
Ref()
: thing_(NULL)
: thing_(nullptr)
{
}
@ -231,10 +296,10 @@ class Ref
{
AddRef();
}
Ref(Moveable<Ref> other)
: thing_(other->thing_)
Ref(Ref &&other)
: thing_(other.thing_)
{
other->thing_ = NULL;
other.thing_ = nullptr;
}
template <typename S>
Ref(const Ref<S> &other)
@ -274,10 +339,27 @@ class Ref
operator T *() {
return thing_;
}
operator T *() const {
return thing_;
}
bool operator !() const {
return !thing_;
}
AlreadyRefed<T> take() {
return AlreadyRefed<T>(ReturnAndVoid(thing_));
}
AlreadyRefed<T> forget() {
return AlreadyRefed<T>(ReturnAndVoid(thing_));
}
bool operator ==(const Ref &other) {
return thing_ == other.thing_;
}
bool operator !=(const Ref &other) {
return thing_ != other.thing_;
}
template <typename S>
Ref &operator =(S *thing) {
Release();
@ -307,10 +389,10 @@ class Ref
return *this;
}
Ref &operator =(Moveable<Ref> other) {
Ref &operator =(Ref &&other) {
Release();
thing_ = other->thing_;
other->thing_ = NULL;
thing_ = other.thing_;
other.thing_ = nullptr;
return *this;
}

View File

@ -58,18 +58,18 @@ class AString
else
length_ = 0;
}
AString(Moveable<AString> other)
: chars_(other->chars_.take()),
length_(other->length_)
AString(AString &&other)
: chars_(other.chars_.take()),
length_(other.length_)
{
other->length_ = 0;
other.length_ = 0;
}
AString &operator =(const char *str) {
if (str && str[0]) {
set(str, strlen(str));
} else {
chars_ = NULL;
chars_ = nullptr;
length_ = 0;
}
return *this;
@ -78,15 +78,15 @@ class AString
if (other.length_) {
set(other.chars_, other.length_);
} else {
chars_ = NULL;
chars_ = nullptr;
length_ = 0;
}
return *this;
}
AString &operator =(Moveable<AString> other) {
chars_ = other->chars_.take();
length_ = other->length_;
other->length_ = 0;
AString &operator =(AString &&other) {
chars_ = other.chars_.take();
length_ = other.length_;
other.length_ = 0;
return *this;
}
@ -106,23 +106,13 @@ 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 isVoid() ? NULL : "";
return "";
return chars_;
}

View File

@ -50,7 +50,7 @@ class Mutex : public Lockable
#if !defined(NDEBUG)
int rv =
#endif
pthread_mutex_init(&mutex_, NULL);
pthread_mutex_init(&mutex_, nullptr);
assert(rv == 0);
}
~Mutex() {
@ -85,7 +85,7 @@ class ConditionVariable : public Lockable
#if !defined(NDEBUG)
int rv =
#endif
pthread_cond_init(&cv_, NULL);
pthread_cond_init(&cv_, nullptr);
assert(rv == 0);
}
~ConditionVariable() {
@ -116,7 +116,7 @@ class ConditionVariable : public Lockable
return Wait_Error;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
gettimeofday(&tv, nullptr);
struct timespec ts;
ts.tv_sec = tv.tv_sec;
@ -165,12 +165,12 @@ class Thread
char name[17];
};
public:
Thread(IRunnable *run, const char *name = NULL) {
Thread(IRunnable *run, const char *name = nullptr) {
ThreadData *data = new ThreadData;
data->run = run;
snprintf(data->name, sizeof(data->name), "%s", name ? name : "");
initialized_ = (pthread_create(&thread_, NULL, Main, data) == 0);
initialized_ = (pthread_create(&thread_, nullptr, Main, data) == 0);
if (!initialized_)
delete data;
}
@ -182,7 +182,7 @@ class Thread
void Join() {
if (!Succeeded())
return;
pthread_join(thread_, NULL);
pthread_join(thread_, nullptr);
}
private:
@ -199,7 +199,7 @@ class Thread
#endif
}
data->run->Run();
return NULL;
return nullptr;
}
private:

View File

@ -199,12 +199,74 @@ class AutoLock
Lockable *lock_;
};
class AutoMaybeLock
{
friend class AutoMaybeUnlock;
public:
AutoMaybeLock(Lockable *lock)
: lock_(lock)
{
if (lock_)
lock_->Lock();
}
~AutoMaybeLock() {
if (lock_)
lock_->Unlock();
}
// Unlock and void the locked object. After calling this, the region covered
// by the AutoMaybeLocked is not guaranteed to be locked! This is useful for
// patterns like:
//
// AutoMaybeLock lock(x);
// {
// ...
// return helper(&lock);
// }
//
// helper_while_locked(AutoMaybeLock *mlock) {
// ...
// mlock->unlock();
// callback
// }
//
// In this situation, we can avoid using AutoMaybeUnlock which would re-lock
// only to unlock again immediately.
void unlock() {
if (lock_) {
lock_->Unlock();
lock_ = nullptr;
}
}
private:
Lockable *lock_;
};
class AutoMaybeUnlock
{
public:
AutoMaybeUnlock(Lockable *lock)
: lock_(lock)
{
if (lock_)
lock_->Unlock();
}
~AutoMaybeUnlock() {
if (lock_)
lock_->Lock();
}
private:
Lockable *lock_;
};
class AutoTryLock
{
public:
AutoTryLock(Lockable *lock)
{
lock_ = lock->TryLock() ? lock : NULL;
AutoTryLock(Lockable *lock) {
lock_ = lock->TryLock() ? lock : nullptr;
}
~AutoTryLock() {
if (lock_)

View File

@ -66,7 +66,7 @@ class ConditionVariable : public Lockable
{
public:
ConditionVariable() {
event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
event_ = CreateEvent(nullptr, FALSE, FALSE, nullptr);
}
~ConditionVariable() {
CloseHandle(event_);
@ -87,12 +87,12 @@ class ConditionVariable : public Lockable
SetEvent(event_);
}
WaitResult Wait(size_t timeout_ms) {
WaitResult Wait(size_t timeoutMs) {
// This will assert if the lock has not been acquired. We don't need to be
// atomic here, like pthread_cond_wait, because the event bit will stick
// until reset by a wait function.
Unlock();
DWORD rv = WaitForSingleObject(event_, timeout_ms);
DWORD rv = WaitForSingleObject(event_, int(timeoutMs));
Lock();
if (rv == WAIT_TIMEOUT)
@ -114,8 +114,8 @@ class ConditionVariable : public Lockable
class Thread
{
public:
Thread(IRunnable *run, const char *name = NULL) {
thread_ = CreateThread(NULL, 0, Main, run, 0, NULL);
Thread(IRunnable *run, const char *name = nullptr) {
thread_ = CreateThread(nullptr, 0, Main, run, 0, nullptr);
}
~Thread() {
if (!thread_)

View File

@ -135,7 +135,7 @@ class ThreadLocal
bool allocate() {
if (!__sync_bool_compare_and_swap(&allocated_, 0, 1))
return true;
return pthread_key_create(&key_, NULL) == 0;
return pthread_key_create(&key_, nullptr) == 0;
}
private:

View File

@ -0,0 +1,64 @@
// vim: set sts=8 ts=2 sw=2 tw=99 et:
//
// Copyright (C) 2013, David Anderson and AlliedModders LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of AlliedModders LLC nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef _include_amtl_type_traits_h_
#define _include_amtl_type_traits_h_
#include <am-cxx.h>
namespace ke {
// Remove references from types.
template <typename T>
struct remove_reference {
typedef T type;
};
template <typename T>
struct remove_reference<T &> {
typedef T type;
};
template <typename T>
struct remove_reference<T &&> {
typedef T type;
};
template <typename T, T Value>
struct integral_constant {
static const T value = Value;
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
template<class T> struct is_lvalue_reference : false_type{};
template<class T> struct is_lvalue_reference<T&> : true_type {};
} // namespace ke
#endif // _include_amtl_type_traits_h_

View File

@ -1,6 +1,6 @@
// vim: set sts=8 ts=2 sw=2 tw=99 et:
//
// Copyright (C) 2013, David Anderson and AlliedModders LLC
// Copyright (C) 2013-2014, David Anderson and AlliedModders LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -30,6 +30,7 @@
#ifndef _include_amtl_utility_h_
#define _include_amtl_utility_h_
#define __STDC_FORMAT_MACROS
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
@ -40,10 +41,11 @@
# include <inttypes.h>
#endif
#include <am-moveable.h>
#define KE_32BIT
#include <am-cxx.h>
#include <am-algorithm.h>
#if defined(_MSC_VER)
// Mac file format warning.
# pragma warning(disable:4355)
#endif
@ -55,8 +57,6 @@ static const size_t kKB = 1024;
static const size_t kMB = 1024 * kKB;
static const size_t kGB = 1024 * kMB;
typedef uint8_t * Address;
template <typename T> T
ReturnAndVoid(T &t)
{
@ -65,45 +65,37 @@ 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>
class AutoPtr
{
T *t_;
public:
AutoPtr()
: t_(NULL)
: t_(nullptr)
{
}
explicit AutoPtr(T *t)
: t_(t)
{
}
AutoPtr(Moveable<AutoPtr<T> > other)
AutoPtr(AutoPtr &&other)
{
t_ = other->t_;
other->t_ = NULL;
t_ = other.t_;
other.t_ = nullptr;
}
~AutoPtr() {
delete t_;
}
T *get() {
return t_;
}
T *take() {
return ReturnAndVoid(t_);
}
T *forget() {
return ReturnAndVoid(t_);
}
T *operator *() const {
return t_;
}
@ -121,10 +113,10 @@ class AutoPtr
T **address() {
return &t_;
}
T *operator =(Moveable<AutoPtr<T> > other) {
T *operator =(AutoPtr &&other) {
delete t_;
t_ = other->t_;
other->t_ = NULL;
t_ = other.t_;
other.t_ = nullptr;
return t_;
}
bool operator !() const {
@ -134,6 +126,9 @@ class AutoPtr
private:
AutoPtr(const AutoPtr &other) KE_DELETE;
AutoPtr &operator =(const AutoPtr &other) KE_DELETE;
private:
T *t_;
};
// Wrapper that automatically deletes its contents. The pointer can be taken
@ -145,7 +140,7 @@ class AutoArray
public:
AutoArray()
: t_(NULL)
: t_(nullptr)
{
}
explicit AutoArray(T *t)
@ -158,15 +153,15 @@ class AutoArray
T *take() {
return ReturnAndVoid(t_);
}
T *operator *() const {
T *forget() {
return ReturnAndVoid(t_);
}
T **address() {
return &t_;
}
T &operator *() const {
return t_;
}
T &operator [](size_t index) {
return t_[index];
}
const T &operator [](size_t index) const {
return t_[index];
}
operator T *() const {
return t_;
}
@ -283,8 +278,6 @@ IsUintPtrMultiplySafe(size_t a, size_t b)
}
#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
#define STATIC_ASSERT(cond) extern int static_assert_f(int a[(cond) ? 1 : -1])
#define IS_ALIGNED(addr, alignment) (!(uintptr_t(addr) & ((alignment) - 1)))
template <typename T>
@ -295,23 +288,11 @@ IsAligned(T addr, size_t alignment)
return !(uintptr_t(addr) & (alignment - 1));
}
static inline Address
AlignedBase(Address addr, size_t alignment)
static inline void *
AlignedBase(void *addr, size_t alignment)
{
assert(IsPowerOfTwo(alignment));
return Address(uintptr_t(addr) & ~(alignment - 1));
}
template <typename T> static inline T
Min(const T &t1, const T &t2)
{
return t1 < t2 ? t1 : t2;
}
template <typename T> static inline T
Max(const T &t1, const T &t2)
{
return t1 > t2 ? t1 : t2;
return reinterpret_cast<void *>(uintptr_t(addr) & ~(alignment - 1));
}
template <typename T>
@ -351,6 +332,36 @@ class SaveAndSet
T old_;
};
template <typename T>
class Maybe
{
public:
Maybe()
: initialized_(false)
{}
~Maybe() {
if (initialized_)
t_.address()->~T();
}
void init() {
new (t_.address()) T();
initialized_ = true;
}
template <typename U>
void init(U &&u) {
new (t_.address()) T(Forward<U>(u));
initialized_ = true;
}
bool initialized() const {
return initialized_;
}
private:
bool initialized_;
StorageBuffer<T> t_;
};
template <typename T>
class StackLinked
{
@ -366,31 +377,19 @@ class StackLinked
*prevp_ = prev_;
}
private:
protected:
T **prevp_;
T *prev_;
};
#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"
# define KE_I64_FMT "%I64d"
# define KE_U64_FMT "%I64u"
# define KE_FMT_SIZET "Iu"
# define KE_FMT_I64 "I64d"
# define KE_FMT_U64 "I64u"
#elif defined(__GNUC__)
# define KE_SIZET_FMT "%zu"
# define KE_I64_FMT "%" PRId64
# define KE_U64_FMT "%" PRIu64
# define KE_FMT_SIZET "zu"
# define KE_FMT_I64 PRId64
# define KE_FMT_U64 PRIu64
#else
# error "Implement format specifier string"
#endif
@ -401,6 +400,22 @@ class StackLinked
# define KE_CRITICAL_LIKELY(x) x
#endif
}
#if defined(_WIN32)
# define KE_IMPORT __declspec(dllimport)
# define KE_EXPORT __declspec(dllexport)
#else
# define KE_IMPORT
# define KE_EXPORT __attribute__((visibility("default")))
#endif
#if defined(KE_EXPORTING)
# define KE_LINK KE_EXPORT
#elif defined(KE_IMPORTING)
# define KE_LINK KE_IMPORT
#else
# define KE_LINK
#endif
} // namespace ke
#endif // _include_amtl_utility_h_

View File

@ -43,45 +43,35 @@ class Vector : public AllocPolicy
{
public:
Vector(AllocPolicy = AllocPolicy())
: data_(NULL),
: data_(nullptr),
nitems_(0),
maxsize_(0)
{
}
Vector(Moveable<Vector<T, AllocPolicy> > other) {
data_ = other->data_;
nitems_ = other->nitems_;
maxsize_ = other->maxsize_;
other->reset();
Vector(Vector &&other) {
data_ = other.data_;
nitems_ = other.nitems_;
maxsize_ = other.maxsize_;
other.reset();
}
~Vector() {
zap();
}
bool append(const T &item) {
template <typename U>
bool append(U &&item) {
if (!growIfNeeded(1))
return false;
new (&data_[nitems_]) T(item);
new (&data_[nitems_]) T(ke::Forward<U>(item));
nitems_++;
return true;
}
bool append(Moveable<T> item) {
if (!growIfNeeded(1))
return false;
new (&data_[nitems_]) T(item);
nitems_++;
return true;
}
void infallibleAppend(const T &item) {
template <typename U>
void infallibleAppend(U &&item) {
assert(growIfNeeded(1));
new (&data_[nitems_]) T(item);
nitems_++;
}
void infallibleAppend(Moveable<T> item) {
assert(growIfNeeded(1));
new (&data_[nitems_]) T(item);
new (&data_[nitems_]) T(ke::Forward<U>(item));
nitems_++;
}
@ -91,20 +81,13 @@ class Vector : public AllocPolicy
// invalid indexes are allowed.
//
// This is a linear-time operation.
bool insert(size_t at, const T &item) {
template <typename U>
bool insert(size_t at, U &&item) {
if (at == length())
return append(item);
return append(ke::Forward<U>(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);
new (&data_[at]) T(ke::Forward<U>(item));
return true;
}
@ -112,7 +95,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] = ke::Move(data_[i + 1]);
pop();
}
@ -156,7 +139,10 @@ class Vector : public AllocPolicy
return at(length() - 1);
}
T *buffer() const {
T *buffer() {
return data_;
}
const T *buffer() const {
return data_;
}
@ -180,11 +166,25 @@ 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();
template <typename U>
bool extend(U &&other) {
if (length() == 0) {
*this = Move(other);
} else {
for (size_t i = 0; i < other.length(); i++) {
if (!append(Move(other[i])))
return false;
}
}
return true;
}
Vector &operator =(Vector &&other) {
zap();
data_ = other.data_;
nitems_ = other.nitems_;
maxsize_ = other.maxsize_;
other.reset();
return *this;
}
@ -201,7 +201,7 @@ class Vector : public AllocPolicy
this->free(data_);
}
void reset() {
data_ = NULL;
data_ = nullptr;
nitems_ = 0;
maxsize_ = 0;
}
@ -214,10 +214,10 @@ class Vector : public AllocPolicy
// references are taken.
if (!growIfNeeded(1))
return false;
new (&data_[nitems_]) T(Moveable<T>(data_[nitems_ - 1]));
new (&data_[nitems_]) T(ke::Move(data_[nitems_ - 1]));
nitems_++;
for (size_t i = nitems_ - 2; i > at; i--)
data_[i] = Moveable<T>(data_[i - 1]);
data_[i] = ke::Move(data_[i - 1]);
return true;
}
@ -240,12 +240,9 @@ class Vector : public AllocPolicy
}
T* newdata = (T*)this->malloc(sizeof(T) * new_maxsize);
if (newdata == NULL)
if (newdata == nullptr)
return false;
for (size_t i = 0; i < nitems_; i++) {
new (&newdata[i]) T(Moveable<T>(data_[i]));
data_[i].~T();
}
MoveRange<T>(newdata, data_, nitems_);
this->free(data_);
data_ = newdata;