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

@ -21,14 +21,14 @@ namespace mozilla {
template<typename T>
class AlignmentFinder
{
struct Aligner
{
char c;
T t;
};
struct Aligner
{
char mChar;
T mT;
};
public:
static const size_t alignment = sizeof(Aligner) - sizeof(T);
public:
static const size_t alignment = sizeof(Aligner) - sizeof(T);
};
#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
@ -71,31 +71,31 @@ struct AlignedElem;
template<>
struct AlignedElem<1>
{
MOZ_ALIGNED_DECL(uint8_t elem, 1);
MOZ_ALIGNED_DECL(uint8_t elem, 1);
};
template<>
struct AlignedElem<2>
{
MOZ_ALIGNED_DECL(uint8_t elem, 2);
MOZ_ALIGNED_DECL(uint8_t elem, 2);
};
template<>
struct AlignedElem<4>
{
MOZ_ALIGNED_DECL(uint8_t elem, 4);
MOZ_ALIGNED_DECL(uint8_t elem, 4);
};
template<>
struct AlignedElem<8>
{
MOZ_ALIGNED_DECL(uint8_t elem, 8);
MOZ_ALIGNED_DECL(uint8_t elem, 8);
};
template<>
struct AlignedElem<16>
{
MOZ_ALIGNED_DECL(uint8_t elem, 16);
MOZ_ALIGNED_DECL(uint8_t elem, 16);
};
/*
@ -111,25 +111,27 @@ struct AlignedElem<16>
template<size_t Nbytes>
struct AlignedStorage
{
union U {
char bytes[Nbytes];
uint64_t _;
} u;
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 _;
} u;
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

@ -49,14 +49,31 @@ 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 {}
};
public:
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,31 +19,35 @@ 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];
}
public:
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];
}
};
template<typename T>
class Array<T, 0>
{
public:
T& operator[](size_t i) {
MOZ_CRASH("indexing into zero-length array");
}
public:
T& operator[](size_t aIndex)
{
MOZ_CRASH("indexing into zero-length array");
}
const T& operator[](size_t i) const {
MOZ_CRASH("indexing into zero-length array");
}
const T& operator[](size_t aIndex) const
{
MOZ_CRASH("indexing into zero-length array");
}
};
} /* namespace mozilla */

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

@ -32,13 +32,13 @@
* number of undesired macros and symbols.
*/
# ifdef __cplusplus
extern "C" {
extern "C" {
# endif
__declspec(dllimport) int __stdcall
TerminateProcess(void* hProcess, unsigned int uExitCode);
__declspec(dllimport) void* __stdcall GetCurrentProcess(void);
__declspec(dllimport) int __stdcall
TerminateProcess(void* hProcess, unsigned int uExitCode);
__declspec(dllimport) void* __stdcall GetCurrentProcess(void);
# ifdef __cplusplus
}
}
# endif
#else
# include <signal.h>
@ -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);
__android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH",
"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
@ -319,13 +321,13 @@ namespace detail {
template<typename T>
struct IsFunction
{
static const bool value = false;
static const bool value = false;
};
template<typename R, typename... A>
struct IsFunction<R(A...)>
{
static const bool value = true;
static const bool value = true;
};
template<typename T>
@ -333,47 +335,51 @@ 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
/* First the single-argument form. */
#define MOZ_ASSERT_HELPER1(expr) \
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!(expr))) { \
MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \
MOZ_REALLY_CRASH(); \
} \
} while (0)
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!(expr))) { \
MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \
MOZ_REALLY_CRASH(); \
} \
} while (0)
/* Now the two-argument form. */
#define MOZ_ASSERT_HELPER2(expr, explain) \
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!(expr))) { \
MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \
MOZ_REALLY_CRASH(); \
} \
} while (0)
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!(expr))) { \
MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \
MOZ_REALLY_CRASH(); \
} \
} while (0)
#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b
#define MOZ_RELEASE_ASSERT(...) \
MOZ_RELEASE_ASSERT_GLUE( \
MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
(__VA_ARGS__))
MOZ_RELEASE_ASSERT_GLUE( \
MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
(__VA_ARGS__))
#ifdef DEBUG
# define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
@ -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()

File diff suppressed because it is too large Load Diff

View File

