mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1014377 - Convert the first quarter of MFBT to Gecko style. r=froydnj.
--HG-- extra : rebase_source : b3b2da775e2c0e8a6ecbed70e7bd0c8f7af67b47
This commit is contained in:
parent
dab2c77f74
commit
0b4c7c33bf
@ -21,14 +21,14 @@ namespace mozilla {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class AlignmentFinder
|
class AlignmentFinder
|
||||||
{
|
{
|
||||||
struct Aligner
|
struct Aligner
|
||||||
{
|
{
|
||||||
char c;
|
char mChar;
|
||||||
T t;
|
T mT;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const size_t alignment = sizeof(Aligner) - sizeof(T);
|
static const size_t alignment = sizeof(Aligner) - sizeof(T);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
|
#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
|
||||||
@ -71,31 +71,31 @@ struct AlignedElem;
|
|||||||
template<>
|
template<>
|
||||||
struct AlignedElem<1>
|
struct AlignedElem<1>
|
||||||
{
|
{
|
||||||
MOZ_ALIGNED_DECL(uint8_t elem, 1);
|
MOZ_ALIGNED_DECL(uint8_t elem, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct AlignedElem<2>
|
struct AlignedElem<2>
|
||||||
{
|
{
|
||||||
MOZ_ALIGNED_DECL(uint8_t elem, 2);
|
MOZ_ALIGNED_DECL(uint8_t elem, 2);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct AlignedElem<4>
|
struct AlignedElem<4>
|
||||||
{
|
{
|
||||||
MOZ_ALIGNED_DECL(uint8_t elem, 4);
|
MOZ_ALIGNED_DECL(uint8_t elem, 4);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct AlignedElem<8>
|
struct AlignedElem<8>
|
||||||
{
|
{
|
||||||
MOZ_ALIGNED_DECL(uint8_t elem, 8);
|
MOZ_ALIGNED_DECL(uint8_t elem, 8);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct AlignedElem<16>
|
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>
|
template<size_t Nbytes>
|
||||||
struct AlignedStorage
|
struct AlignedStorage
|
||||||
{
|
{
|
||||||
union U {
|
union U
|
||||||
char bytes[Nbytes];
|
{
|
||||||
uint64_t _;
|
char mBytes[Nbytes];
|
||||||
} u;
|
uint64_t mDummy;
|
||||||
|
} u;
|
||||||
|
|
||||||
const void* addr() const { return u.bytes; }
|
const void* addr() const { return u.mBytes; }
|
||||||
void* addr() { return u.bytes; }
|
void* addr() { return u.mBytes; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct AlignedStorage2
|
struct AlignedStorage2
|
||||||
{
|
{
|
||||||
union U {
|
union U
|
||||||
char bytes[sizeof(T)];
|
{
|
||||||
uint64_t _;
|
char mBytes[sizeof(T)];
|
||||||
} u;
|
uint64_t mDummy;
|
||||||
|
} u;
|
||||||
|
|
||||||
const T* addr() const { return reinterpret_cast<const T*>(u.bytes); }
|
const T* addr() const { return reinterpret_cast<const T*>(u.mBytes); }
|
||||||
T* addr() { return static_cast<T*>(static_cast<void*>(u.bytes)); }
|
T* addr() { return static_cast<T*>(static_cast<void*>(u.mBytes)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace mozilla */
|
} /* namespace mozilla */
|
||||||
|
@ -49,14 +49,31 @@ namespace mozilla {
|
|||||||
*/
|
*/
|
||||||
class MallocAllocPolicy
|
class MallocAllocPolicy
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void* malloc_(size_t bytes) { return malloc(bytes); }
|
void* malloc_(size_t aBytes)
|
||||||
void* calloc_(size_t bytes) { return calloc(bytes, 1); }
|
{
|
||||||
void* realloc_(void* p, size_t oldBytes, size_t bytes) { return realloc(p, bytes); }
|
return malloc(aBytes);
|
||||||
void free_(void* p) { free(p); }
|
}
|
||||||
void reportAllocOverflow() const {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
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
|
} // namespace mozilla
|
||||||
|
|
||||||
|
38
mfbt/Array.h
38
mfbt/Array.h
@ -19,31 +19,35 @@ namespace mozilla {
|
|||||||
template<typename T, size_t Length>
|
template<typename T, size_t Length>
|
||||||
class Array
|
class Array
|
||||||
{
|
{
|
||||||
T arr[Length];
|
T mArr[Length];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
T& operator[](size_t i) {
|
T& operator[](size_t aIndex)
|
||||||
MOZ_ASSERT(i < Length);
|
{
|
||||||
return arr[i];
|
MOZ_ASSERT(aIndex < Length);
|
||||||
}
|
return mArr[aIndex];
|
||||||
|
}
|
||||||
|
|
||||||
const T& operator[](size_t i) const {
|
const T& operator[](size_t aIndex) const
|
||||||
MOZ_ASSERT(i < Length);
|
{
|
||||||
return arr[i];
|
MOZ_ASSERT(aIndex < Length);
|
||||||
}
|
return mArr[aIndex];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Array<T, 0>
|
class Array<T, 0>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
T& operator[](size_t i) {
|
T& operator[](size_t aIndex)
|
||||||
MOZ_CRASH("indexing into zero-length array");
|
{
|
||||||
}
|
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");
|
{
|
||||||
}
|
MOZ_CRASH("indexing into zero-length array");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace mozilla */
|
} /* namespace mozilla */
|
||||||
|
@ -23,17 +23,17 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Safely subtract two pointers when it is known that end >= begin. This avoids
|
* Safely subtract two pointers when it is known that aEnd >= aBegin. This
|
||||||
* the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB
|
* avoids the common compiler bug that if (size_t(aEnd) - size_t(aBegin)) has
|
||||||
* set, the unsigned subtraction followed by right shift will produce -1, or
|
* the MSB set, the unsigned subtraction followed by right shift will produce
|
||||||
* size_t(-1), instead of the real difference.
|
* -1, or size_t(-1), instead of the real difference.
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
MOZ_ALWAYS_INLINE size_t
|
MOZ_ALWAYS_INLINE size_t
|
||||||
PointerRangeSize(T* begin, T* end)
|
PointerRangeSize(T* aBegin, T* aEnd)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(end >= begin);
|
MOZ_ASSERT(aEnd >= aBegin);
|
||||||
return (size_t(end) - size_t(begin)) / sizeof(T);
|
return (size_t(aEnd) - size_t(aBegin)) / sizeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -44,14 +44,14 @@ PointerRangeSize(T* begin, T* end)
|
|||||||
*/
|
*/
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
MOZ_CONSTEXPR size_t
|
MOZ_CONSTEXPR size_t
|
||||||
ArrayLength(T (&arr)[N])
|
ArrayLength(T (&aArr)[N])
|
||||||
{
|
{
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
MOZ_CONSTEXPR size_t
|
MOZ_CONSTEXPR size_t
|
||||||
ArrayLength(const Array<T, N>& arr)
|
ArrayLength(const Array<T, N>& aArr)
|
||||||
{
|
{
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
@ -63,23 +63,23 @@ ArrayLength(const Array<T, N>& arr)
|
|||||||
*/
|
*/
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
MOZ_CONSTEXPR T*
|
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>
|
template<typename T, size_t N>
|
||||||
MOZ_CONSTEXPR T*
|
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>
|
template<typename T, size_t N>
|
||||||
MOZ_CONSTEXPR const T*
|
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 {
|
namespace detail {
|
||||||
|
@ -32,13 +32,13 @@
|
|||||||
* number of undesired macros and symbols.
|
* number of undesired macros and symbols.
|
||||||
*/
|
*/
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
# endif
|
# endif
|
||||||
__declspec(dllimport) int __stdcall
|
__declspec(dllimport) int __stdcall
|
||||||
TerminateProcess(void* hProcess, unsigned int uExitCode);
|
TerminateProcess(void* hProcess, unsigned int uExitCode);
|
||||||
__declspec(dllimport) void* __stdcall GetCurrentProcess(void);
|
__declspec(dllimport) void* __stdcall GetCurrentProcess(void);
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
# include <signal.h>
|
# include <signal.h>
|
||||||
@ -124,21 +124,23 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prints |s| as an assertion failure (using file and ln as the location of the
|
* Prints |aStr| as an assertion failure (using aFilename and aLine as the
|
||||||
* assertion) to the standard debug-output channel.
|
* location of the assertion) to the standard debug-output channel.
|
||||||
*
|
*
|
||||||
* Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This
|
* 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
|
* method is primarily for internal use in this header, and only secondarily
|
||||||
* for use in implementing release-build assertions.
|
* for use in implementing release-build assertions.
|
||||||
*/
|
*/
|
||||||
static MOZ_ALWAYS_INLINE void
|
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
|
#ifdef ANDROID
|
||||||
__android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert",
|
__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
|
#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
|
#ifdef MOZ_DUMP_ASSERTION_STACK
|
||||||
nsTraceRefcnt::WalkTheStack(stderr);
|
nsTraceRefcnt::WalkTheStack(stderr);
|
||||||
#endif
|
#endif
|
||||||
@ -147,13 +149,13 @@ MOZ_ReportAssertionFailure(const char* s, const char* file, int ln) MOZ_PRETEND_
|
|||||||
}
|
}
|
||||||
|
|
||||||
static MOZ_ALWAYS_INLINE void
|
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
|
#ifdef ANDROID
|
||||||
__android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH",
|
__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
|
#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
|
#ifdef MOZ_DUMP_ASSERTION_STACK
|
||||||
nsTraceRefcnt::WalkTheStack(stderr);
|
nsTraceRefcnt::WalkTheStack(stderr);
|
||||||
#endif
|
#endif
|
||||||
@ -319,13 +321,13 @@ namespace detail {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsFunction
|
struct IsFunction
|
||||||
{
|
{
|
||||||
static const bool value = false;
|
static const bool value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R, typename... A>
|
template<typename R, typename... A>
|
||||||
struct IsFunction<R(A...)>
|
struct IsFunction<R(A...)>
|
||||||
{
|
{
|
||||||
static const bool value = true;
|
static const bool value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -333,47 +335,51 @@ void ValidateAssertConditionType()
|
|||||||
{
|
{
|
||||||
typedef typename RemoveReference<T>::Type ValueT;
|
typedef typename RemoveReference<T>::Type ValueT;
|
||||||
static_assert(!IsArray<ValueT>::value,
|
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,
|
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,
|
static_assert(!IsFloatingPoint<ValueT>::value,
|
||||||
"It's often a bad idea to assert that a floating-point number is nonzero, "
|
"It's often a bad idea to assert that a floating-point number "
|
||||||
"because such assertions tend to intermittently fail. Shouldn't your code gracefully handle "
|
"is nonzero, because such assertions tend to intermittently "
|
||||||
"this case instead of asserting? Anyway, if you really want to "
|
"fail. Shouldn't your code gracefully handle this case instead "
|
||||||
"do that, write an explicit boolean condition, like !!x or x!=0.");
|
"of asserting? Anyway, if you really want to do that, write an "
|
||||||
|
"explicit boolean condition, like !!x or x!=0.");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace mozilla
|
} // 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
|
#else
|
||||||
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x)
|
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* First the single-argument form. */
|
/* First the single-argument form. */
|
||||||
#define MOZ_ASSERT_HELPER1(expr) \
|
#define MOZ_ASSERT_HELPER1(expr) \
|
||||||
do { \
|
do { \
|
||||||
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
|
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
|
||||||
if (MOZ_UNLIKELY(!(expr))) { \
|
if (MOZ_UNLIKELY(!(expr))) { \
|
||||||
MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \
|
MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \
|
||||||
MOZ_REALLY_CRASH(); \
|
MOZ_REALLY_CRASH(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
/* Now the two-argument form. */
|
/* Now the two-argument form. */
|
||||||
#define MOZ_ASSERT_HELPER2(expr, explain) \
|
#define MOZ_ASSERT_HELPER2(expr, explain) \
|
||||||
do { \
|
do { \
|
||||||
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
|
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
|
||||||
if (MOZ_UNLIKELY(!(expr))) { \
|
if (MOZ_UNLIKELY(!(expr))) { \
|
||||||
MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \
|
MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \
|
||||||
MOZ_REALLY_CRASH(); \
|
MOZ_REALLY_CRASH(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b
|
#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b
|
||||||
#define MOZ_RELEASE_ASSERT(...) \
|
#define MOZ_RELEASE_ASSERT(...) \
|
||||||
MOZ_RELEASE_ASSERT_GLUE( \
|
MOZ_RELEASE_ASSERT_GLUE( \
|
||||||
MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
|
MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
|
||||||
(__VA_ARGS__))
|
(__VA_ARGS__))
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
|
# define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
|
||||||
@ -411,10 +417,11 @@ void ValidateAssertConditionType()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that it is
|
* MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that
|
||||||
* undefined behavior for execution to reach this point. No guarantees are made
|
* it is undefined behavior for execution to reach this point. No guarantees
|
||||||
* about what will happen if this is reached at runtime. Most code should use
|
* are made about what will happen if this is reached at runtime. Most code
|
||||||
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra asserts.
|
* should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra
|
||||||
|
* asserts.
|
||||||
*/
|
*/
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
|
# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
|
||||||
|
997
mfbt/Atomics.h
997
mfbt/Atomics.h
File diff suppressed because it is too large
Load Diff
@ -150,10 +150,10 @@
|
|||||||
* template<typename T>
|
* template<typename T>
|
||||||
* class Ptr
|
* class Ptr
|
||||||
* {
|
* {
|
||||||
* T* ptr;
|
* T* ptr;
|
||||||
* MOZ_EXPLICIT_CONVERSION operator bool() const {
|
* MOZ_EXPLICIT_CONVERSION operator bool() const {
|
||||||
* return ptr != nullptr;
|
* return ptr != nullptr;
|
||||||
* }
|
* }
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -267,9 +267,9 @@
|
|||||||
*
|
*
|
||||||
* struct NonCopyable
|
* struct NonCopyable
|
||||||
* {
|
* {
|
||||||
* private:
|
* private:
|
||||||
* NonCopyable(const NonCopyable& other) MOZ_DELETE;
|
* NonCopyable(const NonCopyable& other) MOZ_DELETE;
|
||||||
* void operator=(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
|
* If MOZ_DELETE can't be implemented for the current compiler, use of the
|
||||||
@ -295,23 +295,23 @@
|
|||||||
*
|
*
|
||||||
* class Base
|
* class Base
|
||||||
* {
|
* {
|
||||||
* public:
|
* public:
|
||||||
* virtual void f() = 0;
|
* virtual void f() = 0;
|
||||||
* };
|
* };
|
||||||
* class Derived1 : public Base
|
* class Derived1 : public Base
|
||||||
* {
|
* {
|
||||||
* public:
|
* public:
|
||||||
* virtual void f() MOZ_OVERRIDE;
|
* virtual void f() MOZ_OVERRIDE;
|
||||||
* };
|
* };
|
||||||
* class Derived2 : public Base
|
* class Derived2 : public Base
|
||||||
* {
|
* {
|
||||||
* public:
|
* public:
|
||||||
* virtual void f() MOZ_OVERRIDE = 0;
|
* virtual void f() MOZ_OVERRIDE = 0;
|
||||||
* };
|
* };
|
||||||
* class Derived3 : public Base
|
* class Derived3 : public Base
|
||||||
* {
|
* {
|
||||||
* public:
|
* public:
|
||||||
* virtual void f() MOZ_OVERRIDE { }
|
* virtual void f() MOZ_OVERRIDE { }
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* In compilers supporting C++11 override controls, MOZ_OVERRIDE *requires* that
|
* In compilers supporting C++11 override controls, MOZ_OVERRIDE *requires* that
|
||||||
@ -339,16 +339,16 @@
|
|||||||
*
|
*
|
||||||
* class Base MOZ_FINAL
|
* class Base MOZ_FINAL
|
||||||
* {
|
* {
|
||||||
* public:
|
* public:
|
||||||
* Base();
|
* Base();
|
||||||
* ~Base();
|
* ~Base();
|
||||||
* virtual void f() { }
|
* virtual void f() { }
|
||||||
* };
|
* };
|
||||||
* // This will be an error in some compilers:
|
* // This will be an error in some compilers:
|
||||||
* class Derived : public Base
|
* class Derived : public Base
|
||||||
* {
|
* {
|
||||||
* public:
|
* public:
|
||||||
* ~Derived() { }
|
* ~Derived() { }
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* One particularly common reason to specify MOZ_FINAL upon a class is to tell
|
* One particularly common reason to specify MOZ_FINAL upon a class is to tell
|
||||||
@ -375,14 +375,14 @@
|
|||||||
*
|
*
|
||||||
* class Base
|
* class Base
|
||||||
* {
|
* {
|
||||||
* public:
|
* public:
|
||||||
* virtual void f() MOZ_FINAL;
|
* virtual void f() MOZ_FINAL;
|
||||||
* };
|
* };
|
||||||
* class Derived
|
* class Derived
|
||||||
* {
|
* {
|
||||||
* public:
|
* public:
|
||||||
* // This will be an error in some compilers:
|
* // This will be an error in some compilers:
|
||||||
* virtual void f();
|
* virtual void f();
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* In compilers implementing final controls, it is an error for a derived class
|
* In compilers implementing final controls, it is an error for a derived class
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The algorithm searches the given container 'c' over the sorted index range
|
* The algorithm searches the given container |aContainer| over the sorted
|
||||||
* [begin, end) for an index 'i' where 'c[i] == target'. If such an index 'i' is
|
* index range [aBegin, aEnd) for an index |i| where |aContainer[i] == aTarget|.
|
||||||
* found, BinarySearch returns 'true' and the index is returned via the outparam
|
* If such an index |i| is found, BinarySearch returns |true| and the index is
|
||||||
* 'matchOrInsertionPoint'. If no index is found, BinarySearch returns 'false'
|
* returned via the outparam |aMatchOrInsertionPoint|. If no index is found,
|
||||||
* and the outparam returns the first index in [begin, end] where 'target' can
|
* BinarySearch returns |false| and the outparam returns the first index in
|
||||||
* be inserted to maintain sorted order.
|
* [aBegin, aEnd] where |aTarget| can be inserted to maintain sorted order.
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
@ -32,32 +32,34 @@ namespace mozilla {
|
|||||||
|
|
||||||
template <typename Container, typename T>
|
template <typename Container, typename T>
|
||||||
bool
|
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 low = aBegin;
|
||||||
size_t high = end;
|
size_t high = aEnd;
|
||||||
while (low != high) {
|
while (low != high) {
|
||||||
size_t middle = low + (high - low) / 2;
|
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(aContainer[low] <= aContainer[middle]);
|
||||||
MOZ_ASSERT(c[middle] <= c[high - 1]);
|
MOZ_ASSERT(aContainer[middle] <= aContainer[high - 1]);
|
||||||
MOZ_ASSERT(c[low] <= c[high - 1]);
|
MOZ_ASSERT(aContainer[low] <= aContainer[high - 1]);
|
||||||
|
|
||||||
if (target == middleValue) {
|
if (aTarget == middleValue) {
|
||||||
*matchOrInsertionPoint = middle;
|
*aMatchOrInsertionPoint = middle;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target < middleValue)
|
if (aTarget < middleValue) {
|
||||||
high = middle;
|
high = middle;
|
||||||
else
|
} else {
|
||||||
low = middle + 1;
|
low = middle + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*matchOrInsertionPoint = low;
|
*aMatchOrInsertionPoint = low;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,177 +55,199 @@ namespace mozilla {
|
|||||||
template<unsigned KeySize, class T>
|
template<unsigned KeySize, class T>
|
||||||
class BloomFilter
|
class BloomFilter
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* A counting Bloom filter with 8-bit counters. For now we assume
|
* A counting Bloom filter with 8-bit counters. For now we assume
|
||||||
* that having two hash functions is enough, but we may revisit that
|
* that having two hash functions is enough, but we may revisit that
|
||||||
* decision later.
|
* decision later.
|
||||||
*
|
*
|
||||||
* The filter uses an array with 2**KeySize entries.
|
* The filter uses an array with 2**KeySize entries.
|
||||||
*
|
*
|
||||||
* Assuming a well-distributed hash function, a Bloom filter with
|
* Assuming a well-distributed hash function, a Bloom filter with
|
||||||
* array size M containing N elements and
|
* array size M containing N elements and
|
||||||
* using k hash function has expected false positive rate exactly
|
* using k hash function has expected false positive rate exactly
|
||||||
*
|
*
|
||||||
* $ (1 - (1 - 1/M)^{kN})^k $
|
* $ (1 - (1 - 1/M)^{kN})^k $
|
||||||
*
|
*
|
||||||
* because each array slot has a
|
* because each array slot has a
|
||||||
*
|
*
|
||||||
* $ (1 - 1/M)^{kN} $
|
* $ (1 - 1/M)^{kN} $
|
||||||
*
|
*
|
||||||
* chance of being 0, and the expected false positive rate is the
|
* chance of being 0, and the expected false positive rate is the
|
||||||
* probability that all of the k hash functions will hit a nonzero
|
* probability that all of the k hash functions will hit a nonzero
|
||||||
* slot.
|
* slot.
|
||||||
*
|
*
|
||||||
* For reasonable assumptions (M large, kN large, which should both
|
* For reasonable assumptions (M large, kN large, which should both
|
||||||
* hold if we're worried about false positives) about M and kN this
|
* hold if we're worried about false positives) about M and kN this
|
||||||
* becomes approximately
|
* becomes approximately
|
||||||
*
|
*
|
||||||
* $$ (1 - \exp(-kN/M))^k $$
|
* $$ (1 - \exp(-kN/M))^k $$
|
||||||
*
|
*
|
||||||
* For our special case of k == 2, that's $(1 - \exp(-2N/M))^2$,
|
* For our special case of k == 2, that's $(1 - \exp(-2N/M))^2$,
|
||||||
* or in other words
|
* or in other words
|
||||||
*
|
*
|
||||||
* $$ N/M = -0.5 * \ln(1 - \sqrt(r)) $$
|
* $$ N/M = -0.5 * \ln(1 - \sqrt(r)) $$
|
||||||
*
|
*
|
||||||
* where r is the false positive rate. This can be used to compute
|
* 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.
|
* 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
|
* 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
|
* 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
|
* 1, which doubles M, reduces the false positive rate by about a
|
||||||
* factor of 4, and a false positive rate of 1% corresponds to
|
* factor of 4, and a false positive rate of 1% corresponds to
|
||||||
* about M/N == 20.
|
* about M/N == 20.
|
||||||
*
|
*
|
||||||
* What this means in practice is that for a few hundred keys using a
|
* 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%.
|
* 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
|
* Similarly, using a KeySize of 10 would lead to a 4% false
|
||||||
* positive rate for N == 100 and to quite bad false positive
|
* positive rate for N == 100 and to quite bad false positive
|
||||||
* rates for larger N.
|
* rates for larger N.
|
||||||
*/
|
*/
|
||||||
public:
|
public:
|
||||||
BloomFilter() {
|
BloomFilter()
|
||||||
static_assert(KeySize <= keyShift, "KeySize too big");
|
{
|
||||||
|
static_assert(KeySize <= kKeyShift, "KeySize too big");
|
||||||
|
|
||||||
// Should we have a custom operator new using calloc instead and
|
// Should we have a custom operator new using calloc instead and
|
||||||
// require that we're allocated via the operator?
|
// require that we're allocated via the operator?
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the filter. This should be done before reusing it, because
|
* Clear the filter. This should be done before reusing it, because
|
||||||
* just removing all items doesn't clear counters that hit the upper
|
* just removing all items doesn't clear counters that hit the upper
|
||||||
* bound.
|
* bound.
|
||||||
*/
|
*/
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add an item to the filter.
|
* Add an item to the filter.
|
||||||
*/
|
*/
|
||||||
void add(const T* t);
|
void add(const T* aValue);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove an item from the filter.
|
* 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
|
* Check whether the filter might contain an item. This can
|
||||||
* sometimes return true even if the item is not in the filter,
|
* sometimes return true even if the item is not in the filter,
|
||||||
* but will never return false for items that are actually in the
|
* but will never return false for items that are actually in the
|
||||||
* filter.
|
* 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
|
* Methods for add/remove/contain when we already have a hash computed
|
||||||
*/
|
*/
|
||||||
void add(uint32_t hash);
|
void add(uint32_t aHash);
|
||||||
void remove(uint32_t hash);
|
void remove(uint32_t aHash);
|
||||||
bool mightContain(uint32_t hash) const;
|
bool mightContain(uint32_t aHash) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const size_t arraySize = (1 << KeySize);
|
static const size_t kArraySize = (1 << KeySize);
|
||||||
static const uint32_t keyMask = (1 << KeySize) - 1;
|
static const uint32_t kKeyMask = (1 << KeySize) - 1;
|
||||||
static const uint32_t keyShift = 16;
|
static const uint32_t kKeyShift = 16;
|
||||||
|
|
||||||
static uint32_t hash1(uint32_t hash) { return hash & keyMask; }
|
static uint32_t hash1(uint32_t aHash)
|
||||||
static uint32_t hash2(uint32_t hash) { return (hash >> keyShift) & keyMask; }
|
{
|
||||||
|
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& firstSlot(uint32_t aHash)
|
||||||
uint8_t& secondSlot(uint32_t hash) { return counters[hash2(hash)]; }
|
{
|
||||||
const uint8_t& firstSlot(uint32_t hash) const { return counters[hash1(hash)]; }
|
return mCounters[hash1(aHash)];
|
||||||
const uint8_t& secondSlot(uint32_t hash) const { return counters[hash2(hash)]; }
|
}
|
||||||
|
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>
|
template<unsigned KeySize, class T>
|
||||||
inline void
|
inline void
|
||||||
BloomFilter<KeySize, T>::clear()
|
BloomFilter<KeySize, T>::clear()
|
||||||
{
|
{
|
||||||
memset(counters, 0, arraySize);
|
memset(mCounters, 0, kArraySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned KeySize, class T>
|
template<unsigned KeySize, class T>
|
||||||
inline void
|
inline void
|
||||||
BloomFilter<KeySize, T>::add(uint32_t hash)
|
BloomFilter<KeySize, T>::add(uint32_t aHash)
|
||||||
{
|
{
|
||||||
uint8_t& slot1 = firstSlot(hash);
|
uint8_t& slot1 = firstSlot(aHash);
|
||||||
if (MOZ_LIKELY(!full(slot1)))
|
if (MOZ_LIKELY(!full(slot1))) {
|
||||||
++slot1;
|
++slot1;
|
||||||
|
}
|
||||||
uint8_t& slot2 = secondSlot(hash);
|
uint8_t& slot2 = secondSlot(aHash); {
|
||||||
if (MOZ_LIKELY(!full(slot2)))
|
if (MOZ_LIKELY(!full(slot2)))
|
||||||
++slot2;
|
++slot2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned KeySize, class T>
|
template<unsigned KeySize, class T>
|
||||||
MOZ_ALWAYS_INLINE void
|
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);
|
return add(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned KeySize, class T>
|
template<unsigned KeySize, class T>
|
||||||
inline void
|
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
|
// 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.
|
// there when we added or not, so just leave them full.
|
||||||
uint8_t& slot1 = firstSlot(hash);
|
uint8_t& slot1 = firstSlot(aHash);
|
||||||
if (MOZ_LIKELY(!full(slot1)))
|
if (MOZ_LIKELY(!full(slot1))) {
|
||||||
--slot1;
|
--slot1;
|
||||||
|
}
|
||||||
uint8_t& slot2 = secondSlot(hash);
|
uint8_t& slot2 = secondSlot(aHash);
|
||||||
if (MOZ_LIKELY(!full(slot2)))
|
if (MOZ_LIKELY(!full(slot2))) {
|
||||||
--slot2;
|
--slot2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned KeySize, class T>
|
template<unsigned KeySize, class T>
|
||||||
MOZ_ALWAYS_INLINE void
|
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);
|
remove(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned KeySize, class T>
|
template<unsigned KeySize, class T>
|
||||||
MOZ_ALWAYS_INLINE bool
|
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
|
// 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>
|
template<unsigned KeySize, class T>
|
||||||
MOZ_ALWAYS_INLINE bool
|
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);
|
return mightContain(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
141
mfbt/Casting.h
141
mfbt/Casting.h
@ -17,7 +17,8 @@
|
|||||||
namespace mozilla {
|
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
|
* |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
|
* size differences, or this might fail to compile on some but not all
|
||||||
@ -25,16 +26,17 @@ namespace mozilla {
|
|||||||
*/
|
*/
|
||||||
template<typename To, typename From>
|
template<typename To, typename From>
|
||||||
inline To
|
inline To
|
||||||
BitwiseCast(const From from)
|
BitwiseCast(const From aFrom)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(From) == sizeof(To),
|
static_assert(sizeof(From) == sizeof(To),
|
||||||
"To and From must have the same size");
|
"To and From must have the same size");
|
||||||
union {
|
union
|
||||||
From from;
|
{
|
||||||
To to;
|
From mFrom;
|
||||||
|
To mTo;
|
||||||
} u;
|
} u;
|
||||||
u.from = from;
|
u.mFrom = aFrom;
|
||||||
return u.to;
|
return u.mTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -58,34 +60,39 @@ enum UUComparison { FromIsBigger, FromIsNotBigger };
|
|||||||
// Unsigned-to-unsigned range check
|
// Unsigned-to-unsigned range check
|
||||||
|
|
||||||
template<typename From, typename To,
|
template<typename From, typename To,
|
||||||
UUComparison = (sizeof(From) > sizeof(To)) ? FromIsBigger : FromIsNotBigger>
|
UUComparison = (sizeof(From) > sizeof(To))
|
||||||
|
? FromIsBigger
|
||||||
|
: FromIsNotBigger>
|
||||||
struct UnsignedUnsignedCheck;
|
struct UnsignedUnsignedCheck;
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
struct UnsignedUnsignedCheck<From, To, FromIsBigger>
|
struct UnsignedUnsignedCheck<From, To, FromIsBigger>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool checkBounds(const From from) {
|
static bool checkBounds(const From aFrom)
|
||||||
return from <= From(To(-1));
|
{
|
||||||
}
|
return aFrom <= From(To(-1));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
struct UnsignedUnsignedCheck<From, To, FromIsNotBigger>
|
struct UnsignedUnsignedCheck<From, To, FromIsNotBigger>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool checkBounds(const From from) {
|
static bool checkBounds(const From aFrom)
|
||||||
return true;
|
{
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
|
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool checkBounds(const From from) {
|
static bool checkBounds(const From aFrom)
|
||||||
return UnsignedUnsignedCheck<From, To>::checkBounds(from);
|
{
|
||||||
}
|
return UnsignedUnsignedCheck<From, To>::checkBounds(aFrom);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Signed-to-unsigned range check
|
// Signed-to-unsigned range check
|
||||||
@ -93,14 +100,17 @@ struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
|
|||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
|
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool checkBounds(const From from) {
|
static bool checkBounds(const From aFrom)
|
||||||
if (from < 0)
|
{
|
||||||
return false;
|
if (aFrom < 0) {
|
||||||
if (sizeof(To) >= sizeof(From))
|
return false;
|
||||||
return true;
|
|
||||||
return from <= From(To(-1));
|
|
||||||
}
|
}
|
||||||
|
if (sizeof(To) >= sizeof(From)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return aFrom <= From(To(-1));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Unsigned-to-signed range check
|
// Unsigned-to-signed range check
|
||||||
@ -108,35 +118,40 @@ struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
|
|||||||
enum USComparison { FromIsSmaller, FromIsNotSmaller };
|
enum USComparison { FromIsSmaller, FromIsNotSmaller };
|
||||||
|
|
||||||
template<typename From, typename To,
|
template<typename From, typename To,
|
||||||
USComparison = (sizeof(From) < sizeof(To)) ? FromIsSmaller : FromIsNotSmaller>
|
USComparison = (sizeof(From) < sizeof(To))
|
||||||
|
? FromIsSmaller
|
||||||
|
: FromIsNotSmaller>
|
||||||
struct UnsignedSignedCheck;
|
struct UnsignedSignedCheck;
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
struct UnsignedSignedCheck<From, To, FromIsSmaller>
|
struct UnsignedSignedCheck<From, To, FromIsSmaller>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool checkBounds(const From from) {
|
static bool checkBounds(const From aFrom)
|
||||||
return true;
|
{
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
|
struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
|
||||||
{
|
{
|
||||||
public:
|
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);
|
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
|
||||||
}
|
return aFrom <= From(MaxValue);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
|
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool checkBounds(const From from) {
|
static bool checkBounds(const From aFrom)
|
||||||
return UnsignedSignedCheck<From, To>::checkBounds(from);
|
{
|
||||||
}
|
return UnsignedSignedCheck<From, To>::checkBounds(aFrom);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Signed-to-signed range check
|
// Signed-to-signed range check
|
||||||
@ -144,42 +159,46 @@ struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
|
|||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned>
|
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool checkBounds(const From from) {
|
static bool checkBounds(const From aFrom)
|
||||||
if (sizeof(From) <= sizeof(To))
|
{
|
||||||
return true;
|
if (sizeof(From) <= sizeof(To)) {
|
||||||
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
|
return true;
|
||||||
const To MinValue = -MaxValue - To(1);
|
|
||||||
return From(MinValue) <= from &&
|
|
||||||
From(from) <= From(MaxValue);
|
|
||||||
}
|
}
|
||||||
|
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,
|
template<typename From, typename To,
|
||||||
bool TypesAreIntegral = IsIntegral<From>::value && IsIntegral<To>::value>
|
bool TypesAreIntegral = IsIntegral<From>::value &&
|
||||||
|
IsIntegral<To>::value>
|
||||||
class BoundsChecker;
|
class BoundsChecker;
|
||||||
|
|
||||||
template<typename From>
|
template<typename From>
|
||||||
class BoundsChecker<From, From, true>
|
class BoundsChecker<From, From, true>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool checkBounds(const From from) { return true; }
|
static bool checkBounds(const From aFrom) { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
class BoundsChecker<From, To, true>
|
class BoundsChecker<From, To, true>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool checkBounds(const From from) {
|
static bool checkBounds(const From aFrom)
|
||||||
return BoundsCheckImpl<From, To>::checkBounds(from);
|
{
|
||||||
}
|
return BoundsCheckImpl<From, To>::checkBounds(aFrom);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
inline bool
|
inline bool
|
||||||
IsInBounds(const From from)
|
IsInBounds(const From aFrom)
|
||||||
{
|
{
|
||||||
return BoundsChecker<From, To>::checkBounds(from);
|
return BoundsChecker<From, To>::checkBounds(aFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -191,10 +210,10 @@ IsInBounds(const From from)
|
|||||||
*/
|
*/
|
||||||
template<typename To, typename From>
|
template<typename To, typename From>
|
||||||
inline To
|
inline To
|
||||||
SafeCast(const From from)
|
SafeCast(const From aFrom)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT((detail::IsInBounds<From, To>(from)));
|
MOZ_ASSERT((detail::IsInBounds<From, To>(aFrom)));
|
||||||
return static_cast<To>(from);
|
return static_cast<To>(aFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -19,21 +19,21 @@ namespace mozilla {
|
|||||||
*/
|
*/
|
||||||
class ChaosMode
|
class ChaosMode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool isActive()
|
static bool isActive()
|
||||||
{
|
{
|
||||||
// Flip this to true to activate chaos mode
|
// Flip this to true to activate chaos mode
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a somewhat (but not uniformly) random uint32_t < 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.
|
* Not to be used for anything except ChaosMode, since it's not very random.
|
||||||
*/
|
*/
|
||||||
static uint32_t randomUint32LessThan(uint32_t aBound)
|
static uint32_t randomUint32LessThan(uint32_t aBound)
|
||||||
{
|
{
|
||||||
return uint32_t(rand()) % aBound;
|
return uint32_t(rand()) % aBound;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace mozilla */
|
} /* namespace mozilla */
|
||||||
|
168
mfbt/Char16.h
168
mfbt/Char16.h
@ -32,8 +32,8 @@
|
|||||||
*/
|
*/
|
||||||
# define MOZ_UTF16_HELPER(s) L##s
|
# define MOZ_UTF16_HELPER(s) L##s
|
||||||
# define _CHAR16T
|
# define _CHAR16T
|
||||||
typedef wchar_t char16_t;
|
typedef wchar_t char16_t;
|
||||||
typedef unsigned int char32_t;
|
typedef unsigned int char32_t;
|
||||||
#else
|
#else
|
||||||
/* C++11 has a builtin char16_t type. */
|
/* C++11 has a builtin char16_t type. */
|
||||||
# define MOZ_UTF16_HELPER(s) u##s
|
# define MOZ_UTF16_HELPER(s) u##s
|
||||||
@ -61,86 +61,108 @@
|
|||||||
*/
|
*/
|
||||||
class char16ptr_t
|
class char16ptr_t
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const char16_t* ptr;
|
const char16_t* mPtr;
|
||||||
static_assert(sizeof(char16_t) == sizeof(wchar_t), "char16_t and wchar_t sizes differ");
|
static_assert(sizeof(char16_t) == sizeof(wchar_t),
|
||||||
|
"char16_t and wchar_t sizes differ");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
char16ptr_t(const char16_t* p) : ptr(p) {}
|
char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {}
|
||||||
char16ptr_t(const wchar_t* p) : ptr(reinterpret_cast<const char16_t*>(p)) {}
|
char16ptr_t(const wchar_t* aPtr) :
|
||||||
|
mPtr(reinterpret_cast<const char16_t*>(aPtr))
|
||||||
|
{}
|
||||||
|
|
||||||
/* Without this, nullptr assignment would be ambiguous. */
|
/* 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 {
|
operator const char16_t*() const
|
||||||
return ptr;
|
{
|
||||||
}
|
return mPtr;
|
||||||
operator const wchar_t*() const {
|
}
|
||||||
return reinterpret_cast<const wchar_t*>(ptr);
|
operator const wchar_t*() const
|
||||||
}
|
{
|
||||||
operator const void*() const {
|
return reinterpret_cast<const wchar_t*>(mPtr);
|
||||||
return ptr;
|
}
|
||||||
}
|
operator const void*() const
|
||||||
operator bool() const {
|
{
|
||||||
return ptr != nullptr;
|
return mPtr;
|
||||||
}
|
}
|
||||||
operator std::wstring() const {
|
operator bool() const
|
||||||
return std::wstring(static_cast<const wchar_t*>(*this));
|
{
|
||||||
}
|
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 cast operators to allow things like (char16_t*)str. */
|
||||||
explicit operator char16_t*() const {
|
explicit operator char16_t*() const
|
||||||
return const_cast<char16_t*>(ptr);
|
{
|
||||||
}
|
return const_cast<char16_t*>(mPtr);
|
||||||
explicit operator wchar_t*() const {
|
}
|
||||||
return const_cast<wchar_t*>(static_cast<const wchar_t*>(*this));
|
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*.
|
* Some Windows API calls accept BYTE* but require that data actually be WCHAR*.
|
||||||
* Supporting this requires explicit operators to support the requisite explicit
|
* Supporting this requires explicit operators to support the requisite explicit
|
||||||
* casts.
|
* casts.
|
||||||
*/
|
*/
|
||||||
explicit operator const char*() const {
|
explicit operator const char*() const
|
||||||
return reinterpret_cast<const char*>(ptr);
|
{
|
||||||
}
|
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
|
||||||
}
|
{
|
||||||
explicit operator unsigned char*() const {
|
return reinterpret_cast<const unsigned char*>(mPtr);
|
||||||
return const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(ptr));
|
}
|
||||||
}
|
explicit operator unsigned char*() const
|
||||||
explicit operator void*() const {
|
{
|
||||||
return const_cast<char16_t*>(ptr);
|
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. */
|
/* Some operators used on pointers. */
|
||||||
char16_t operator[](size_t i) const {
|
char16_t operator[](size_t aIndex) const
|
||||||
return ptr[i];
|
{
|
||||||
}
|
return mPtr[aIndex];
|
||||||
bool operator==(const char16ptr_t &x) const {
|
}
|
||||||
return ptr == x.ptr;
|
bool operator==(const char16ptr_t &aOther) const
|
||||||
}
|
{
|
||||||
bool operator==(decltype(nullptr)) const {
|
return mPtr == aOther.mPtr;
|
||||||
return ptr == nullptr;
|
}
|
||||||
}
|
bool operator==(decltype(nullptr)) const
|
||||||
bool operator!=(const char16ptr_t &x) const {
|
{
|
||||||
return ptr != x.ptr;
|
return mPtr == nullptr;
|
||||||
}
|
}
|
||||||
bool operator!=(decltype(nullptr)) const {
|
bool operator!=(const char16ptr_t &aOther) const
|
||||||
return ptr != nullptr;
|
{
|
||||||
}
|
return mPtr != aOther.mPtr;
|
||||||
char16ptr_t operator+(size_t add) const {
|
}
|
||||||
return char16ptr_t(ptr + add);
|
bool operator!=(decltype(nullptr)) const
|
||||||
}
|
{
|
||||||
ptrdiff_t operator-(const char16ptr_t &other) const {
|
return mPtr != nullptr;
|
||||||
return ptr - other.ptr;
|
}
|
||||||
}
|
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)
|
inline decltype((char*)0-(char*)0)
|
||||||
operator-(const char16_t* x, const char16ptr_t y) {
|
operator-(const char16_t* aX, const char16ptr_t aY)
|
||||||
return x - static_cast<const char16_t*>(y);
|
{
|
||||||
|
return aX - static_cast<const char16_t*>(aY);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -35,13 +35,13 @@ struct UnsupportedType {};
|
|||||||
template<typename IntegerType>
|
template<typename IntegerType>
|
||||||
struct IsSupportedPass2
|
struct IsSupportedPass2
|
||||||
{
|
{
|
||||||
static const bool value = false;
|
static const bool value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename IntegerType>
|
template<typename IntegerType>
|
||||||
struct IsSupported
|
struct IsSupported
|
||||||
{
|
{
|
||||||
static const bool value = IsSupportedPass2<IntegerType>::value;
|
static const bool value = IsSupportedPass2<IntegerType>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@ -130,36 +130,37 @@ struct IsSupportedPass2<unsigned long long>
|
|||||||
template<typename IntegerType, size_t Size = sizeof(IntegerType)>
|
template<typename IntegerType, size_t Size = sizeof(IntegerType)>
|
||||||
struct TwiceBiggerType
|
struct TwiceBiggerType
|
||||||
{
|
{
|
||||||
typedef typename detail::StdintTypeForSizeAndSignedness<
|
typedef typename detail::StdintTypeForSizeAndSignedness<
|
||||||
sizeof(IntegerType) * 2,
|
sizeof(IntegerType) * 2,
|
||||||
IsSigned<IntegerType>::value
|
IsSigned<IntegerType>::value
|
||||||
>::Type Type;
|
>::Type Type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename IntegerType>
|
template<typename IntegerType>
|
||||||
struct TwiceBiggerType<IntegerType, 8>
|
struct TwiceBiggerType<IntegerType, 8>
|
||||||
{
|
{
|
||||||
typedef UnsupportedType Type;
|
typedef UnsupportedType Type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline bool
|
inline bool
|
||||||
HasSignBit(T x)
|
HasSignBit(T aX)
|
||||||
{
|
{
|
||||||
// In C++, right bit shifts on negative values is undefined by the standard.
|
// 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
|
// Notice that signed-to-unsigned conversions are always well-defined in the
|
||||||
// standard, as the value congruent modulo 2**n as expected. By contrast,
|
// standard, as the value congruent modulo 2**n as expected. By contrast,
|
||||||
// unsigned-to-signed is only well-defined if the value is representable.
|
// 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
|
// 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.
|
// helper guaranteeing that the result is really of type T.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T
|
inline T
|
||||||
BinaryComplement(T x)
|
BinaryComplement(T aX)
|
||||||
{
|
{
|
||||||
return ~x;
|
return ~aX;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,
|
template<typename T,
|
||||||
@ -173,19 +174,19 @@ struct DoesRangeContainRange
|
|||||||
template<typename T, typename U, bool Signedness>
|
template<typename T, typename U, bool Signedness>
|
||||||
struct DoesRangeContainRange<T, U, Signedness, 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>
|
template<typename T, typename U>
|
||||||
struct DoesRangeContainRange<T, U, true, false>
|
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>
|
template<typename T, typename U>
|
||||||
struct DoesRangeContainRange<T, U, false, true>
|
struct DoesRangeContainRange<T, U, false, true>
|
||||||
{
|
{
|
||||||
static const bool value = false;
|
static const bool value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T,
|
template<typename T,
|
||||||
@ -198,89 +199,89 @@ struct IsInRangeImpl {};
|
|||||||
template<typename T, typename U, bool IsTSigned, bool IsUSigned>
|
template<typename T, typename U, bool IsTSigned, bool IsUSigned>
|
||||||
struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
|
struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
|
||||||
{
|
{
|
||||||
static bool run(U)
|
static bool run(U)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
struct IsInRangeImpl<T, U, true, true, false>
|
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>
|
template<typename T, typename U>
|
||||||
struct IsInRangeImpl<T, U, false, false, false>
|
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>
|
template<typename T, typename U>
|
||||||
struct IsInRangeImpl<T, U, true, false, false>
|
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>
|
template<typename T, typename U>
|
||||||
struct IsInRangeImpl<T, U, false, true, false>
|
struct IsInRangeImpl<T, U, false, true, false>
|
||||||
{
|
{
|
||||||
static bool run(U x)
|
static bool run(U aX)
|
||||||
{
|
{
|
||||||
return sizeof(T) >= sizeof(U)
|
return sizeof(T) >= sizeof(U)
|
||||||
? x >= 0
|
? aX >= 0
|
||||||
: x >= 0 && x <= U(MaxValue<T>::value);
|
: aX >= 0 && aX <= U(MaxValue<T>::value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
inline bool
|
inline bool
|
||||||
IsInRange(U x)
|
IsInRange(U aX)
|
||||||
{
|
{
|
||||||
return IsInRangeImpl<T, U>::run(x);
|
return IsInRangeImpl<T, U>::run(aX);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline bool
|
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
|
// Addition is valid if the sign of aX+aY is equal to either that of aX or
|
||||||
// of y. Since the value of x+y is undefined if we have a signed type, we
|
// that of aY. Since the value of aX+aY is undefined if we have a signed
|
||||||
// compute it using the unsigned type of the same size.
|
// type, we compute it using the unsigned type of the same size. Beware!
|
||||||
// Beware! These bitwise operations can return a larger integer type,
|
// These bitwise operations can return a larger integer type, if T was a
|
||||||
// if T was a small type like int8_t, so we explicitly cast to T.
|
// small type like int8_t, so we explicitly cast to T.
|
||||||
|
|
||||||
typename MakeUnsigned<T>::Type ux = x;
|
typename MakeUnsigned<T>::Type ux = aX;
|
||||||
typename MakeUnsigned<T>::Type uy = y;
|
typename MakeUnsigned<T>::Type uy = aY;
|
||||||
typename MakeUnsigned<T>::Type result = ux + uy;
|
typename MakeUnsigned<T>::Type result = ux + uy;
|
||||||
return IsSigned<T>::value
|
return IsSigned<T>::value
|
||||||
? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y))))
|
? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY))))
|
||||||
: BinaryComplement(x) >= y;
|
: BinaryComplement(aX) >= aY;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline bool
|
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
|
// Subtraction is valid if either aX and aY have same sign, or aX-aY and aX
|
||||||
// same sign. Since the value of x-y is undefined if we have a signed type,
|
// have same sign. Since the value of aX-aY is undefined if we have a signed
|
||||||
// we compute it using the unsigned type of the same size.
|
// type, we compute it using the unsigned type of the same size.
|
||||||
typename MakeUnsigned<T>::Type ux = x;
|
typename MakeUnsigned<T>::Type ux = aX;
|
||||||
typename MakeUnsigned<T>::Type uy = y;
|
typename MakeUnsigned<T>::Type uy = aY;
|
||||||
typename MakeUnsigned<T>::Type result = ux - uy;
|
typename MakeUnsigned<T>::Type result = ux - uy;
|
||||||
|
|
||||||
return IsSigned<T>::value
|
return IsSigned<T>::value
|
||||||
? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y))))
|
? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY))))
|
||||||
: x >= y;
|
: aX >= aY;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,
|
template<typename T,
|
||||||
@ -292,61 +293,62 @@ struct IsMulValidImpl {};
|
|||||||
template<typename T, bool IsTSigned>
|
template<typename T, bool IsTSigned>
|
||||||
struct IsMulValidImpl<T, IsTSigned, true>
|
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;
|
typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
|
||||||
TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y);
|
TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY);
|
||||||
return IsInRange<T>(product);
|
return IsInRange<T>(product);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsMulValidImpl<T, true, false>
|
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 max = MaxValue<T>::value;
|
||||||
const T min = MinValue<T>::value;
|
const T min = MinValue<T>::value;
|
||||||
|
|
||||||
if (x == 0 || y == 0)
|
if (aX == 0 || aY == 0) {
|
||||||
return true;
|
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) {
|
||||||
|
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>
|
template<typename T>
|
||||||
struct IsMulValidImpl<T, false, false>
|
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>
|
template<typename T>
|
||||||
inline bool
|
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>
|
template<typename T>
|
||||||
inline bool
|
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.
|
// Keep in mind that in the signed case, min/-1 is invalid because
|
||||||
return y != 0 &&
|
// abs(min)>max.
|
||||||
!(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1));
|
return aY != 0 &&
|
||||||
|
!(IsSigned<T>::value && aX == MinValue<T>::value && aY == T(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool IsTSigned = IsSigned<T>::value>
|
template<typename T, bool IsTSigned = IsSigned<T>::value>
|
||||||
@ -354,36 +356,40 @@ struct IsModValidImpl;
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline bool
|
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.
|
* Mod is pretty simple.
|
||||||
* For now, let's just use the ANSI C definition:
|
* 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.
|
* Consider these invalid.
|
||||||
* Undefined for y=0.
|
* Undefined for aY=0.
|
||||||
* The result will never exceed either x or y.
|
* 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>
|
template<typename T>
|
||||||
struct IsModValidImpl<T, false> {
|
struct IsModValidImpl<T, false>
|
||||||
static inline bool run(T x, T y) {
|
{
|
||||||
return y >= 1;
|
static inline bool run(T aX, T aY)
|
||||||
|
{
|
||||||
|
return aY >= 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsModValidImpl<T, true> {
|
struct IsModValidImpl<T, true>
|
||||||
static inline bool run(T x, T y) {
|
{
|
||||||
if (x < 0)
|
static inline bool run(T aX, T aY)
|
||||||
|
{
|
||||||
|
if (aX < 0) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return y >= 1;
|
return aY >= 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -393,25 +399,26 @@ struct NegateImpl;
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct NegateImpl<T, false>
|
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
|
// Handle negation separately for signed/unsigned, for simpler code and to
|
||||||
// avoid an MSVC warning negating an unsigned value.
|
// 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>
|
template<typename T>
|
||||||
struct NegateImpl<T, true>
|
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
|
// Watch out for the min-value, which (with twos-complement) can't be
|
||||||
// negated as -min-value is then (max-value + 1).
|
// negated as -min-value is then (max-value + 1).
|
||||||
if (!val.isValid() || val.mValue == MinValue<T>::value)
|
if (!aVal.isValid() || aVal.mValue == MinValue<T>::value) {
|
||||||
return CheckedInt<T>(val.mValue, false);
|
return CheckedInt<T>(aVal.mValue, false);
|
||||||
return CheckedInt<T>(-val.mValue, true);
|
|
||||||
}
|
}
|
||||||
|
return CheckedInt<T>(-aVal.mValue, true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -437,18 +444,18 @@ struct NegateImpl<T, true>
|
|||||||
* (e.g. in case of a division by zero).
|
* (e.g. in case of a division by zero).
|
||||||
*
|
*
|
||||||
* For example, suppose that you want to implement a function that computes
|
* 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:
|
* zero or integer overflow). You could code it as follows:
|
||||||
@code
|
@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()) {
|
if (checkedResult.isValid()) {
|
||||||
*result = checkedResult.value();
|
*aResult = checkedResult.value();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
*
|
*
|
||||||
@ -491,193 +498,188 @@ struct NegateImpl<T, true>
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class CheckedInt
|
class CheckedInt
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
T mValue;
|
T mValue;
|
||||||
bool mIsValid;
|
bool mIsValid;
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid)
|
CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid)
|
||||||
{
|
{
|
||||||
static_assert(detail::IsSupported<T>::value &&
|
static_assert(detail::IsSupported<T>::value &&
|
||||||
detail::IsSupported<U>::value,
|
detail::IsSupported<U>::value,
|
||||||
"This type is not supported by CheckedInt");
|
"This type is not supported by CheckedInt");
|
||||||
}
|
}
|
||||||
|
|
||||||
friend struct detail::NegateImpl<T>;
|
friend struct detail::NegateImpl<T>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructs a checked integer with given @a value. The checked integer is
|
* Constructs a checked integer with given @a value. The checked integer is
|
||||||
* initialized as valid or invalid depending on whether the @a value
|
* initialized as valid or invalid depending on whether the @a value
|
||||||
* is in range.
|
* is in range.
|
||||||
*
|
*
|
||||||
* This constructor is not explicit. Instead, the type of its argument is a
|
* This constructor is not explicit. Instead, the type of its argument is a
|
||||||
* separate template parameter, ensuring that no conversion is performed
|
* separate template parameter, ensuring that no conversion is performed
|
||||||
* before this constructor is actually called. As explained in the above
|
* before this constructor is actually called. As explained in the above
|
||||||
* documentation for class CheckedInt, this constructor checks that its
|
* documentation for class CheckedInt, this constructor checks that its
|
||||||
* argument is valid.
|
* argument is valid.
|
||||||
*/
|
*/
|
||||||
template<typename U>
|
template<typename U>
|
||||||
CheckedInt(U aValue)
|
CheckedInt(U aValue)
|
||||||
: mValue(T(aValue)),
|
: mValue(T(aValue)),
|
||||||
mIsValid(detail::IsInRange<T>(aValue))
|
mIsValid(detail::IsInRange<T>(aValue))
|
||||||
{
|
{
|
||||||
static_assert(detail::IsSupported<T>::value &&
|
static_assert(detail::IsSupported<T>::value &&
|
||||||
detail::IsSupported<U>::value,
|
detail::IsSupported<U>::value,
|
||||||
"This type is not supported by CheckedInt");
|
"This type is not supported by CheckedInt");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
friend class CheckedInt;
|
friend class CheckedInt;
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
CheckedInt<U> toChecked() const
|
CheckedInt<U> toChecked() const
|
||||||
{
|
{
|
||||||
CheckedInt<U> ret(mValue);
|
CheckedInt<U> ret(mValue);
|
||||||
ret.mIsValid = ret.mIsValid && mIsValid;
|
ret.mIsValid = ret.mIsValid && mIsValid;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Constructs a valid checked integer with initial value 0 */
|
/** Constructs a valid checked integer with initial value 0 */
|
||||||
CheckedInt() : mValue(0), mIsValid(true)
|
CheckedInt() : mValue(0), mIsValid(true)
|
||||||
{
|
{
|
||||||
static_assert(detail::IsSupported<T>::value,
|
static_assert(detail::IsSupported<T>::value,
|
||||||
"This type is not supported by CheckedInt");
|
"This type is not supported by CheckedInt");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns the actual value */
|
/** @returns the actual value */
|
||||||
T value() const
|
T value() const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
|
MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
|
||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns true if the checked integer is valid, i.e. is not the result
|
* @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
|
* of an invalid operation or of an operation involving an invalid checked
|
||||||
* integer
|
* integer
|
||||||
*/
|
*/
|
||||||
bool isValid() const
|
bool isValid() const
|
||||||
{
|
{
|
||||||
return mIsValid;
|
return mIsValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
|
friend CheckedInt<U> operator +(const CheckedInt<U>& aLhs,
|
||||||
const CheckedInt<U>& rhs);
|
const CheckedInt<U>& aRhs);
|
||||||
template<typename U>
|
template<typename U>
|
||||||
CheckedInt& operator +=(U rhs);
|
CheckedInt& operator +=(U aRhs);
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
|
friend CheckedInt<U> operator -(const CheckedInt<U>& aLhs,
|
||||||
const CheckedInt<U>& rhs);
|
const CheckedInt<U>& aRhs);
|
||||||
template<typename U>
|
template<typename U>
|
||||||
CheckedInt& operator -=(U rhs);
|
CheckedInt& operator -=(U aRhs);
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
|
friend CheckedInt<U> operator *(const CheckedInt<U>& aLhs,
|
||||||
const CheckedInt<U>& rhs);
|
const CheckedInt<U>& aRhs);
|
||||||
template<typename U>
|
template<typename U>
|
||||||
CheckedInt& operator *=(U rhs);
|
CheckedInt& operator *=(U aRhs);
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
|
friend CheckedInt<U> operator /(const CheckedInt<U>& aLhs,
|
||||||
const CheckedInt<U>& rhs);
|
const CheckedInt<U>& aRhs);
|
||||||
template<typename U>
|
template<typename U>
|
||||||
CheckedInt& operator /=(U rhs);
|
CheckedInt& operator /=(U aRhs);
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
friend CheckedInt<U> operator %(const CheckedInt<U>& lhs,
|
friend CheckedInt<U> operator %(const CheckedInt<U>& aLhs,
|
||||||
const CheckedInt<U>& rhs);
|
const CheckedInt<U>& aRhs);
|
||||||
template<typename U>
|
template<typename U>
|
||||||
CheckedInt& operator %=(U rhs);
|
CheckedInt& operator %=(U aRhs);
|
||||||
|
|
||||||
CheckedInt operator -() const
|
CheckedInt operator -() const
|
||||||
{
|
{
|
||||||
return detail::NegateImpl<T>::negate(*this);
|
return detail::NegateImpl<T>::negate(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns true if the left and right hand sides are valid
|
* @returns true if the left and right hand sides are valid
|
||||||
* and have the same value.
|
* and have the same value.
|
||||||
*
|
*
|
||||||
* Note that these semantics are the reason why we don't offer
|
* 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)
|
* 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
|
* but that would mean that whenever a or b is invalid, a!=b
|
||||||
* is always true, which would be very confusing.
|
* is always true, which would be very confusing.
|
||||||
*
|
*
|
||||||
* For similar reasons, operators <, >, <=, >= would be very tricky to
|
* For similar reasons, operators <, >, <=, >= would be very tricky to
|
||||||
* specify, so we just avoid offering them.
|
* specify, so we just avoid offering them.
|
||||||
*
|
*
|
||||||
* Notice that these == semantics are made more reasonable by these facts:
|
* Notice that these == semantics are made more reasonable by these facts:
|
||||||
* 1. a==b implies equality at the raw data level
|
* 1. a==b implies equality at the raw data level
|
||||||
* (the converse is false, as a==b is never true among invalids)
|
* (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
|
* 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.
|
* 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 ++ */
|
/** prefix ++ */
|
||||||
CheckedInt& operator++()
|
CheckedInt& operator++()
|
||||||
{
|
{
|
||||||
*this += 1;
|
*this += 1;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** postfix ++ */
|
/** postfix ++ */
|
||||||
CheckedInt operator++(int)
|
CheckedInt operator++(int)
|
||||||
{
|
{
|
||||||
CheckedInt tmp = *this;
|
CheckedInt tmp = *this;
|
||||||
*this += 1;
|
*this += 1;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** prefix -- */
|
/** prefix -- */
|
||||||
CheckedInt& operator--()
|
CheckedInt& operator--()
|
||||||
{
|
{
|
||||||
*this -= 1;
|
*this -= 1;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** postfix -- */
|
/** postfix -- */
|
||||||
CheckedInt operator--(int)
|
CheckedInt operator--(int)
|
||||||
{
|
{
|
||||||
CheckedInt tmp = *this;
|
CheckedInt tmp = *this;
|
||||||
*this -= 1;
|
*this -= 1;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* The !=, <, <=, >, >= operators are disabled:
|
* The !=, <, <=, >, >= operators are disabled:
|
||||||
* see the comment on operator==.
|
* see the comment on operator==.
|
||||||
*/
|
*/
|
||||||
template<typename U>
|
template<typename U> bool operator !=(U aOther) const MOZ_DELETE;
|
||||||
bool operator !=(U other) const MOZ_DELETE;
|
template<typename U> bool operator < (U aOther) const MOZ_DELETE;
|
||||||
template<typename U>
|
template<typename U> bool operator <=(U aOther) const MOZ_DELETE;
|
||||||
bool operator <(U other) const MOZ_DELETE;
|
template<typename U> bool operator > (U aOther) const MOZ_DELETE;
|
||||||
template<typename U>
|
template<typename U> bool operator >=(U aOther) const MOZ_DELETE;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
|
#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
|
||||||
template<typename T> \
|
template<typename T> \
|
||||||
inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, \
|
inline CheckedInt<T> \
|
||||||
const CheckedInt<T> &rhs) \
|
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>(0, false); \
|
||||||
\
|
} \
|
||||||
return CheckedInt<T>(lhs.mValue OP rhs.mValue, \
|
return CheckedInt<T>(aLhs.mValue OP aRhs.mValue, \
|
||||||
lhs.mIsValid && rhs.mIsValid); \
|
aLhs.mIsValid && aRhs.mIsValid); \
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
|
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
|
||||||
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
|
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
|
||||||
@ -698,47 +700,47 @@ namespace detail {
|
|||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
struct CastToCheckedIntImpl
|
struct CastToCheckedIntImpl
|
||||||
{
|
{
|
||||||
typedef CheckedInt<T> ReturnType;
|
typedef CheckedInt<T> ReturnType;
|
||||||
static CheckedInt<T> run(U u) { return u; }
|
static CheckedInt<T> run(U aU) { return aU; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct CastToCheckedIntImpl<T, CheckedInt<T> >
|
struct CastToCheckedIntImpl<T, CheckedInt<T> >
|
||||||
{
|
{
|
||||||
typedef const CheckedInt<T>& ReturnType;
|
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
|
} // namespace detail
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
|
inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
|
||||||
castToCheckedInt(U u)
|
castToCheckedInt(U aU)
|
||||||
{
|
{
|
||||||
static_assert(detail::IsSupported<T>::value &&
|
static_assert(detail::IsSupported<T>::value &&
|
||||||
detail::IsSupported<U>::value,
|
detail::IsSupported<U>::value,
|
||||||
"This type is not supported by CheckedInt");
|
"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) \
|
#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
|
||||||
template<typename T> \
|
template<typename T> \
|
||||||
template<typename U> \
|
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; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
template<typename T, typename U> \
|
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> \
|
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(+, +=)
|
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
|
||||||
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
|
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
|
||||||
@ -750,16 +752,16 @@ MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
|
|||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
inline bool
|
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>
|
template<typename T, typename U>
|
||||||
inline bool
|
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.
|
// Convenience typedefs.
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "mozilla/Compression.h"
|
#include "mozilla/Compression.h"
|
||||||
#include "mozilla/CheckedInt.h"
|
#include "mozilla/CheckedInt.h"
|
||||||
|
|
||||||
using namespace mozilla::Compression;
|
using namespace mozilla::Compression;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -15,50 +18,51 @@ namespace {
|
|||||||
/* Our wrappers */
|
/* Our wrappers */
|
||||||
|
|
||||||
size_t
|
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());
|
MOZ_ASSERT(inputSizeChecked.isValid());
|
||||||
return LZ4_compress(source, dest, inputSizeChecked.value());
|
return LZ4_compress(aSource, aDest, inputSizeChecked.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
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());
|
MOZ_ASSERT(inputSizeChecked.isValid());
|
||||||
CheckedInt<int> maxOutputSizeChecked = maxOutputSize;
|
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
|
||||||
MOZ_ASSERT(maxOutputSizeChecked.isValid());
|
MOZ_ASSERT(maxOutputSizeChecked.isValid());
|
||||||
return LZ4_compress_limitedOutput(source, dest, inputSizeChecked.value(),
|
return LZ4_compress_limitedOutput(aSource, aDest, inputSizeChecked.value(),
|
||||||
maxOutputSizeChecked.value());
|
maxOutputSizeChecked.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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());
|
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;
|
return ret >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LZ4::decompress(const char* source, size_t inputSize, char* dest, size_t maxOutputSize,
|
LZ4::decompress(const char* aSource, size_t aInputSize, char* aDest,
|
||||||
size_t *outputSize)
|
size_t aMaxOutputSize, size_t *aOutputSize)
|
||||||
{
|
{
|
||||||
CheckedInt<int> maxOutputSizeChecked = maxOutputSize;
|
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
|
||||||
MOZ_ASSERT(maxOutputSizeChecked.isValid());
|
MOZ_ASSERT(maxOutputSizeChecked.isValid());
|
||||||
CheckedInt<int> inputSizeChecked = inputSize;
|
CheckedInt<int> inputSizeChecked = aInputSize;
|
||||||
MOZ_ASSERT(inputSizeChecked.isValid());
|
MOZ_ASSERT(inputSizeChecked.isValid());
|
||||||
|
|
||||||
int ret = LZ4_decompress_safe(source, dest, inputSizeChecked.value(),
|
int ret = LZ4_decompress_safe(aSource, aDest, inputSizeChecked.value(),
|
||||||
maxOutputSizeChecked.value());
|
maxOutputSizeChecked.value());
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
*outputSize = ret;
|
*aOutputSize = ret;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
*outputSize = 0;
|
|
||||||
return false;
|
*aOutputSize = 0;
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* 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/. */
|
* 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
|
* 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.
|
* 4x the speed and produces output of about 1.5x the size.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class LZ4
|
class LZ4
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compresses 'inputSize' bytes from 'source' into 'dest'.
|
* Compresses |aInputSize| bytes from |aSource| into |aDest|. Destination
|
||||||
* Destination buffer must be already allocated,
|
* buffer must be already allocated, and must be sized to handle worst cases
|
||||||
* and must be sized to handle worst cases situations (input data not compressible)
|
* situations (input data not compressible). Worst case size evaluation is
|
||||||
* Worst case size evaluation is provided by function maxCompressedSize()
|
* provided by function maxCompressedSize()
|
||||||
*
|
*
|
||||||
* @param inputSize is the input size. Max supported value is ~1.9GB
|
* @param aInputSize is the input size. Max supported value is ~1.9GB
|
||||||
* @param return the number of bytes written in buffer dest
|
* @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
|
* Compress |aInputSize| bytes from |aSource| into an output buffer
|
||||||
* 'dest' of maximum size 'maxOutputSize'. If it cannot achieve it,
|
* |aDest| of maximum size |aMaxOutputSize|. If it cannot achieve it,
|
||||||
* compression will stop, and result of the function will be zero,
|
* 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.
|
* bytes consumed is not returned the result is not usable.
|
||||||
*
|
*
|
||||||
* This function never writes outside of provided output buffer.
|
* This function never writes outside of provided output buffer.
|
||||||
*
|
*
|
||||||
* @param inputSize is the input size. Max supported value is ~1.9GB
|
* @param aInputSize is the input size. Max supported value is ~1.9GB
|
||||||
* @param maxOutputSize is the size of the destination buffer (which must be already allocated)
|
* @param aMaxOutputSize is the size of the destination buffer (which must
|
||||||
* @return the number of bytes written in buffer 'dest'
|
* be already allocated)
|
||||||
or 0 if the compression fails
|
* @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
|
* 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
|
* This function never writes outside of provided buffers, and never
|
||||||
* modifies input buffer.
|
* modifies input buffer.
|
||||||
*
|
*
|
||||||
* note : destination buffer must be already allocated.
|
* Note: destination buffer must be already allocated, and its size must be a
|
||||||
* its size must be a minimum of 'outputSize' bytes.
|
* minimum of |aOutputSize| bytes.
|
||||||
* @param outputSize is the output size, therefore the original size
|
*
|
||||||
|
* @param aOutputSize is the output size, therefore the original size
|
||||||
* @return the number of bytes read in the source buffer
|
* @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
|
* If the source stream is malformed, the function will stop decoding
|
||||||
* and return false.
|
* 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.
|
* therefore protected against malicious data packets.
|
||||||
*
|
*
|
||||||
* note : Destination buffer must be already allocated.
|
* Note: Destination buffer must be already allocated. This version is
|
||||||
* This version is slightly slower than the decompress
|
* slightly slower than the decompress without the aMaxOutputSize.
|
||||||
* without the maxOutputSize
|
|
||||||
*
|
*
|
||||||
* @param inputSize is the length of the input compressed data
|
* @param aInputSize is the length of the input compressed data
|
||||||
* @param maxOutputSize is the size of the destination buffer (which must be already allocated)
|
* @param aMaxOutputSize is the size of the destination buffer (which must be
|
||||||
* @param outputSize the actual number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)
|
* 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"
|
* Provides the maximum size that LZ4 may output in a "worst case"
|
||||||
scenario (input data not compressible) primarily useful for memory
|
* scenario (input data not compressible) primarily useful for memory
|
||||||
allocation of output buffer.
|
* allocation of output buffer.
|
||||||
note : this function is limited by "int" range (2^31-1)
|
* note : this function is limited by "int" range (2^31-1)
|
||||||
|
*
|
||||||
@param inputSize is the input size. Max supported value is ~1.9GB
|
* @param aInputSize is the input size. Max supported value is ~1.9GB
|
||||||
@return maximum output size in a "worst case" scenario
|
* @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);
|
size_t max = (aInputSize + (aInputSize / 255) + 16);
|
||||||
MOZ_ASSERT(max > inputSize);
|
MOZ_ASSERT(max > aInputSize);
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace Compression */
|
} /* namespace Compression */
|
||||||
|
@ -34,47 +34,44 @@ namespace mozilla {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class DebugOnly
|
class DebugOnly
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
T value;
|
T value;
|
||||||
|
|
||||||
DebugOnly() { }
|
DebugOnly() { }
|
||||||
DebugOnly(const T& other) : value(other) { }
|
DebugOnly(const T& aOther) : value(aOther) { }
|
||||||
DebugOnly(const DebugOnly& other) : value(other.value) { }
|
DebugOnly(const DebugOnly& aOther) : value(aOther.value) { }
|
||||||
DebugOnly& operator=(const T& rhs) {
|
DebugOnly& operator=(const T& aRhs) {
|
||||||
value = rhs;
|
value = aRhs;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
void operator++(int) {
|
|
||||||
value++;
|
|
||||||
}
|
|
||||||
void operator--(int) {
|
|
||||||
value--;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* operator&() { return &value; }
|
void operator++(int) { value++; }
|
||||||
|
void operator--(int) { value--; }
|
||||||
|
|
||||||
operator T&() { return value; }
|
T* operator&() { return &value; }
|
||||||
operator const T&() const { return value; }
|
|
||||||
|
|
||||||
T& operator->() { return value; }
|
operator T&() { return value; }
|
||||||
const T& operator->() const { return value; }
|
operator const T&() const { return value; }
|
||||||
|
|
||||||
|
T& operator->() { return value; }
|
||||||
|
const T& operator->() const { return value; }
|
||||||
|
|
||||||
#else
|
#else
|
||||||
DebugOnly() { }
|
DebugOnly() { }
|
||||||
DebugOnly(const T&) { }
|
DebugOnly(const T&) { }
|
||||||
DebugOnly(const DebugOnly&) { }
|
DebugOnly(const DebugOnly&) { }
|
||||||
DebugOnly& operator=(const T&) { return *this; }
|
DebugOnly& operator=(const T&) { return *this; }
|
||||||
void operator++(int) { }
|
void operator++(int) { }
|
||||||
void operator--(int) { }
|
void operator--(int) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DebugOnly must always have a destructor or else it will
|
* DebugOnly must always have a destructor or else it will
|
||||||
* generate "unused variable" warnings, exactly what it's intended
|
* generate "unused variable" warnings, exactly what it's intended
|
||||||
* to avoid!
|
* to avoid!
|
||||||
*/
|
*/
|
||||||
~DebugOnly() {}
|
~DebugOnly() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user