mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1014377 - Convert the first quarter of MFBT to Gecko style. r=froydnj.
--HG-- extra : rebase_source : b3b2da775e2c0e8a6ecbed70e7bd0c8f7af67b47
This commit is contained in:
parent
dab2c77f74
commit
0b4c7c33bf
@ -23,8 +23,8 @@ class AlignmentFinder
|
||||
{
|
||||
struct Aligner
|
||||
{
|
||||
char c;
|
||||
T t;
|
||||
char mChar;
|
||||
T mT;
|
||||
};
|
||||
|
||||
public:
|
||||
@ -111,25 +111,27 @@ struct AlignedElem<16>
|
||||
template<size_t Nbytes>
|
||||
struct AlignedStorage
|
||||
{
|
||||
union U {
|
||||
char bytes[Nbytes];
|
||||
uint64_t _;
|
||||
union U
|
||||
{
|
||||
char mBytes[Nbytes];
|
||||
uint64_t mDummy;
|
||||
} u;
|
||||
|
||||
const void* addr() const { return u.bytes; }
|
||||
void* addr() { return u.bytes; }
|
||||
const void* addr() const { return u.mBytes; }
|
||||
void* addr() { return u.mBytes; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct AlignedStorage2
|
||||
{
|
||||
union U {
|
||||
char bytes[sizeof(T)];
|
||||
uint64_t _;
|
||||
union U
|
||||
{
|
||||
char mBytes[sizeof(T)];
|
||||
uint64_t mDummy;
|
||||
} u;
|
||||
|
||||
const T* addr() const { return reinterpret_cast<const T*>(u.bytes); }
|
||||
T* addr() { return static_cast<T*>(static_cast<void*>(u.bytes)); }
|
||||
const T* addr() const { return reinterpret_cast<const T*>(u.mBytes); }
|
||||
T* addr() { return static_cast<T*>(static_cast<void*>(u.mBytes)); }
|
||||
};
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
@ -50,13 +50,30 @@ namespace mozilla {
|
||||
class MallocAllocPolicy
|
||||
{
|
||||
public:
|
||||
void* malloc_(size_t bytes) { return malloc(bytes); }
|
||||
void* calloc_(size_t bytes) { return calloc(bytes, 1); }
|
||||
void* realloc_(void* p, size_t oldBytes, size_t bytes) { return realloc(p, bytes); }
|
||||
void free_(void* p) { free(p); }
|
||||
void reportAllocOverflow() const {}
|
||||
};
|
||||
void* malloc_(size_t aBytes)
|
||||
{
|
||||
return malloc(aBytes);
|
||||
}
|
||||
|
||||
void* calloc_(size_t aBytes)
|
||||
{
|
||||
return calloc(aBytes, 1);
|
||||
}
|
||||
|
||||
void* realloc_(void* aPtr, size_t aOldBytes, size_t aBytes)
|
||||
{
|
||||
return realloc(aPtr, aBytes);
|
||||
}
|
||||
|
||||
void free_(void* aPtr)
|
||||
{
|
||||
free(aPtr);
|
||||
}
|
||||
|
||||
void reportAllocOverflow() const
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
22
mfbt/Array.h
22
mfbt/Array.h
@ -19,17 +19,19 @@ namespace mozilla {
|
||||
template<typename T, size_t Length>
|
||||
class Array
|
||||
{
|
||||
T arr[Length];
|
||||
T mArr[Length];
|
||||
|
||||
public:
|
||||
T& operator[](size_t i) {
|
||||
MOZ_ASSERT(i < Length);
|
||||
return arr[i];
|
||||
T& operator[](size_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(aIndex < Length);
|
||||
return mArr[aIndex];
|
||||
}
|
||||
|
||||
const T& operator[](size_t i) const {
|
||||
MOZ_ASSERT(i < Length);
|
||||
return arr[i];
|
||||
const T& operator[](size_t aIndex) const
|
||||
{
|
||||
MOZ_ASSERT(aIndex < Length);
|
||||
return mArr[aIndex];
|
||||
}
|
||||
};
|
||||
|
||||
@ -37,11 +39,13 @@ template<typename T>
|
||||
class Array<T, 0>
|
||||
{
|
||||
public:
|
||||
T& operator[](size_t i) {
|
||||
T& operator[](size_t aIndex)
|
||||
{
|
||||
MOZ_CRASH("indexing into zero-length array");
|
||||
}
|
||||
|
||||
const T& operator[](size_t i) const {
|
||||
const T& operator[](size_t aIndex) const
|
||||
{
|
||||
MOZ_CRASH("indexing into zero-length array");
|
||||
}
|
||||
};
|
||||
|
@ -23,17 +23,17 @@
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* Safely subtract two pointers when it is known that end >= begin. This avoids
|
||||
* the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB
|
||||
* set, the unsigned subtraction followed by right shift will produce -1, or
|
||||
* size_t(-1), instead of the real difference.
|
||||
* Safely subtract two pointers when it is known that aEnd >= aBegin. This
|
||||
* avoids the common compiler bug that if (size_t(aEnd) - size_t(aBegin)) has
|
||||
* the MSB set, the unsigned subtraction followed by right shift will produce
|
||||
* -1, or size_t(-1), instead of the real difference.
|
||||
*/
|
||||
template<class T>
|
||||
MOZ_ALWAYS_INLINE size_t
|
||||
PointerRangeSize(T* begin, T* end)
|
||||
PointerRangeSize(T* aBegin, T* aEnd)
|
||||
{
|
||||
MOZ_ASSERT(end >= begin);
|
||||
return (size_t(end) - size_t(begin)) / sizeof(T);
|
||||
MOZ_ASSERT(aEnd >= aBegin);
|
||||
return (size_t(aEnd) - size_t(aBegin)) / sizeof(T);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -44,14 +44,14 @@ PointerRangeSize(T* begin, T* end)
|
||||
*/
|
||||
template<typename T, size_t N>
|
||||
MOZ_CONSTEXPR size_t
|
||||
ArrayLength(T (&arr)[N])
|
||||
ArrayLength(T (&aArr)[N])
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
MOZ_CONSTEXPR size_t
|
||||
ArrayLength(const Array<T, N>& arr)
|
||||
ArrayLength(const Array<T, N>& aArr)
|
||||
{
|
||||
return N;
|
||||
}
|
||||
@ -63,23 +63,23 @@ ArrayLength(const Array<T, N>& arr)
|
||||
*/
|
||||
template<typename T, size_t N>
|
||||
MOZ_CONSTEXPR T*
|
||||
ArrayEnd(T (&arr)[N])
|
||||
ArrayEnd(T (&aArr)[N])
|
||||
{
|
||||
return arr + ArrayLength(arr);
|
||||
return aArr + ArrayLength(aArr);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
MOZ_CONSTEXPR T*
|
||||
ArrayEnd(Array<T, N>& arr)
|
||||
ArrayEnd(Array<T, N>& aArr)
|
||||
{
|
||||
return &arr[0] + ArrayLength(arr);
|
||||
return &aArr[0] + ArrayLength(aArr);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
MOZ_CONSTEXPR const T*
|
||||
ArrayEnd(const Array<T, N>& arr)
|
||||
ArrayEnd(const Array<T, N>& aArr)
|
||||
{
|
||||
return &arr[0] + ArrayLength(arr);
|
||||
return &aArr[0] + ArrayLength(aArr);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
@ -124,21 +124,23 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prints |s| as an assertion failure (using file and ln as the location of the
|
||||
* assertion) to the standard debug-output channel.
|
||||
* Prints |aStr| as an assertion failure (using aFilename and aLine as the
|
||||
* location of the assertion) to the standard debug-output channel.
|
||||
*
|
||||
* Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This
|
||||
* method is primarily for internal use in this header, and only secondarily
|
||||
* for use in implementing release-build assertions.
|
||||
*/
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
MOZ_ReportAssertionFailure(const char* s, const char* file, int ln) MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
|
||||
MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine)
|
||||
MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
|
||||
{
|
||||
#ifdef ANDROID
|
||||
__android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert",
|
||||
"Assertion failure: %s, at %s:%d\n", s, file, ln);
|
||||
"Assertion failure: %s, at %s:%d\n",
|
||||
aStr, aFilename, aLine);
|
||||
#else
|
||||
fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
|
||||
fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine);
|
||||
#ifdef MOZ_DUMP_ASSERTION_STACK
|
||||
nsTraceRefcnt::WalkTheStack(stderr);
|
||||
#endif
|
||||
@ -147,13 +149,13 @@ MOZ_ReportAssertionFailure(const char* s, const char* file, int ln) MOZ_PRETEND_
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
MOZ_ReportCrash(const char* s, const char* file, int ln) MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
|
||||
MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine) MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
|
||||
{
|
||||
#ifdef ANDROID
|
||||
__android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH",
|
||||
"Hit MOZ_CRASH(%s) at %s:%d\n", s, file, ln);
|
||||
"Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
|
||||
#else
|
||||
fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", s, file, ln);
|
||||
fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
|
||||
#ifdef MOZ_DUMP_ASSERTION_STACK
|
||||
nsTraceRefcnt::WalkTheStack(stderr);
|
||||
#endif
|
||||
@ -333,19 +335,23 @@ void ValidateAssertConditionType()
|
||||
{
|
||||
typedef typename RemoveReference<T>::Type ValueT;
|
||||
static_assert(!IsArray<ValueT>::value,
|
||||
"Expected boolean assertion condition, got an array or a string!");
|
||||
"Expected boolean assertion condition, got an array or a "
|
||||
"string!");
|
||||
static_assert(!IsFunction<ValueT>::value,
|
||||
"Expected boolean assertion condition, got a function! Did you intend to call that function?");
|
||||
"Expected boolean assertion condition, got a function! Did "
|
||||
"you intend to call that function?");
|
||||
static_assert(!IsFloatingPoint<ValueT>::value,
|
||||
"It's often a bad idea to assert that a floating-point number is nonzero, "
|
||||
"because such assertions tend to intermittently fail. Shouldn't your code gracefully handle "
|
||||
"this case instead of asserting? Anyway, if you really want to "
|
||||
"do that, write an explicit boolean condition, like !!x or x!=0.");
|
||||
"It's often a bad idea to assert that a floating-point number "
|
||||
"is nonzero, because such assertions tend to intermittently "
|
||||
"fail. Shouldn't your code gracefully handle this case instead "
|
||||
"of asserting? Anyway, if you really want to do that, write an "
|
||||
"explicit boolean condition, like !!x or x!=0.");
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mozilla
|
||||
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) mozilla::detail::ValidateAssertConditionType<decltype(x)>()
|
||||
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \
|
||||
mozilla::detail::ValidateAssertConditionType<decltype(x)>()
|
||||
#else
|
||||
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x)
|
||||
#endif
|
||||
@ -411,10 +417,11 @@ void ValidateAssertConditionType()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that it is
|
||||
* undefined behavior for execution to reach this point. No guarantees are made
|
||||
* about what will happen if this is reached at runtime. Most code should use
|
||||
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra asserts.
|
||||
* MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that
|
||||
* it is undefined behavior for execution to reach this point. No guarantees
|
||||
* are made about what will happen if this is reached at runtime. Most code
|
||||
* should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra
|
||||
* asserts.
|
||||
*/
|
||||
#if defined(__clang__)
|
||||
# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
|
||||
|
511
mfbt/Atomics.h
511
mfbt/Atomics.h
@ -114,6 +114,7 @@ enum MemoryOrdering {
|
||||
* ordering if you can't easily test non-x86 architectures!
|
||||
*/
|
||||
Relaxed,
|
||||
|
||||
/*
|
||||
* When an atomic value is updated with ReleaseAcquire ordering, and
|
||||
* that new value is observed with ReleaseAcquire ordering, prior
|
||||
@ -135,6 +136,7 @@ enum MemoryOrdering {
|
||||
* a good, hard look at actual lock or mutex primitives first.
|
||||
*/
|
||||
ReleaseAcquire,
|
||||
|
||||
/*
|
||||
* When an atomic value is updated with SequentiallyConsistent
|
||||
* ordering, all writes observable when the update is observed, just
|
||||
@ -222,17 +224,26 @@ template<typename T, MemoryOrdering Order>
|
||||
struct IntrinsicMemoryOps : public IntrinsicBase<T, Order>
|
||||
{
|
||||
typedef IntrinsicBase<T, Order> Base;
|
||||
static T load(const typename Base::ValueType& ptr) {
|
||||
return ptr.load(Base::OrderedOp::LoadOrder);
|
||||
|
||||
static T load(const typename Base::ValueType& aPtr)
|
||||
{
|
||||
return aPtr.load(Base::OrderedOp::LoadOrder);
|
||||
}
|
||||
static void store(typename Base::ValueType& ptr, T val) {
|
||||
ptr.store(val, Base::OrderedOp::StoreOrder);
|
||||
|
||||
static void store(typename Base::ValueType& aPtr, T aVal)
|
||||
{
|
||||
aPtr.store(aVal, Base::OrderedOp::StoreOrder);
|
||||
}
|
||||
static T exchange(typename Base::ValueType& ptr, T val) {
|
||||
return ptr.exchange(val, Base::OrderedOp::AtomicRMWOrder);
|
||||
|
||||
static T exchange(typename Base::ValueType& aPtr, T aVal)
|
||||
{
|
||||
return aPtr.exchange(aVal, Base::OrderedOp::AtomicRMWOrder);
|
||||
}
|
||||
static bool compareExchange(typename Base::ValueType& ptr, T oldVal, T newVal) {
|
||||
return ptr.compare_exchange_strong(oldVal, newVal,
|
||||
|
||||
static bool compareExchange(typename Base::ValueType& aPtr,
|
||||
T aOldVal, T aNewVal)
|
||||
{
|
||||
return aPtr.compare_exchange_strong(aOldVal, aNewVal,
|
||||
Base::OrderedOp::AtomicRMWOrder,
|
||||
Base::OrderedOp::CompareExchangeFailureOrder);
|
||||
}
|
||||
@ -242,11 +253,15 @@ template<typename T, MemoryOrdering Order>
|
||||
struct IntrinsicAddSub : public IntrinsicBase<T, Order>
|
||||
{
|
||||
typedef IntrinsicBase<T, Order> Base;
|
||||
static T add(typename Base::ValueType& ptr, T val) {
|
||||
return ptr.fetch_add(val, Base::OrderedOp::AtomicRMWOrder);
|
||||
|
||||
static T add(typename Base::ValueType& aPtr, T aVal)
|
||||
{
|
||||
return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
|
||||
}
|
||||
static T sub(typename Base::ValueType& ptr, T val) {
|
||||
return ptr.fetch_sub(val, Base::OrderedOp::AtomicRMWOrder);
|
||||
|
||||
static T sub(typename Base::ValueType& aPtr, T aVal)
|
||||
{
|
||||
return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
|
||||
}
|
||||
};
|
||||
|
||||
@ -254,11 +269,15 @@ template<typename T, MemoryOrdering Order>
|
||||
struct IntrinsicAddSub<T*, Order> : public IntrinsicBase<T*, Order>
|
||||
{
|
||||
typedef IntrinsicBase<T*, Order> Base;
|
||||
static T* add(typename Base::ValueType& ptr, ptrdiff_t val) {
|
||||
return ptr.fetch_add(fixupAddend(val), Base::OrderedOp::AtomicRMWOrder);
|
||||
|
||||
static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal)
|
||||
{
|
||||
return aPtr.fetch_add(fixupAddend(aVal), Base::OrderedOp::AtomicRMWOrder);
|
||||
}
|
||||
static T* sub(typename Base::ValueType& ptr, ptrdiff_t val) {
|
||||
return ptr.fetch_sub(fixupAddend(val), Base::OrderedOp::AtomicRMWOrder);
|
||||
|
||||
static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal)
|
||||
{
|
||||
return aPtr.fetch_sub(fixupAddend(aVal), Base::OrderedOp::AtomicRMWOrder);
|
||||
}
|
||||
private:
|
||||
/*
|
||||
@ -266,14 +285,14 @@ struct IntrinsicAddSub<T*, Order> : public IntrinsicBase<T*, Order>
|
||||
* atomic<T*> is not the same as adding X to a T*. Hence the need
|
||||
* for this function to provide the correct addend.
|
||||
*/
|
||||
static ptrdiff_t fixupAddend(ptrdiff_t val) {
|
||||
static ptrdiff_t fixupAddend(ptrdiff_t aVal) {
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
return val;
|
||||
return aVal;
|
||||
#elif defined(__GNUC__) && MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) && \
|
||||
!MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
|
||||
return val * sizeof(T);
|
||||
return aVal * sizeof(T);
|
||||
#else
|
||||
return val;
|
||||
return aVal;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@ -282,11 +301,15 @@ template<typename T, MemoryOrdering Order>
|
||||
struct IntrinsicIncDec : public IntrinsicAddSub<T, Order>
|
||||
{
|
||||
typedef IntrinsicBase<T, Order> Base;
|
||||
static T inc(typename Base::ValueType& ptr) {
|
||||
return IntrinsicAddSub<T, Order>::add(ptr, 1);
|
||||
|
||||
static T inc(typename Base::ValueType& aPtr)
|
||||
{
|
||||
return IntrinsicAddSub<T, Order>::add(aPtr, 1);
|
||||
}
|
||||
static T dec(typename Base::ValueType& ptr) {
|
||||
return IntrinsicAddSub<T, Order>::sub(ptr, 1);
|
||||
|
||||
static T dec(typename Base::ValueType& aPtr)
|
||||
{
|
||||
return IntrinsicAddSub<T, Order>::sub(aPtr, 1);
|
||||
}
|
||||
};
|
||||
|
||||
@ -295,14 +318,20 @@ struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>,
|
||||
public IntrinsicIncDec<T, Order>
|
||||
{
|
||||
typedef IntrinsicBase<T, Order> Base;
|
||||
static T or_(typename Base::ValueType& ptr, T val) {
|
||||
return ptr.fetch_or(val, Base::OrderedOp::AtomicRMWOrder);
|
||||
|
||||
static T or_(typename Base::ValueType& aPtr, T aVal)
|
||||
{
|
||||
return aPtr.fetch_or(aVal, Base::OrderedOp::AtomicRMWOrder);
|
||||
}
|
||||
static T xor_(typename Base::ValueType& ptr, T val) {
|
||||
return ptr.fetch_xor(val, Base::OrderedOp::AtomicRMWOrder);
|
||||
|
||||
static T xor_(typename Base::ValueType& aPtr, T aVal)
|
||||
{
|
||||
return aPtr.fetch_xor(aVal, Base::OrderedOp::AtomicRMWOrder);
|
||||
}
|
||||
static T and_(typename Base::ValueType& ptr, T val) {
|
||||
return ptr.fetch_and(val, Base::OrderedOp::AtomicRMWOrder);
|
||||
|
||||
static T and_(typename Base::ValueType& aPtr, T aVal)
|
||||
{
|
||||
return aPtr.fetch_and(aVal, Base::OrderedOp::AtomicRMWOrder);
|
||||
}
|
||||
};
|
||||
|
||||
@ -379,28 +408,34 @@ struct Barrier<SequentiallyConsistent>
|
||||
template<typename T, MemoryOrdering Order>
|
||||
struct IntrinsicMemoryOps
|
||||
{
|
||||
static T load(const T& ptr) {
|
||||
static T load(const T& aPtr)
|
||||
{
|
||||
Barrier<Order>::beforeLoad();
|
||||
T val = ptr;
|
||||
T val = aPtr;
|
||||
Barrier<Order>::afterLoad();
|
||||
return val;
|
||||
}
|
||||
static void store(T& ptr, T val) {
|
||||
|
||||
static void store(T& aPtr, T aVal)
|
||||
{
|
||||
Barrier<Order>::beforeStore();
|
||||
ptr = val;
|
||||
aPtr = aVal;
|
||||
Barrier<Order>::afterStore();
|
||||
}
|
||||
static T exchange(T& ptr, T val) {
|
||||
|
||||
static T exchange(T& aPtr, T aVal)
|
||||
{
|
||||
// __sync_lock_test_and_set is only an acquire barrier; loads and stores
|
||||
// can't be moved up from after to before it, but they can be moved down
|
||||
// from before to after it. We may want a stricter ordering, so we need
|
||||
// an explicit barrier.
|
||||
|
||||
Barrier<Order>::beforeStore();
|
||||
return __sync_lock_test_and_set(&ptr, val);
|
||||
return __sync_lock_test_and_set(&aPtr, aVal);
|
||||
}
|
||||
static bool compareExchange(T& ptr, T oldVal, T newVal) {
|
||||
return __sync_bool_compare_and_swap(&ptr, oldVal, newVal);
|
||||
|
||||
static bool compareExchange(T& aPtr, T aOldVal, T aNewVal)
|
||||
{
|
||||
return __sync_bool_compare_and_swap(&aPtr, aOldVal, aNewVal);
|
||||
}
|
||||
};
|
||||
|
||||
@ -408,11 +443,15 @@ template<typename T>
|
||||
struct IntrinsicAddSub
|
||||
{
|
||||
typedef T ValueType;
|
||||
static T add(T& ptr, T val) {
|
||||
return __sync_fetch_and_add(&ptr, val);
|
||||
|
||||
static T add(T& aPtr, T aVal)
|
||||
{
|
||||
return __sync_fetch_and_add(&aPtr, aVal);
|
||||
}
|
||||
static T sub(T& ptr, T val) {
|
||||
return __sync_fetch_and_sub(&ptr, val);
|
||||
|
||||
static T sub(T& aPtr, T aVal)
|
||||
{
|
||||
return __sync_fetch_and_sub(&aPtr, aVal);
|
||||
}
|
||||
};
|
||||
|
||||
@ -420,6 +459,7 @@ template<typename T>
|
||||
struct IntrinsicAddSub<T*>
|
||||
{
|
||||
typedef T* ValueType;
|
||||
|
||||
/*
|
||||
* The reinterpret_casts are needed so that
|
||||
* __sync_fetch_and_{add,sub} will properly type-check.
|
||||
@ -427,36 +467,33 @@ struct IntrinsicAddSub<T*>
|
||||
* Also, these functions do not provide standard semantics for
|
||||
* pointer types, so we need to adjust the addend.
|
||||
*/
|
||||
static ValueType add(ValueType& ptr, ptrdiff_t val) {
|
||||
ValueType amount = reinterpret_cast<ValueType>(val * sizeof(T));
|
||||
return __sync_fetch_and_add(&ptr, amount);
|
||||
static ValueType add(ValueType& aPtr, ptrdiff_t aVal)
|
||||
{
|
||||
ValueType amount = reinterpret_cast<ValueType>(aVal * sizeof(T));
|
||||
return __sync_fetch_and_add(&aPtr, amount);
|
||||
}
|
||||
static ValueType sub(ValueType& ptr, ptrdiff_t val) {
|
||||
ValueType amount = reinterpret_cast<ValueType>(val * sizeof(T));
|
||||
return __sync_fetch_and_sub(&ptr, amount);
|
||||
|
||||
static ValueType sub(ValueType& aPtr, ptrdiff_t aVal)
|
||||
{
|
||||
ValueType amount = reinterpret_cast<ValueType>(aVal * sizeof(T));
|
||||
return __sync_fetch_and_sub(&aPtr, amount);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IntrinsicIncDec : public IntrinsicAddSub<T>
|
||||
{
|
||||
static T inc(T& ptr) { return IntrinsicAddSub<T>::add(ptr, 1); }
|
||||
static T dec(T& ptr) { return IntrinsicAddSub<T>::sub(ptr, 1); }
|
||||
static T inc(T& aPtr) { return IntrinsicAddSub<T>::add(aPtr, 1); }
|
||||
static T dec(T& aPtr) { return IntrinsicAddSub<T>::sub(aPtr, 1); }
|
||||
};
|
||||
|
||||
template<typename T, MemoryOrdering Order>
|
||||
struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>,
|
||||
public IntrinsicIncDec<T>
|
||||
{
|
||||
static T or_(T& ptr, T val) {
|
||||
return __sync_fetch_and_or(&ptr, val);
|
||||
}
|
||||
static T xor_(T& ptr, T val) {
|
||||
return __sync_fetch_and_xor(&ptr, val);
|
||||
}
|
||||
static T and_(T& ptr, T val) {
|
||||
return __sync_fetch_and_and(&ptr, val);
|
||||
}
|
||||
static T or_( T& aPtr, T aVal) { return __sync_fetch_and_or(&aPtr, aVal); }
|
||||
static T xor_(T& aPtr, T aVal) { return __sync_fetch_and_xor(&aPtr, aVal); }
|
||||
static T and_(T& aPtr, T aVal) { return __sync_fetch_and_and(&aPtr, aVal); }
|
||||
};
|
||||
|
||||
template<typename T, MemoryOrdering Order>
|
||||
@ -483,12 +520,12 @@ struct AtomicIntrinsics<T*, Order> : public IntrinsicMemoryOps<T*, Order>,
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
long __cdecl _InterlockedExchangeAdd(long volatile* dst, long value);
|
||||
long __cdecl _InterlockedOr(long volatile* dst, long value);
|
||||
long __cdecl _InterlockedXor(long volatile* dst, long value);
|
||||
long __cdecl _InterlockedAnd(long volatile* dst, long value);
|
||||
long __cdecl _InterlockedExchange(long volatile *dst, long value);
|
||||
long __cdecl _InterlockedCompareExchange(long volatile *dst, long newVal, long oldVal);
|
||||
long __cdecl _InterlockedExchangeAdd(long volatile* aDst, long aVal);
|
||||
long __cdecl _InterlockedOr(long volatile* aDst, long aVal);
|
||||
long __cdecl _InterlockedXor(long volatile* aDst, long aVal);
|
||||
long __cdecl _InterlockedAnd(long volatile* aDst, long aVal);
|
||||
long __cdecl _InterlockedExchange(long volatile *aDst, long aVal);
|
||||
long __cdecl _InterlockedCompareExchange(long volatile *aDst, long aNewVal, long aOldVal);
|
||||
}
|
||||
|
||||
# pragma intrinsic(_InterlockedExchangeAdd)
|
||||
@ -514,34 +551,34 @@ namespace detail {
|
||||
* The PrimitiveIntrinsics template should define |Type|, the datatype of size
|
||||
* DataSize upon which we operate, and the following eight functions.
|
||||
*
|
||||
* static Type add(Type* ptr, Type val);
|
||||
* static Type sub(Type* ptr, Type val);
|
||||
* static Type or_(Type* ptr, Type val);
|
||||
* static Type xor_(Type* ptr, Type val);
|
||||
* static Type and_(Type* ptr, Type val);
|
||||
* static Type add(Type* aPtr, Type aVal);
|
||||
* static Type sub(Type* aPtr, Type aVal);
|
||||
* static Type or_(Type* aPtr, Type aVal);
|
||||
* static Type xor_(Type* aPtr, Type aVal);
|
||||
* static Type and_(Type* aPtr, Type aVal);
|
||||
*
|
||||
* These functions perform the obvious operation on the value contained in
|
||||
* |*ptr| combined with |val| and return the value previously stored in
|
||||
* |*ptr|.
|
||||
* |*aPtr| combined with |aVal| and return the value previously stored in
|
||||
* |*aPtr|.
|
||||
*
|
||||
* static void store(Type* ptr, Type val);
|
||||
* static void store(Type* aPtr, Type aVal);
|
||||
*
|
||||
* This function atomically stores |val| into |*ptr| and must provide a full
|
||||
* This function atomically stores |aVal| into |*aPtr| and must provide a full
|
||||
* memory fence after the store to prevent compiler and hardware instruction
|
||||
* reordering. It should also act as a compiler barrier to prevent reads and
|
||||
* writes from moving to after the store.
|
||||
*
|
||||
* static Type exchange(Type* ptr, Type val);
|
||||
* static Type exchange(Type* aPtr, Type aVal);
|
||||
*
|
||||
* This function atomically stores |val| into |*ptr| and returns the previous
|
||||
* contents of *ptr;
|
||||
* This function atomically stores |aVal| into |*aPtr| and returns the
|
||||
* previous contents of |*aPtr|;
|
||||
*
|
||||
* static bool compareExchange(Type* ptr, Type oldVal, Type newVal);
|
||||
* static bool compareExchange(Type* aPtr, Type aOldVal, Type aNewVal);
|
||||
*
|
||||
* This function atomically performs the following operation:
|
||||
*
|
||||
* if (*ptr == oldVal) {
|
||||
* *ptr = newVal;
|
||||
* if (*aPtr == aOldVal) {
|
||||
* *aPtr = aNewVal;
|
||||
* return true;
|
||||
* } else {
|
||||
* return false;
|
||||
@ -555,52 +592,67 @@ struct PrimitiveIntrinsics<4>
|
||||
{
|
||||
typedef long Type;
|
||||
|
||||
static Type add(Type* ptr, Type val) {
|
||||
return _InterlockedExchangeAdd(ptr, val);
|
||||
static Type add(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedExchangeAdd(aPtr, aVal);
|
||||
}
|
||||
static Type sub(Type* ptr, Type val) {
|
||||
|
||||
static Type sub(Type* aPtr, Type aVal)
|
||||
{
|
||||
/*
|
||||
* _InterlockedExchangeSubtract isn't available before Windows 7,
|
||||
* and we must support Windows XP.
|
||||
*/
|
||||
return _InterlockedExchangeAdd(ptr, -val);
|
||||
return _InterlockedExchangeAdd(aPtr, -aVal);
|
||||
}
|
||||
static Type or_(Type* ptr, Type val) {
|
||||
return _InterlockedOr(ptr, val);
|
||||
|
||||
static Type or_(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedOr(aPtr, aVal);
|
||||
}
|
||||
static Type xor_(Type* ptr, Type val) {
|
||||
return _InterlockedXor(ptr, val);
|
||||
|
||||
static Type xor_(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedXor(aPtr, aVal);
|
||||
}
|
||||
static Type and_(Type* ptr, Type val) {
|
||||
return _InterlockedAnd(ptr, val);
|
||||
|
||||
static Type and_(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedAnd(aPtr, aVal);
|
||||
}
|
||||
static void store(Type* ptr, Type val) {
|
||||
_InterlockedExchange(ptr, val);
|
||||
|
||||
static void store(Type* aPtr, Type aVal)
|
||||
{
|
||||
_InterlockedExchange(aPtr, aVal);
|
||||
}
|
||||
static Type exchange(Type* ptr, Type val) {
|
||||
return _InterlockedExchange(ptr, val);
|
||||
|
||||
static Type exchange(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedExchange(aPtr, aVal);
|
||||
}
|
||||
static bool compareExchange(Type* ptr, Type oldVal, Type newVal) {
|
||||
return _InterlockedCompareExchange(ptr, newVal, oldVal) == oldVal;
|
||||
|
||||
static bool compareExchange(Type* aPtr, Type aOldVal, Type aNewVal)
|
||||
{
|
||||
return _InterlockedCompareExchange(aPtr, aNewVal, aOldVal) == aOldVal;
|
||||
}
|
||||
};
|
||||
|
||||
# if defined(_M_X64)
|
||||
|
||||
extern "C" {
|
||||
long long __cdecl _InterlockedExchangeAdd64(long long volatile* dst,
|
||||
long long value);
|
||||
long long __cdecl _InterlockedOr64(long long volatile* dst,
|
||||
long long value);
|
||||
long long __cdecl _InterlockedXor64(long long volatile* dst,
|
||||
long long value);
|
||||
long long __cdecl _InterlockedAnd64(long long volatile* dst,
|
||||
long long value);
|
||||
long long __cdecl _InterlockedExchange64(long long volatile* dst,
|
||||
long long value);
|
||||
long long __cdecl _InterlockedCompareExchange64(long long volatile* dst,
|
||||
long long newVal,
|
||||
long long oldVal);
|
||||
long long __cdecl _InterlockedExchangeAdd64(long long volatile* aDst,
|
||||
long long aVal);
|
||||
long long __cdecl _InterlockedOr64(long long volatile* aDst,
|
||||
long long aVal);
|
||||
long long __cdecl _InterlockedXor64(long long volatile* aDst,
|
||||
long long aVal);
|
||||
long long __cdecl _InterlockedAnd64(long long volatile* aDst,
|
||||
long long aVal);
|
||||
long long __cdecl _InterlockedExchange64(long long volatile* aDst,
|
||||
long long aVal);
|
||||
long long __cdecl _InterlockedCompareExchange64(long long volatile* aDst,
|
||||
long long aNewVal,
|
||||
long long aOldVal);
|
||||
}
|
||||
|
||||
# pragma intrinsic(_InterlockedExchangeAdd64)
|
||||
@ -615,32 +667,47 @@ struct PrimitiveIntrinsics<8>
|
||||
{
|
||||
typedef __int64 Type;
|
||||
|
||||
static Type add(Type* ptr, Type val) {
|
||||
return _InterlockedExchangeAdd64(ptr, val);
|
||||
static Type add(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedExchangeAdd64(aPtr, aVal);
|
||||
}
|
||||
static Type sub(Type* ptr, Type val) {
|
||||
|
||||
static Type sub(Type* aPtr, Type aVal)
|
||||
{
|
||||
/*
|
||||
* There is no _InterlockedExchangeSubtract64.
|
||||
*/
|
||||
return _InterlockedExchangeAdd64(ptr, -val);
|
||||
return _InterlockedExchangeAdd64(aPtr, -aVal);
|
||||
}
|
||||
static Type or_(Type* ptr, Type val) {
|
||||
return _InterlockedOr64(ptr, val);
|
||||
|
||||
static Type or_(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedOr64(aPtr, aVal);
|
||||
}
|
||||
static Type xor_(Type* ptr, Type val) {
|
||||
return _InterlockedXor64(ptr, val);
|
||||
|
||||
static Type xor_(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedXor64(aPtr, aVal);
|
||||
}
|
||||
static Type and_(Type* ptr, Type val) {
|
||||
return _InterlockedAnd64(ptr, val);
|
||||
|
||||
static Type and_(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedAnd64(aPtr, aVal);
|
||||
}
|
||||
static void store(Type* ptr, Type val) {
|
||||
_InterlockedExchange64(ptr, val);
|
||||
|
||||
static void store(Type* aPtr, Type aVal)
|
||||
{
|
||||
_InterlockedExchange64(aPtr, aVal);
|
||||
}
|
||||
static Type exchange(Type* ptr, Type val) {
|
||||
return _InterlockedExchange64(ptr, val);
|
||||
|
||||
static Type exchange(Type* aPtr, Type aVal)
|
||||
{
|
||||
return _InterlockedExchange64(aPtr, aVal);
|
||||
}
|
||||
static bool compareExchange(Type* ptr, Type oldVal, Type newVal) {
|
||||
return _InterlockedCompareExchange64(ptr, newVal, oldVal) == oldVal;
|
||||
|
||||
static bool compareExchange(Type* aPtr, Type aOldVal, Type aNewVal)
|
||||
{
|
||||
return _InterlockedCompareExchange64(aPtr, aNewVal, aOldVal) == aOldVal;
|
||||
}
|
||||
};
|
||||
|
||||
@ -685,15 +752,15 @@ struct Barrier<SequentiallyConsistent>
|
||||
template<typename PrimType, typename T>
|
||||
struct CastHelper
|
||||
{
|
||||
static PrimType toPrimType(T val) { return static_cast<PrimType>(val); }
|
||||
static T fromPrimType(PrimType val) { return static_cast<T>(val); }
|
||||
static PrimType toPrimType(T aVal) { return static_cast<PrimType>(aVal); }
|
||||
static T fromPrimType(PrimType aVal) { return static_cast<T>(aVal); }
|
||||
};
|
||||
|
||||
template<typename PrimType, typename T>
|
||||
struct CastHelper<PrimType, T*>
|
||||
{
|
||||
static PrimType toPrimType(T* val) { return reinterpret_cast<PrimType>(val); }
|
||||
static T* fromPrimType(PrimType val) { return reinterpret_cast<T*>(val); }
|
||||
static PrimType toPrimType(T* aVal) { return reinterpret_cast<PrimType>(aVal); }
|
||||
static T* fromPrimType(PrimType aVal) { return reinterpret_cast<T*>(aVal); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@ -714,34 +781,43 @@ struct IntrinsicMemoryOps : public IntrinsicBase<T>
|
||||
typedef typename IntrinsicBase<T>::Primitives Primitives;
|
||||
typedef typename IntrinsicBase<T>::PrimType PrimType;
|
||||
typedef typename IntrinsicBase<T>::Cast Cast;
|
||||
static ValueType load(const ValueType& ptr) {
|
||||
|
||||
static ValueType load(const ValueType& aPtr)
|
||||
{
|
||||
Barrier<Order>::beforeLoad();
|
||||
ValueType val = ptr;
|
||||
ValueType val = aPtr;
|
||||
Barrier<Order>::afterLoad();
|
||||
return val;
|
||||
}
|
||||
static void store(ValueType& ptr, ValueType val) {
|
||||
|
||||
static void store(ValueType& aPtr, ValueType aVal)
|
||||
{
|
||||
// For SequentiallyConsistent, Primitives::store() will generate the
|
||||
// proper memory fence. Everything else just needs a barrier before
|
||||
// the store.
|
||||
if (Order == SequentiallyConsistent) {
|
||||
Primitives::store(reinterpret_cast<PrimType*>(&ptr),
|
||||
Cast::toPrimType(val));
|
||||
Primitives::store(reinterpret_cast<PrimType*>(&aPtr),
|
||||
Cast::toPrimType(aVal));
|
||||
} else {
|
||||
Barrier<Order>::beforeStore();
|
||||
ptr = val;
|
||||
aPtr = aVal;
|
||||
}
|
||||
}
|
||||
static ValueType exchange(ValueType& ptr, ValueType val) {
|
||||
|
||||
static ValueType exchange(ValueType& aPtr, ValueType aVal)
|
||||
{
|
||||
PrimType oldval =
|
||||
Primitives::exchange(reinterpret_cast<PrimType*>(&ptr),
|
||||
Cast::toPrimType(val));
|
||||
Primitives::exchange(reinterpret_cast<PrimType*>(&aPtr),
|
||||
Cast::toPrimType(aVal));
|
||||
return Cast::fromPrimType(oldval);
|
||||
}
|
||||
static bool compareExchange(ValueType& ptr, ValueType oldVal, ValueType newVal) {
|
||||
return Primitives::compareExchange(reinterpret_cast<PrimType*>(&ptr),
|
||||
Cast::toPrimType(oldVal),
|
||||
Cast::toPrimType(newVal));
|
||||
|
||||
static bool compareExchange(ValueType& aPtr, ValueType aOldVal,
|
||||
ValueType aNewVal)
|
||||
{
|
||||
return Primitives::compareExchange(reinterpret_cast<PrimType*>(&aPtr),
|
||||
Cast::toPrimType(aOldVal),
|
||||
Cast::toPrimType(aNewVal));
|
||||
}
|
||||
};
|
||||
|
||||
@ -754,16 +830,18 @@ struct IntrinsicApplyHelper : public IntrinsicBase<T>
|
||||
typedef PrimType (*BinaryOp)(PrimType*, PrimType);
|
||||
typedef PrimType (*UnaryOp)(PrimType*);
|
||||
|
||||
static ValueType applyBinaryFunction(BinaryOp op, ValueType& ptr,
|
||||
ValueType val) {
|
||||
PrimType* primTypePtr = reinterpret_cast<PrimType*>(&ptr);
|
||||
PrimType primTypeVal = Cast::toPrimType(val);
|
||||
return Cast::fromPrimType(op(primTypePtr, primTypeVal));
|
||||
static ValueType applyBinaryFunction(BinaryOp aOp, ValueType& aPtr,
|
||||
ValueType aVal)
|
||||
{
|
||||
PrimType* primTypePtr = reinterpret_cast<PrimType*>(&aPtr);
|
||||
PrimType primTypeVal = Cast::toPrimType(aVal);
|
||||
return Cast::fromPrimType(aOp(primTypePtr, primTypeVal));
|
||||
}
|
||||
|
||||
static ValueType applyUnaryFunction(UnaryOp op, ValueType& ptr) {
|
||||
PrimType* primTypePtr = reinterpret_cast<PrimType*>(&ptr);
|
||||
return Cast::fromPrimType(op(primTypePtr));
|
||||
static ValueType applyUnaryFunction(UnaryOp aOp, ValueType& aPtr)
|
||||
{
|
||||
PrimType* primTypePtr = reinterpret_cast<PrimType*>(&aPtr);
|
||||
return Cast::fromPrimType(aOp(primTypePtr));
|
||||
}
|
||||
};
|
||||
|
||||
@ -772,11 +850,15 @@ struct IntrinsicAddSub : public IntrinsicApplyHelper<T>
|
||||
{
|
||||
typedef typename IntrinsicApplyHelper<T>::ValueType ValueType;
|
||||
typedef typename IntrinsicBase<T>::Primitives Primitives;
|
||||
static ValueType add(ValueType& ptr, ValueType val) {
|
||||
return applyBinaryFunction(&Primitives::add, ptr, val);
|
||||
|
||||
static ValueType add(ValueType& aPtr, ValueType aVal)
|
||||
{
|
||||
return applyBinaryFunction(&Primitives::add, aPtr, aVal);
|
||||
}
|
||||
static ValueType sub(ValueType& ptr, ValueType val) {
|
||||
return applyBinaryFunction(&Primitives::sub, ptr, val);
|
||||
|
||||
static ValueType sub(ValueType& aPtr, ValueType aVal)
|
||||
{
|
||||
return applyBinaryFunction(&Primitives::sub, aPtr, aVal);
|
||||
}
|
||||
};
|
||||
|
||||
@ -784,13 +866,17 @@ template<typename T>
|
||||
struct IntrinsicAddSub<T*> : public IntrinsicApplyHelper<T*>
|
||||
{
|
||||
typedef typename IntrinsicApplyHelper<T*>::ValueType ValueType;
|
||||
static ValueType add(ValueType& ptr, ptrdiff_t amount) {
|
||||
return applyBinaryFunction(&Primitives::add, ptr,
|
||||
(ValueType)(amount * sizeof(ValueType)));
|
||||
|
||||
static ValueType add(ValueType& aPtr, ptrdiff_t aAmount)
|
||||
{
|
||||
return applyBinaryFunction(&Primitives::add, aPtr,
|
||||
(ValueType)(aAmount * sizeof(ValueType)));
|
||||
}
|
||||
static ValueType sub(ValueType& ptr, ptrdiff_t amount) {
|
||||
return applyBinaryFunction(&Primitives::sub, ptr,
|
||||
(ValueType)(amount * sizeof(ValueType)));
|
||||
|
||||
static ValueType sub(ValueType& aPtr, ptrdiff_t aAmount)
|
||||
{
|
||||
return applyBinaryFunction(&Primitives::sub, aPtr,
|
||||
(ValueType)(aAmount * sizeof(ValueType)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -798,8 +884,8 @@ template<typename T>
|
||||
struct IntrinsicIncDec : public IntrinsicAddSub<T>
|
||||
{
|
||||
typedef typename IntrinsicAddSub<T>::ValueType ValueType;
|
||||
static ValueType inc(ValueType& ptr) { return add(ptr, 1); }
|
||||
static ValueType dec(ValueType& ptr) { return sub(ptr, 1); }
|
||||
static ValueType inc(ValueType& aPtr) { return add(aPtr, 1); }
|
||||
static ValueType dec(ValueType& aPtr) { return sub(aPtr, 1); }
|
||||
};
|
||||
|
||||
template<typename T, MemoryOrdering Order>
|
||||
@ -807,14 +893,20 @@ struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>,
|
||||
public IntrinsicIncDec<T>
|
||||
{
|
||||
typedef typename IntrinsicIncDec<T>::ValueType ValueType;
|
||||
static ValueType or_(ValueType& ptr, T val) {
|
||||
return applyBinaryFunction(&Primitives::or_, ptr, val);
|
||||
|
||||
static ValueType or_(ValueType& aPtr, T aVal)
|
||||
{
|
||||
return applyBinaryFunction(&Primitives::or_, aPtr, aVal);
|
||||
}
|
||||
static ValueType xor_(ValueType& ptr, T val) {
|
||||
return applyBinaryFunction(&Primitives::xor_, ptr, val);
|
||||
|
||||
static ValueType xor_(ValueType& aPtr, T aVal)
|
||||
{
|
||||
return applyBinaryFunction(&Primitives::xor_, aPtr, aVal);
|
||||
}
|
||||
static ValueType and_(ValueType& ptr, T val) {
|
||||
return applyBinaryFunction(&Primitives::and_, ptr, val);
|
||||
|
||||
static ValueType and_(ValueType& aPtr, T aVal)
|
||||
{
|
||||
return applyBinaryFunction(&Primitives::and_, aPtr, aVal);
|
||||
}
|
||||
};
|
||||
|
||||
@ -857,17 +949,19 @@ class AtomicBase
|
||||
// operator T() here, it would cause errors when comparing Atomic<bool> with
|
||||
// a regular bool.
|
||||
|
||||
T operator=(T aValue) {
|
||||
Intrinsics::store(mValue, aValue);
|
||||
return aValue;
|
||||
T operator=(T aVal)
|
||||
{
|
||||
Intrinsics::store(mValue, aVal);
|
||||
return aVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an atomic swap operation. aValue is stored and the previous
|
||||
* Performs an atomic swap operation. aVal is stored and the previous
|
||||
* value of this variable is returned.
|
||||
*/
|
||||
T exchange(T aValue) {
|
||||
return Intrinsics::exchange(mValue, aValue);
|
||||
T exchange(T aVal)
|
||||
{
|
||||
return Intrinsics::exchange(mValue, aVal);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -881,7 +975,8 @@ class AtomicBase
|
||||
* return false;
|
||||
* }
|
||||
*/
|
||||
bool compareExchange(T aOldValue, T aNewValue) {
|
||||
bool compareExchange(T aOldValue, T aNewValue)
|
||||
{
|
||||
return Intrinsics::compareExchange(mValue, aOldValue, aNewValue);
|
||||
}
|
||||
|
||||
@ -945,7 +1040,8 @@ class Atomic;
|
||||
* swap method is provided.
|
||||
*/
|
||||
template<typename T, MemoryOrdering Order>
|
||||
class Atomic<T, Order, typename EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value>::Type>
|
||||
class Atomic<T, Order, typename EnableIf<IsIntegral<T>::value &&
|
||||
!IsSame<T, bool>::value>::Type>
|
||||
: public detail::AtomicBaseIncDec<T, Order>
|
||||
{
|
||||
typedef typename detail::AtomicBaseIncDec<T, Order> Base;
|
||||
@ -956,11 +1052,30 @@ class Atomic<T, Order, typename EnableIf<IsIntegral<T>::value && !IsSame<T, bool
|
||||
|
||||
using Base::operator=;
|
||||
|
||||
T operator+=(T delta) { return Base::Intrinsics::add(Base::mValue, delta) + delta; }
|
||||
T operator-=(T delta) { return Base::Intrinsics::sub(Base::mValue, delta) - delta; }
|
||||
T operator|=(T val) { return Base::Intrinsics::or_(Base::mValue, val) | val; }
|
||||
T operator^=(T val) { return Base::Intrinsics::xor_(Base::mValue, val) ^ val; }
|
||||
T operator&=(T val) { return Base::Intrinsics::and_(Base::mValue, val) & val; }
|
||||
T operator+=(T aDelta)
|
||||
{
|
||||
return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
|
||||
}
|
||||
|
||||
T operator-=(T aDelta)
|
||||
{
|
||||
return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
|
||||
}
|
||||
|
||||
T operator|=(T aVal)
|
||||
{
|
||||
return Base::Intrinsics::or_(Base::mValue, aVal) | aVal;
|
||||
}
|
||||
|
||||
T operator^=(T aVal)
|
||||
{
|
||||
return Base::Intrinsics::xor_(Base::mValue, aVal) ^ aVal;
|
||||
}
|
||||
|
||||
T operator&=(T aVal)
|
||||
{
|
||||
return Base::Intrinsics::and_(Base::mValue, aVal) & aVal;
|
||||
}
|
||||
|
||||
private:
|
||||
Atomic(Atomic<T, Order>& aOther) MOZ_DELETE;
|
||||
@ -985,11 +1100,14 @@ class Atomic<T*, Order> : public detail::AtomicBaseIncDec<T*, Order>
|
||||
|
||||
using Base::operator=;
|
||||
|
||||
T* operator+=(ptrdiff_t delta) {
|
||||
return Base::Intrinsics::add(Base::mValue, delta) + delta;
|
||||
T* operator+=(ptrdiff_t aDelta)
|
||||
{
|
||||
return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
|
||||
}
|
||||
T* operator-=(ptrdiff_t delta) {
|
||||
return Base::Intrinsics::sub(Base::mValue, delta) - delta;
|
||||
|
||||
T* operator-=(ptrdiff_t aDelta)
|
||||
{
|
||||
return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1046,10 +1164,23 @@ class Atomic<bool, Order>
|
||||
MOZ_CONSTEXPR Atomic(bool aInit) : Base(aInit) {}
|
||||
|
||||
// We provide boolean wrappers for the underlying AtomicBase methods.
|
||||
operator bool() const { return Base::Intrinsics::load(Base::mValue); }
|
||||
bool operator=(bool aValue) { return Base::operator=(aValue); }
|
||||
bool exchange(bool aValue) { return Base::exchange(aValue); }
|
||||
bool compareExchange(bool aOldValue, bool aNewValue) {
|
||||
operator bool() const
|
||||
{
|
||||
return Base::Intrinsics::load(Base::mValue);
|
||||
}
|
||||
|
||||
bool operator=(bool aVal)
|
||||
{
|
||||
return Base::operator=(aVal);
|
||||
}
|
||||
|
||||
bool exchange(bool aVal)
|
||||
{
|
||||
return Base::exchange(aVal);
|
||||
}
|
||||
|
||||
bool compareExchange(bool aOldValue, bool aNewValue)
|
||||
{
|
||||
return Base::compareExchange(aOldValue, aNewValue);
|
||||
}
|
||||
|
||||
|
@ -14,12 +14,12 @@
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* The algorithm searches the given container 'c' over the sorted index range
|
||||
* [begin, end) for an index 'i' where 'c[i] == target'. If such an index 'i' is
|
||||
* found, BinarySearch returns 'true' and the index is returned via the outparam
|
||||
* 'matchOrInsertionPoint'. If no index is found, BinarySearch returns 'false'
|
||||
* and the outparam returns the first index in [begin, end] where 'target' can
|
||||
* be inserted to maintain sorted order.
|
||||
* The algorithm searches the given container |aContainer| over the sorted
|
||||
* index range [aBegin, aEnd) for an index |i| where |aContainer[i] == aTarget|.
|
||||
* If such an index |i| is found, BinarySearch returns |true| and the index is
|
||||
* returned via the outparam |aMatchOrInsertionPoint|. If no index is found,
|
||||
* BinarySearch returns |false| and the outparam returns the first index in
|
||||
* [aBegin, aEnd] where |aTarget| can be inserted to maintain sorted order.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
@ -32,32 +32,34 @@ namespace mozilla {
|
||||
|
||||
template <typename Container, typename T>
|
||||
bool
|
||||
BinarySearch(const Container &c, size_t begin, size_t end, T target, size_t *matchOrInsertionPoint)
|
||||
BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
|
||||
T aTarget, size_t* aMatchOrInsertionPoint)
|
||||
{
|
||||
MOZ_ASSERT(begin <= end);
|
||||
MOZ_ASSERT(aBegin <= aEnd);
|
||||
|
||||
size_t low = begin;
|
||||
size_t high = end;
|
||||
size_t low = aBegin;
|
||||
size_t high = aEnd;
|
||||
while (low != high) {
|
||||
size_t middle = low + (high - low) / 2;
|
||||
const T &middleValue = c[middle];
|
||||
const T& middleValue = aContainer[middle];
|
||||
|
||||
MOZ_ASSERT(c[low] <= c[middle]);
|
||||
MOZ_ASSERT(c[middle] <= c[high - 1]);
|
||||
MOZ_ASSERT(c[low] <= c[high - 1]);
|
||||
MOZ_ASSERT(aContainer[low] <= aContainer[middle]);
|
||||
MOZ_ASSERT(aContainer[middle] <= aContainer[high - 1]);
|
||||
MOZ_ASSERT(aContainer[low] <= aContainer[high - 1]);
|
||||
|
||||
if (target == middleValue) {
|
||||
*matchOrInsertionPoint = middle;
|
||||
if (aTarget == middleValue) {
|
||||
*aMatchOrInsertionPoint = middle;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target < middleValue)
|
||||
if (aTarget < middleValue) {
|
||||
high = middle;
|
||||
else
|
||||
} else {
|
||||
low = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
*matchOrInsertionPoint = low;
|
||||
*aMatchOrInsertionPoint = low;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -104,8 +104,9 @@ class BloomFilter
|
||||
* rates for larger N.
|
||||
*/
|
||||
public:
|
||||
BloomFilter() {
|
||||
static_assert(KeySize <= keyShift, "KeySize too big");
|
||||
BloomFilter()
|
||||
{
|
||||
static_assert(KeySize <= kKeyShift, "KeySize too big");
|
||||
|
||||
// Should we have a custom operator new using calloc instead and
|
||||
// require that we're allocated via the operator?
|
||||
@ -122,12 +123,12 @@ class BloomFilter
|
||||
/*
|
||||
* Add an item to the filter.
|
||||
*/
|
||||
void add(const T* t);
|
||||
void add(const T* aValue);
|
||||
|
||||
/*
|
||||
* Remove an item from the filter.
|
||||
*/
|
||||
void remove(const T* t);
|
||||
void remove(const T* aValue);
|
||||
|
||||
/*
|
||||
* Check whether the filter might contain an item. This can
|
||||
@ -135,97 +136,118 @@ class BloomFilter
|
||||
* but will never return false for items that are actually in the
|
||||
* filter.
|
||||
*/
|
||||
bool mightContain(const T* t) const;
|
||||
bool mightContain(const T* aValue) const;
|
||||
|
||||
/*
|
||||
* Methods for add/remove/contain when we already have a hash computed
|
||||
*/
|
||||
void add(uint32_t hash);
|
||||
void remove(uint32_t hash);
|
||||
bool mightContain(uint32_t hash) const;
|
||||
void add(uint32_t aHash);
|
||||
void remove(uint32_t aHash);
|
||||
bool mightContain(uint32_t aHash) const;
|
||||
|
||||
private:
|
||||
static const size_t arraySize = (1 << KeySize);
|
||||
static const uint32_t keyMask = (1 << KeySize) - 1;
|
||||
static const uint32_t keyShift = 16;
|
||||
static const size_t kArraySize = (1 << KeySize);
|
||||
static const uint32_t kKeyMask = (1 << KeySize) - 1;
|
||||
static const uint32_t kKeyShift = 16;
|
||||
|
||||
static uint32_t hash1(uint32_t hash) { return hash & keyMask; }
|
||||
static uint32_t hash2(uint32_t hash) { return (hash >> keyShift) & keyMask; }
|
||||
static uint32_t hash1(uint32_t aHash)
|
||||
{
|
||||
return aHash & kKeyMask;
|
||||
}
|
||||
static uint32_t hash2(uint32_t aHash)
|
||||
{
|
||||
return (aHash >> kKeyShift) & kKeyMask;
|
||||
}
|
||||
|
||||
uint8_t& firstSlot(uint32_t hash) { return counters[hash1(hash)]; }
|
||||
uint8_t& secondSlot(uint32_t hash) { return counters[hash2(hash)]; }
|
||||
const uint8_t& firstSlot(uint32_t hash) const { return counters[hash1(hash)]; }
|
||||
const uint8_t& secondSlot(uint32_t hash) const { return counters[hash2(hash)]; }
|
||||
uint8_t& firstSlot(uint32_t aHash)
|
||||
{
|
||||
return mCounters[hash1(aHash)];
|
||||
}
|
||||
uint8_t& secondSlot(uint32_t aHash)
|
||||
{
|
||||
return mCounters[hash2(aHash)];
|
||||
}
|
||||
|
||||
static bool full(const uint8_t& slot) { return slot == UINT8_MAX; }
|
||||
const uint8_t& firstSlot(uint32_t aHash) const
|
||||
{
|
||||
return mCounters[hash1(aHash)];
|
||||
}
|
||||
const uint8_t& secondSlot(uint32_t aHash) const
|
||||
{
|
||||
return mCounters[hash2(aHash)];
|
||||
}
|
||||
|
||||
uint8_t counters[arraySize];
|
||||
static bool full(const uint8_t& aSlot) { return aSlot == UINT8_MAX; }
|
||||
|
||||
uint8_t mCounters[kArraySize];
|
||||
};
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
inline void
|
||||
BloomFilter<KeySize, T>::clear()
|
||||
{
|
||||
memset(counters, 0, arraySize);
|
||||
memset(mCounters, 0, kArraySize);
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
inline void
|
||||
BloomFilter<KeySize, T>::add(uint32_t hash)
|
||||
BloomFilter<KeySize, T>::add(uint32_t aHash)
|
||||
{
|
||||
uint8_t& slot1 = firstSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot1)))
|
||||
uint8_t& slot1 = firstSlot(aHash);
|
||||
if (MOZ_LIKELY(!full(slot1))) {
|
||||
++slot1;
|
||||
|
||||
uint8_t& slot2 = secondSlot(hash);
|
||||
}
|
||||
uint8_t& slot2 = secondSlot(aHash); {
|
||||
if (MOZ_LIKELY(!full(slot2)))
|
||||
++slot2;
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
MOZ_ALWAYS_INLINE void
|
||||
BloomFilter<KeySize, T>::add(const T* t)
|
||||
BloomFilter<KeySize, T>::add(const T* aValue)
|
||||
{
|
||||
uint32_t hash = t->hash();
|
||||
uint32_t hash = aValue->hash();
|
||||
return add(hash);
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
inline void
|
||||
BloomFilter<KeySize, T>::remove(uint32_t hash)
|
||||
BloomFilter<KeySize, T>::remove(uint32_t aHash)
|
||||
{
|
||||
// If the slots are full, we don't know whether we bumped them to be
|
||||
// there when we added or not, so just leave them full.
|
||||
uint8_t& slot1 = firstSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot1)))
|
||||
uint8_t& slot1 = firstSlot(aHash);
|
||||
if (MOZ_LIKELY(!full(slot1))) {
|
||||
--slot1;
|
||||
|
||||
uint8_t& slot2 = secondSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot2)))
|
||||
}
|
||||
uint8_t& slot2 = secondSlot(aHash);
|
||||
if (MOZ_LIKELY(!full(slot2))) {
|
||||
--slot2;
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
MOZ_ALWAYS_INLINE void
|
||||
BloomFilter<KeySize, T>::remove(const T* t)
|
||||
BloomFilter<KeySize, T>::remove(const T* aValue)
|
||||
{
|
||||
uint32_t hash = t->hash();
|
||||
uint32_t hash = aValue->hash();
|
||||
remove(hash);
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
BloomFilter<KeySize, T>::mightContain(uint32_t hash) const
|
||||
BloomFilter<KeySize, T>::mightContain(uint32_t aHash) const
|
||||
{
|
||||
// Check that all the slots for this hash contain something
|
||||
return firstSlot(hash) && secondSlot(hash);
|
||||
return firstSlot(aHash) && secondSlot(aHash);
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
BloomFilter<KeySize, T>::mightContain(const T* t) const
|
||||
BloomFilter<KeySize, T>::mightContain(const T* aValue) const
|
||||
{
|
||||
uint32_t hash = t->hash();
|
||||
uint32_t hash = aValue->hash();
|
||||
return mightContain(hash);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,8 @@
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Return a value of type |To|, containing the underlying bit pattern of |from|.
|
||||
* Return a value of type |To|, containing the underlying bit pattern of
|
||||
* |aFrom|.
|
||||
*
|
||||
* |To| and |From| must be types of the same size; be careful of cross-platform
|
||||
* size differences, or this might fail to compile on some but not all
|
||||
@ -25,16 +26,17 @@ namespace mozilla {
|
||||
*/
|
||||
template<typename To, typename From>
|
||||
inline To
|
||||
BitwiseCast(const From from)
|
||||
BitwiseCast(const From aFrom)
|
||||
{
|
||||
static_assert(sizeof(From) == sizeof(To),
|
||||
"To and From must have the same size");
|
||||
union {
|
||||
From from;
|
||||
To to;
|
||||
union
|
||||
{
|
||||
From mFrom;
|
||||
To mTo;
|
||||
} u;
|
||||
u.from = from;
|
||||
return u.to;
|
||||
u.mFrom = aFrom;
|
||||
return u.mTo;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@ -58,15 +60,18 @@ enum UUComparison { FromIsBigger, FromIsNotBigger };
|
||||
// Unsigned-to-unsigned range check
|
||||
|
||||
template<typename From, typename To,
|
||||
UUComparison = (sizeof(From) > sizeof(To)) ? FromIsBigger : FromIsNotBigger>
|
||||
UUComparison = (sizeof(From) > sizeof(To))
|
||||
? FromIsBigger
|
||||
: FromIsNotBigger>
|
||||
struct UnsignedUnsignedCheck;
|
||||
|
||||
template<typename From, typename To>
|
||||
struct UnsignedUnsignedCheck<From, To, FromIsBigger>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) {
|
||||
return from <= From(To(-1));
|
||||
static bool checkBounds(const From aFrom)
|
||||
{
|
||||
return aFrom <= From(To(-1));
|
||||
}
|
||||
};
|
||||
|
||||
@ -74,7 +79,8 @@ template<typename From, typename To>
|
||||
struct UnsignedUnsignedCheck<From, To, FromIsNotBigger>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) {
|
||||
static bool checkBounds(const From aFrom)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -83,8 +89,9 @@ template<typename From, typename To>
|
||||
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) {
|
||||
return UnsignedUnsignedCheck<From, To>::checkBounds(from);
|
||||
static bool checkBounds(const From aFrom)
|
||||
{
|
||||
return UnsignedUnsignedCheck<From, To>::checkBounds(aFrom);
|
||||
}
|
||||
};
|
||||
|
||||
@ -94,12 +101,15 @@ template<typename From, typename To>
|
||||
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) {
|
||||
if (from < 0)
|
||||
static bool checkBounds(const From aFrom)
|
||||
{
|
||||
if (aFrom < 0) {
|
||||
return false;
|
||||
if (sizeof(To) >= sizeof(From))
|
||||
}
|
||||
if (sizeof(To) >= sizeof(From)) {
|
||||
return true;
|
||||
return from <= From(To(-1));
|
||||
}
|
||||
return aFrom <= From(To(-1));
|
||||
}
|
||||
};
|
||||
|
||||
@ -108,14 +118,17 @@ struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
|
||||
enum USComparison { FromIsSmaller, FromIsNotSmaller };
|
||||
|
||||
template<typename From, typename To,
|
||||
USComparison = (sizeof(From) < sizeof(To)) ? FromIsSmaller : FromIsNotSmaller>
|
||||
USComparison = (sizeof(From) < sizeof(To))
|
||||
? FromIsSmaller
|
||||
: FromIsNotSmaller>
|
||||
struct UnsignedSignedCheck;
|
||||
|
||||
template<typename From, typename To>
|
||||
struct UnsignedSignedCheck<From, To, FromIsSmaller>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) {
|
||||
static bool checkBounds(const From aFrom)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -124,9 +137,10 @@ template<typename From, typename To>
|
||||
struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) {
|
||||
static bool checkBounds(const From aFrom)
|
||||
{
|
||||
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
|
||||
return from <= From(MaxValue);
|
||||
return aFrom <= From(MaxValue);
|
||||
}
|
||||
};
|
||||
|
||||
@ -134,8 +148,9 @@ template<typename From, typename To>
|
||||
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) {
|
||||
return UnsignedSignedCheck<From, To>::checkBounds(from);
|
||||
static bool checkBounds(const From aFrom)
|
||||
{
|
||||
return UnsignedSignedCheck<From, To>::checkBounds(aFrom);
|
||||
}
|
||||
};
|
||||
|
||||
@ -145,41 +160,45 @@ template<typename From, typename To>
|
||||
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) {
|
||||
if (sizeof(From) <= sizeof(To))
|
||||
static bool checkBounds(const From aFrom)
|
||||
{
|
||||
if (sizeof(From) <= sizeof(To)) {
|
||||
return true;
|
||||
}
|
||||
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
|
||||
const To MinValue = -MaxValue - To(1);
|
||||
return From(MinValue) <= from &&
|
||||
From(from) <= From(MaxValue);
|
||||
return From(MinValue) <= aFrom &&
|
||||
From(aFrom) <= From(MaxValue);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename From, typename To,
|
||||
bool TypesAreIntegral = IsIntegral<From>::value && IsIntegral<To>::value>
|
||||
bool TypesAreIntegral = IsIntegral<From>::value &&
|
||||
IsIntegral<To>::value>
|
||||
class BoundsChecker;
|
||||
|
||||
template<typename From>
|
||||
class BoundsChecker<From, From, true>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) { return true; }
|
||||
static bool checkBounds(const From aFrom) { return true; }
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
class BoundsChecker<From, To, true>
|
||||
{
|
||||
public:
|
||||
static bool checkBounds(const From from) {
|
||||
return BoundsCheckImpl<From, To>::checkBounds(from);
|
||||
static bool checkBounds(const From aFrom)
|
||||
{
|
||||
return BoundsCheckImpl<From, To>::checkBounds(aFrom);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
inline bool
|
||||
IsInBounds(const From from)
|
||||
IsInBounds(const From aFrom)
|
||||
{
|
||||
return BoundsChecker<From, To>::checkBounds(from);
|
||||
return BoundsChecker<From, To>::checkBounds(aFrom);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@ -191,10 +210,10 @@ IsInBounds(const From from)
|
||||
*/
|
||||
template<typename To, typename From>
|
||||
inline To
|
||||
SafeCast(const From from)
|
||||
SafeCast(const From aFrom)
|
||||
{
|
||||
MOZ_ASSERT((detail::IsInBounds<From, To>(from)));
|
||||
return static_cast<To>(from);
|
||||
MOZ_ASSERT((detail::IsInBounds<From, To>(aFrom)));
|
||||
return static_cast<To>(aFrom);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
104
mfbt/Char16.h
104
mfbt/Char16.h
@ -62,37 +62,47 @@
|
||||
class char16ptr_t
|
||||
{
|
||||
private:
|
||||
const char16_t* ptr;
|
||||
static_assert(sizeof(char16_t) == sizeof(wchar_t), "char16_t and wchar_t sizes differ");
|
||||
const char16_t* mPtr;
|
||||
static_assert(sizeof(char16_t) == sizeof(wchar_t),
|
||||
"char16_t and wchar_t sizes differ");
|
||||
|
||||
public:
|
||||
char16ptr_t(const char16_t* p) : ptr(p) {}
|
||||
char16ptr_t(const wchar_t* p) : ptr(reinterpret_cast<const char16_t*>(p)) {}
|
||||
char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {}
|
||||
char16ptr_t(const wchar_t* aPtr) :
|
||||
mPtr(reinterpret_cast<const char16_t*>(aPtr))
|
||||
{}
|
||||
|
||||
/* Without this, nullptr assignment would be ambiguous. */
|
||||
constexpr char16ptr_t(decltype(nullptr)) : ptr(nullptr) {}
|
||||
constexpr char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {}
|
||||
|
||||
operator const char16_t*() const {
|
||||
return ptr;
|
||||
operator const char16_t*() const
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
operator const wchar_t*() const {
|
||||
return reinterpret_cast<const wchar_t*>(ptr);
|
||||
operator const wchar_t*() const
|
||||
{
|
||||
return reinterpret_cast<const wchar_t*>(mPtr);
|
||||
}
|
||||
operator const void*() const {
|
||||
return ptr;
|
||||
operator const void*() const
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
operator bool() const {
|
||||
return ptr != nullptr;
|
||||
operator bool() const
|
||||
{
|
||||
return mPtr != nullptr;
|
||||
}
|
||||
operator std::wstring() const {
|
||||
operator std::wstring() const
|
||||
{
|
||||
return std::wstring(static_cast<const wchar_t*>(*this));
|
||||
}
|
||||
|
||||
/* Explicit cast operators to allow things like (char16_t*)str. */
|
||||
explicit operator char16_t*() const {
|
||||
return const_cast<char16_t*>(ptr);
|
||||
explicit operator char16_t*() const
|
||||
{
|
||||
return const_cast<char16_t*>(mPtr);
|
||||
}
|
||||
explicit operator wchar_t*() const {
|
||||
explicit operator wchar_t*() const
|
||||
{
|
||||
return const_cast<wchar_t*>(static_cast<const wchar_t*>(*this));
|
||||
}
|
||||
|
||||
@ -101,46 +111,58 @@ class char16ptr_t
|
||||
* Supporting this requires explicit operators to support the requisite explicit
|
||||
* casts.
|
||||
*/
|
||||
explicit operator const char*() const {
|
||||
return reinterpret_cast<const char*>(ptr);
|
||||
explicit operator const char*() const
|
||||
{
|
||||
return reinterpret_cast<const char*>(mPtr);
|
||||
}
|
||||
explicit operator const unsigned char*() const {
|
||||
return reinterpret_cast<const unsigned char*>(ptr);
|
||||
explicit operator const unsigned char*() const
|
||||
{
|
||||
return reinterpret_cast<const unsigned char*>(mPtr);
|
||||
}
|
||||
explicit operator unsigned char*() const {
|
||||
return const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(ptr));
|
||||
explicit operator unsigned char*() const
|
||||
{
|
||||
return const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(mPtr));
|
||||
}
|
||||
explicit operator void*() const {
|
||||
return const_cast<char16_t*>(ptr);
|
||||
explicit operator void*() const
|
||||
{
|
||||
return const_cast<char16_t*>(mPtr);
|
||||
}
|
||||
|
||||
/* Some operators used on pointers. */
|
||||
char16_t operator[](size_t i) const {
|
||||
return ptr[i];
|
||||
char16_t operator[](size_t aIndex) const
|
||||
{
|
||||
return mPtr[aIndex];
|
||||
}
|
||||
bool operator==(const char16ptr_t &x) const {
|
||||
return ptr == x.ptr;
|
||||
bool operator==(const char16ptr_t &aOther) const
|
||||
{
|
||||
return mPtr == aOther.mPtr;
|
||||
}
|
||||
bool operator==(decltype(nullptr)) const {
|
||||
return ptr == nullptr;
|
||||
bool operator==(decltype(nullptr)) const
|
||||
{
|
||||
return mPtr == nullptr;
|
||||
}
|
||||
bool operator!=(const char16ptr_t &x) const {
|
||||
return ptr != x.ptr;
|
||||
bool operator!=(const char16ptr_t &aOther) const
|
||||
{
|
||||
return mPtr != aOther.mPtr;
|
||||
}
|
||||
bool operator!=(decltype(nullptr)) const {
|
||||
return ptr != nullptr;
|
||||
bool operator!=(decltype(nullptr)) const
|
||||
{
|
||||
return mPtr != nullptr;
|
||||
}
|
||||
char16ptr_t operator+(size_t add) const {
|
||||
return char16ptr_t(ptr + add);
|
||||
char16ptr_t operator+(size_t aValue) const
|
||||
{
|
||||
return char16ptr_t(mPtr + aValue);
|
||||
}
|
||||
ptrdiff_t operator-(const char16ptr_t &other) const {
|
||||
return ptr - other.ptr;
|
||||
ptrdiff_t operator-(const char16ptr_t &aOther) const
|
||||
{
|
||||
return mPtr - aOther.mPtr;
|
||||
}
|
||||
};
|
||||
|
||||
inline decltype((char*)0-(char*)0)
|
||||
operator-(const char16_t* x, const char16ptr_t y) {
|
||||
return x - static_cast<const char16_t*>(y);
|
||||
operator-(const char16_t* aX, const char16ptr_t aY)
|
||||
{
|
||||
return aX - static_cast<const char16_t*>(aY);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -144,22 +144,23 @@ struct TwiceBiggerType<IntegerType, 8>
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
HasSignBit(T x)
|
||||
HasSignBit(T aX)
|
||||
{
|
||||
// In C++, right bit shifts on negative values is undefined by the standard.
|
||||
// Notice that signed-to-unsigned conversions are always well-defined in the
|
||||
// standard, as the value congruent modulo 2**n as expected. By contrast,
|
||||
// unsigned-to-signed is only well-defined if the value is representable.
|
||||
return bool(typename MakeUnsigned<T>::Type(x) >> PositionOfSignBit<T>::value);
|
||||
return bool(typename MakeUnsigned<T>::Type(aX) >>
|
||||
PositionOfSignBit<T>::value);
|
||||
}
|
||||
|
||||
// Bitwise ops may return a larger type, so it's good to use this inline
|
||||
// helper guaranteeing that the result is really of type T.
|
||||
template<typename T>
|
||||
inline T
|
||||
BinaryComplement(T x)
|
||||
BinaryComplement(T aX)
|
||||
{
|
||||
return ~x;
|
||||
return ~aX;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
@ -207,80 +208,80 @@ struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
|
||||
template<typename T, typename U>
|
||||
struct IsInRangeImpl<T, U, true, true, false>
|
||||
{
|
||||
static bool run(U x)
|
||||
static bool run(U aX)
|
||||
{
|
||||
return x <= MaxValue<T>::value && x >= MinValue<T>::value;
|
||||
return aX <= MaxValue<T>::value && aX >= MinValue<T>::value;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct IsInRangeImpl<T, U, false, false, false>
|
||||
{
|
||||
static bool run(U x)
|
||||
static bool run(U aX)
|
||||
{
|
||||
return x <= MaxValue<T>::value;
|
||||
return aX <= MaxValue<T>::value;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct IsInRangeImpl<T, U, true, false, false>
|
||||
{
|
||||
static bool run(U x)
|
||||
static bool run(U aX)
|
||||
{
|
||||
return sizeof(T) > sizeof(U) || x <= U(MaxValue<T>::value);
|
||||
return sizeof(T) > sizeof(U) || aX <= U(MaxValue<T>::value);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct IsInRangeImpl<T, U, false, true, false>
|
||||
{
|
||||
static bool run(U x)
|
||||
static bool run(U aX)
|
||||
{
|
||||
return sizeof(T) >= sizeof(U)
|
||||
? x >= 0
|
||||
: x >= 0 && x <= U(MaxValue<T>::value);
|
||||
? aX >= 0
|
||||
: aX >= 0 && aX <= U(MaxValue<T>::value);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
inline bool
|
||||
IsInRange(U x)
|
||||
IsInRange(U aX)
|
||||
{
|
||||
return IsInRangeImpl<T, U>::run(x);
|
||||
return IsInRangeImpl<T, U>::run(aX);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
IsAddValid(T x, T y)
|
||||
IsAddValid(T aX, T aY)
|
||||
{
|
||||
// Addition is valid if the sign of x+y is equal to either that of x or that
|
||||
// of y. Since the value of x+y is undefined if we have a signed type, we
|
||||
// compute it using the unsigned type of the same size.
|
||||
// Beware! These bitwise operations can return a larger integer type,
|
||||
// if T was a small type like int8_t, so we explicitly cast to T.
|
||||
// Addition is valid if the sign of aX+aY is equal to either that of aX or
|
||||
// that of aY. Since the value of aX+aY is undefined if we have a signed
|
||||
// type, we compute it using the unsigned type of the same size. Beware!
|
||||
// These bitwise operations can return a larger integer type, if T was a
|
||||
// small type like int8_t, so we explicitly cast to T.
|
||||
|
||||
typename MakeUnsigned<T>::Type ux = x;
|
||||
typename MakeUnsigned<T>::Type uy = y;
|
||||
typename MakeUnsigned<T>::Type ux = aX;
|
||||
typename MakeUnsigned<T>::Type uy = aY;
|
||||
typename MakeUnsigned<T>::Type result = ux + uy;
|
||||
return IsSigned<T>::value
|
||||
? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y))))
|
||||
: BinaryComplement(x) >= y;
|
||||
? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY))))
|
||||
: BinaryComplement(aX) >= aY;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
IsSubValid(T x, T y)
|
||||
IsSubValid(T aX, T aY)
|
||||
{
|
||||
// Subtraction is valid if either x and y have same sign, or x-y and x have
|
||||
// same sign. Since the value of x-y is undefined if we have a signed type,
|
||||
// we compute it using the unsigned type of the same size.
|
||||
typename MakeUnsigned<T>::Type ux = x;
|
||||
typename MakeUnsigned<T>::Type uy = y;
|
||||
// Subtraction is valid if either aX and aY have same sign, or aX-aY and aX
|
||||
// have same sign. Since the value of aX-aY is undefined if we have a signed
|
||||
// type, we compute it using the unsigned type of the same size.
|
||||
typename MakeUnsigned<T>::Type ux = aX;
|
||||
typename MakeUnsigned<T>::Type uy = aY;
|
||||
typename MakeUnsigned<T>::Type result = ux - uy;
|
||||
|
||||
return IsSigned<T>::value
|
||||
? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y))))
|
||||
: x >= y;
|
||||
? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY))))
|
||||
: aX >= aY;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
@ -292,10 +293,10 @@ struct IsMulValidImpl {};
|
||||
template<typename T, bool IsTSigned>
|
||||
struct IsMulValidImpl<T, IsTSigned, true>
|
||||
{
|
||||
static bool run(T x, T y)
|
||||
static bool run(T aX, T aY)
|
||||
{
|
||||
typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
|
||||
TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y);
|
||||
TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY);
|
||||
return IsInRange<T>(product);
|
||||
}
|
||||
};
|
||||
@ -303,50 +304,51 @@ struct IsMulValidImpl<T, IsTSigned, true>
|
||||
template<typename T>
|
||||
struct IsMulValidImpl<T, true, false>
|
||||
{
|
||||
static bool run(T x, T y)
|
||||
static bool run(T aX, T aY)
|
||||
{
|
||||
const T max = MaxValue<T>::value;
|
||||
const T min = MinValue<T>::value;
|
||||
|
||||
if (x == 0 || y == 0)
|
||||
if (aX == 0 || aY == 0) {
|
||||
return true;
|
||||
|
||||
if (x > 0) {
|
||||
return y > 0
|
||||
? x <= max / y
|
||||
: y >= min / x;
|
||||
}
|
||||
if (aX > 0) {
|
||||
return aY > 0
|
||||
? aX <= max / aY
|
||||
: aY >= min / aX;
|
||||
}
|
||||
|
||||
// If we reach this point, we know that x < 0.
|
||||
return y > 0
|
||||
? x >= min / y
|
||||
: y >= max / x;
|
||||
// If we reach this point, we know that aX < 0.
|
||||
return aY > 0
|
||||
? aX >= min / aY
|
||||
: aY >= max / aX;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IsMulValidImpl<T, false, false>
|
||||
{
|
||||
static bool run(T x, T y)
|
||||
static bool run(T aX, T aY)
|
||||
{
|
||||
return y == 0 || x <= MaxValue<T>::value / y;
|
||||
return aY == 0 || aX <= MaxValue<T>::value / aY;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
IsMulValid(T x, T y)
|
||||
IsMulValid(T aX, T aY)
|
||||
{
|
||||
return IsMulValidImpl<T>::run(x, y);
|
||||
return IsMulValidImpl<T>::run(aX, aY);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
IsDivValid(T x, T y)
|
||||
IsDivValid(T aX, T aY)
|
||||
{
|
||||
// Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max.
|
||||
return y != 0 &&
|
||||
!(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1));
|
||||
// Keep in mind that in the signed case, min/-1 is invalid because
|
||||
// abs(min)>max.
|
||||
return aY != 0 &&
|
||||
!(IsSigned<T>::value && aX == MinValue<T>::value && aY == T(-1));
|
||||
}
|
||||
|
||||
template<typename T, bool IsTSigned = IsSigned<T>::value>
|
||||
@ -354,36 +356,40 @@ struct IsModValidImpl;
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
IsModValid(T x, T y)
|
||||
IsModValid(T aX, T aY)
|
||||
{
|
||||
return IsModValidImpl<T>::run(x, y);
|
||||
return IsModValidImpl<T>::run(aX, aY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mod is pretty simple.
|
||||
* For now, let's just use the ANSI C definition:
|
||||
* If x or y are negative, the results are implementation defined.
|
||||
* If aX or aY are negative, the results are implementation defined.
|
||||
* Consider these invalid.
|
||||
* Undefined for y=0.
|
||||
* The result will never exceed either x or y.
|
||||
* Undefined for aY=0.
|
||||
* The result will never exceed either aX or aY.
|
||||
*
|
||||
* Checking that x>=0 is a warning when T is unsigned.
|
||||
* Checking that aX>=0 is a warning when T is unsigned.
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
struct IsModValidImpl<T, false> {
|
||||
static inline bool run(T x, T y) {
|
||||
return y >= 1;
|
||||
struct IsModValidImpl<T, false>
|
||||
{
|
||||
static inline bool run(T aX, T aY)
|
||||
{
|
||||
return aY >= 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IsModValidImpl<T, true> {
|
||||
static inline bool run(T x, T y) {
|
||||
if (x < 0)
|
||||
struct IsModValidImpl<T, true>
|
||||
{
|
||||
static inline bool run(T aX, T aY)
|
||||
{
|
||||
if (aX < 0) {
|
||||
return false;
|
||||
|
||||
return y >= 1;
|
||||
}
|
||||
return aY >= 1;
|
||||
}
|
||||
};
|
||||
|
||||
@ -393,24 +399,25 @@ struct NegateImpl;
|
||||
template<typename T>
|
||||
struct NegateImpl<T, false>
|
||||
{
|
||||
static CheckedInt<T> negate(const CheckedInt<T>& val)
|
||||
static CheckedInt<T> negate(const CheckedInt<T>& aVal)
|
||||
{
|
||||
// Handle negation separately for signed/unsigned, for simpler code and to
|
||||
// avoid an MSVC warning negating an unsigned value.
|
||||
return CheckedInt<T>(0, val.isValid() && val.mValue == 0);
|
||||
return CheckedInt<T>(0, aVal.isValid() && aVal.mValue == 0);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct NegateImpl<T, true>
|
||||
{
|
||||
static CheckedInt<T> negate(const CheckedInt<T>& val)
|
||||
static CheckedInt<T> negate(const CheckedInt<T>& aVal)
|
||||
{
|
||||
// Watch out for the min-value, which (with twos-complement) can't be
|
||||
// negated as -min-value is then (max-value + 1).
|
||||
if (!val.isValid() || val.mValue == MinValue<T>::value)
|
||||
return CheckedInt<T>(val.mValue, false);
|
||||
return CheckedInt<T>(-val.mValue, true);
|
||||
if (!aVal.isValid() || aVal.mValue == MinValue<T>::value) {
|
||||
return CheckedInt<T>(aVal.mValue, false);
|
||||
}
|
||||
return CheckedInt<T>(-aVal.mValue, true);
|
||||
}
|
||||
};
|
||||
|
||||
@ -437,14 +444,14 @@ struct NegateImpl<T, true>
|
||||
* (e.g. in case of a division by zero).
|
||||
*
|
||||
* For example, suppose that you want to implement a function that computes
|
||||
* (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by
|
||||
* (aX+aY)/aZ, that doesn't crash if aZ==0, and that reports on error (divide by
|
||||
* zero or integer overflow). You could code it as follows:
|
||||
@code
|
||||
bool computeXPlusYOverZ(int x, int y, int z, int *result)
|
||||
bool computeXPlusYOverZ(int aX, int aY, int aZ, int *aResult)
|
||||
{
|
||||
CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z;
|
||||
CheckedInt<int> checkedResult = (CheckedInt<int>(aX) + aY) / aZ;
|
||||
if (checkedResult.isValid()) {
|
||||
*result = checkedResult.value();
|
||||
*aResult = checkedResult.value();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -563,34 +570,34 @@ class CheckedInt
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
|
||||
const CheckedInt<U>& rhs);
|
||||
friend CheckedInt<U> operator +(const CheckedInt<U>& aLhs,
|
||||
const CheckedInt<U>& aRhs);
|
||||
template<typename U>
|
||||
CheckedInt& operator +=(U rhs);
|
||||
CheckedInt& operator +=(U aRhs);
|
||||
|
||||
template<typename U>
|
||||
friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
|
||||
const CheckedInt<U>& rhs);
|
||||
friend CheckedInt<U> operator -(const CheckedInt<U>& aLhs,
|
||||
const CheckedInt<U>& aRhs);
|
||||
template<typename U>
|
||||
CheckedInt& operator -=(U rhs);
|
||||
CheckedInt& operator -=(U aRhs);
|
||||
|
||||
template<typename U>
|
||||
friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
|
||||
const CheckedInt<U>& rhs);
|
||||
friend CheckedInt<U> operator *(const CheckedInt<U>& aLhs,
|
||||
const CheckedInt<U>& aRhs);
|
||||
template<typename U>
|
||||
CheckedInt& operator *=(U rhs);
|
||||
CheckedInt& operator *=(U aRhs);
|
||||
|
||||
template<typename U>
|
||||
friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
|
||||
const CheckedInt<U>& rhs);
|
||||
friend CheckedInt<U> operator /(const CheckedInt<U>& aLhs,
|
||||
const CheckedInt<U>& aRhs);
|
||||
template<typename U>
|
||||
CheckedInt& operator /=(U rhs);
|
||||
CheckedInt& operator /=(U aRhs);
|
||||
|
||||
template<typename U>
|
||||
friend CheckedInt<U> operator %(const CheckedInt<U>& lhs,
|
||||
const CheckedInt<U>& rhs);
|
||||
friend CheckedInt<U> operator %(const CheckedInt<U>& aLhs,
|
||||
const CheckedInt<U>& aRhs);
|
||||
template<typename U>
|
||||
CheckedInt& operator %=(U rhs);
|
||||
CheckedInt& operator %=(U aRhs);
|
||||
|
||||
CheckedInt operator -() const
|
||||
{
|
||||
@ -615,9 +622,9 @@ class CheckedInt
|
||||
* 2. This is similar to the behavior of IEEE floats, where a==b
|
||||
* means that a and b have the same value *and* neither is NaN.
|
||||
*/
|
||||
bool operator ==(const CheckedInt& other) const
|
||||
bool operator ==(const CheckedInt& aOther) const
|
||||
{
|
||||
return mIsValid && other.mIsValid && mValue == other.mValue;
|
||||
return mIsValid && aOther.mIsValid && mValue == aOther.mValue;
|
||||
}
|
||||
|
||||
/** prefix ++ */
|
||||
@ -655,28 +662,23 @@ class CheckedInt
|
||||
* The !=, <, <=, >, >= operators are disabled:
|
||||
* see the comment on operator==.
|
||||
*/
|
||||
template<typename U>
|
||||
bool operator !=(U other) const MOZ_DELETE;
|
||||
template<typename U>
|
||||
bool operator <(U other) const MOZ_DELETE;
|
||||
template<typename U>
|
||||
bool operator <=(U other) const MOZ_DELETE;
|
||||
template<typename U>
|
||||
bool operator >(U other) const MOZ_DELETE;
|
||||
template<typename U>
|
||||
bool operator >=(U other) const MOZ_DELETE;
|
||||
template<typename U> bool operator !=(U aOther) const MOZ_DELETE;
|
||||
template<typename U> bool operator < (U aOther) const MOZ_DELETE;
|
||||
template<typename U> bool operator <=(U aOther) const MOZ_DELETE;
|
||||
template<typename U> bool operator > (U aOther) const MOZ_DELETE;
|
||||
template<typename U> bool operator >=(U aOther) const MOZ_DELETE;
|
||||
};
|
||||
|
||||
#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
|
||||
template<typename T> \
|
||||
inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, \
|
||||
const CheckedInt<T> &rhs) \
|
||||
inline CheckedInt<T> \
|
||||
operator OP(const CheckedInt<T> &aLhs, const CheckedInt<T> &aRhs) \
|
||||
{ \
|
||||
if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue)) \
|
||||
if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \
|
||||
return CheckedInt<T>(0, false); \
|
||||
\
|
||||
return CheckedInt<T>(lhs.mValue OP rhs.mValue, \
|
||||
lhs.mIsValid && rhs.mIsValid); \
|
||||
} \
|
||||
return CheckedInt<T>(aLhs.mValue OP aRhs.mValue, \
|
||||
aLhs.mIsValid && aRhs.mIsValid); \
|
||||
}
|
||||
|
||||
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
|
||||
@ -699,45 +701,45 @@ template<typename T, typename U>
|
||||
struct CastToCheckedIntImpl
|
||||
{
|
||||
typedef CheckedInt<T> ReturnType;
|
||||
static CheckedInt<T> run(U u) { return u; }
|
||||
static CheckedInt<T> run(U aU) { return aU; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct CastToCheckedIntImpl<T, CheckedInt<T> >
|
||||
{
|
||||
typedef const CheckedInt<T>& ReturnType;
|
||||
static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
|
||||
static const CheckedInt<T>& run(const CheckedInt<T>& aU) { return aU; }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, typename U>
|
||||
inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
|
||||
castToCheckedInt(U u)
|
||||
castToCheckedInt(U aU)
|
||||
{
|
||||
static_assert(detail::IsSupported<T>::value &&
|
||||
detail::IsSupported<U>::value,
|
||||
"This type is not supported by CheckedInt");
|
||||
return detail::CastToCheckedIntImpl<T, U>::run(u);
|
||||
return detail::CastToCheckedIntImpl<T, U>::run(aU);
|
||||
}
|
||||
|
||||
#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
|
||||
template<typename T> \
|
||||
template<typename U> \
|
||||
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \
|
||||
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U aRhs) \
|
||||
{ \
|
||||
*this = *this OP castToCheckedInt<T>(rhs); \
|
||||
*this = *this OP castToCheckedInt<T>(aRhs); \
|
||||
return *this; \
|
||||
} \
|
||||
template<typename T, typename U> \
|
||||
inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
|
||||
inline CheckedInt<T> operator OP(const CheckedInt<T> &aLhs, U aRhs) \
|
||||
{ \
|
||||
return lhs OP castToCheckedInt<T>(rhs); \
|
||||
return aLhs OP castToCheckedInt<T>(aRhs); \
|
||||
} \
|
||||
template<typename T, typename U> \
|
||||
inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
|
||||
inline CheckedInt<T> operator OP(U aLhs, const CheckedInt<T> &aRhs) \
|
||||
{ \
|
||||
return castToCheckedInt<T>(lhs) OP rhs; \
|
||||
return castToCheckedInt<T>(aLhs) OP aRhs; \
|
||||
}
|
||||
|
||||
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
|
||||
@ -750,16 +752,16 @@ MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
|
||||
|
||||
template<typename T, typename U>
|
||||
inline bool
|
||||
operator ==(const CheckedInt<T> &lhs, U rhs)
|
||||
operator ==(const CheckedInt<T> &aLhs, U aRhs)
|
||||
{
|
||||
return lhs == castToCheckedInt<T>(rhs);
|
||||
return aLhs == castToCheckedInt<T>(aRhs);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline bool
|
||||
operator ==(U lhs, const CheckedInt<T> &rhs)
|
||||
operator ==(U aLhs, const CheckedInt<T> &aRhs)
|
||||
{
|
||||
return castToCheckedInt<T>(lhs) == rhs;
|
||||
return castToCheckedInt<T>(aLhs) == aRhs;
|
||||
}
|
||||
|
||||
// Convenience typedefs.
|
||||
|
@ -1,9 +1,12 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Compression.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
||||
using namespace mozilla::Compression;
|
||||
|
||||
namespace {
|
||||
@ -15,50 +18,51 @@ namespace {
|
||||
/* Our wrappers */
|
||||
|
||||
size_t
|
||||
LZ4::compress(const char* source, size_t inputSize, char* dest)
|
||||
LZ4::compress(const char* aSource, size_t aInputSize, char* aDest)
|
||||
{
|
||||
CheckedInt<int> inputSizeChecked = inputSize;
|
||||
CheckedInt<int> inputSizeChecked = aInputSize;
|
||||
MOZ_ASSERT(inputSizeChecked.isValid());
|
||||
return LZ4_compress(source, dest, inputSizeChecked.value());
|
||||
return LZ4_compress(aSource, aDest, inputSizeChecked.value());
|
||||
}
|
||||
|
||||
size_t
|
||||
LZ4::compressLimitedOutput(const char* source, size_t inputSize, char* dest, size_t maxOutputSize)
|
||||
LZ4::compressLimitedOutput(const char* aSource, size_t aInputSize, char* aDest,
|
||||
size_t aMaxOutputSize)
|
||||
{
|
||||
CheckedInt<int> inputSizeChecked = inputSize;
|
||||
CheckedInt<int> inputSizeChecked = aInputSize;
|
||||
MOZ_ASSERT(inputSizeChecked.isValid());
|
||||
CheckedInt<int> maxOutputSizeChecked = maxOutputSize;
|
||||
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
|
||||
MOZ_ASSERT(maxOutputSizeChecked.isValid());
|
||||
return LZ4_compress_limitedOutput(source, dest, inputSizeChecked.value(),
|
||||
return LZ4_compress_limitedOutput(aSource, aDest, inputSizeChecked.value(),
|
||||
maxOutputSizeChecked.value());
|
||||
}
|
||||
|
||||
bool
|
||||
LZ4::decompress(const char* source, char* dest, size_t outputSize)
|
||||
LZ4::decompress(const char* aSource, char* aDest, size_t aOutputSize)
|
||||
{
|
||||
CheckedInt<int> outputSizeChecked = outputSize;
|
||||
CheckedInt<int> outputSizeChecked = aOutputSize;
|
||||
MOZ_ASSERT(outputSizeChecked.isValid());
|
||||
int ret = LZ4_decompress_fast(source, dest, outputSizeChecked.value());
|
||||
int ret = LZ4_decompress_fast(aSource, aDest, outputSizeChecked.value());
|
||||
return ret >= 0;
|
||||
}
|
||||
|
||||
bool
|
||||
LZ4::decompress(const char* source, size_t inputSize, char* dest, size_t maxOutputSize,
|
||||
size_t *outputSize)
|
||||
LZ4::decompress(const char* aSource, size_t aInputSize, char* aDest,
|
||||
size_t aMaxOutputSize, size_t *aOutputSize)
|
||||
{
|
||||
CheckedInt<int> maxOutputSizeChecked = maxOutputSize;
|
||||
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
|
||||
MOZ_ASSERT(maxOutputSizeChecked.isValid());
|
||||
CheckedInt<int> inputSizeChecked = inputSize;
|
||||
CheckedInt<int> inputSizeChecked = aInputSize;
|
||||
MOZ_ASSERT(inputSizeChecked.isValid());
|
||||
|
||||
int ret = LZ4_decompress_safe(source, dest, inputSizeChecked.value(),
|
||||
int ret = LZ4_decompress_safe(aSource, aDest, inputSizeChecked.value(),
|
||||
maxOutputSizeChecked.value());
|
||||
if (ret >= 0) {
|
||||
*outputSize = ret;
|
||||
*aOutputSize = ret;
|
||||
return true;
|
||||
} else {
|
||||
*outputSize = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*aOutputSize = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -22,41 +23,41 @@ namespace Compression {
|
||||
*
|
||||
* Compared to zlib it compresses at about 10x the speed, decompresses at about
|
||||
* 4x the speed and produces output of about 1.5x the size.
|
||||
*
|
||||
*/
|
||||
|
||||
class LZ4
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Compresses 'inputSize' bytes from 'source' into 'dest'.
|
||||
* Destination buffer must be already allocated,
|
||||
* and must be sized to handle worst cases situations (input data not compressible)
|
||||
* Worst case size evaluation is provided by function maxCompressedSize()
|
||||
* Compresses |aInputSize| bytes from |aSource| into |aDest|. Destination
|
||||
* buffer must be already allocated, and must be sized to handle worst cases
|
||||
* situations (input data not compressible). Worst case size evaluation is
|
||||
* provided by function maxCompressedSize()
|
||||
*
|
||||
* @param inputSize is the input size. Max supported value is ~1.9GB
|
||||
* @param return the number of bytes written in buffer dest
|
||||
* @param aInputSize is the input size. Max supported value is ~1.9GB
|
||||
* @return the number of bytes written in buffer |aDest|
|
||||
*/
|
||||
static MFBT_API size_t compress(const char* source, size_t inputSize, char* dest);
|
||||
static MFBT_API size_t
|
||||
compress(const char* aSource, size_t aInputSize, char* aDest);
|
||||
|
||||
/**
|
||||
* Compress 'inputSize' bytes from 'source' into an output buffer
|
||||
* 'dest' of maximum size 'maxOutputSize'. If it cannot achieve it,
|
||||
* Compress |aInputSize| bytes from |aSource| into an output buffer
|
||||
* |aDest| of maximum size |aMaxOutputSize|. If it cannot achieve it,
|
||||
* compression will stop, and result of the function will be zero,
|
||||
* 'dest' will still be written to, but since the number of input
|
||||
* |aDest| will still be written to, but since the number of input
|
||||
* bytes consumed is not returned the result is not usable.
|
||||
*
|
||||
* This function never writes outside of provided output buffer.
|
||||
*
|
||||
* @param inputSize is the input size. Max supported value is ~1.9GB
|
||||
* @param maxOutputSize is the size of the destination buffer (which must be already allocated)
|
||||
* @return the number of bytes written in buffer 'dest'
|
||||
or 0 if the compression fails
|
||||
* @param aInputSize is the input size. Max supported value is ~1.9GB
|
||||
* @param aMaxOutputSize is the size of the destination buffer (which must
|
||||
* be already allocated)
|
||||
* @return the number of bytes written in buffer |aDest| or 0 if the
|
||||
* compression fails
|
||||
*/
|
||||
static MFBT_API size_t compressLimitedOutput(const char* source, size_t inputSize, char* dest,
|
||||
size_t maxOutputSize);
|
||||
static MFBT_API size_t
|
||||
compressLimitedOutput(const char* aSource, size_t aInputSize, char* aDest,
|
||||
size_t aMaxOutputSize);
|
||||
|
||||
/**
|
||||
* If the source stream is malformed, the function will stop decoding
|
||||
@ -66,48 +67,50 @@ public:
|
||||
* This function never writes outside of provided buffers, and never
|
||||
* modifies input buffer.
|
||||
*
|
||||
* note : destination buffer must be already allocated.
|
||||
* its size must be a minimum of 'outputSize' bytes.
|
||||
* @param outputSize is the output size, therefore the original size
|
||||
* Note: destination buffer must be already allocated, and its size must be a
|
||||
* minimum of |aOutputSize| bytes.
|
||||
*
|
||||
* @param aOutputSize is the output size, therefore the original size
|
||||
* @return the number of bytes read in the source buffer
|
||||
*/
|
||||
static MFBT_API bool decompress(const char* source, char* dest, size_t outputSize);
|
||||
static MFBT_API bool
|
||||
decompress(const char* aSource, char* aDest, size_t aOutputSize);
|
||||
|
||||
/**
|
||||
* If the source stream is malformed, the function will stop decoding
|
||||
* and return false.
|
||||
*
|
||||
* This function never writes beyond dest + maxOutputSize, and is
|
||||
* This function never writes beyond aDest + aMaxOutputSize, and is
|
||||
* therefore protected against malicious data packets.
|
||||
*
|
||||
* note : Destination buffer must be already allocated.
|
||||
* This version is slightly slower than the decompress
|
||||
* without the maxOutputSize
|
||||
* Note: Destination buffer must be already allocated. This version is
|
||||
* slightly slower than the decompress without the aMaxOutputSize.
|
||||
*
|
||||
* @param inputSize is the length of the input compressed data
|
||||
* @param maxOutputSize is the size of the destination buffer (which must be already allocated)
|
||||
* @param outputSize the actual number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)
|
||||
|
||||
* @param aInputSize is the length of the input compressed data
|
||||
* @param aMaxOutputSize is the size of the destination buffer (which must be
|
||||
* already allocated)
|
||||
* @param aOutputSize the actual number of bytes decoded in the destination
|
||||
* buffer (necessarily <= aMaxOutputSize)
|
||||
*/
|
||||
static MFBT_API bool decompress(const char* source, size_t inputSize, char* dest,
|
||||
size_t maxOutputSize, size_t *outputSize);
|
||||
static MFBT_API bool
|
||||
decompress(const char* aSource, size_t aInputSize, char* aDest,
|
||||
size_t aMaxOutputSize, size_t *aOutputSize);
|
||||
|
||||
/*
|
||||
Provides the maximum size that LZ4 may output in a "worst case"
|
||||
scenario (input data not compressible) primarily useful for memory
|
||||
allocation of output buffer.
|
||||
note : this function is limited by "int" range (2^31-1)
|
||||
|
||||
@param inputSize is the input size. Max supported value is ~1.9GB
|
||||
@return maximum output size in a "worst case" scenario
|
||||
* Provides the maximum size that LZ4 may output in a "worst case"
|
||||
* scenario (input data not compressible) primarily useful for memory
|
||||
* allocation of output buffer.
|
||||
* note : this function is limited by "int" range (2^31-1)
|
||||
*
|
||||
* @param aInputSize is the input size. Max supported value is ~1.9GB
|
||||
* @return maximum output size in a "worst case" scenario
|
||||
*/
|
||||
static inline size_t maxCompressedSize(size_t inputSize)
|
||||
static inline size_t maxCompressedSize(size_t aInputSize)
|
||||
{
|
||||
size_t max = ((inputSize) + ((inputSize)/255) + 16);
|
||||
MOZ_ASSERT(max > inputSize);
|
||||
size_t max = (aInputSize + (aInputSize / 255) + 16);
|
||||
MOZ_ASSERT(max > aInputSize);
|
||||
return max;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} /* namespace Compression */
|
||||
|
@ -39,18 +39,15 @@ class DebugOnly
|
||||
T value;
|
||||
|
||||
DebugOnly() { }
|
||||
DebugOnly(const T& other) : value(other) { }
|
||||
DebugOnly(const DebugOnly& other) : value(other.value) { }
|
||||
DebugOnly& operator=(const T& rhs) {
|
||||
value = rhs;
|
||||
DebugOnly(const T& aOther) : value(aOther) { }
|
||||
DebugOnly(const DebugOnly& aOther) : value(aOther.value) { }
|
||||
DebugOnly& operator=(const T& aRhs) {
|
||||
value = aRhs;
|
||||
return *this;
|
||||
}
|
||||
void operator++(int) {
|
||||
value++;
|
||||
}
|
||||
void operator--(int) {
|
||||
value--;
|
||||
}
|
||||
|
||||
void operator++(int) { value++; }
|
||||
void operator--(int) { value--; }
|
||||
|
||||
T* operator&() { return &value; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user