@ -150,10 +150,10 @@
* template<typename T>
* class Ptr
* {
* T* ptr;
* MOZ_EXPLICIT_CONVERSION operator bool() const {
* return ptr != nullptr;
* }
* T* ptr;
* MOZ_EXPLICIT_CONVERSION operator bool() const {
* return ptr != nullptr;
* }
* };
*
*/
@ -267,9 +267,9 @@
*
* struct NonCopyable
* {
* private:
* NonCopyable(const NonCopyable& other) MOZ_DELETE;
* void operator=(const NonCopyable& other) MOZ_DELETE;
* private:
* NonCopyable(const NonCopyable& other) MOZ_DELETE;
* void operator=(const NonCopyable& other) MOZ_DELETE;
* };
*
* If MOZ_DELETE can't be implemented for the current compiler, use of the
@ -295,23 +295,23 @@
*
* class Base
* {
* public:
* virtual void f() = 0;
* public:
* virtual void f() = 0;
* };
* class Derived1 : public Base
* {
* public:
* virtual void f() MOZ_OVERRIDE;
* public:
* virtual void f() MOZ_OVERRIDE;
* };
* class Derived2 : public Base
* {
* public:
* virtual void f() MOZ_OVERRIDE = 0;
* public:
* virtual void f() MOZ_OVERRIDE = 0;
* };
* class Derived3 : public Base
* {
* public:
* virtual void f() MOZ_OVERRIDE { }
* public:
* virtual void f() MOZ_OVERRIDE { }
* };
*
* In compilers supporting C++11 override controls, MOZ_OVERRIDE *requires* that
@ -339,16 +339,16 @@
*
* class Base MOZ_FINAL
* {
* public:
* Base();
* ~Base();
* virtual void f() { }
* public:
* Base();
* ~Base();
* virtual void f() { }
* };
* // This will be an error in some compilers:
* class Derived : public Base
* {
* public:
* ~Derived() { }
* public:
* ~Derived() { }
* };
*
* One particularly common reason to specify MOZ_FINAL upon a class is to tell
@ -375,14 +375,14 @@
*
* class Base
* {
* public:
* virtual void f() MOZ_FINAL;
* public:
* virtual void f() MOZ_FINAL;
* };
* class Derived
* {
* public:
* // This will be an error in some compilers:
* virtual void f();
* public:
* // This will be an error in some compilers:
* virtual void f();
* };
*
* In compilers implementing final controls, it is an error for a derived class

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

