Bug 1014377 - Convert the first quarter of MFBT to Gecko style. r=froydnj.

--HG--
extra : rebase_source : b3b2da775e2c0e8a6ecbed70e7bd0c8f7af67b47
This commit is contained in:
Nicholas Nethercote 2014-05-29 22:40:33 -07:00
parent dab2c77f74
commit 0b4c7c33bf
16 changed files with 1510 additions and 1278 deletions

View File

@ -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 */

View File

@ -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

View File

@ -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");
}
};

View File

@ -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 {

View File

@ -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()

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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;
}

View File

@ -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 */

View File

@ -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; }