@ -55,177 +55,199 @@ namespace mozilla {
template<unsigned KeySize, class T>
class BloomFilter
{
/*
* A counting Bloom filter with 8-bit counters. For now we assume
* that having two hash functions is enough, but we may revisit that
* decision later.
*
* The filter uses an array with 2**KeySize entries.
*
* Assuming a well-distributed hash function, a Bloom filter with
* array size M containing N elements and
* using k hash function has expected false positive rate exactly
*
* $ (1 - (1 - 1/M)^{kN})^k $
*
* because each array slot has a
*
* $ (1 - 1/M)^{kN} $
*
* chance of being 0, and the expected false positive rate is the
* probability that all of the k hash functions will hit a nonzero
* slot.
*
* For reasonable assumptions (M large, kN large, which should both
* hold if we're worried about false positives) about M and kN this
* becomes approximately
*
* $$ (1 - \exp(-kN/M))^k $$
*
* For our special case of k == 2, that's $(1 - \exp(-2N/M))^2$,
* or in other words
*
* $$ N/M = -0.5 * \ln(1 - \sqrt(r)) $$
*
* where r is the false positive rate. This can be used to compute
* the desired KeySize for a given load N and false positive rate r.
*
* If N/M is assumed small, then the false positive rate can
* further be approximated as 4*N^2/M^2. So increasing KeySize by
* 1, which doubles M, reduces the false positive rate by about a
* factor of 4, and a false positive rate of 1% corresponds to
* about M/N == 20.
*
* What this means in practice is that for a few hundred keys using a
* KeySize of 12 gives false positive rates on the order of 0.25-4%.
*
* Similarly, using a KeySize of 10 would lead to a 4% false
* positive rate for N == 100 and to quite bad false positive
* rates for larger N.
*/
public:
BloomFilter() {
static_assert(KeySize <= keyShift, "KeySize too big");
/*
* A counting Bloom filter with 8-bit counters. For now we assume
* that having two hash functions is enough, but we may revisit that
* decision later.
*
* The filter uses an array with 2**KeySize entries.
*
* Assuming a well-distributed hash function, a Bloom filter with
* array size M containing N elements and
* using k hash function has expected false positive rate exactly
*
* $ (1 - (1 - 1/M)^{kN})^k $
*
* because each array slot has a
*
* $ (1 - 1/M)^{kN} $
*
* chance of being 0, and the expected false positive rate is the
* probability that all of the k hash functions will hit a nonzero
* slot.
*
* For reasonable assumptions (M large, kN large, which should both
* hold if we're worried about false positives) about M and kN this
* becomes approximately
*
* $$ (1 - \exp(-kN/M))^k $$
*
* For our special case of k == 2, that's $(1 - \exp(-2N/M))^2$,
* or in other words
*
* $$ N/M = -0.5 * \ln(1 - \sqrt(r)) $$
*
* where r is the false positive rate. This can be used to compute
* the desired KeySize for a given load N and false positive rate r.
*
* If N/M is assumed small, then the false positive rate can
* further be approximated as 4*N^2/M^2. So increasing KeySize by
* 1, which doubles M, reduces the false positive rate by about a
* factor of 4, and a false positive rate of 1% corresponds to
* about M/N == 20.
*
* What this means in practice is that for a few hundred keys using a
* KeySize of 12 gives false positive rates on the order of 0.25-4%.
*
* Similarly, using a KeySize of 10 would lead to a 4% false
* positive rate for N == 100 and to quite bad false positive
* rates for larger N.
*/
public:
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?
clear();
}
// Should we have a custom operator new using calloc instead and
// require that we're allocated via the operator?
clear();
}
/*
* Clear the filter. This should be done before reusing it, because
* just removing all items doesn't clear counters that hit the upper
* bound.
*/
void clear();
/*
* Clear the filter. This should be done before reusing it, because
* just removing all items doesn't clear counters that hit the upper
* bound.
*/
void clear();
/*
* Add an item to the filter.
*/
void add(const T* t);
/*
* Add an item to the filter.
*/
void add(const T* aValue);
/*
* Remove an item from the filter.
*/
void remove(const T* t);
/*
* Remove an item from the filter.
*/
void remove(const T* aValue);
/*
* Check whether the filter might contain an item. This can
* sometimes return true even if the item is not in the filter,
* but will never return false for items that are actually in the
* filter.
*/
bool mightContain(const T* t) const;
/*
* Check whether the filter might contain an item. This can
* sometimes return true even if the item is not in the filter,
* but will never return false for items that are actually in the
* filter.
*/
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;
/*
* Methods for add/remove/contain when we already have a hash computed
*/
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;
private:
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,34 +60,39 @@ 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));
}
public:
static bool checkBounds(const From aFrom)
{
return aFrom <= From(To(-1));
}
};
template<typename From, typename To>
struct UnsignedUnsignedCheck<From, To, FromIsNotBigger>
{
public:
static bool checkBounds(const From from) {
return true;
}
public:
static bool checkBounds(const From aFrom)
{
return true;
}
};
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
{
public:
static bool checkBounds(const From from) {
return UnsignedUnsignedCheck<From, To>::checkBounds(from);
}
public:
static bool checkBounds(const From aFrom)
{
return UnsignedUnsignedCheck<From, To>::checkBounds(aFrom);
}
};
// Signed-to-unsigned range check
@ -93,14 +100,17 @@ struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
{
public:
static bool checkBounds(const From from) {
if (from < 0)
return false;
if (sizeof(To) >= sizeof(From))
return true;
return from <= From(To(-1));
public:
static bool checkBounds(const From aFrom)
{
if (aFrom < 0) {
return false;
}
if (sizeof(To) >= sizeof(From)) {
return true;
}
return aFrom <= From(To(-1));
}
};
// Unsigned-to-signed range check
@ -108,35 +118,40 @@ 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) {
return true;
}
public:
static bool checkBounds(const From aFrom)
{
return true;
}
};
template<typename From, typename To>
struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
{
public:
static bool checkBounds(const From from) {
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
return from <= From(MaxValue);
}
public:
static bool checkBounds(const From aFrom)
{
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
return aFrom <= From(MaxValue);
}
};
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
{
public:
static bool checkBounds(const From from) {
return UnsignedSignedCheck<From, To>::checkBounds(from);
}
public:
static bool checkBounds(const From aFrom)
{
return UnsignedSignedCheck<From, To>::checkBounds(aFrom);
}
};
// Signed-to-signed range check
@ -144,42 +159,46 @@ struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned>
{
public:
static bool checkBounds(const From from) {
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);
public:
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) <= 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; }
public:
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);
}
public:
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

@ -19,21 +19,21 @@ namespace mozilla {
*/
class ChaosMode
{
public:
static bool isActive()
{
// Flip this to true to activate chaos mode
return false;
}
public:
static bool isActive()
{
// Flip this to true to activate chaos mode
return false;
}
/**
* Returns a somewhat (but not uniformly) random uint32_t < aBound.
* Not to be used for anything except ChaosMode, since it's not very random.
*/
static uint32_t randomUint32LessThan(uint32_t aBound)
{
return uint32_t(rand()) % aBound;
}
/**
* Returns a somewhat (but not uniformly) random uint32_t < aBound.
* Not to be used for anything except ChaosMode, since it's not very random.
*/
static uint32_t randomUint32LessThan(uint32_t aBound)
{
return uint32_t(rand()) % aBound;
}
};
} /* namespace mozilla */

View File

@ -32,8 +32,8 @@
*/
# define MOZ_UTF16_HELPER(s) L##s
# define _CHAR16T
typedef wchar_t char16_t;
typedef unsigned int char32_t;
typedef wchar_t char16_t;
typedef unsigned int char32_t;
#else
/* C++11 has a builtin char16_t type. */
# define MOZ_UTF16_HELPER(s) u##s
@ -61,86 +61,108 @@
*/
class char16ptr_t
{
private:
const char16_t* ptr;
static_assert(sizeof(char16_t) == sizeof(wchar_t), "char16_t and wchar_t sizes differ");
private:
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)) {}
public:
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) {}
/* Without this, nullptr assignment would be ambiguous. */
constexpr char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {}
operator const char16_t*() const {
return ptr;
}
operator const wchar_t*() const {
return reinterpret_cast<const wchar_t*>(ptr);
}
operator const void*() const {
return ptr;
}
operator bool() const {
return ptr != nullptr;
}
operator std::wstring() const {
return std::wstring(static_cast<const wchar_t*>(*this));
}
operator const char16_t*() const
{
return mPtr;
}
operator const wchar_t*() const
{
return reinterpret_cast<const wchar_t*>(mPtr);
}
operator const void*() const
{
return mPtr;
}
operator bool() const
{
return mPtr != nullptr;
}
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 wchar_t*() const {
return const_cast<wchar_t*>(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*>(mPtr);
}
explicit operator wchar_t*() const
{
return const_cast<wchar_t*>(static_cast<const wchar_t*>(*this));
}
/**
* Some Windows API calls accept BYTE* but require that data actually be WCHAR*.
* 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 unsigned char*() const {
return reinterpret_cast<const unsigned char*>(ptr);
}
explicit operator unsigned char*() const {
return const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(ptr));
}
explicit operator void*() const {
return const_cast<char16_t*>(ptr);
}
/**
* Some Windows API calls accept BYTE* but require that data actually be WCHAR*.
* Supporting this requires explicit operators to support the requisite explicit
* casts.
*/
explicit operator const char*() const
{
return reinterpret_cast<const char*>(mPtr);
}
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*>(mPtr));
}
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];
}
bool operator==(const char16ptr_t &x) const {
return ptr == x.ptr;
}
bool operator==(decltype(nullptr)) const {
return ptr == nullptr;
}
bool operator!=(const char16ptr_t &x) const {
return ptr != x.ptr;
}
bool operator!=(decltype(nullptr)) const {
return ptr != nullptr;
}
char16ptr_t operator+(size_t add) const {
return char16ptr_t(ptr + add);
}
ptrdiff_t operator-(const char16ptr_t &other) const {
return ptr - other.ptr;
}
/* Some operators used on pointers. */
char16_t operator[](size_t aIndex) const
{
return mPtr[aIndex];
}
bool operator==(const char16ptr_t &aOther) const
{
return mPtr == aOther.mPtr;
}
bool operator==(decltype(nullptr)) const
{
return mPtr == nullptr;
}
bool operator!=(const char16ptr_t &aOther) const
{
return mPtr != aOther.mPtr;
}
bool operator!=(decltype(nullptr)) const
{
return mPtr != nullptr;
}
char16ptr_t operator+(size_t aValue) const
{
return char16ptr_t(mPtr + aValue);
}
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

@ -35,13 +35,13 @@ struct UnsupportedType {};
template<typename IntegerType>
struct IsSupportedPass2
{
static const bool value = false;
static const bool value = false;
};
template<typename IntegerType>
struct IsSupported
{
static const bool value = IsSupportedPass2<IntegerType>::value;
static const bool value = IsSupportedPass2<IntegerType>::value;
};
template<>
@ -130,36 +130,37 @@ struct IsSupportedPass2<unsigned long long>
template<typename IntegerType, size_t Size = sizeof(IntegerType)>
struct TwiceBiggerType
{
typedef typename detail::StdintTypeForSizeAndSignedness<
sizeof(IntegerType) * 2,
IsSigned<IntegerType>::value
>::Type Type;
typedef typename detail::StdintTypeForSizeAndSignedness<
sizeof(IntegerType) * 2,
IsSigned<IntegerType>::value
>::Type Type;
};
template<typename IntegerType>
struct TwiceBiggerType<IntegerType, 8>
{
typedef UnsupportedType Type;
typedef UnsupportedType Type;
};
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,
@ -173,19 +174,19 @@ struct DoesRangeContainRange
template<typename T, typename U, bool Signedness>
struct DoesRangeContainRange<T, U, Signedness, Signedness>
{
static const bool value = sizeof(T) >= sizeof(U);
static const bool value = sizeof(T) >= sizeof(U);
};
template<typename T, typename U>
struct DoesRangeContainRange<T, U, true, false>
{
static const bool value = sizeof(T) > sizeof(U);
static const bool value = sizeof(T) > sizeof(U);
};
template<typename T, typename U>
struct DoesRangeContainRange<T, U, false, true>
{
static const bool value = false;
static const bool value = false;
};
template<typename T,
@ -198,89 +199,89 @@ struct IsInRangeImpl {};
template<typename T, typename U, bool IsTSigned, bool IsUSigned>
struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
{
static bool run(U)
{
return true;
}
static bool run(U)
{
return true;
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, true, true, false>
{
static bool run(U x)
{
return x <= MaxValue<T>::value && x >= MinValue<T>::value;
}
static bool run(U aX)
{
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)
{
return x <= MaxValue<T>::value;
}
static bool run(U aX)
{
return aX <= MaxValue<T>::value;
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, true, false, false>
{
static bool run(U x)
{
return sizeof(T) > sizeof(U) || x <= U(MaxValue<T>::value);
}
static bool run(U aX)
{
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)
{
return sizeof(T) >= sizeof(U)
? x >= 0
: x >= 0 && x <= U(MaxValue<T>::value);
}
static bool run(U aX)
{
return sizeof(T) >= sizeof(U)
? 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,61 +293,62 @@ struct IsMulValidImpl {};
template<typename T, bool IsTSigned>
struct IsMulValidImpl<T, IsTSigned, true>
{
static bool run(T x, T y)
{
typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y);
return IsInRange<T>(product);
}
static bool run(T aX, T aY)
{
typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY);
return IsInRange<T>(product);
}
};
template<typename T>
struct IsMulValidImpl<T, true, false>
{
static bool run(T x, T y)
{
const T max = MaxValue<T>::value;
const T min = MinValue<T>::value;
static bool run(T aX, T aY)
{
const T max = MaxValue<T>::value;
const T min = MinValue<T>::value;
if (x == 0 || y == 0)
return true;
if (x > 0) {
return y > 0
? x <= max / y
: y >= min / x;
}
// If we reach this point, we know that x < 0.
return y > 0
? x >= min / y
: y >= max / x;
if (aX == 0 || aY == 0) {
return true;
}
if (aX > 0) {
return aY > 0
? aX <= max / aY
: aY >= min / aX;
}
// 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)
{
return y == 0 || x <= MaxValue<T>::value / y;
}
static bool run(T aX, T aY)
{
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,25 +399,26 @@ struct NegateImpl;
template<typename T>
struct NegateImpl<T, false>
{
static CheckedInt<T> negate(const CheckedInt<T>& val)
{
// 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);
}
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, aVal.isValid() && aVal.mValue == 0);
}
};
template<typename T>
struct NegateImpl<T, true>
{
static CheckedInt<T> negate(const CheckedInt<T>& val)
{
// 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);
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 (!aVal.isValid() || aVal.mValue == MinValue<T>::value) {
return CheckedInt<T>(aVal.mValue, false);
}
return CheckedInt<T>(-aVal.mValue, true);
}
};
} // namespace detail
@ -437,18 +444,18 @@ 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;
if (checkedResult.isValid()) {
*result = checkedResult.value();
return true;
} else {
return false;
}
CheckedInt<int> checkedResult = (CheckedInt<int>(aX) + aY) / aZ;
if (checkedResult.isValid()) {
*aResult = checkedResult.value();
return true;
} else {
return false;
}
}
@endcode
*
@ -491,193 +498,188 @@ struct NegateImpl<T, true>
template<typename T>
class CheckedInt
{
protected:
T mValue;
bool mIsValid;
protected:
T mValue;
bool mIsValid;
template<typename U>
CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid)
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
}
template<typename U>
CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid)
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
}
friend struct detail::NegateImpl<T>;
friend struct detail::NegateImpl<T>;
public:
/**
* Constructs a checked integer with given @a value. The checked integer is
* initialized as valid or invalid depending on whether the @a value
* is in range.
*
* This constructor is not explicit. Instead, the type of its argument is a
* separate template parameter, ensuring that no conversion is performed
* before this constructor is actually called. As explained in the above
* documentation for class CheckedInt, this constructor checks that its
* argument is valid.
*/
template<typename U>
CheckedInt(U aValue)
: mValue(T(aValue)),
mIsValid(detail::IsInRange<T>(aValue))
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
}
public:
/**
* Constructs a checked integer with given @a value. The checked integer is
* initialized as valid or invalid depending on whether the @a value
* is in range.
*
* This constructor is not explicit. Instead, the type of its argument is a
* separate template parameter, ensuring that no conversion is performed
* before this constructor is actually called. As explained in the above
* documentation for class CheckedInt, this constructor checks that its
* argument is valid.
*/
template<typename U>
CheckedInt(U aValue)
: mValue(T(aValue)),
mIsValid(detail::IsInRange<T>(aValue))
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
}
template<typename U>
friend class CheckedInt;
template<typename U>
friend class CheckedInt;
template<typename U>
CheckedInt<U> toChecked() const
{
CheckedInt<U> ret(mValue);
ret.mIsValid = ret.mIsValid && mIsValid;
return ret;
}
template<typename U>
CheckedInt<U> toChecked() const
{
CheckedInt<U> ret(mValue);
ret.mIsValid = ret.mIsValid && mIsValid;
return ret;
}
/** Constructs a valid checked integer with initial value 0 */
CheckedInt() : mValue(0), mIsValid(true)
{
static_assert(detail::IsSupported<T>::value,
"This type is not supported by CheckedInt");
}
/** Constructs a valid checked integer with initial value 0 */
CheckedInt() : mValue(0), mIsValid(true)
{
static_assert(detail::IsSupported<T>::value,
"This type is not supported by CheckedInt");
}
/** @returns the actual value */
T value() const
{
MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
return mValue;
}
/** @returns the actual value */
T value() const
{
MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
return mValue;
}
/**
* @returns true if the checked integer is valid, i.e. is not the result
* of an invalid operation or of an operation involving an invalid checked
* integer
*/
bool isValid() const
{
return mIsValid;
}
/**
* @returns true if the checked integer is valid, i.e. is not the result
* of an invalid operation or of an operation involving an invalid checked
* integer
*/
bool isValid() const
{
return mIsValid;
}
template<typename U>
friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
const CheckedInt<U>& rhs);
template<typename U>
CheckedInt& operator +=(U rhs);
template<typename U>
friend CheckedInt<U> operator +(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator +=(U aRhs);
template<typename U>
friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
const CheckedInt<U>& rhs);
template<typename U>
CheckedInt& operator -=(U rhs);
template<typename U>
friend CheckedInt<U> operator -(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator -=(U aRhs);
template<typename U>
friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
const CheckedInt<U>& rhs);
template<typename U>
CheckedInt& operator *=(U rhs);
template<typename U>
friend CheckedInt<U> operator *(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator *=(U aRhs);
template<typename U>
friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
const CheckedInt<U>& rhs);
template<typename U>
CheckedInt& operator /=(U rhs);
template<typename U>
friend CheckedInt<U> operator /(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator /=(U aRhs);
template<typename U>
friend CheckedInt<U> operator %(const CheckedInt<U>& lhs,
const CheckedInt<U>& rhs);
template<typename U>
CheckedInt& operator %=(U rhs);
template<typename U>
friend CheckedInt<U> operator %(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator %=(U aRhs);
CheckedInt operator -() const
{
return detail::NegateImpl<T>::negate(*this);
}
CheckedInt operator -() const
{
return detail::NegateImpl<T>::negate(*this);
}
/**
* @returns true if the left and right hand sides are valid
* and have the same value.
*
* Note that these semantics are the reason why we don't offer
* a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
* but that would mean that whenever a or b is invalid, a!=b
* is always true, which would be very confusing.
*
* For similar reasons, operators <, >, <=, >= would be very tricky to
* specify, so we just avoid offering them.
*
* Notice that these == semantics are made more reasonable by these facts:
* 1. a==b implies equality at the raw data level
* (the converse is false, as a==b is never true among invalids)
* 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
{
return mIsValid && other.mIsValid && mValue == other.mValue;
}
/**
* @returns true if the left and right hand sides are valid
* and have the same value.
*
* Note that these semantics are the reason why we don't offer
* a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
* but that would mean that whenever a or b is invalid, a!=b
* is always true, which would be very confusing.
*
* For similar reasons, operators <, >, <=, >= would be very tricky to
* specify, so we just avoid offering them.
*
* Notice that these == semantics are made more reasonable by these facts:
* 1. a==b implies equality at the raw data level
* (the converse is false, as a==b is never true among invalids)
* 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& aOther) const
{
return mIsValid && aOther.mIsValid && mValue == aOther.mValue;
}
/** prefix ++ */
CheckedInt& operator++()
{
*this += 1;
return *this;
}
/** prefix ++ */
CheckedInt& operator++()
{
*this += 1;
return *this;
}
/** postfix ++ */
CheckedInt operator++(int)
{
CheckedInt tmp = *this;
*this += 1;
return tmp;
}
/** postfix ++ */
CheckedInt operator++(int)
{
CheckedInt tmp = *this;
*this += 1;
return tmp;
}
/** prefix -- */
CheckedInt& operator--()
{
*this -= 1;
return *this;
}
/** prefix -- */
CheckedInt& operator--()
{
*this -= 1;
return *this;
}
/** postfix -- */
CheckedInt operator--(int)
{
CheckedInt tmp = *this;
*this -= 1;
return tmp;
}
/** postfix -- */
CheckedInt operator--(int)
{
CheckedInt tmp = *this;
*this -= 1;
return tmp;
}
private:
/**
* 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;
private:
/**
* The !=, <, <=, >, >= operators are disabled:
* see the comment on operator==.
*/
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) \
{ \
if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue)) \
return CheckedInt<T>(0, false); \
\
return CheckedInt<T>(lhs.mValue OP rhs.mValue, \
lhs.mIsValid && rhs.mIsValid); \
}
#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
template<typename T> \
inline CheckedInt<T> \
operator OP(const CheckedInt<T> &aLhs, const CheckedInt<T> &aRhs) \
{ \
if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \
return CheckedInt<T>(0, false); \
} \
return CheckedInt<T>(aLhs.mValue OP aRhs.mValue, \
aLhs.mIsValid && aRhs.mIsValid); \
}
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
@ -698,47 +700,47 @@ namespace detail {
template<typename T, typename U>
struct CastToCheckedIntImpl
{
typedef CheckedInt<T> ReturnType;
static CheckedInt<T> run(U u) { return u; }
typedef CheckedInt<T> ReturnType;
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; }
typedef const CheckedInt<T>& ReturnType;
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) \
{ \
*this = *this OP castToCheckedInt<T>(rhs); \
return *this; \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
{ \
return lhs OP castToCheckedInt<T>(rhs); \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
{ \
return castToCheckedInt<T>(lhs) OP rhs; \
}
#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
template<typename T> \
template<typename U> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U aRhs) \
{ \
*this = *this OP castToCheckedInt<T>(aRhs); \
return *this; \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(const CheckedInt<T> &aLhs, U aRhs) \
{ \
return aLhs OP castToCheckedInt<T>(aRhs); \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(U aLhs, const CheckedInt<T> &aRhs) \
{ \
return castToCheckedInt<T>(aLhs) OP aRhs; \
}
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
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;
MOZ_ASSERT(inputSizeChecked.isValid());
return LZ4_compress(source, dest, inputSizeChecked.value());
CheckedInt<int> inputSizeChecked = aInputSize;
MOZ_ASSERT(inputSizeChecked.isValid());
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;
MOZ_ASSERT(inputSizeChecked.isValid());
CheckedInt<int> maxOutputSizeChecked = maxOutputSize;
MOZ_ASSERT(maxOutputSizeChecked.isValid());
return LZ4_compress_limitedOutput(source, dest, inputSizeChecked.value(),
maxOutputSizeChecked.value());
CheckedInt<int> inputSizeChecked = aInputSize;
MOZ_ASSERT(inputSizeChecked.isValid());
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
MOZ_ASSERT(maxOutputSizeChecked.isValid());
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;
MOZ_ASSERT(outputSizeChecked.isValid());
int ret = LZ4_decompress_fast(source, dest, outputSizeChecked.value());
return ret >= 0;
CheckedInt<int> outputSizeChecked = aOutputSize;
MOZ_ASSERT(outputSizeChecked.isValid());
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;
MOZ_ASSERT(maxOutputSizeChecked.isValid());
CheckedInt<int> inputSizeChecked = inputSize;
MOZ_ASSERT(inputSizeChecked.isValid());
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
MOZ_ASSERT(maxOutputSizeChecked.isValid());
CheckedInt<int> inputSizeChecked = aInputSize;
MOZ_ASSERT(inputSizeChecked.isValid());
int ret = LZ4_decompress_safe(source, dest, inputSizeChecked.value(),
maxOutputSizeChecked.value());
if (ret >= 0) {
*outputSize = ret;
return true;
} else {
*outputSize = 0;
return false;
}
int ret = LZ4_decompress_safe(aSource, aDest, inputSizeChecked.value(),
maxOutputSizeChecked.value());
if (ret >= 0) {
*aOutputSize = ret;
return true;
}
*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
*/
static MFBT_API size_t compressLimitedOutput(const char* source, size_t inputSize, char* dest,
size_t maxOutputSize);
* @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* 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)
*/
static MFBT_API bool decompress(const char* source, size_t inputSize, char* dest,
size_t maxOutputSize, size_t *outputSize);
* @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* 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
*/
static inline size_t maxCompressedSize(size_t inputSize)
* 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 aInputSize)
{
size_t max = ((inputSize) + ((inputSize)/255) + 16);
MOZ_ASSERT(max > inputSize);
return max;
size_t max = (aInputSize + (aInputSize / 255) + 16);
MOZ_ASSERT(max > aInputSize);
return max;
}
};
} /* namespace Compression */

View File

@ -34,47 +34,44 @@ namespace mozilla {
template<typename T>
class DebugOnly
{
public:
public:
#ifdef DEBUG
T value;
T value;
DebugOnly() { }
DebugOnly(const T& other) : value(other) { }
DebugOnly(const DebugOnly& other) : value(other.value) { }
DebugOnly& operator=(const T& rhs) {
value = rhs;
return *this;
}
void operator++(int) {
value++;
}
void operator--(int) {
value--;
}
DebugOnly() { }
DebugOnly(const T& aOther) : value(aOther) { }
DebugOnly(const DebugOnly& aOther) : value(aOther.value) { }
DebugOnly& operator=(const T& aRhs) {
value = aRhs;
return *this;
}
T* operator&() { return &value; }
void operator++(int) { value++; }
void operator--(int) { value--; }
operator T&() { return value; }
operator const T&() const { return value; }
T* operator&() { return &value; }
T& operator->() { return value; }
const T& operator->() const { return value; }
operator T&() { return value; }
operator const T&() const { return value; }
T& operator->() { return value; }
const T& operator->() const { return value; }
#else
DebugOnly() { }
DebugOnly(const T&) { }
DebugOnly(const DebugOnly&) { }
DebugOnly& operator=(const T&) { return *this; }
void operator++(int) { }
void operator--(int) { }
DebugOnly() { }
DebugOnly(const T&) { }
DebugOnly(const DebugOnly&) { }
DebugOnly& operator=(const T&) { return *this; }
void operator++(int) { }
void operator--(int) { }
#endif
/*
* DebugOnly must always have a destructor or else it will
* generate "unused variable" warnings, exactly what it's intended
* to avoid!
*/
~DebugOnly() {}
/*
* DebugOnly must always have a destructor or else it will
* generate "unused variable" warnings, exactly what it's intended
* to avoid!
*/
~DebugOnly() {}
};
}