补充某些必要的文件

This commit is contained in:
SmallMain
2022-06-25 11:52:00 +08:00
parent 4ecc470f86
commit 03533b046c
2869 changed files with 1345388 additions and 2 deletions

View File

@@ -0,0 +1,154 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Functionality related to memory alignment. */
#ifndef mozilla_Alignment_h
#define mozilla_Alignment_h
#include "mozilla/Attributes.h"
#include <stddef.h>
#include <stdint.h>
namespace mozilla {
/*
* This class, and the corresponding macro MOZ_ALIGNOF, figures out how many
* bytes of alignment a given type needs.
*/
template<typename T>
class AlignmentFinder
{
struct Aligner
{
char mChar;
T mT;
};
public:
static const size_t alignment = sizeof(Aligner) - sizeof(T);
};
#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
/*
* Declare the MOZ_ALIGNED_DECL macro for declaring aligned types.
*
* For instance,
*
* MOZ_ALIGNED_DECL(char arr[2], 8);
*
* will declare a two-character array |arr| aligned to 8 bytes.
*/
#if defined(__GNUC__)
# define MOZ_ALIGNED_DECL(_type, _align) \
_type __attribute__((aligned(_align)))
#elif defined(_MSC_VER)
# define MOZ_ALIGNED_DECL(_type, _align) \
__declspec(align(_align)) _type
#else
# warning "We don't know how to align variables on this compiler."
# define MOZ_ALIGNED_DECL(_type, _align) _type
#endif
/*
* AlignedElem<N> is a structure whose alignment is guaranteed to be at least N
* bytes.
*
* We support 1, 2, 4, 8, and 16-bit alignment.
*/
template<size_t Align>
struct AlignedElem;
/*
* We have to specialize this template because GCC doesn't like
* __attribute__((aligned(foo))) where foo is a template parameter.
*/
template<>
struct AlignedElem<1>
{
MOZ_ALIGNED_DECL(uint8_t elem, 1);
};
template<>
struct AlignedElem<2>
{
MOZ_ALIGNED_DECL(uint8_t elem, 2);
};
template<>
struct AlignedElem<4>
{
MOZ_ALIGNED_DECL(uint8_t elem, 4);
};
template<>
struct AlignedElem<8>
{
MOZ_ALIGNED_DECL(uint8_t elem, 8);
};
template<>
struct AlignedElem<16>
{
MOZ_ALIGNED_DECL(uint8_t elem, 16);
};
/*
* This utility pales in comparison to Boost's aligned_storage. The utility
* simply assumes that uint64_t is enough alignment for anyone. This may need
* to be extended one day...
*
* As an important side effect, pulling the storage into this template is
* enough obfuscation to confuse gcc's strict-aliasing analysis into not giving
* false negatives when we cast from the char buffer to whatever type we've
* constructed using the bytes.
*/
template<size_t Nbytes>
struct AlignedStorage
{
union U
{
char mBytes[Nbytes];
uint64_t mDummy;
} u;
const void* addr() const { return u.mBytes; }
void* addr() { return u.mBytes; }
AlignedStorage() = default;
// AlignedStorage is non-copyable: the default copy constructor violates
// strict aliasing rules, per bug 1269319.
AlignedStorage(const AlignedStorage&) = delete;
void operator=(const AlignedStorage&) = delete;
};
template<typename T>
struct MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS AlignedStorage2
{
union U
{
char mBytes[sizeof(T)];
uint64_t mDummy;
} u;
const T* addr() const { return reinterpret_cast<const T*>(u.mBytes); }
T* addr() { return static_cast<T*>(static_cast<void*>(u.mBytes)); }
AlignedStorage2() = default;
// AlignedStorage2 is non-copyable: the default copy constructor violates
// strict aliasing rules, per bug 1269319.
AlignedStorage2(const AlignedStorage2&) = delete;
void operator=(const AlignedStorage2&) = delete;
};
} /* namespace mozilla */
#endif /* mozilla_Alignment_h */

View File

@@ -0,0 +1,133 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* An allocation policy concept, usable for structures and algorithms to
* control how memory is allocated and how failures are handled.
*/
#ifndef mozilla_AllocPolicy_h
#define mozilla_AllocPolicy_h
#include "mozilla/Attributes.h"
#include "mozilla/TemplateLib.h"
#include <stddef.h>
#include <stdlib.h>
namespace mozilla {
/*
* Allocation policies are used to implement the standard allocation behaviors
* in a customizable way. Additionally, custom behaviors may be added to these
* behaviors, such as additionally reporting an error through an out-of-band
* mechanism when OOM occurs. The concept modeled here is as follows:
*
* - public copy constructor, assignment, destructor
* - template <typename T> T* maybe_pod_malloc(size_t)
* Fallible, but doesn't report an error on OOM.
* - template <typename T> T* maybe_pod_calloc(size_t)
* Fallible, but doesn't report an error on OOM.
* - template <typename T> T* maybe_pod_realloc(T*, size_t, size_t)
* Fallible, but doesn't report an error on OOM. The old allocation
* size is passed in, in addition to the new allocation size requested.
* - template <typename T> T* pod_malloc(size_t)
* Responsible for OOM reporting when null is returned.
* - template <typename T> T* pod_calloc(size_t)
* Responsible for OOM reporting when null is returned.
* - template <typename T> T* pod_realloc(T*, size_t, size_t)
* Responsible for OOM reporting when null is returned. The old allocation
* size is passed in, in addition to the new allocation size requested.
* - void free_(void*)
* - void reportAllocOverflow() const
* Called on allocation overflow (that is, an allocation implicitly tried
* to allocate more than the available memory space -- think allocating an
* array of large-size objects, where N * size overflows) before null is
* returned.
* - bool checkSimulatedOOM() const
* Some clients generally allocate memory yet in some circumstances won't
* need to do so. For example, appending to a vector with a small amount of
* inline storage generally allocates memory, but no allocation occurs
* unless appending exceeds inline storage. But for testing purposes, it
* can be useful to treat *every* operation as allocating.
* Clients (such as this hypothetical append method implementation) should
* call this method in situations that don't allocate, but could generally,
* to support this. The default behavior should return true; more
* complicated behavior might be to return false only after a certain
* number of allocations-or-check-simulated-OOMs (coordinating with the
* other AllocPolicy methods) have occurred.
*
* mfbt provides (and typically uses by default) only MallocAllocPolicy, which
* does nothing more than delegate to the malloc/alloc/free functions.
*/
/*
* A policy that straightforwardly uses malloc/calloc/realloc/free and adds no
* extra behaviors.
*/
class MallocAllocPolicy
{
public:
template <typename T>
T* maybe_pod_malloc(size_t aNumElems)
{
if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
return nullptr;
}
return static_cast<T*>(malloc(aNumElems * sizeof(T)));
}
template <typename T>
T* maybe_pod_calloc(size_t aNumElems)
{
return static_cast<T*>(calloc(aNumElems, sizeof(T)));
}
template <typename T>
T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
{
if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
return nullptr;
}
return static_cast<T*>(realloc(aPtr, aNewSize * sizeof(T)));
}
template <typename T>
T* pod_malloc(size_t aNumElems)
{
return maybe_pod_malloc<T>(aNumElems);
}
template <typename T>
T* pod_calloc(size_t aNumElems)
{
return maybe_pod_calloc<T>(aNumElems);
}
template <typename T>
T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
{
return maybe_pod_realloc<T>(aPtr, aOldSize, aNewSize);
}
void free_(void* aPtr)
{
free(aPtr);
}
void reportAllocOverflow() const
{
}
MOZ_MUST_USE bool checkSimulatedOOM() const
{
return true;
}
};
} // namespace mozilla
#endif /* mozilla_AllocPolicy_h */

View File

@@ -0,0 +1,147 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Typed temporary pointers for reference-counted smart pointers. */
#ifndef AlreadyAddRefed_h
#define AlreadyAddRefed_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
namespace mozilla {
struct unused_t;
} // namespace mozilla
/**
* already_AddRefed cooperates with reference counting smart pointers to enable
* you to assign in a pointer _without_ |AddRef|ing it. You might want to use
* this as a return type from a function that returns an already |AddRef|ed
* pointer.
*
* TODO Move already_AddRefed to namespace mozilla. This has not yet been done
* because of the sheer number of usages of already_AddRefed.
*/
template<class T>
struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed
{
/*
* We want to allow returning nullptr from functions returning
* already_AddRefed<T>, for simplicity. But we also don't want to allow
* returning raw T*, instead preferring creation of already_AddRefed<T> from
* a reference counting smart pointer.
*
* We address the latter requirement by making the (T*) constructor explicit.
* But |return nullptr| won't consider an explicit constructor, so we need
* another constructor to handle it. Plain old (decltype(nullptr)) doesn't
* cut it, because if nullptr is emulated as __null (with type int or long),
* passing nullptr to an int/long parameter triggers compiler warnings. We
* need a type that no one can pass accidentally; a pointer-to-member-function
* (where no such function exists) does the trick nicely.
*
* That handles the return-value case. What about for locals, argument types,
* and so on? |already_AddRefed<T>(nullptr)| considers both overloads (and
* the (already_AddRefed<T>&&) overload as well!), so there's an ambiguity.
* We can target true nullptr using decltype(nullptr), but we can't target
* emulated nullptr the same way, because passing __null to an int/long
* parameter triggers compiler warnings. So just give up on this, and provide
* this behavior through the default constructor.
*
* We can revert to simply explicit (T*) and implicit (decltype(nullptr)) when
* nullptr no longer needs to be emulated to support the ancient b2g compiler.
* (The () overload could also be removed, if desired, if we changed callers.)
*/
already_AddRefed() : mRawPtr(nullptr) {}
// The return and argument types here are arbitrarily selected so no
// corresponding member function exists.
typedef void (already_AddRefed::* MatchNullptr)(double, float);
MOZ_IMPLICIT already_AddRefed(MatchNullptr aRawPtr) : mRawPtr(nullptr) {}
explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {}
// Disallow copy constructor and copy assignment operator: move semantics used instead.
already_AddRefed(const already_AddRefed<T>& aOther) = delete;
already_AddRefed<T>& operator=(const already_AddRefed<T>& aOther) = delete;
already_AddRefed(already_AddRefed<T>&& aOther) : mRawPtr(aOther.take()) {}
already_AddRefed<T>& operator=(already_AddRefed<T>&& aOther)
{
mRawPtr = aOther.take();
return *this;
}
/**
* This helper is useful in cases like
*
* already_AddRefed<BaseClass>
* Foo()
* {
* RefPtr<SubClass> x = ...;
* return x.forget();
* }
*
* The autoconversion allows one to omit the idiom
*
* RefPtr<BaseClass> y = x.forget();
* return y.forget();
*
* Note that nsRefPtr is the XPCOM reference counting smart pointer class.
*/
template <typename U>
MOZ_IMPLICIT already_AddRefed(already_AddRefed<U>&& aOther) : mRawPtr(aOther.take()) {}
~already_AddRefed() { MOZ_ASSERT(!mRawPtr); }
// Specialize the unused operator<< for already_AddRefed, to allow
// nsCOMPtr<nsIFoo> foo;
// Unused << foo.forget();
// Note that nsCOMPtr is the XPCOM reference counting smart pointer class.
friend void operator<<(const mozilla::unused_t& aUnused,
const already_AddRefed<T>& aRhs)
{
auto mutableAlreadyAddRefed = const_cast<already_AddRefed<T>*>(&aRhs);
aUnused << mutableAlreadyAddRefed->take();
}
MOZ_MUST_USE T* take()
{
T* rawPtr = mRawPtr;
mRawPtr = nullptr;
return rawPtr;
}
/**
* This helper provides a static_cast replacement for already_AddRefed, so
* if you have
*
* already_AddRefed<Parent> F();
*
* you can write
*
* already_AddRefed<Child>
* G()
* {
* return F().downcast<Child>();
* }
*/
template<class U>
already_AddRefed<U> downcast()
{
U* tmp = static_cast<U*>(mRawPtr);
mRawPtr = nullptr;
return already_AddRefed<U>(tmp);
}
private:
T* MOZ_OWNING_REF mRawPtr;
};
#endif // AlreadyAddRefed_h

View File

@@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A compile-time constant-length array with bounds-checking assertions. */
#ifndef mozilla_Array_h
#define mozilla_Array_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/ReverseIterator.h"
#include <stddef.h>
namespace mozilla {
template<typename T, size_t Length>
class Array
{
T mArr[Length];
public:
Array() {}
template <typename... Args>
MOZ_IMPLICIT Array(Args&&... aArgs)
: mArr{mozilla::Forward<Args>(aArgs)...}
{
static_assert(sizeof...(aArgs) == Length,
"The number of arguments should be equal to the template parameter Length");
}
T& operator[](size_t aIndex)
{
MOZ_ASSERT(aIndex < Length);
return mArr[aIndex];
}
const T& operator[](size_t aIndex) const
{
MOZ_ASSERT(aIndex < Length);
return mArr[aIndex];
}
typedef T* iterator;
typedef const T* const_iterator;
typedef ReverseIterator<T*> reverse_iterator;
typedef ReverseIterator<const T*> const_reverse_iterator;
// Methods for range-based for loops.
iterator begin() { return mArr; }
const_iterator begin() const { return mArr; }
const_iterator cbegin() const { return begin(); }
iterator end() { return mArr + Length; }
const_iterator end() const { return mArr + Length; }
const_iterator cend() const { return end(); }
// Methods for reverse iterating.
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
const_reverse_iterator crend() const { return rend(); }
};
template<typename T>
class Array<T, 0>
{
public:
T& operator[](size_t aIndex)
{
MOZ_CRASH("indexing into zero-length array");
}
const T& operator[](size_t aIndex) const
{
MOZ_CRASH("indexing into zero-length array");
}
};
} /* namespace mozilla */
#endif /* mozilla_Array_h */

View File

@@ -0,0 +1,194 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implements various helper functions related to arrays.
*/
#ifndef mozilla_ArrayUtils_h
#define mozilla_ArrayUtils_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include <stddef.h>
#ifdef __cplusplus
#include "mozilla/Alignment.h"
#include "mozilla/Array.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
/*
* Safely subtract two pointers when it is known that aEnd >= aBegin, yielding a
* size_t result.
*
* Ordinary pointer subtraction yields a ptrdiff_t result, which, being signed,
* has insufficient range to express the distance between pointers at opposite
* ends of the address space. Furthermore, most compilers use ptrdiff_t to
* represent the intermediate byte address distance, before dividing by
* sizeof(T); if that intermediate result overflows, they'll produce results
* with the wrong sign even when the correct scaled distance would fit in a
* ptrdiff_t.
*/
template<class T>
MOZ_ALWAYS_INLINE size_t
PointerRangeSize(T* aBegin, T* aEnd)
{
MOZ_ASSERT(aEnd >= aBegin);
return (size_t(aEnd) - size_t(aBegin)) / sizeof(T);
}
/*
* Compute the length of an array with constant length. (Use of this method
* with a non-array pointer will not compile.)
*
* Beware of the implicit trailing '\0' when using this with string constants.
*/
template<typename T, size_t N>
constexpr size_t
ArrayLength(T (&aArr)[N])
{
return N;
}
template<typename T, size_t N>
constexpr size_t
ArrayLength(const Array<T, N>& aArr)
{
return N;
}
template<typename E, E N, typename T>
constexpr size_t
ArrayLength(const EnumeratedArray<E, N, T>& aArr)
{
return size_t(N);
}
/*
* Compute the address one past the last element of a constant-length array.
*
* Beware of the implicit trailing '\0' when using this with string constants.
*/
template<typename T, size_t N>
constexpr T*
ArrayEnd(T (&aArr)[N])
{
return aArr + ArrayLength(aArr);
}
template<typename T, size_t N>
constexpr T*
ArrayEnd(Array<T, N>& aArr)
{
return &aArr[0] + ArrayLength(aArr);
}
template<typename T, size_t N>
constexpr const T*
ArrayEnd(const Array<T, N>& aArr)
{
return &aArr[0] + ArrayLength(aArr);
}
namespace detail {
template<typename AlignType, typename Pointee,
typename = EnableIf<!IsVoid<AlignType>::value>>
struct AlignedChecker
{
static void
test(const Pointee* aPtr)
{
MOZ_ASSERT((uintptr_t(aPtr) % MOZ_ALIGNOF(AlignType)) == 0,
"performing a range-check with a misaligned pointer");
}
};
template<typename AlignType, typename Pointee>
struct AlignedChecker<AlignType, Pointee>
{
static void
test(const Pointee* aPtr)
{
}
};
} // namespace detail
/**
* Determines whether |aPtr| points at an object in the range [aBegin, aEnd).
*
* |aPtr| must have the same alignment as |aBegin| and |aEnd|. This usually
* should be achieved by ensuring |aPtr| points at a |U|, not just that it
* points at a |T|.
*
* It is a usage error for any argument to be misaligned.
*
* It's okay for T* to be void*, and if so U* may also be void*. In the latter
* case no argument is required to be aligned (obviously, as void* implies no
* particular alignment).
*/
template<typename T, typename U>
inline typename EnableIf<IsSame<T, U>::value ||
IsBaseOf<T, U>::value ||
IsVoid<T>::value,
bool>::Type
IsInRange(const T* aPtr, const U* aBegin, const U* aEnd)
{
MOZ_ASSERT(aBegin <= aEnd);
detail::AlignedChecker<U, T>::test(aPtr);
detail::AlignedChecker<U, U>::test(aBegin);
detail::AlignedChecker<U, U>::test(aEnd);
return aBegin <= reinterpret_cast<const U*>(aPtr) &&
reinterpret_cast<const U*>(aPtr) < aEnd;
}
/**
* Convenience version of the above method when the valid range is specified as
* uintptr_t values. As above, |aPtr| must be aligned, and |aBegin| and |aEnd|
* must be aligned with respect to |T|.
*/
template<typename T>
inline bool
IsInRange(const T* aPtr, uintptr_t aBegin, uintptr_t aEnd)
{
return IsInRange(aPtr,
reinterpret_cast<const T*>(aBegin),
reinterpret_cast<const T*>(aEnd));
}
namespace detail {
/*
* Helper for the MOZ_ARRAY_LENGTH() macro to make the length a typesafe
* compile-time constant even on compilers lacking constexpr support.
*/
template <typename T, size_t N>
char (&ArrayLengthHelper(T (&array)[N]))[N];
} /* namespace detail */
} /* namespace mozilla */
#endif /* __cplusplus */
/*
* MOZ_ARRAY_LENGTH() is an alternative to mozilla::ArrayLength() for C files
* that can't use C++ template functions and for static_assert() calls that
* can't call ArrayLength() when it is not a C++11 constexpr function.
*/
#ifdef __cplusplus
# define MOZ_ARRAY_LENGTH(array) sizeof(mozilla::detail::ArrayLengthHelper(array))
#else
# define MOZ_ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0]))
#endif
#endif /* mozilla_ArrayUtils_h */

View File

@@ -0,0 +1,585 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implementations of runtime and static assertion macros for C and C++. */
#ifndef mozilla_Assertions_h
#define mozilla_Assertions_h
#if defined(MOZILLA_INTERNAL_API) && defined(__cplusplus)
#define MOZ_DUMP_ASSERTION_STACK
#endif
#include "mozilla/Attributes.h"
#include "mozilla/Compiler.h"
#include "mozilla/Likely.h"
#include "mozilla/MacroArgs.h"
#include "mozilla/StaticAnalysisFunctions.h"
#include "mozilla/Types.h"
#ifdef MOZ_DUMP_ASSERTION_STACK
#include "nsTraceRefcnt.h"
#endif
#if defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API)
/*
* The crash reason set by MOZ_CRASH_ANNOTATE is consumed by the crash reporter
* if present. It is declared here (and defined in Assertions.cpp) to make it
* available to all code, even libraries that don't link with the crash reporter
* directly.
*/
MOZ_BEGIN_EXTERN_C
extern MFBT_DATA const char* gMozCrashReason;
MOZ_END_EXTERN_C
static inline void
AnnotateMozCrashReason(const char* reason)
{
gMozCrashReason = reason;
}
# define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__)
#else
# define MOZ_CRASH_ANNOTATE(...) do { /* nothing */ } while (0)
#endif
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
/*
* TerminateProcess and GetCurrentProcess are defined in <winbase.h>, which
* further depends on <windef.h>. We hardcode these few definitions manually
* because those headers clutter the global namespace with a significant
* number of undesired macros and symbols.
*/
# ifdef __cplusplus
extern "C" {
# endif
__declspec(dllimport) int __stdcall
TerminateProcess(void* hProcess, unsigned int uExitCode);
__declspec(dllimport) void* __stdcall GetCurrentProcess(void);
# ifdef __cplusplus
}
# endif
#else
# include <signal.h>
#endif
#ifdef ANDROID
# include <android/log.h>
#endif
/*
* MOZ_STATIC_ASSERT may be used to assert a condition *at compile time* in C.
* In C++11, static_assert is provided by the compiler to the same effect.
* This can be useful when you make certain assumptions about what must hold for
* optimal, or even correct, behavior. For example, you might assert that the
* size of a struct is a multiple of the target architecture's word size:
*
* struct S { ... };
* // C
* MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0,
* "S should be a multiple of word size for efficiency");
* // C++11
* static_assert(sizeof(S) % sizeof(size_t) == 0,
* "S should be a multiple of word size for efficiency");
*
* This macro can be used in any location where both an extern declaration and a
* typedef could be used.
*/
#ifndef __cplusplus
/*
* Some of the definitions below create an otherwise-unused typedef. This
* triggers compiler warnings with some versions of gcc, so mark the typedefs
* as permissibly-unused to disable the warnings.
*/
# if defined(__GNUC__)
# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
# else
# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */
# endif
# define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y
# define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y)
# if defined(__SUNPRO_CC)
/*
* The Sun Studio C++ compiler is buggy when declaring, inside a function,
* another extern'd function with an array argument whose length contains a
* sizeof, triggering the error message "sizeof expression not accepted as
* size of array parameter". This bug (6688515, not public yet) would hit
* defining moz_static_assert as a function, so we always define an extern
* array for Sun Studio.
*
* We include the line number in the symbol name in a best-effort attempt
* to avoid conflicts (see below).
*/
# define MOZ_STATIC_ASSERT(cond, reason) \
extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1]
# elif defined(__COUNTER__)
/*
* If there was no preferred alternative, use a compiler-agnostic version.
*
* Note that the non-__COUNTER__ version has a bug in C++: it can't be used
* in both |extern "C"| and normal C++ in the same translation unit. (Alas
* |extern "C"| isn't allowed in a function.) The only affected compiler
* we really care about is gcc 4.2. For that compiler and others like it,
* we include the line number in the function name to do the best we can to
* avoid conflicts. These should be rare: a conflict would require use of
* MOZ_STATIC_ASSERT on the same line in separate files in the same
* translation unit, *and* the uses would have to be in code with
* different linkage, *and* the first observed use must be in C++-linkage
* code.
*/
# define MOZ_STATIC_ASSERT(cond, reason) \
typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE
# else
# define MOZ_STATIC_ASSERT(cond, reason) \
extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE
# endif
#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason)
#else
#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) static_assert(!(cond) || (expr), reason)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* Prints |aStr| as an assertion failure (using aFilename and aLine as the
* location of the assertion) to the standard debug-output channel.
*
* Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This
* method is primarily for internal use in this header, and only secondarily
* for use in implementing release-build assertions.
*/
static MOZ_COLD MOZ_ALWAYS_INLINE void
MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine)
MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
{
#ifdef ANDROID
__android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert",
"Assertion failure: %s, at %s:%d\n",
aStr, aFilename, aLine);
#else
fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine);
#if defined (MOZ_DUMP_ASSERTION_STACK)
nsTraceRefcnt::WalkTheStack(stderr);
#endif
fflush(stderr);
#endif
}
static MOZ_COLD MOZ_ALWAYS_INLINE void
MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine)
MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
{
#ifdef ANDROID
__android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH",
"Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
#else
fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
#if defined(MOZ_DUMP_ASSERTION_STACK)
nsTraceRefcnt::WalkTheStack(stderr);
#endif
fflush(stderr);
#endif
}
/**
* MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH(). You should
* call MOZ_CRASH instead.
*/
#if defined(_MSC_VER)
/*
* On MSVC use the __debugbreak compiler intrinsic, which produces an inline
* (not nested in a system function) breakpoint. This distinctively invokes
* Breakpad without requiring system library symbols on all stack-processing
* machines, as a nested breakpoint would require.
*
* We use TerminateProcess with the exit code aborting would generate
* because we don't want to invoke atexit handlers, destructors, library
* unload handlers, and so on when our process might be in a compromised
* state.
*
* We don't use abort() because it'd cause Windows to annoyingly pop up the
* process error dialog multiple times. See bug 345118 and bug 426163.
*
* We follow TerminateProcess() with a call to MOZ_NoReturn() so that the
* compiler doesn't hassle us to provide a return statement after a
* MOZ_REALLY_CRASH() call.
*
* (Technically these are Windows requirements, not MSVC requirements. But
* practically you need MSVC for debugging, and we only ship builds created
* by MSVC, so doing it this way reduces complexity.)
*/
__declspec(noreturn) __inline void MOZ_NoReturn() {}
# ifdef __cplusplus
# define MOZ_REALLY_CRASH() \
do { \
::__debugbreak(); \
*((volatile int*) NULL) = __LINE__; \
::TerminateProcess(::GetCurrentProcess(), 3); \
::MOZ_NoReturn(); \
} while (0)
# else
# define MOZ_REALLY_CRASH() \
do { \
__debugbreak(); \
*((volatile int*) NULL) = __LINE__; \
TerminateProcess(GetCurrentProcess(), 3); \
MOZ_NoReturn(); \
} while (0)
# endif
#else
# ifdef __cplusplus
# define MOZ_REALLY_CRASH() \
do { \
*((volatile int*) NULL) = __LINE__; \
::abort(); \
} while (0)
# else
# define MOZ_REALLY_CRASH() \
do { \
*((volatile int*) NULL) = __LINE__; \
abort(); \
} while (0)
# endif
#endif
/*
* MOZ_CRASH([explanation-string]) crashes the program, plain and simple, in a
* Breakpad-compatible way, in both debug and release builds.
*
* MOZ_CRASH is a good solution for "handling" failure cases when you're
* unwilling or unable to handle them more cleanly -- for OOM, for likely memory
* corruption, and so on. It's also a good solution if you need safe behavior
* in release builds as well as debug builds. But if the failure is one that
* should be debugged and fixed, MOZ_ASSERT is generally preferable.
*
* The optional explanation-string, if provided, must be a string literal
* explaining why we're crashing. This argument is intended for use with
* MOZ_CRASH() calls whose rationale is non-obvious; don't use it if it's
* obvious why we're crashing.
*
* If we're a DEBUG build and we crash at a MOZ_CRASH which provides an
* explanation-string, we print the string to stderr. Otherwise, we don't
* print anything; this is because we want MOZ_CRASH to be 100% safe in release
* builds, and it's hard to print to stderr safely when memory might have been
* corrupted.
*/
#ifndef DEBUG
# define MOZ_CRASH(...) \
do { \
MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \
MOZ_REALLY_CRASH(); \
} while (0)
#else
# define MOZ_CRASH(...) \
do { \
MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \
MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \
MOZ_REALLY_CRASH(); \
} while (0)
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/*
* MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in
* debug builds. If it is, execution continues. Otherwise, an error message
* including the expression and the explanation-string (if provided) is printed,
* an attempt is made to invoke any existing debugger, and execution halts.
* MOZ_ASSERT is fatal: no recovery is possible. Do not assert a condition
* which can correctly be falsy.
*
* The optional explanation-string, if provided, must be a string literal
* explaining the assertion. It is intended for use with assertions whose
* correctness or rationale is non-obvious, and for assertions where the "real"
* condition being tested is best described prosaically. Don't provide an
* explanation if it's not actually helpful.
*
* // No explanation needed: pointer arguments often must not be NULL.
* MOZ_ASSERT(arg);
*
* // An explanation can be helpful to explain exactly how we know an
* // assertion is valid.
* MOZ_ASSERT(state == WAITING_FOR_RESPONSE,
* "given that <thingA> and <thingB>, we must have...");
*
* // Or it might disambiguate multiple identical (save for their location)
* // assertions of the same expression.
* MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
* "we already set [[PrimitiveThis]] for this Boolean object");
* MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
* "we already set [[PrimitiveThis]] for this String object");
*
* MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs
* *only* during debugging, not "in the field". If you want the latter, use
* MOZ_RELEASE_ASSERT, which applies to non-debug builds as well.
*
* MOZ_DIAGNOSTIC_ASSERT works like MOZ_RELEASE_ASSERT in Nightly/Aurora and
* MOZ_ASSERT in Beta/Release - use this when a condition is potentially rare
* enough to require real user testing to hit, but is not security-sensitive.
* This can cause user pain, so use it sparingly. If a MOZ_DIAGNOSTIC_ASSERT
* is firing, it should promptly be converted to a MOZ_ASSERT while the failure
* is being investigated, rather than letting users suffer.
*/
/*
* Implement MOZ_VALIDATE_ASSERT_CONDITION_TYPE, which is used to guard against
* accidentally passing something unintended in lieu of an assertion condition.
*/
#ifdef __cplusplus
# include "mozilla/TypeTraits.h"
namespace mozilla {
namespace detail {
template<typename T>
struct AssertionConditionType
{
typedef typename RemoveReference<T>::Type ValueT;
static_assert(!IsArray<ValueT>::value,
"Expected boolean assertion condition, got an array or a "
"string!");
static_assert(!IsFunction<ValueT>::value,
"Expected boolean assertion condition, got a function! Did "
"you intend to call that function?");
static_assert(!IsFloatingPoint<ValueT>::value,
"It's often a bad idea to assert that a floating-point number "
"is nonzero, because such assertions tend to intermittently "
"fail. Shouldn't your code gracefully handle this case instead "
"of asserting? Anyway, if you really want to do that, write an "
"explicit boolean condition, like !!x or x!=0.");
static const bool isValid = true;
};
} // namespace detail
} // namespace mozilla
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \
static_assert(mozilla::detail::AssertionConditionType<decltype(x)>::isValid, \
"invalid assertion condition")
#else
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x)
#endif
/* First the single-argument form. */
#define MOZ_ASSERT_HELPER1(expr) \
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \
MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \
MOZ_REALLY_CRASH(); \
} \
} while (0)
/* Now the two-argument form. */
#define MOZ_ASSERT_HELPER2(expr, explain) \
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \
MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ") (" explain ")"); \
MOZ_REALLY_CRASH(); \
} \
} while (0)
#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b
#define MOZ_RELEASE_ASSERT(...) \
MOZ_RELEASE_ASSERT_GLUE( \
MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
(__VA_ARGS__))
#ifdef DEBUG
# define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
#else
# define MOZ_ASSERT(...) do { } while (0)
#endif /* DEBUG */
#ifdef RELEASE_OR_BETA
# define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT
#else
# define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT
#endif
/*
* MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is
* true.
*
* MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num));
*
* As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds. It is
* designed to catch bugs during debugging, not "in the field".
*/
#ifdef DEBUG
# define MOZ_ASSERT_IF(cond, expr) \
do { \
if (cond) { \
MOZ_ASSERT(expr); \
} \
} while (0)
#else
# define MOZ_ASSERT_IF(cond, expr) do { } while (0)
#endif
/*
* MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that
* it is undefined behavior for execution to reach this point. No guarantees
* are made about what will happen if this is reached at runtime. Most code
* should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra
* asserts.
*/
#if defined(__clang__) || defined(__GNUC__)
# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
#elif defined(_MSC_VER)
# define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0)
#else
# ifdef __cplusplus
# define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort()
# else
# define MOZ_ASSUME_UNREACHABLE_MARKER() abort()
# endif
#endif
/*
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE([reason]) tells the compiler that it
* can assume that the macro call cannot be reached during execution. This lets
* the compiler generate better-optimized code under some circumstances, at the
* expense of the program's behavior being undefined if control reaches the
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE.
*
* In Gecko, you probably should not use this macro outside of performance- or
* size-critical code, because it's unsafe. If you don't care about code size
* or performance, you should probably use MOZ_ASSERT or MOZ_CRASH.
*
* SpiderMonkey is a different beast, and there it's acceptable to use
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE more widely.
*
* Note that MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE is noreturn, so it's valid
* not to return a value following a MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE
* call.
*
* Example usage:
*
* enum ValueType {
* VALUE_STRING,
* VALUE_INT,
* VALUE_FLOAT
* };
*
* int ptrToInt(ValueType type, void* value) {
* {
* // We know for sure that type is either INT or FLOAT, and we want this
* // code to run as quickly as possible.
* switch (type) {
* case VALUE_INT:
* return *(int*) value;
* case VALUE_FLOAT:
* return (int) *(float*) value;
* default:
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected ValueType");
* }
* }
*/
/*
* Unconditional assert in debug builds for (assumed) unreachable code paths
* that have a safe return without crashing in release builds.
*/
#define MOZ_ASSERT_UNREACHABLE(reason) \
MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason)
#define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \
do { \
MOZ_ASSERT_UNREACHABLE(reason); \
MOZ_ASSUME_UNREACHABLE_MARKER(); \
} while (0)
/**
* MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
* switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
* debug builds, but intentionally fall through in release builds to handle
* unexpected values.
*
* Why do we need MOZ_FALLTHROUGH_ASSERT in addition to MOZ_FALLTHROUGH? In
* release builds, the MOZ_ASSERT(false) will expand to `do { } while (0)`,
* requiring a MOZ_FALLTHROUGH annotation to suppress a -Wimplicit-fallthrough
* warning. In debug builds, the MOZ_ASSERT(false) will expand to something like
* `if (true) { MOZ_CRASH(); }` and the MOZ_FALLTHROUGH annotation will cause
* a -Wunreachable-code warning. The MOZ_FALLTHROUGH_ASSERT macro breaks this
* warning stalemate.
*
* // Example before MOZ_FALLTHROUGH_ASSERT:
* switch (foo) {
* default:
* // This case wants to assert in debug builds, fall through in release.
* MOZ_ASSERT(false); // -Wimplicit-fallthrough warning in release builds!
* MOZ_FALLTHROUGH; // but -Wunreachable-code warning in debug builds!
* case 5:
* return 5;
* }
*
* // Example with MOZ_FALLTHROUGH_ASSERT:
* switch (foo) {
* default:
* // This case asserts in debug builds, falls through in release.
* MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
* case 5:
* return 5;
* }
*/
#ifdef DEBUG
# define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason)
#else
# define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH
#endif
/*
* MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided
* expression, in debug builds and in release builds both. Then, in debug
* builds only, the value of the expression is asserted either true or false
* using MOZ_ASSERT.
*/
#ifdef DEBUG
# define MOZ_ALWAYS_TRUE(expr) \
do { \
if ((expr)) { \
/* Do nothing. */ \
} else { \
MOZ_ASSERT(false, #expr); \
} \
} while (0)
# define MOZ_ALWAYS_FALSE(expr) \
do { \
if ((expr)) { \
MOZ_ASSERT(false, #expr); \
} else { \
/* Do nothing. */ \
} \
} while (0)
#else
# define MOZ_ALWAYS_TRUE(expr) \
do { \
if ((expr)) { \
/* Silence MOZ_MUST_USE. */ \
} \
} while (0)
# define MOZ_ALWAYS_FALSE(expr) \
do { \
if ((expr)) { \
/* Silence MOZ_MUST_USE. */ \
} \
} while (0)
#endif
#undef MOZ_DUMP_ASSERTION_STACK
#undef MOZ_CRASH_CRASHREPORT
#endif /* mozilla_Assertions_h */

View File

@@ -0,0 +1,800 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implements (almost always) lock-free atomic operations. The operations here
* are a subset of that which can be found in C++11's <atomic> header, with a
* different API to enforce consistent memory ordering constraints.
*
* Anyone caught using |volatile| for inter-thread memory safety needs to be
* sent a copy of this header and the C++11 standard.
*/
#ifndef mozilla_Atomics_h
#define mozilla_Atomics_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Compiler.h"
#include "mozilla/TypeTraits.h"
#include <stdint.h>
/*
* Our minimum deployment target on clang/OS X is OS X 10.6, whose SDK
* does not have <atomic>. So be sure to check for <atomic> support
* along with C++0x support.
*/
#if defined(_MSC_VER)
# define MOZ_HAVE_CXX11_ATOMICS
#elif defined(__clang__) || defined(__GNUC__)
/*
* Clang doesn't like <atomic> from libstdc++ before 4.7 due to the
* loose typing of the atomic builtins. GCC 4.5 and 4.6 lacks inline
* definitions for unspecialized std::atomic and causes linking errors.
* Therefore, we require at least 4.7.0 for using libstdc++.
*
* libc++ <atomic> is only functional with clang.
*/
# if MOZ_USING_LIBSTDCXX && MOZ_LIBSTDCXX_VERSION_AT_LEAST(4, 7, 0)
# define MOZ_HAVE_CXX11_ATOMICS
# elif MOZ_USING_LIBCXX && defined(__clang__)
# define MOZ_HAVE_CXX11_ATOMICS
# endif
#endif
namespace mozilla {
/**
* An enum of memory ordering possibilities for atomics.
*
* Memory ordering is the observable state of distinct values in memory.
* (It's a separate concept from atomicity, which concerns whether an
* operation can ever be observed in an intermediate state. Don't
* conflate the two!) Given a sequence of operations in source code on
* memory, it is *not* always the case that, at all times and on all
* cores, those operations will appear to have occurred in that exact
* sequence. First, the compiler might reorder that sequence, if it
* thinks another ordering will be more efficient. Second, the CPU may
* not expose so consistent a view of memory. CPUs will often perform
* their own instruction reordering, above and beyond that performed by
* the compiler. And each core has its own memory caches, and accesses
* (reads and writes both) to "memory" may only resolve to out-of-date
* cache entries -- not to the "most recently" performed operation in
* some global sense. Any access to a value that may be used by
* multiple threads, potentially across multiple cores, must therefore
* have a memory ordering imposed on it, for all code on all
* threads/cores to have a sufficiently coherent worldview.
*
* http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync and
* http://en.cppreference.com/w/cpp/atomic/memory_order go into more
* detail on all this, including examples of how each mode works.
*
* Note that for simplicity and practicality, not all of the modes in
* C++11 are supported. The missing C++11 modes are either subsumed by
* the modes we provide below, or not relevant for the CPUs we support
* in Gecko. These three modes are confusing enough as it is!
*/
enum MemoryOrdering {
/*
* Relaxed ordering is the simplest memory ordering: none at all.
* When the result of a write is observed, nothing may be inferred
* about other memory. Writes ostensibly performed "before" on the
* writing thread may not yet be visible. Writes performed "after" on
* the writing thread may already be visible, if the compiler or CPU
* reordered them. (The latter can happen if reads and/or writes get
* held up in per-processor caches.) Relaxed ordering means
* operations can always use cached values (as long as the actual
* updates to atomic values actually occur, correctly, eventually), so
* it's usually the fastest sort of atomic access. For this reason,
* *it's also the most dangerous kind of access*.
*
* Relaxed ordering is good for things like process-wide statistics
* counters that don't need to be consistent with anything else, so
* long as updates themselves are atomic. (And so long as any
* observations of that value can tolerate being out-of-date -- if you
* need some sort of up-to-date value, you need some sort of other
* synchronizing operation.) It's *not* good for locks, mutexes,
* reference counts, etc. that mediate access to other memory, or must
* be observably consistent with other memory.
*
* x86 architectures don't take advantage of the optimization
* opportunities that relaxed ordering permits. Thus it's possible
* that using relaxed ordering will "work" on x86 but fail elsewhere
* (ARM, say, which *does* implement non-sequentially-consistent
* relaxed ordering semantics). Be extra-careful using relaxed
* ordering if you can't easily test non-x86 architectures!
*/
Relaxed,
/*
* When an atomic value is updated with ReleaseAcquire ordering, and
* that new value is observed with ReleaseAcquire ordering, prior
* writes (atomic or not) are also observable. What ReleaseAcquire
* *doesn't* give you is any observable ordering guarantees for
* ReleaseAcquire-ordered operations on different objects. For
* example, if there are two cores that each perform ReleaseAcquire
* operations on separate objects, each core may or may not observe
* the operations made by the other core. The only way the cores can
* be synchronized with ReleaseAcquire is if they both
* ReleaseAcquire-access the same object. This implies that you can't
* necessarily describe some global total ordering of ReleaseAcquire
* operations.
*
* ReleaseAcquire ordering is good for (as the name implies) atomic
* operations on values controlling ownership of things: reference
* counts, mutexes, and the like. However, if you are thinking about
* using these to implement your own locks or mutexes, you should take
* a good, hard look at actual lock or mutex primitives first.
*/
ReleaseAcquire,
/*
* When an atomic value is updated with SequentiallyConsistent
* ordering, all writes observable when the update is observed, just
* as with ReleaseAcquire ordering. But, furthermore, a global total
* ordering of SequentiallyConsistent operations *can* be described.
* For example, if two cores perform SequentiallyConsistent operations
* on separate objects, one core will observably perform its update
* (and all previous operations will have completed), then the other
* core will observably perform its update (and all previous
* operations will have completed). (Although those previous
* operations aren't themselves ordered -- they could be intermixed,
* or ordered if they occur on atomic values with ordering
* requirements.) SequentiallyConsistent is the *simplest and safest*
* ordering of atomic operations -- it's always as if one operation
* happens, then another, then another, in some order -- and every
* core observes updates to happen in that single order. Because it
* has the most synchronization requirements, operations ordered this
* way also tend to be slowest.
*
* SequentiallyConsistent ordering can be desirable when multiple
* threads observe objects, and they all have to agree on the
* observable order of changes to them. People expect
* SequentiallyConsistent ordering, even if they shouldn't, when
* writing code, atomic or otherwise. SequentiallyConsistent is also
* the ordering of choice when designing lockless data structures. If
* you don't know what order to use, use this one.
*/
SequentiallyConsistent,
};
} // namespace mozilla
// Build up the underlying intrinsics.
#ifdef MOZ_HAVE_CXX11_ATOMICS
# include <atomic>
namespace mozilla {
namespace detail {
/*
* We provide CompareExchangeFailureOrder to work around a bug in some
* versions of GCC's <atomic> header. See bug 898491.
*/
template<MemoryOrdering Order> struct AtomicOrderConstraints;
template<>
struct AtomicOrderConstraints<Relaxed>
{
static const std::memory_order AtomicRMWOrder = std::memory_order_relaxed;
static const std::memory_order LoadOrder = std::memory_order_relaxed;
static const std::memory_order StoreOrder = std::memory_order_relaxed;
static const std::memory_order CompareExchangeFailureOrder =
std::memory_order_relaxed;
};
template<>
struct AtomicOrderConstraints<ReleaseAcquire>
{
static const std::memory_order AtomicRMWOrder = std::memory_order_acq_rel;
static const std::memory_order LoadOrder = std::memory_order_acquire;
static const std::memory_order StoreOrder = std::memory_order_release;
static const std::memory_order CompareExchangeFailureOrder =
std::memory_order_acquire;
};
template<>
struct AtomicOrderConstraints<SequentiallyConsistent>
{
static const std::memory_order AtomicRMWOrder = std::memory_order_seq_cst;
static const std::memory_order LoadOrder = std::memory_order_seq_cst;
static const std::memory_order StoreOrder = std::memory_order_seq_cst;
static const std::memory_order CompareExchangeFailureOrder =
std::memory_order_seq_cst;
};
template<typename T, MemoryOrdering Order>
struct IntrinsicBase
{
typedef std::atomic<T> ValueType;
typedef AtomicOrderConstraints<Order> OrderedOp;
};
template<typename T, MemoryOrdering Order>
struct IntrinsicMemoryOps : public IntrinsicBase<T, Order>
{
typedef IntrinsicBase<T, Order> Base;
static T load(const typename Base::ValueType& aPtr)
{
return aPtr.load(Base::OrderedOp::LoadOrder);
}
static void store(typename Base::ValueType& aPtr, T aVal)
{
aPtr.store(aVal, Base::OrderedOp::StoreOrder);
}
static T exchange(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.exchange(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static bool compareExchange(typename Base::ValueType& aPtr,
T aOldVal, T aNewVal)
{
return aPtr.compare_exchange_strong(aOldVal, aNewVal,
Base::OrderedOp::AtomicRMWOrder,
Base::OrderedOp::CompareExchangeFailureOrder);
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub : public IntrinsicBase<T, Order>
{
typedef IntrinsicBase<T, Order> Base;
static T add(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static T sub(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub<T*, Order> : public IntrinsicBase<T*, Order>
{
typedef IntrinsicBase<T*, Order> Base;
static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal)
{
return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal)
{
return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicIncDec : public IntrinsicAddSub<T, Order>
{
typedef IntrinsicBase<T, Order> Base;
static T inc(typename Base::ValueType& aPtr)
{
return IntrinsicAddSub<T, Order>::add(aPtr, 1);
}
static T dec(typename Base::ValueType& aPtr)
{
return IntrinsicAddSub<T, Order>::sub(aPtr, 1);
}
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>,
public IntrinsicIncDec<T, Order>
{
typedef IntrinsicBase<T, Order> Base;
static T or_(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_or(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static T xor_(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_xor(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static T and_(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_and(aVal, Base::OrderedOp::AtomicRMWOrder);
}
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics<T*, Order>
: public IntrinsicMemoryOps<T*, Order>, public IntrinsicIncDec<T*, Order>
{
};
template<typename T>
struct ToStorageTypeArgument
{
static constexpr T convert (T aT) { return aT; }
};
} // namespace detail
} // namespace mozilla
#elif defined(__GNUC__)
namespace mozilla {
namespace detail {
/*
* The __sync_* family of intrinsics is documented here:
*
* http://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Atomic-Builtins.html
*
* While these intrinsics are deprecated in favor of the newer __atomic_*
* family of intrincs:
*
* http://gcc.gnu.org/onlinedocs/gcc-4.7.3/gcc/_005f_005fatomic-Builtins.html
*
* any GCC version that supports the __atomic_* intrinsics will also support
* the <atomic> header and so will be handled above. We provide a version of
* atomics using the __sync_* intrinsics to support older versions of GCC.
*
* All __sync_* intrinsics that we use below act as full memory barriers, for
* both compiler and hardware reordering, except for __sync_lock_test_and_set,
* which is a only an acquire barrier. When we call __sync_lock_test_and_set,
* we add a barrier above it as appropriate.
*/
template<MemoryOrdering Order> struct Barrier;
/*
* Some processors (in particular, x86) don't require quite so many calls to
* __sync_sychronize as our specializations of Barrier produce. If
* performance turns out to be an issue, defining these specializations
* on a per-processor basis would be a good first tuning step.
*/
template<>
struct Barrier<Relaxed>
{
static void beforeLoad() {}
static void afterLoad() {}
static void beforeStore() {}
static void afterStore() {}
};
template<>
struct Barrier<ReleaseAcquire>
{
static void beforeLoad() {}
static void afterLoad() { __sync_synchronize(); }
static void beforeStore() { __sync_synchronize(); }
static void afterStore() {}
};
template<>
struct Barrier<SequentiallyConsistent>
{
static void beforeLoad() { __sync_synchronize(); }
static void afterLoad() { __sync_synchronize(); }
static void beforeStore() { __sync_synchronize(); }
static void afterStore() { __sync_synchronize(); }
};
template<typename T, bool TIsEnum = IsEnum<T>::value>
struct AtomicStorageType
{
// For non-enums, just use the type directly.
typedef T Type;
};
template<typename T>
struct AtomicStorageType<T, true>
: Conditional<sizeof(T) == 4, uint32_t, uint64_t>
{
static_assert(sizeof(T) == 4 || sizeof(T) == 8,
"wrong type computed in conditional above");
};
template<typename T, MemoryOrdering Order>
struct IntrinsicMemoryOps
{
typedef typename AtomicStorageType<T>::Type ValueType;
static T load(const ValueType& aPtr)
{
Barrier<Order>::beforeLoad();
T val = T(aPtr);
Barrier<Order>::afterLoad();
return val;
}
static void store(ValueType& aPtr, T aVal)
{
Barrier<Order>::beforeStore();
aPtr = ValueType(aVal);
Barrier<Order>::afterStore();
}
static T exchange(ValueType& aPtr, T aVal)
{
// __sync_lock_test_and_set is only an acquire barrier; loads and stores
// can't be moved up from after to before it, but they can be moved down
// from before to after it. We may want a stricter ordering, so we need
// an explicit barrier.
Barrier<Order>::beforeStore();
return T(__sync_lock_test_and_set(&aPtr, ValueType(aVal)));
}
static bool compareExchange(ValueType& aPtr, T aOldVal, T aNewVal)
{
return __sync_bool_compare_and_swap(&aPtr, ValueType(aOldVal), ValueType(aNewVal));
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub
: public IntrinsicMemoryOps<T, Order>
{
typedef IntrinsicMemoryOps<T, Order> Base;
typedef typename Base::ValueType ValueType;
static T add(ValueType& aPtr, T aVal)
{
return T(__sync_fetch_and_add(&aPtr, ValueType(aVal)));
}
static T sub(ValueType& aPtr, T aVal)
{
return T(__sync_fetch_and_sub(&aPtr, ValueType(aVal)));
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub<T*, Order>
: public IntrinsicMemoryOps<T*, Order>
{
typedef IntrinsicMemoryOps<T*, Order> Base;
typedef typename Base::ValueType ValueType;
/*
* The reinterpret_casts are needed so that
* __sync_fetch_and_{add,sub} will properly type-check.
*
* Also, these functions do not provide standard semantics for
* pointer types, so we need to adjust the addend.
*/
static ValueType add(ValueType& aPtr, ptrdiff_t aVal)
{
ValueType amount = reinterpret_cast<ValueType>(aVal * sizeof(T));
return __sync_fetch_and_add(&aPtr, amount);
}
static ValueType sub(ValueType& aPtr, ptrdiff_t aVal)
{
ValueType amount = reinterpret_cast<ValueType>(aVal * sizeof(T));
return __sync_fetch_and_sub(&aPtr, amount);
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicIncDec : public IntrinsicAddSub<T, Order>
{
typedef IntrinsicAddSub<T, Order> Base;
typedef typename Base::ValueType ValueType;
static T inc(ValueType& aPtr) { return Base::add(aPtr, 1); }
static T dec(ValueType& aPtr) { return Base::sub(aPtr, 1); }
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics : public IntrinsicIncDec<T, Order>
{
static T or_( T& aPtr, T aVal) { return __sync_fetch_and_or(&aPtr, aVal); }
static T xor_(T& aPtr, T aVal) { return __sync_fetch_and_xor(&aPtr, aVal); }
static T and_(T& aPtr, T aVal) { return __sync_fetch_and_and(&aPtr, aVal); }
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics<T*, Order> : public IntrinsicIncDec<T*, Order>
{
};
template<typename T, bool TIsEnum = IsEnum<T>::value>
struct ToStorageTypeArgument
{
typedef typename AtomicStorageType<T>::Type ResultType;
static constexpr ResultType convert (T aT) { return ResultType(aT); }
};
template<typename T>
struct ToStorageTypeArgument<T, false>
{
static constexpr T convert (T aT) { return aT; }
};
} // namespace detail
} // namespace mozilla
#else
# error "Atomic compiler intrinsics are not supported on your platform"
#endif
namespace mozilla {
namespace detail {
template<typename T, MemoryOrdering Order>
class AtomicBase
{
static_assert(sizeof(T) == 4 || sizeof(T) == 8,
"mozilla/Atomics.h only supports 32-bit and 64-bit types");
protected:
typedef typename detail::AtomicIntrinsics<T, Order> Intrinsics;
typedef typename Intrinsics::ValueType ValueType;
ValueType mValue;
public:
constexpr AtomicBase() : mValue() {}
explicit constexpr AtomicBase(T aInit)
: mValue(ToStorageTypeArgument<T>::convert(aInit))
{}
// Note: we can't provide operator T() here because Atomic<bool> inherits
// from AtomcBase with T=uint32_t and not T=bool. If we implemented
// operator T() here, it would cause errors when comparing Atomic<bool> with
// a regular bool.
T operator=(T aVal)
{
Intrinsics::store(mValue, aVal);
return aVal;
}
/**
* Performs an atomic swap operation. aVal is stored and the previous
* value of this variable is returned.
*/
T exchange(T aVal)
{
return Intrinsics::exchange(mValue, aVal);
}
/**
* Performs an atomic compare-and-swap operation and returns true if it
* succeeded. This is equivalent to atomically doing
*
* if (mValue == aOldValue) {
* mValue = aNewValue;
* return true;
* } else {
* return false;
* }
*/
bool compareExchange(T aOldValue, T aNewValue)
{
return Intrinsics::compareExchange(mValue, aOldValue, aNewValue);
}
private:
template<MemoryOrdering AnyOrder>
AtomicBase(const AtomicBase<T, AnyOrder>& aCopy) = delete;
};
template<typename T, MemoryOrdering Order>
class AtomicBaseIncDec : public AtomicBase<T, Order>
{
typedef typename detail::AtomicBase<T, Order> Base;
public:
constexpr AtomicBaseIncDec() : Base() {}
explicit constexpr AtomicBaseIncDec(T aInit) : Base(aInit) {}
using Base::operator=;
operator T() const { return Base::Intrinsics::load(Base::mValue); }
T operator++(int) { return Base::Intrinsics::inc(Base::mValue); }
T operator--(int) { return Base::Intrinsics::dec(Base::mValue); }
T operator++() { return Base::Intrinsics::inc(Base::mValue) + 1; }
T operator--() { return Base::Intrinsics::dec(Base::mValue) - 1; }
private:
template<MemoryOrdering AnyOrder>
AtomicBaseIncDec(const AtomicBaseIncDec<T, AnyOrder>& aCopy) = delete;
};
} // namespace detail
/**
* A wrapper for a type that enforces that all memory accesses are atomic.
*
* In general, where a variable |T foo| exists, |Atomic<T> foo| can be used in
* its place. Implementations for integral and pointer types are provided
* below.
*
* Atomic accesses are sequentially consistent by default. You should
* use the default unless you are tall enough to ride the
* memory-ordering roller coaster (if you're not sure, you aren't) and
* you have a compelling reason to do otherwise.
*
* There is one exception to the case of atomic memory accesses: providing an
* initial value of the atomic value is not guaranteed to be atomic. This is a
* deliberate design choice that enables static atomic variables to be declared
* without introducing extra static constructors.
*/
template<typename T,
MemoryOrdering Order = SequentiallyConsistent,
typename Enable = void>
class Atomic;
/**
* Atomic<T> implementation for integral types.
*
* In addition to atomic store and load operations, compound assignment and
* increment/decrement operators are implemented which perform the
* corresponding read-modify-write operation atomically. Finally, an atomic
* swap method is provided.
*/
template<typename T, MemoryOrdering Order>
class Atomic<T, Order, typename EnableIf<IsIntegral<T>::value &&
!IsSame<T, bool>::value>::Type>
: public detail::AtomicBaseIncDec<T, Order>
{
typedef typename detail::AtomicBaseIncDec<T, Order> Base;
public:
constexpr Atomic() : Base() {}
explicit constexpr Atomic(T aInit) : Base(aInit) {}
using Base::operator=;
T operator+=(T aDelta)
{
return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
}
T operator-=(T aDelta)
{
return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
}
T operator|=(T aVal)
{
return Base::Intrinsics::or_(Base::mValue, aVal) | aVal;
}
T operator^=(T aVal)
{
return Base::Intrinsics::xor_(Base::mValue, aVal) ^ aVal;
}
T operator&=(T aVal)
{
return Base::Intrinsics::and_(Base::mValue, aVal) & aVal;
}
private:
Atomic(Atomic<T, Order>& aOther) = delete;
};
/**
* Atomic<T> implementation for pointer types.
*
* An atomic compare-and-swap primitive for pointer variables is provided, as
* are atomic increment and decement operators. Also provided are the compound
* assignment operators for addition and subtraction. Atomic swap (via
* exchange()) is included as well.
*/
template<typename T, MemoryOrdering Order>
class Atomic<T*, Order> : public detail::AtomicBaseIncDec<T*, Order>
{
typedef typename detail::AtomicBaseIncDec<T*, Order> Base;
public:
constexpr Atomic() : Base() {}
explicit constexpr Atomic(T* aInit) : Base(aInit) {}
using Base::operator=;
T* operator+=(ptrdiff_t aDelta)
{
return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
}
T* operator-=(ptrdiff_t aDelta)
{
return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
}
private:
Atomic(Atomic<T*, Order>& aOther) = delete;
};
/**
* Atomic<T> implementation for enum types.
*
* The atomic store and load operations and the atomic swap method is provided.
*/
template<typename T, MemoryOrdering Order>
class Atomic<T, Order, typename EnableIf<IsEnum<T>::value>::Type>
: public detail::AtomicBase<T, Order>
{
typedef typename detail::AtomicBase<T, Order> Base;
public:
constexpr Atomic() : Base() {}
explicit constexpr Atomic(T aInit) : Base(aInit) {}
operator T() const { return T(Base::Intrinsics::load(Base::mValue)); }
using Base::operator=;
private:
Atomic(Atomic<T, Order>& aOther) = delete;
};
/**
* Atomic<T> implementation for boolean types.
*
* The atomic store and load operations and the atomic swap method is provided.
*
* Note:
*
* - sizeof(Atomic<bool>) != sizeof(bool) for some implementations of
* bool and/or some implementations of std::atomic. This is allowed in
* [atomic.types.generic]p9.
*
* - It's not obvious whether the 8-bit atomic functions on Windows are always
* inlined or not. If they are not inlined, the corresponding functions in the
* runtime library are not available on Windows XP. This is why we implement
* Atomic<bool> with an underlying type of uint32_t.
*/
template<MemoryOrdering Order>
class Atomic<bool, Order>
: protected detail::AtomicBase<uint32_t, Order>
{
typedef typename detail::AtomicBase<uint32_t, Order> Base;
public:
constexpr Atomic() : Base() {}
explicit constexpr Atomic(bool aInit) : Base(aInit) {}
// We provide boolean wrappers for the underlying AtomicBase methods.
MOZ_IMPLICIT operator bool() const
{
return Base::Intrinsics::load(Base::mValue);
}
bool operator=(bool aVal)
{
return Base::operator=(aVal);
}
bool exchange(bool aVal)
{
return Base::exchange(aVal);
}
bool compareExchange(bool aOldValue, bool aNewValue)
{
return Base::compareExchange(aOldValue, aNewValue);
}
private:
Atomic(Atomic<bool, Order>& aOther) = delete;
};
} // namespace mozilla
#endif /* mozilla_Atomics_h */

View File

@@ -0,0 +1,604 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implementations of various class and method modifier attributes. */
#ifndef mozilla_Attributes_h
#define mozilla_Attributes_h
#include "mozilla/Compiler.h"
/*
* MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the
* method decorated with it must be inlined, even if the compiler thinks
* otherwise. This is only a (much) stronger version of the inline hint:
* compilers are not guaranteed to respect it (although they're much more likely
* to do so).
*
* The MOZ_ALWAYS_INLINE_EVEN_DEBUG macro is yet stronger. It tells the
* compiler to inline even in DEBUG builds. It should be used very rarely.
*/
#if defined(_MSC_VER)
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline
#elif defined(__GNUC__)
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline
#else
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline
#endif
#if !defined(DEBUG)
# define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG
#elif defined(_MSC_VER) && !defined(__cplusplus)
# define MOZ_ALWAYS_INLINE __inline
#else
# define MOZ_ALWAYS_INLINE inline
#endif
#if defined(_MSC_VER)
/*
* g++ requires -std=c++0x or -std=gnu++0x to support C++11 functionality
* without warnings (functionality used by the macros below). These modes are
* detectable by checking whether __GXX_EXPERIMENTAL_CXX0X__ is defined or, more
* standardly, by checking whether __cplusplus has a C++11 or greater value.
* Current versions of g++ do not correctly set __cplusplus, so we check both
* for forward compatibility.
*/
# define MOZ_HAVE_NEVER_INLINE __declspec(noinline)
# define MOZ_HAVE_NORETURN __declspec(noreturn)
#elif defined(__clang__)
/*
* Per Clang documentation, "Note that marketing version numbers should not
* be used to check for language features, as different vendors use different
* numbering schemes. Instead, use the feature checking macros."
*/
# ifndef __has_extension
# define __has_extension __has_feature /* compatibility, for older versions of clang */
# endif
# if __has_attribute(noinline)
# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline))
# endif
# if __has_attribute(noreturn)
# define MOZ_HAVE_NORETURN __attribute__((noreturn))
# endif
#elif defined(__GNUC__)
# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline))
# define MOZ_HAVE_NORETURN __attribute__((noreturn))
#endif
/*
* When built with clang analyzer (a.k.a scan-build), define MOZ_HAVE_NORETURN
* to mark some false positives
*/
#ifdef __clang_analyzer__
# if __has_extension(attribute_analyzer_noreturn)
# define MOZ_HAVE_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
# endif
#endif
/*
* MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the
* method decorated with it must never be inlined, even if the compiler would
* otherwise choose to inline the method. Compilers aren't absolutely
* guaranteed to support this, but most do.
*/
#if defined(MOZ_HAVE_NEVER_INLINE)
# define MOZ_NEVER_INLINE MOZ_HAVE_NEVER_INLINE
#else
# define MOZ_NEVER_INLINE /* no support */
#endif
/*
* MOZ_NORETURN, specified at the start of a function declaration, indicates
* that the given function does not return. (The function definition does not
* need to be annotated.)
*
* MOZ_NORETURN void abort(const char* msg);
*
* This modifier permits the compiler to optimize code assuming a call to such a
* function will never return. It also enables the compiler to avoid spurious
* warnings about not initializing variables, or about any other seemingly-dodgy
* operations performed after the function returns.
*
* This modifier does not affect the corresponding function's linking behavior.
*/
#if defined(MOZ_HAVE_NORETURN)
# define MOZ_NORETURN MOZ_HAVE_NORETURN
#else
# define MOZ_NORETURN /* no support */
#endif
/**
* MOZ_COLD tells the compiler that a function is "cold", meaning infrequently
* executed. This may lead it to optimize for size more aggressively than speed,
* or to allocate the body of the function in a distant part of the text segment
* to help keep it from taking up unnecessary icache when it isn't in use.
*
* Place this attribute at the very beginning of a function definition. For
* example, write
*
* MOZ_COLD int foo();
*
* or
*
* MOZ_COLD int foo() { return 42; }
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_COLD __attribute__ ((cold))
#else
# define MOZ_COLD
#endif
/**
* MOZ_NONNULL tells the compiler that some of the arguments to a function are
* known to be non-null. The arguments are a list of 1-based argument indexes
* identifying arguments which are known to be non-null.
*
* Place this attribute at the very beginning of a function definition. For
* example, write
*
* MOZ_NONNULL(1, 2) int foo(char *p, char *q);
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_NONNULL(...) __attribute__ ((nonnull(__VA_ARGS__)))
#else
# define MOZ_NONNULL(...)
#endif
/*
* MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS, specified at the end of a function
* declaration, indicates that for the purposes of static analysis, this
* function does not return. (The function definition does not need to be
* annotated.)
*
* MOZ_ReportCrash(const char* s, const char* file, int ln)
* MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
*
* Some static analyzers, like scan-build from clang, can use this information
* to eliminate false positives. From the upstream documentation of scan-build:
* "This attribute is useful for annotating assertion handlers that actually
* can return, but for the purpose of using the analyzer we want to pretend
* that such functions do not return."
*
*/
#if defined(MOZ_HAVE_ANALYZER_NORETURN)
# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS MOZ_HAVE_ANALYZER_NORETURN
#else
# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS /* no support */
#endif
/*
* MOZ_ASAN_BLACKLIST is a macro to tell AddressSanitizer (a compile-time
* instrumentation shipped with Clang and GCC) to not instrument the annotated
* function. Furthermore, it will prevent the compiler from inlining the
* function because inlining currently breaks the blacklisting mechanism of
* AddressSanitizer.
*/
#if defined(__has_feature)
# if __has_feature(address_sanitizer)
# define MOZ_HAVE_ASAN_BLACKLIST
# endif
#elif defined(__GNUC__)
# if defined(__SANITIZE_ADDRESS__)
# define MOZ_HAVE_ASAN_BLACKLIST
# endif
#endif
#if defined(MOZ_HAVE_ASAN_BLACKLIST)
# define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_address))
#else
# define MOZ_ASAN_BLACKLIST /* nothing */
#endif
/*
* MOZ_TSAN_BLACKLIST is a macro to tell ThreadSanitizer (a compile-time
* instrumentation shipped with Clang) to not instrument the annotated function.
* Furthermore, it will prevent the compiler from inlining the function because
* inlining currently breaks the blacklisting mechanism of ThreadSanitizer.
*/
#if defined(__has_feature)
# if __has_feature(thread_sanitizer)
# define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread))
# else
# define MOZ_TSAN_BLACKLIST /* nothing */
# endif
#else
# define MOZ_TSAN_BLACKLIST /* nothing */
#endif
/**
* MOZ_ALLOCATOR tells the compiler that the function it marks returns either a
* "fresh", "pointer-free" block of memory, or nullptr. "Fresh" means that the
* block is not pointed to by any other reachable pointer in the program.
* "Pointer-free" means that the block contains no pointers to any valid object
* in the program. It may be initialized with other (non-pointer) values.
*
* Placing this attribute on appropriate functions helps GCC analyze pointer
* aliasing more accurately in their callers.
*
* GCC warns if a caller ignores the value returned by a function marked with
* MOZ_ALLOCATOR: it is hard to imagine cases where dropping the value returned
* by a function that meets the criteria above would be intentional.
*
* Place this attribute after the argument list and 'this' qualifiers of a
* function definition. For example, write
*
* void *my_allocator(size_t) MOZ_ALLOCATOR;
*
* or
*
* void *my_allocator(size_t bytes) MOZ_ALLOCATOR { ... }
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_ALLOCATOR __attribute__ ((malloc, warn_unused_result))
#else
# define MOZ_ALLOCATOR
#endif
/**
* MOZ_MUST_USE tells the compiler to emit a warning if a function's
* return value is not used by the caller.
*
* Place this attribute at the very beginning of a function declaration. For
* example, write
*
* MOZ_MUST_USE int foo();
*
* or
*
* MOZ_MUST_USE int foo() { return 42; }
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_MUST_USE __attribute__ ((warn_unused_result))
#else
# define MOZ_MUST_USE
#endif
/**
* MOZ_FALLTHROUGH is an annotation to suppress compiler warnings about switch
* cases that fall through without a break or return statement. MOZ_FALLTHROUGH
* is only needed on cases that have code.
*
* MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
* switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
* debug builds, but intentionally fall through in release builds. See comment
* in Assertions.h for more details.
*
* switch (foo) {
* case 1: // These cases have no code. No fallthrough annotations are needed.
* case 2:
* case 3: // This case has code, so a fallthrough annotation is needed!
* foo++;
* MOZ_FALLTHROUGH;
* case 4:
* return foo;
*
* default:
* // This case asserts in debug builds, falls through in release.
* MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
* case 5:
* return 5;
* }
*/
#if defined(__clang__) && __cplusplus >= 201103L
/* clang's fallthrough annotations are only available starting in C++11. */
# define MOZ_FALLTHROUGH [[clang::fallthrough]]
#elif defined(_MSC_VER)
/*
* MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
* https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
*/
# include <sal.h>
# define MOZ_FALLTHROUGH __fallthrough
#else
# define MOZ_FALLTHROUGH /* FALLTHROUGH */
#endif
#ifdef __cplusplus
/*
* The following macros are attributes that support the static analysis plugin
* included with Mozilla, and will be implemented (when such support is enabled)
* as C++11 attributes. Since such attributes are legal pretty much everywhere
* and have subtly different semantics depending on their placement, the
* following is a guide on where to place the attributes.
*
* Attributes that apply to a struct or class precede the name of the class:
* (Note that this is different from the placement of final for classes!)
*
* class MOZ_CLASS_ATTRIBUTE SomeClass {};
*
* Attributes that apply to functions follow the parentheses and const
* qualifiers but precede final, override and the function body:
*
* void DeclaredFunction() MOZ_FUNCTION_ATTRIBUTE;
* void SomeFunction() MOZ_FUNCTION_ATTRIBUTE {}
* void PureFunction() const MOZ_FUNCTION_ATTRIBUTE = 0;
* void OverriddenFunction() MOZ_FUNCTION_ATTIRBUTE override;
*
* Attributes that apply to variables or parameters follow the variable's name:
*
* int variable MOZ_VARIABLE_ATTRIBUTE;
*
* Attributes that apply to types follow the type name:
*
* typedef int MOZ_TYPE_ATTRIBUTE MagicInt;
* int MOZ_TYPE_ATTRIBUTE someVariable;
* int* MOZ_TYPE_ATTRIBUTE magicPtrInt;
* int MOZ_TYPE_ATTRIBUTE* ptrToMagicInt;
*
* Attributes that apply to statements precede the statement:
*
* MOZ_IF_ATTRIBUTE if (x == 0)
* MOZ_DO_ATTRIBUTE do { } while (0);
*
* Attributes that apply to labels precede the label:
*
* MOZ_LABEL_ATTRIBUTE target:
* goto target;
* MOZ_CASE_ATTRIBUTE case 5:
* MOZ_DEFAULT_ATTRIBUTE default:
*
* The static analyses that are performed by the plugin are as follows:
*
* MOZ_MUST_OVERRIDE: Applies to all C++ member functions. All immediate
* subclasses must provide an exact override of this method; if a subclass
* does not override this method, the compiler will emit an error. This
* attribute is not limited to virtual methods, so if it is applied to a
* nonvirtual method and the subclass does not provide an equivalent
* definition, the compiler will emit an error.
* MOZ_STACK_CLASS: Applies to all classes. Any class with this annotation is
* expected to live on the stack, so it is a compile-time error to use it, or
* an array of such objects, as a global or static variable, or as the type of
* a new expression (unless placement new is being used). If a member of
* another class uses this class, or if another class inherits from this
* class, then it is considered to be a stack class as well, although this
* attribute need not be provided in such cases.
* MOZ_NONHEAP_CLASS: Applies to all classes. Any class with this annotation is
* expected to live on the stack or in static storage, so it is a compile-time
* error to use it, or an array of such objects, as the type of a new
* expression. If a member of another class uses this class, or if another
* class inherits from this class, then it is considered to be a non-heap class
* as well, although this attribute need not be provided in such cases.
* MOZ_HEAP_CLASS: Applies to all classes. Any class with this annotation is
* expected to live on the heap, so it is a compile-time error to use it, or
* an array of such objects, as the type of a variable declaration, or as a
* temporary object. If a member of another class uses this class, or if
* another class inherits from this class, then it is considered to be a heap
* class as well, although this attribute need not be provided in such cases.
* MOZ_NON_TEMPORARY_CLASS: Applies to all classes. Any class with this
* annotation is expected not to live in a temporary. If a member of another
* class uses this class or if another class inherits from this class, then it
* is considered to be a non-temporary class as well, although this attribute
* need not be provided in such cases.
* MOZ_RAII: Applies to all classes. Any class with this annotation is assumed
* to be a RAII guard, which is expected to live on the stack in an automatic
* allocation. It is prohibited from being allocated in a temporary, static
* storage, or on the heap. This is a combination of MOZ_STACK_CLASS and
* MOZ_NON_TEMPORARY_CLASS.
* MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS: Applies to all classes that are
* intended to prevent introducing static initializers. This attribute
* currently makes it a compile-time error to instantiate these classes
* anywhere other than at the global scope, or as a static member of a class.
* In non-debug mode, it also prohibits non-trivial constructors and
* destructors.
* MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial
* or constexpr constructor and a trivial destructor. Setting this attribute
* on a class makes it a compile-time error for that class to get a
* non-trivial constructor or destructor for any reason.
* MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return
* value is allocated on the heap, and will as a result check such allocations
* during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking.
* MOZ_IMPLICIT: Applies to constructors. Implicit conversion constructors
* are disallowed by default unless they are marked as MOZ_IMPLICIT. This
* attribute must be used for constructors which intend to provide implicit
* conversions.
* MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT: Applies to functions. Makes it a compile
* time error to pass arithmetic expressions on variables to the function.
* MOZ_OWNING_REF: Applies to declarations of pointers to reference counted
* types. This attribute tells the compiler that the raw pointer is a strong
* reference, where ownership through methods such as AddRef and Release is
* managed manually. This can make the compiler ignore these pointers when
* validating the usage of pointers otherwise.
*
* Example uses include owned pointers inside of unions, and pointers stored
* in POD types where a using a smart pointer class would make the object
* non-POD.
* MOZ_NON_OWNING_REF: Applies to declarations of pointers to reference counted
* types. This attribute tells the compiler that the raw pointer is a weak
* reference, which is ensured to be valid by a guarantee that the reference
* will be nulled before the pointer becomes invalid. This can make the compiler
* ignore these pointers when validating the usage of pointers otherwise.
*
* Examples include an mOwner pointer, which is nulled by the owning class's
* destructor, and is null-checked before dereferencing.
* MOZ_UNSAFE_REF: Applies to declarations of pointers to reference counted types.
* Occasionally there are non-owning references which are valid, but do not take
* the form of a MOZ_NON_OWNING_REF. Their safety may be dependent on the behaviour
* of API consumers. The string argument passed to this macro documents the safety
* conditions. This can make the compiler ignore these pointers when validating
* the usage of pointers elsewhere.
*
* Examples include an nsIAtom* member which is known at compile time to point to a
* static atom which is valid throughout the lifetime of the program, or an API which
* stores a pointer, but doesn't take ownership over it, instead requiring the API
* consumer to correctly null the value before it becomes invalid.
*
* Use of this annotation is discouraged when a strong reference or one of the above
* two annotations can be used instead.
* MOZ_NO_ADDREF_RELEASE_ON_RETURN: Applies to function declarations. Makes it
* a compile time error to call AddRef or Release on the return value of a
* function. This is intended to be used with operator->() of our smart
* pointer classes to ensure that the refcount of an object wrapped in a
* smart pointer is not manipulated directly.
* MOZ_MUST_USE_TYPE: Applies to type declarations. Makes it a compile time
* error to not use the return value of a function which has this type. This
* is intended to be used with types which it is an error to not use.
* MOZ_NEEDS_NO_VTABLE_TYPE: Applies to template class declarations. Makes it
* a compile time error to instantiate this template with a type parameter which
* has a VTable.
* MOZ_NON_MEMMOVABLE: Applies to class declarations for types that are not safe
* to be moved in memory using memmove().
* MOZ_NEEDS_MEMMOVABLE_TYPE: Applies to template class declarations where the
* template arguments are required to be safe to move in memory using
* memmove(). Passing MOZ_NON_MEMMOVABLE types to these templates is a
* compile time error.
* MOZ_NEEDS_MEMMOVABLE_MEMBERS: Applies to class declarations where each member
* must be safe to move in memory using memmove(). MOZ_NON_MEMMOVABLE types
* used in members of these classes are compile time errors.
* MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS: Applies to template class
* declarations where an instance of the template should be considered, for
* static analysis purposes, to inherit any type annotations (such as
* MOZ_MUST_USE_TYPE and MOZ_STACK_CLASS) from its template arguments.
* MOZ_INIT_OUTSIDE_CTOR: Applies to class member declarations. Occasionally
* there are class members that are not initialized in the constructor,
* but logic elsewhere in the class ensures they are initialized prior to use.
* Using this attribute on a member disables the check that this member must be
* initialized in constructors via list-initialization, in the constructor body,
* or via functions called from the constructor body.
* MOZ_IS_CLASS_INIT: Applies to class method declarations. Occasionally the
* constructor doesn't initialize all of the member variables and another function
* is used to initialize the rest. This marker is used to make the static analysis
* tool aware that the marked function is part of the initialization process
* and to include the marked function in the scan mechanism that determines witch
* member variables still remain uninitialized.
* MOZ_NON_PARAM: Applies to types. Makes it compile time error to use the type
* in parameter without pointer or reference.
* MOZ_NON_AUTOABLE: Applies to class declarations. Makes it a compile time error to
* use `auto` in place of this type in variable declarations. This is intended to
* be used with types which are intended to be implicitly constructed into other
* other types before being assigned to variables.
* MOZ_REQUIRED_BASE_METHOD: Applies to virtual class method declarations.
* Sometimes derived classes override methods that need to be called by their
* overridden counterparts. This marker indicates that the marked method must
* be called by the method that it overrides.
*/
#ifdef MOZ_CLANG_PLUGIN
# define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override")))
# define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
# define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class")))
# define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class")))
# define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class")))
# define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor")))
# ifdef DEBUG
/* in debug builds, these classes do have non-trivial constructors. */
# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class")))
# else
# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \
MOZ_TRIVIAL_CTOR_DTOR
# endif
# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg")))
# define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref")))
# define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref")))
# define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref")))
# define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return")))
# define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type")))
# define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type")))
# define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
# define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
# define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members")))
# define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \
__attribute__((annotate("moz_inherit_type_annotations_from_template_args")))
# define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable")))
# define MOZ_INIT_OUTSIDE_CTOR \
__attribute__((annotate("moz_ignore_ctor_initialization")))
# define MOZ_IS_CLASS_INIT \
__attribute__((annotate("moz_is_class_init")))
# define MOZ_NON_PARAM \
__attribute__((annotate("moz_non_param")))
# define MOZ_REQUIRED_BASE_METHOD \
__attribute__((annotate("moz_required_base_method")))
/*
* It turns out that clang doesn't like void func() __attribute__ {} without a
* warning, so use pragmas to disable the warning. This code won't work on GCC
* anyways, so the warning is safe to ignore.
*/
# define MOZ_HEAP_ALLOCATOR \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
__attribute__((annotate("moz_heap_allocator"))) \
_Pragma("clang diagnostic pop")
#else
# define MOZ_MUST_OVERRIDE /* nothing */
# define MOZ_STACK_CLASS /* nothing */
# define MOZ_NONHEAP_CLASS /* nothing */
# define MOZ_HEAP_CLASS /* nothing */
# define MOZ_NON_TEMPORARY_CLASS /* nothing */
# define MOZ_TRIVIAL_CTOR_DTOR /* nothing */
# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */
# define MOZ_IMPLICIT /* nothing */
# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */
# define MOZ_HEAP_ALLOCATOR /* nothing */
# define MOZ_OWNING_REF /* nothing */
# define MOZ_NON_OWNING_REF /* nothing */
# define MOZ_UNSAFE_REF(reason) /* nothing */
# define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */
# define MOZ_MUST_USE_TYPE /* nothing */
# define MOZ_NEEDS_NO_VTABLE_TYPE /* nothing */
# define MOZ_NON_MEMMOVABLE /* nothing */
# define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */
# define MOZ_NEEDS_MEMMOVABLE_MEMBERS /* nothing */
# define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */
# define MOZ_INIT_OUTSIDE_CTOR /* nothing */
# define MOZ_IS_CLASS_INIT /* nothing */
# define MOZ_NON_PARAM /* nothing */
# define MOZ_NON_AUTOABLE /* nothing */
# define MOZ_REQUIRED_BASE_METHOD /* nothing */
#endif /* MOZ_CLANG_PLUGIN */
#define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS
/*
* MOZ_HAVE_REF_QUALIFIERS is defined for compilers that support C++11's rvalue
* qualifier, "&&".
*/
#if defined(_MSC_VER) && _MSC_VER >= 1900
# define MOZ_HAVE_REF_QUALIFIERS
#elif defined(__clang__)
// All supported Clang versions
# define MOZ_HAVE_REF_QUALIFIERS
#elif defined(__GNUC__)
# include "mozilla/Compiler.h"
# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 1)
# define MOZ_HAVE_REF_QUALIFIERS
# endif
#endif
#endif /* __cplusplus */
/**
* Printf style formats. MOZ_FORMAT_PRINTF can be used to annotate a
* function or method that is "printf-like"; this will let (some)
* compilers check that the arguments match the template string.
*
* This macro takes two arguments. The first argument is the argument
* number of the template string. The second argument is the argument
* number of the '...' argument holding the arguments.
*
* Argument numbers start at 1. Note that the implicit "this"
* argument of a non-static member function counts as an argument.
*
* So, for a simple case like:
* void print_something (int whatever, const char *fmt, ...);
* The corresponding annotation would be
* MOZ_FORMAT_PRINTF(2, 3)
* However, if "print_something" were a non-static member function,
* then the annotation would be:
* MOZ_FORMAT_PRINTF(3, 4)
*
* Note that the checking is limited to standards-conforming
* printf-likes, and in particular this should not be used for
* PR_snprintf and friends, which are "printf-like" but which assign
* different meanings to the various formats.
*/
#ifdef __GNUC__
#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \
__attribute__ ((format (printf, stringIndex, firstToCheck)))
#else
#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck)
#endif
#endif /* mozilla_Attributes_h */

View File

@@ -0,0 +1,139 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_BinarySearch_h
#define mozilla_BinarySearch_h
#include "mozilla/Assertions.h"
#include <stddef.h>
namespace mozilla {
/*
* The BinarySearch() algorithm searches the given container |aContainer| over
* the sorted index range [aBegin, aEnd) for an index |i| where
* |aContainer[i] == aTarget|.
* If such an index |i| is found, BinarySearch returns |true| and the index is
* returned via the outparam |aMatchOrInsertionPoint|. If no index is found,
* BinarySearch returns |false| and the outparam returns the first index in
* [aBegin, aEnd] where |aTarget| can be inserted to maintain sorted order.
*
* Example:
*
* Vector<int> sortedInts = ...
*
* size_t match;
* if (BinarySearch(sortedInts, 0, sortedInts.length(), 13, &match)) {
* printf("found 13 at %lu\n", match);
* }
*
* The BinarySearchIf() version behaves similarly, but takes |aComparator|, a
* functor to compare the values with, instead of a value to find.
* That functor should take one argument - the value to compare - and return an
* |int| with the comparison result:
*
* * 0, if the argument is equal to,
* * less than 0, if the argument is greater than,
* * greater than 0, if the argument is less than
*
* the value.
*
* Example:
*
* struct Comparator {
* int operator()(int aVal) const {
* if (mTarget < aVal) { return -1; }
* if (mTarget > aVal) { return 1; }
* return 0;
* }
* explicit Comparator(int aTarget) : mTarget(aTarget) {}
* const int mTarget;
* };
*
* Vector<int> sortedInts = ...
*
* size_t match;
* if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13), &match)) {
* printf("found 13 at %lu\n", match);
* }
*
*/
template<typename Container, typename Comparator>
bool
BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd,
const Comparator& aCompare, size_t* aMatchOrInsertionPoint)
{
MOZ_ASSERT(aBegin <= aEnd);
size_t low = aBegin;
size_t high = aEnd;
while (high != low) {
size_t middle = low + (high - low) / 2;
// Allow any intermediate type so long as it provides a suitable ordering
// relation.
const int result = aCompare(aContainer[middle]);
if (result == 0) {
*aMatchOrInsertionPoint = middle;
return true;
}
if (result < 0) {
high = middle;
} else {
low = middle + 1;
}
}
*aMatchOrInsertionPoint = low;
return false;
}
namespace detail {
template<class T>
class BinarySearchDefaultComparator
{
public:
explicit BinarySearchDefaultComparator(const T& aTarget)
: mTarget(aTarget)
{}
template <class U>
int operator()(const U& aVal) const {
if (mTarget == aVal) {
return 0;
}
if (mTarget < aVal) {
return -1;
}
return 1;
}
private:
const T& mTarget;
};
} // namespace detail
template <typename Container, typename T>
bool
BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
T aTarget, size_t* aMatchOrInsertionPoint)
{
return BinarySearchIf(aContainer, aBegin, aEnd,
detail::BinarySearchDefaultComparator<T>(aTarget),
aMatchOrInsertionPoint);
}
} // namespace mozilla
#endif // mozilla_BinarySearch_h

View File

@@ -0,0 +1,256 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* A counting Bloom filter implementation. This allows consumers to
* do fast probabilistic "is item X in set Y?" testing which will
* never answer "no" when the correct answer is "yes" (but might
* incorrectly answer "yes" when the correct answer is "no").
*/
#ifndef mozilla_BloomFilter_h
#define mozilla_BloomFilter_h
#include "mozilla/Assertions.h"
#include "mozilla/Likely.h"
#include <stdint.h>
#include <string.h>
namespace mozilla {
/*
* This class implements a counting Bloom filter as described at
* <http://en.wikipedia.org/wiki/Bloom_filter#Counting_filters>, with
* 8-bit counters. This allows quick probabilistic answers to the
* question "is object X in set Y?" where the contents of Y might not
* be time-invariant. The probabilistic nature of the test means that
* sometimes the answer will be "yes" when it should be "no". If the
* answer is "no", then X is guaranteed not to be in Y.
*
* The filter is parametrized on KeySize, which is the size of the key
* generated by each of hash functions used by the filter, in bits,
* and the type of object T being added and removed. T must implement
* a |uint32_t hash() const| method which returns a uint32_t hash key
* that will be used to generate the two separate hash functions for
* the Bloom filter. This hash key MUST be well-distributed for good
* results! KeySize is not allowed to be larger than 16.
*
* The filter uses exactly 2**KeySize bytes of memory. From now on we
* will refer to the memory used by the filter as M.
*
* The expected rate of incorrect "yes" answers depends on M and on
* the number N of objects in set Y. As long as N is small compared
* to M, the rate of such answers is expected to be approximately
* 4*(N/M)**2 for this filter. In practice, if Y has a few hundred
* elements then using a KeySize of 12 gives a reasonably low
* incorrect answer rate. A KeySize of 12 has the additional benefit
* of using exactly one page for the filter in typical hardware
* configurations.
*/
template<unsigned KeySize, class T>
class BloomFilter
{
/*
* A counting Bloom filter with 8-bit counters. For now we assume
* that having two hash functions is enough, but we may revisit that
* decision later.
*
* The filter uses an array with 2**KeySize entries.
*
* Assuming a well-distributed hash function, a Bloom filter with
* array size M containing N elements and
* using k hash function has expected false positive rate exactly
*
* $ (1 - (1 - 1/M)^{kN})^k $
*
* because each array slot has a
*
* $ (1 - 1/M)^{kN} $
*
* chance of being 0, and the expected false positive rate is the
* probability that all of the k hash functions will hit a nonzero
* slot.
*
* For reasonable assumptions (M large, kN large, which should both
* hold if we're worried about false positives) about M and kN this
* becomes approximately
*
* $$ (1 - \exp(-kN/M))^k $$
*
* For our special case of k == 2, that's $(1 - \exp(-2N/M))^2$,
* or in other words
*
* $$ N/M = -0.5 * \ln(1 - \sqrt(r)) $$
*
* where r is the false positive rate. This can be used to compute
* the desired KeySize for a given load N and false positive rate r.
*
* If N/M is assumed small, then the false positive rate can
* further be approximated as 4*N^2/M^2. So increasing KeySize by
* 1, which doubles M, reduces the false positive rate by about a
* factor of 4, and a false positive rate of 1% corresponds to
* about M/N == 20.
*
* What this means in practice is that for a few hundred keys using a
* KeySize of 12 gives false positive rates on the order of 0.25-4%.
*
* Similarly, using a KeySize of 10 would lead to a 4% false
* positive rate for N == 100 and to quite bad false positive
* rates for larger N.
*/
public:
BloomFilter()
{
static_assert(KeySize <= kKeyShift, "KeySize too big");
// Should we have a custom operator new using calloc instead and
// require that we're allocated via the operator?
clear();
}
/*
* Clear the filter. This should be done before reusing it, because
* just removing all items doesn't clear counters that hit the upper
* bound.
*/
void clear();
/*
* Add an item to the filter.
*/
void add(const T* aValue);
/*
* Remove an item from the filter.
*/
void remove(const T* aValue);
/*
* Check whether the filter might contain an item. This can
* sometimes return true even if the item is not in the filter,
* but will never return false for items that are actually in the
* filter.
*/
bool mightContain(const T* aValue) const;
/*
* Methods for add/remove/contain when we already have a hash computed
*/
void add(uint32_t aHash);
void remove(uint32_t aHash);
bool mightContain(uint32_t aHash) const;
private:
static const size_t kArraySize = (1 << KeySize);
static const uint32_t kKeyMask = (1 << KeySize) - 1;
static const uint32_t kKeyShift = 16;
static uint32_t hash1(uint32_t aHash)
{
return aHash & kKeyMask;
}
static uint32_t hash2(uint32_t aHash)
{
return (aHash >> kKeyShift) & kKeyMask;
}
uint8_t& firstSlot(uint32_t aHash)
{
return mCounters[hash1(aHash)];
}
uint8_t& secondSlot(uint32_t aHash)
{
return mCounters[hash2(aHash)];
}
const uint8_t& firstSlot(uint32_t aHash) const
{
return mCounters[hash1(aHash)];
}
const uint8_t& secondSlot(uint32_t aHash) const
{
return mCounters[hash2(aHash)];
}
static bool full(const uint8_t& aSlot) { return aSlot == UINT8_MAX; }
uint8_t mCounters[kArraySize];
};
template<unsigned KeySize, class T>
inline void
BloomFilter<KeySize, T>::clear()
{
memset(mCounters, 0, kArraySize);
}
template<unsigned KeySize, class T>
inline void
BloomFilter<KeySize, T>::add(uint32_t aHash)
{
uint8_t& slot1 = firstSlot(aHash);
if (MOZ_LIKELY(!full(slot1))) {
++slot1;
}
uint8_t& slot2 = secondSlot(aHash);
if (MOZ_LIKELY(!full(slot2))) {
++slot2;
}
}
template<unsigned KeySize, class T>
MOZ_ALWAYS_INLINE void
BloomFilter<KeySize, T>::add(const T* aValue)
{
uint32_t hash = aValue->hash();
return add(hash);
}
template<unsigned KeySize, class T>
inline void
BloomFilter<KeySize, T>::remove(uint32_t aHash)
{
// If the slots are full, we don't know whether we bumped them to be
// there when we added or not, so just leave them full.
uint8_t& slot1 = firstSlot(aHash);
if (MOZ_LIKELY(!full(slot1))) {
--slot1;
}
uint8_t& slot2 = secondSlot(aHash);
if (MOZ_LIKELY(!full(slot2))) {
--slot2;
}
}
template<unsigned KeySize, class T>
MOZ_ALWAYS_INLINE void
BloomFilter<KeySize, T>::remove(const T* aValue)
{
uint32_t hash = aValue->hash();
remove(hash);
}
template<unsigned KeySize, class T>
MOZ_ALWAYS_INLINE bool
BloomFilter<KeySize, T>::mightContain(uint32_t aHash) const
{
// Check that all the slots for this hash contain something
return firstSlot(aHash) && secondSlot(aHash);
}
template<unsigned KeySize, class T>
MOZ_ALWAYS_INLINE bool
BloomFilter<KeySize, T>::mightContain(const T* aValue) const
{
uint32_t hash = aValue->hash();
return mightContain(hash);
}
} // namespace mozilla
#endif /* mozilla_BloomFilter_h */

View File

@@ -0,0 +1,517 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_BufferList_h
#define mozilla_BufferList_h
#include <algorithm>
#include "mozilla/AllocPolicy.h"
#include "mozilla/Move.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Types.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/Vector.h"
#include <string.h>
// BufferList represents a sequence of buffers of data. A BufferList can choose
// to own its buffers or not. The class handles writing to the buffers,
// iterating over them, and reading data out. Unlike SegmentedVector, the
// buffers may be of unequal size. Like SegmentedVector, BufferList is a nice
// way to avoid large contiguous allocations (which can trigger OOMs).
namespace mozilla {
template<typename AllocPolicy>
class BufferList : private AllocPolicy
{
// Each buffer in a BufferList has a size and a capacity. The first mSize
// bytes are initialized and the remaining |mCapacity - mSize| bytes are free.
struct Segment
{
char* mData;
size_t mSize;
size_t mCapacity;
Segment(char* aData, size_t aSize, size_t aCapacity)
: mData(aData),
mSize(aSize),
mCapacity(aCapacity)
{
}
Segment(const Segment&) = delete;
Segment& operator=(const Segment&) = delete;
Segment(Segment&&) = default;
Segment& operator=(Segment&&) = default;
char* Start() const { return mData; }
char* End() const { return mData + mSize; }
};
template<typename OtherAllocPolicy>
friend class BufferList;
public:
// For the convenience of callers, all segments are required to be a multiple
// of 8 bytes in capacity. Also, every buffer except the last one is required
// to be full (i.e., size == capacity). Therefore, a byte at offset N within
// the BufferList and stored in memory at an address A will satisfy
// (N % Align == A % Align) if Align == 2, 4, or 8.
static const size_t kSegmentAlignment = 8;
// Allocate a BufferList. The BufferList will free all its buffers when it is
// destroyed. An initial buffer of size aInitialSize and capacity
// aInitialCapacity is allocated automatically. This data will be contiguous
// an can be accessed via |Start()|. Subsequent buffers will be allocated with
// capacity aStandardCapacity.
BufferList(size_t aInitialSize,
size_t aInitialCapacity,
size_t aStandardCapacity,
AllocPolicy aAP = AllocPolicy())
: AllocPolicy(aAP),
mOwning(true),
mSegments(aAP),
mSize(0),
mStandardCapacity(aStandardCapacity)
{
MOZ_ASSERT(aInitialCapacity % kSegmentAlignment == 0);
MOZ_ASSERT(aStandardCapacity % kSegmentAlignment == 0);
if (aInitialCapacity) {
AllocateSegment(aInitialSize, aInitialCapacity);
}
}
BufferList(const BufferList& aOther) = delete;
BufferList(BufferList&& aOther)
: mOwning(aOther.mOwning),
mSegments(Move(aOther.mSegments)),
mSize(aOther.mSize),
mStandardCapacity(aOther.mStandardCapacity)
{
aOther.mSegments.clear();
aOther.mSize = 0;
}
BufferList& operator=(const BufferList& aOther) = delete;
BufferList& operator=(BufferList&& aOther)
{
Clear();
mOwning = aOther.mOwning;
mSegments = Move(aOther.mSegments);
mSize = aOther.mSize;
aOther.mSegments.clear();
aOther.mSize = 0;
return *this;
}
~BufferList() { Clear(); }
// Returns the sum of the sizes of all the buffers.
size_t Size() const { return mSize; }
void Clear()
{
if (mOwning) {
for (Segment& segment : mSegments) {
this->free_(segment.mData);
}
}
mSegments.clear();
mSize = 0;
}
// Iterates over bytes in the segments. You can advance it by as many bytes as
// you choose.
class IterImpl
{
// Invariants:
// (0) mSegment <= bufferList.mSegments.size()
// (1) mData <= mDataEnd
// (2) If mSegment is not the last segment, mData < mDataEnd
uintptr_t mSegment;
char* mData;
char* mDataEnd;
friend class BufferList;
public:
explicit IterImpl(const BufferList& aBuffers)
: mSegment(0),
mData(nullptr),
mDataEnd(nullptr)
{
if (!aBuffers.mSegments.empty()) {
mData = aBuffers.mSegments[0].Start();
mDataEnd = aBuffers.mSegments[0].End();
}
}
// Returns a pointer to the raw data. It is valid to access up to
// RemainingInSegment bytes of this buffer.
char* Data() const
{
MOZ_RELEASE_ASSERT(!Done());
return mData;
}
// Returns true if the memory in the range [Data(), Data() + aBytes) is all
// part of one contiguous buffer.
bool HasRoomFor(size_t aBytes) const
{
MOZ_RELEASE_ASSERT(mData <= mDataEnd);
return size_t(mDataEnd - mData) >= aBytes;
}
// Returns the maximum value aBytes for which HasRoomFor(aBytes) will be
// true.
size_t RemainingInSegment() const
{
MOZ_RELEASE_ASSERT(mData <= mDataEnd);
return mDataEnd - mData;
}
// Advances the iterator by aBytes bytes. aBytes must be less than
// RemainingInSegment(). If advancing by aBytes takes the iterator to the
// end of a buffer, it will be moved to the beginning of the next buffer
// unless it is the last buffer.
void Advance(const BufferList& aBuffers, size_t aBytes)
{
const Segment& segment = aBuffers.mSegments[mSegment];
MOZ_RELEASE_ASSERT(segment.Start() <= mData);
MOZ_RELEASE_ASSERT(mData <= mDataEnd);
MOZ_RELEASE_ASSERT(mDataEnd == segment.End());
MOZ_RELEASE_ASSERT(HasRoomFor(aBytes));
mData += aBytes;
if (mData == mDataEnd && mSegment + 1 < aBuffers.mSegments.length()) {
mSegment++;
const Segment& nextSegment = aBuffers.mSegments[mSegment];
mData = nextSegment.Start();
mDataEnd = nextSegment.End();
MOZ_RELEASE_ASSERT(mData < mDataEnd);
}
}
// Advance the iterator by aBytes, possibly crossing segments. This function
// returns false if it runs out of buffers to advance through. Otherwise it
// returns true.
bool AdvanceAcrossSegments(const BufferList& aBuffers, size_t aBytes)
{
size_t bytes = aBytes;
while (bytes) {
size_t toAdvance = std::min(bytes, RemainingInSegment());
if (!toAdvance) {
return false;
}
Advance(aBuffers, toAdvance);
bytes -= toAdvance;
}
return true;
}
// Returns true when the iterator reaches the end of the BufferList.
bool Done() const
{
return mData == mDataEnd;
}
private:
// Count the bytes we would need to advance in order to reach aTarget.
size_t BytesUntil(const BufferList& aBuffers, const IterImpl& aTarget) const {
size_t offset = 0;
MOZ_ASSERT(aTarget.IsIn(aBuffers));
char* data = mData;
for (uintptr_t segment = mSegment; segment < aTarget.mSegment; segment++) {
offset += aBuffers.mSegments[segment].End() - data;
data = aBuffers.mSegments[segment].mData;
}
MOZ_RELEASE_ASSERT(IsIn(aBuffers));
MOZ_RELEASE_ASSERT(aTarget.mData >= data);
offset += aTarget.mData - data;
return offset;
}
bool IsIn(const BufferList& aBuffers) const {
return mSegment < aBuffers.mSegments.length() &&
mData >= aBuffers.mSegments[mSegment].mData &&
mData < aBuffers.mSegments[mSegment].End();
}
};
// Special convenience method that returns Iter().Data().
char* Start() { return mSegments[0].mData; }
const char* Start() const { return mSegments[0].mData; }
IterImpl Iter() const { return IterImpl(*this); }
// Copies aSize bytes from aData into the BufferList. The storage for these
// bytes may be split across multiple buffers. Size() is increased by aSize.
inline bool WriteBytes(const char* aData, size_t aSize);
// Copies possibly non-contiguous byte range starting at aIter into
// aData. aIter is advanced by aSize bytes. Returns false if it runs out of
// data before aSize.
inline bool ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const;
// Return a new BufferList that shares storage with this BufferList. The new
// BufferList is read-only. It allows iteration over aSize bytes starting at
// aIter. Borrow can fail, in which case *aSuccess will be false upon
// return. The borrowed BufferList can use a different AllocPolicy than the
// original one. However, it is not responsible for freeing buffers, so the
// AllocPolicy is only used for the buffer vector.
template<typename BorrowingAllocPolicy>
BufferList<BorrowingAllocPolicy> Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess,
BorrowingAllocPolicy aAP = BorrowingAllocPolicy()) const;
// Return a new BufferList and move storage from this BufferList to it. The
// new BufferList owns the buffers. Move can fail, in which case *aSuccess
// will be false upon return. The new BufferList can use a different
// AllocPolicy than the original one. The new OtherAllocPolicy is responsible
// for freeing buffers, so the OtherAllocPolicy must use freeing method
// compatible to the original one.
template<typename OtherAllocPolicy>
BufferList<OtherAllocPolicy> MoveFallible(bool* aSuccess, OtherAllocPolicy aAP = OtherAllocPolicy());
// Return a new BufferList that adopts the byte range starting at Iter so that
// range [aIter, aIter + aSize) is transplanted to the returned BufferList.
// Contents of the buffer before aIter + aSize is left undefined.
// Extract can fail, in which case *aSuccess will be false upon return. The
// moved buffers are erased from the original BufferList. In case of extract
// fails, the original BufferList is intact. All other iterators except aIter
// are invalidated.
// This method requires aIter and aSize to be 8-byte aligned.
BufferList Extract(IterImpl& aIter, size_t aSize, bool* aSuccess);
// Return the number of bytes from 'start' to 'end', two iterators within
// this BufferList.
size_t RangeLength(const IterImpl& start, const IterImpl& end) const {
MOZ_ASSERT(start.IsIn(*this) && end.IsIn(*this));
return start.BytesUntil(*this, end);
}
private:
explicit BufferList(AllocPolicy aAP)
: AllocPolicy(aAP),
mOwning(false),
mSize(0),
mStandardCapacity(0)
{
}
void* AllocateSegment(size_t aSize, size_t aCapacity)
{
MOZ_RELEASE_ASSERT(mOwning);
char* data = this->template pod_malloc<char>(aCapacity);
if (!data) {
return nullptr;
}
if (!mSegments.append(Segment(data, aSize, aCapacity))) {
this->free_(data);
return nullptr;
}
mSize += aSize;
return data;
}
bool mOwning;
Vector<Segment, 1, AllocPolicy> mSegments;
size_t mSize;
size_t mStandardCapacity;
};
template<typename AllocPolicy>
bool
BufferList<AllocPolicy>::WriteBytes(const char* aData, size_t aSize)
{
MOZ_RELEASE_ASSERT(mOwning);
MOZ_RELEASE_ASSERT(mStandardCapacity);
size_t copied = 0;
size_t remaining = aSize;
if (!mSegments.empty()) {
Segment& lastSegment = mSegments.back();
size_t toCopy = std::min(aSize, lastSegment.mCapacity - lastSegment.mSize);
memcpy(lastSegment.mData + lastSegment.mSize, aData, toCopy);
lastSegment.mSize += toCopy;
mSize += toCopy;
copied += toCopy;
remaining -= toCopy;
}
while (remaining) {
size_t toCopy = std::min(remaining, mStandardCapacity);
void* data = AllocateSegment(toCopy, mStandardCapacity);
if (!data) {
return false;
}
memcpy(data, aData + copied, toCopy);
copied += toCopy;
remaining -= toCopy;
}
return true;
}
template<typename AllocPolicy>
bool
BufferList<AllocPolicy>::ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const
{
size_t copied = 0;
size_t remaining = aSize;
while (remaining) {
size_t toCopy = std::min(aIter.RemainingInSegment(), remaining);
if (!toCopy) {
// We've run out of data in the last segment.
return false;
}
memcpy(aData + copied, aIter.Data(), toCopy);
copied += toCopy;
remaining -= toCopy;
aIter.Advance(*this, toCopy);
}
return true;
}
template<typename AllocPolicy> template<typename BorrowingAllocPolicy>
BufferList<BorrowingAllocPolicy>
BufferList<AllocPolicy>::Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess,
BorrowingAllocPolicy aAP) const
{
BufferList<BorrowingAllocPolicy> result(aAP);
size_t size = aSize;
while (size) {
size_t toAdvance = std::min(size, aIter.RemainingInSegment());
if (!toAdvance || !result.mSegments.append(typename BufferList<BorrowingAllocPolicy>::Segment(aIter.mData, toAdvance, toAdvance))) {
*aSuccess = false;
return result;
}
aIter.Advance(*this, toAdvance);
size -= toAdvance;
}
result.mSize = aSize;
*aSuccess = true;
return result;
}
template<typename AllocPolicy> template<typename OtherAllocPolicy>
BufferList<OtherAllocPolicy>
BufferList<AllocPolicy>::MoveFallible(bool* aSuccess, OtherAllocPolicy aAP)
{
BufferList<OtherAllocPolicy> result(0, 0, mStandardCapacity, aAP);
IterImpl iter = Iter();
while (!iter.Done()) {
size_t toAdvance = iter.RemainingInSegment();
if (!toAdvance || !result.mSegments.append(typename BufferList<OtherAllocPolicy>::Segment(iter.mData, toAdvance, toAdvance))) {
*aSuccess = false;
result.mSegments.clear();
return result;
}
iter.Advance(*this, toAdvance);
}
result.mSize = mSize;
mSegments.clear();
mSize = 0;
*aSuccess = true;
return result;
}
template<typename AllocPolicy>
BufferList<AllocPolicy>
BufferList<AllocPolicy>::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess)
{
MOZ_RELEASE_ASSERT(aSize);
MOZ_RELEASE_ASSERT(mOwning);
MOZ_ASSERT(aSize % kSegmentAlignment == 0);
MOZ_ASSERT(intptr_t(aIter.mData) % kSegmentAlignment == 0);
IterImpl iter = aIter;
size_t size = aSize;
size_t toCopy = std::min(size, aIter.RemainingInSegment());
MOZ_ASSERT(toCopy % kSegmentAlignment == 0);
BufferList result(0, toCopy, mStandardCapacity);
BufferList error(0, 0, mStandardCapacity);
// Copy the head
if (!result.WriteBytes(aIter.mData, toCopy)) {
*aSuccess = false;
return error;
}
iter.Advance(*this, toCopy);
size -= toCopy;
// Move segments to result
auto resultGuard = MakeScopeExit([&] {
*aSuccess = false;
result.mSegments.erase(result.mSegments.begin()+1, result.mSegments.end());
});
size_t movedSize = 0;
uintptr_t toRemoveStart = iter.mSegment;
uintptr_t toRemoveEnd = iter.mSegment;
while (!iter.Done() &&
!iter.HasRoomFor(size)) {
if (!result.mSegments.append(Segment(mSegments[iter.mSegment].mData,
mSegments[iter.mSegment].mSize,
mSegments[iter.mSegment].mCapacity))) {
return error;
}
movedSize += iter.RemainingInSegment();
size -= iter.RemainingInSegment();
toRemoveEnd++;
iter.Advance(*this, iter.RemainingInSegment());
}
if (size) {
if (!iter.HasRoomFor(size) ||
!result.WriteBytes(iter.Data(), size)) {
return error;
}
iter.Advance(*this, size);
}
mSegments.erase(mSegments.begin() + toRemoveStart, mSegments.begin() + toRemoveEnd);
mSize -= movedSize;
aIter.mSegment = iter.mSegment - (toRemoveEnd - toRemoveStart);
aIter.mData = iter.mData;
aIter.mDataEnd = iter.mDataEnd;
MOZ_ASSERT(aIter.mDataEnd == mSegments[aIter.mSegment].End());
result.mSize = aSize;
resultGuard.release();
*aSuccess = true;
return result;
}
} // namespace mozilla
#endif /* mozilla_BufferList_h */

View File

@@ -0,0 +1,243 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Cast operations to supplement the built-in casting operations. */
#ifndef mozilla_Casting_h
#define mozilla_Casting_h
#include "mozilla/Assertions.h"
#include "mozilla/TypeTraits.h"
#include <limits.h>
namespace mozilla {
/**
* Sets the outparam value of type |To| with the same underlying bit pattern of
* |aFrom|.
*
* |To| and |From| must be types of the same size; be careful of cross-platform
* size differences, or this might fail to compile on some but not all
* platforms.
*
* There is also a variant that returns the value directly. In most cases, the
* two variants should be identical. However, in the specific case of x86
* chips, the behavior differs: returning floating-point values directly is done
* through the x87 stack, and x87 loads and stores turn signaling NaNs into
* quiet NaNs... silently. Returning floating-point values via outparam,
* however, is done entirely within the SSE registers when SSE2 floating-point
* is enabled in the compiler, which has semantics-preserving behavior you would
* expect.
*
* If preserving the distinction between signaling NaNs and quiet NaNs is
* important to you, you should use the outparam version. In all other cases,
* you should use the direct return version.
*/
template<typename To, typename From>
inline void
BitwiseCast(const From aFrom, To* aResult)
{
static_assert(sizeof(From) == sizeof(To),
"To and From must have the same size");
union
{
From mFrom;
To mTo;
} u;
u.mFrom = aFrom;
*aResult = u.mTo;
}
template<typename To, typename From>
inline To
BitwiseCast(const From aFrom)
{
To temp;
BitwiseCast<To, From>(aFrom, &temp);
return temp;
}
namespace detail {
enum ToSignedness { ToIsSigned, ToIsUnsigned };
enum FromSignedness { FromIsSigned, FromIsUnsigned };
template<typename From,
typename To,
FromSignedness = IsSigned<From>::value ? FromIsSigned : FromIsUnsigned,
ToSignedness = IsSigned<To>::value ? ToIsSigned : ToIsUnsigned>
struct BoundsCheckImpl;
// Implicit conversions on operands to binary operations make this all a bit
// hard to verify. Attempt to ease the pain below by *only* comparing values
// that are obviously the same type (and will undergo no further conversions),
// even when it's not strictly necessary, for explicitness.
enum UUComparison { FromIsBigger, FromIsNotBigger };
// Unsigned-to-unsigned range check
template<typename From, typename To,
UUComparison = (sizeof(From) > sizeof(To))
? FromIsBigger
: FromIsNotBigger>
struct UnsignedUnsignedCheck;
template<typename From, typename To>
struct UnsignedUnsignedCheck<From, To, FromIsBigger>
{
public:
static bool checkBounds(const From aFrom)
{
return aFrom <= From(To(-1));
}
};
template<typename From, typename To>
struct UnsignedUnsignedCheck<From, To, FromIsNotBigger>
{
public:
static bool checkBounds(const From aFrom)
{
return true;
}
};
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
{
public:
static bool checkBounds(const From aFrom)
{
return UnsignedUnsignedCheck<From, To>::checkBounds(aFrom);
}
};
// Signed-to-unsigned range check
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
{
public:
static bool checkBounds(const From aFrom)
{
if (aFrom < 0) {
return false;
}
if (sizeof(To) >= sizeof(From)) {
return true;
}
return aFrom <= From(To(-1));
}
};
// Unsigned-to-signed range check
enum USComparison { FromIsSmaller, FromIsNotSmaller };
template<typename From, typename To,
USComparison = (sizeof(From) < sizeof(To))
? FromIsSmaller
: FromIsNotSmaller>
struct UnsignedSignedCheck;
template<typename From, typename To>
struct UnsignedSignedCheck<From, To, FromIsSmaller>
{
public:
static bool checkBounds(const From aFrom)
{
return true;
}
};
template<typename From, typename To>
struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
{
public:
static bool checkBounds(const From aFrom)
{
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
return aFrom <= From(MaxValue);
}
};
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
{
public:
static bool checkBounds(const From aFrom)
{
return UnsignedSignedCheck<From, To>::checkBounds(aFrom);
}
};
// Signed-to-signed range check
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned>
{
public:
static bool checkBounds(const From aFrom)
{
if (sizeof(From) <= sizeof(To)) {
return true;
}
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
const To MinValue = -MaxValue - To(1);
return From(MinValue) <= aFrom &&
From(aFrom) <= From(MaxValue);
}
};
template<typename From, typename To,
bool TypesAreIntegral = IsIntegral<From>::value &&
IsIntegral<To>::value>
class BoundsChecker;
template<typename From>
class BoundsChecker<From, From, true>
{
public:
static bool checkBounds(const From aFrom) { return true; }
};
template<typename From, typename To>
class BoundsChecker<From, To, true>
{
public:
static bool checkBounds(const From aFrom)
{
return BoundsCheckImpl<From, To>::checkBounds(aFrom);
}
};
template<typename From, typename To>
inline bool
IsInBounds(const From aFrom)
{
return BoundsChecker<From, To>::checkBounds(aFrom);
}
} // namespace detail
/**
* Cast a value of integral type |From| to a value of integral type |To|,
* asserting that the cast will be a safe cast per C++ (that is, that |to| is in
* the range of values permitted for the type |From|).
*/
template<typename To, typename From>
inline To
AssertedCast(const From aFrom)
{
MOZ_ASSERT((detail::IsInBounds<From, To>(aFrom)));
return static_cast<To>(aFrom);
}
} // namespace mozilla
#endif /* mozilla_Casting_h */

View File

@@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ChaosMode_h
#define mozilla_ChaosMode_h
#include "mozilla/Atomics.h"
#include "mozilla/EnumSet.h"
#include <stdint.h>
#include <stdlib.h>
namespace mozilla {
enum ChaosFeature {
None = 0x0,
// Altering thread scheduling.
ThreadScheduling = 0x1,
// Altering network request scheduling.
NetworkScheduling = 0x2,
// Altering timer scheduling.
TimerScheduling = 0x4,
// Read and write less-than-requested amounts.
IOAmounts = 0x8,
// Iterate over hash tables in random order.
HashTableIteration = 0x10,
// Randomly refuse to use cached version of image (when allowed by spec).
ImageCache = 0x20,
Any = 0xffffffff,
};
namespace detail {
extern MFBT_DATA Atomic<uint32_t> gChaosModeCounter;
extern MFBT_DATA ChaosFeature gChaosFeatures;
} // namespace detail
/**
* When "chaos mode" is activated, code that makes implicitly nondeterministic
* choices is encouraged to make random and extreme choices, to test more
* code paths and uncover bugs.
*/
class ChaosMode
{
public:
static void SetChaosFeature(ChaosFeature aChaosFeature)
{
detail::gChaosFeatures = aChaosFeature;
}
static bool isActive(ChaosFeature aFeature)
{
if (detail::gChaosModeCounter > 0) {
return true;
}
return detail::gChaosFeatures & aFeature;
}
/**
* Increase the chaos mode activation level. An equivalent number of
* calls to leaveChaosMode must be made in order to restore the original
* chaos mode state. If the activation level is nonzero all chaos mode
* features are activated.
*/
static void enterChaosMode()
{
detail::gChaosModeCounter++;
}
/**
* Decrease the chaos mode activation level. See enterChaosMode().
*/
static void leaveChaosMode()
{
MOZ_ASSERT(detail::gChaosModeCounter > 0);
detail::gChaosModeCounter--;
}
/**
* Returns a somewhat (but not uniformly) random uint32_t < aBound.
* Not to be used for anything except ChaosMode, since it's not very random.
*/
static uint32_t randomUint32LessThan(uint32_t aBound)
{
MOZ_ASSERT(aBound != 0);
return uint32_t(rand()) % aBound;
}
};
} /* namespace mozilla */
#endif /* mozilla_ChaosMode_h */

View File

@@ -0,0 +1,194 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implements a UTF-16 character type. */
#ifndef mozilla_Char16_h
#define mozilla_Char16_h
#ifdef __cplusplus
/*
* C++11 introduces a char16_t type and support for UTF-16 string and character
* literals. C++11's char16_t is a distinct builtin type. Technically, char16_t
* is a 16-bit code unit of a Unicode code point, not a "character".
*/
#ifdef WIN32
# define MOZ_USE_CHAR16_WRAPPER
# include <cstdint>
/**
* Win32 API extensively uses wchar_t, which is represented by a separated
* builtin type than char16_t per spec. It's not the case for MSVC prior to
* MSVC 2015, but other compilers follow the spec. We want to mix wchar_t and
* char16_t on Windows builds. This class is supposed to make it easier. It
* stores char16_t const pointer, but provides implicit casts for wchar_t as
* well. On other platforms, we simply use
* |typedef const char16_t* char16ptr_t|. Here, we want to make the class as
* similar to this typedef, including providing some casts that are allowed
* by the typedef.
*/
class char16ptr_t
{
private:
const char16_t* mPtr;
static_assert(sizeof(char16_t) == sizeof(wchar_t),
"char16_t and wchar_t sizes differ");
public:
char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {}
char16ptr_t(const wchar_t* aPtr) :
mPtr(reinterpret_cast<const char16_t*>(aPtr))
{}
/* Without this, nullptr assignment would be ambiguous. */
constexpr char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {}
operator const char16_t*() const
{
return mPtr;
}
operator const wchar_t*() const
{
return reinterpret_cast<const wchar_t*>(mPtr);
}
operator const void*() const
{
return mPtr;
}
operator bool() const
{
return mPtr != nullptr;
}
/* Explicit cast operators to allow things like (char16_t*)str. */
explicit operator char16_t*() const
{
return const_cast<char16_t*>(mPtr);
}
explicit operator wchar_t*() const
{
return const_cast<wchar_t*>(static_cast<const wchar_t*>(*this));
}
explicit operator int() const
{
return reinterpret_cast<intptr_t>(mPtr);
}
explicit operator unsigned int() const
{
return reinterpret_cast<uintptr_t>(mPtr);
}
explicit operator long() const
{
return reinterpret_cast<intptr_t>(mPtr);
}
explicit operator unsigned long() const
{
return reinterpret_cast<uintptr_t>(mPtr);
}
explicit operator long long() const
{
return reinterpret_cast<intptr_t>(mPtr);
}
explicit operator unsigned long long() const
{
return reinterpret_cast<uintptr_t>(mPtr);
}
/**
* Some Windows API calls accept BYTE* but require that data actually be
* WCHAR*. Supporting this requires explicit operators to support the
* requisite explicit casts.
*/
explicit operator const char*() const
{
return reinterpret_cast<const char*>(mPtr);
}
explicit operator const unsigned char*() const
{
return reinterpret_cast<const unsigned char*>(mPtr);
}
explicit operator unsigned char*() const
{
return
const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(mPtr));
}
explicit operator void*() const
{
return const_cast<char16_t*>(mPtr);
}
/* Some operators used on pointers. */
char16_t operator[](size_t aIndex) const
{
return mPtr[aIndex];
}
bool operator==(const char16ptr_t& aOther) const
{
return mPtr == aOther.mPtr;
}
bool operator==(decltype(nullptr)) const
{
return mPtr == nullptr;
}
bool operator!=(const char16ptr_t& aOther) const
{
return mPtr != aOther.mPtr;
}
bool operator!=(decltype(nullptr)) const
{
return mPtr != nullptr;
}
char16ptr_t operator+(int aValue) const
{
return char16ptr_t(mPtr + aValue);
}
char16ptr_t operator+(unsigned int aValue) const
{
return char16ptr_t(mPtr + aValue);
}
char16ptr_t operator+(long aValue) const
{
return char16ptr_t(mPtr + aValue);
}
char16ptr_t operator+(unsigned long aValue) const
{
return char16ptr_t(mPtr + aValue);
}
char16ptr_t operator+(long long aValue) const
{
return char16ptr_t(mPtr + aValue);
}
char16ptr_t operator+(unsigned long long aValue) const
{
return char16ptr_t(mPtr + aValue);
}
ptrdiff_t operator-(const char16ptr_t& aOther) const
{
return mPtr - aOther.mPtr;
}
};
inline decltype((char*)0-(char*)0)
operator-(const char16_t* aX, const char16ptr_t aY)
{
return aX - static_cast<const char16_t*>(aY);
}
#else
typedef const char16_t* char16ptr_t;
#endif
static_assert(sizeof(char16_t) == 2, "Is char16_t type 16 bits?");
static_assert(char16_t(-1) > char16_t(0), "Is char16_t type unsigned?");
static_assert(sizeof(u'A') == 2, "Is unicode char literal 16 bits?");
static_assert(sizeof(u""[0]) == 2, "Is unicode string char 16 bits?");
#endif
#endif /* mozilla_Char16_h */

View File

@@ -0,0 +1,791 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Provides checked integers, detecting integer overflow and divide-by-0. */
#ifndef mozilla_CheckedInt_h
#define mozilla_CheckedInt_h
#include <stdint.h>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/IntegerTypeTraits.h"
namespace mozilla {
template<typename T> class CheckedInt;
namespace detail {
/*
* Step 1: manually record supported types
*
* What's nontrivial here is that there are different families of integer
* types: basic integer types and stdint types. It is merrily undefined which
* types from one family may be just typedefs for a type from another family.
*
* For example, on GCC 4.6, aside from the basic integer types, the only other
* type that isn't just a typedef for some of them, is int8_t.
*/
struct UnsupportedType {};
template<typename IntegerType>
struct IsSupportedPass2
{
static const bool value = false;
};
template<typename IntegerType>
struct IsSupported
{
static const bool value = IsSupportedPass2<IntegerType>::value;
};
template<>
struct IsSupported<int8_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint8_t>
{ static const bool value = true; };
template<>
struct IsSupported<int16_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint16_t>
{ static const bool value = true; };
template<>
struct IsSupported<int32_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint32_t>
{ static const bool value = true; };
template<>
struct IsSupported<int64_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint64_t>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<char>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<signed char>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned char>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<short>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned short>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<int>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned int>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<long>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned long>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<long long>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned long long>
{ static const bool value = true; };
/*
* Step 2: Implement the actual validity checks.
*
* Ideas taken from IntegerLib, code different.
*/
template<typename IntegerType, size_t Size = sizeof(IntegerType)>
struct TwiceBiggerType
{
typedef typename detail::StdintTypeForSizeAndSignedness<
sizeof(IntegerType) * 2,
IsSigned<IntegerType>::value
>::Type Type;
};
template<typename IntegerType>
struct TwiceBiggerType<IntegerType, 8>
{
typedef UnsupportedType Type;
};
template<typename T>
inline bool
HasSignBit(T aX)
{
// In C++, right bit shifts on negative values is undefined by the standard.
// Notice that signed-to-unsigned conversions are always well-defined in the
// standard, as the value congruent modulo 2**n as expected. By contrast,
// unsigned-to-signed is only well-defined if the value is representable.
return bool(typename MakeUnsigned<T>::Type(aX) >>
PositionOfSignBit<T>::value);
}
// Bitwise ops may return a larger type, so it's good to use this inline
// helper guaranteeing that the result is really of type T.
template<typename T>
inline T
BinaryComplement(T aX)
{
return ~aX;
}
template<typename T,
typename U,
bool IsTSigned = IsSigned<T>::value,
bool IsUSigned = IsSigned<U>::value>
struct DoesRangeContainRange
{
};
template<typename T, typename U, bool Signedness>
struct DoesRangeContainRange<T, U, Signedness, Signedness>
{
static const bool value = sizeof(T) >= sizeof(U);
};
template<typename T, typename U>
struct DoesRangeContainRange<T, U, true, false>
{
static const bool value = sizeof(T) > sizeof(U);
};
template<typename T, typename U>
struct DoesRangeContainRange<T, U, false, true>
{
static const bool value = false;
};
template<typename T,
typename U,
bool IsTSigned = IsSigned<T>::value,
bool IsUSigned = IsSigned<U>::value,
bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
struct IsInRangeImpl {};
template<typename T, typename U, bool IsTSigned, bool IsUSigned>
struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
{
static bool run(U)
{
return true;
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, true, true, false>
{
static bool run(U aX)
{
return aX <= MaxValue<T>::value && aX >= MinValue<T>::value;
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, false, false, false>
{
static bool run(U aX)
{
return aX <= MaxValue<T>::value;
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, true, false, false>
{
static bool run(U aX)
{
return sizeof(T) > sizeof(U) || aX <= U(MaxValue<T>::value);
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, false, true, false>
{
static bool run(U aX)
{
return sizeof(T) >= sizeof(U)
? aX >= 0
: aX >= 0 && aX <= U(MaxValue<T>::value);
}
};
template<typename T, typename U>
inline bool
IsInRange(U aX)
{
return IsInRangeImpl<T, U>::run(aX);
}
template<typename T>
inline bool
IsAddValid(T aX, T aY)
{
// Addition is valid if the sign of aX+aY is equal to either that of aX or
// that of aY. Since the value of aX+aY is undefined if we have a signed
// type, we compute it using the unsigned type of the same size. Beware!
// These bitwise operations can return a larger integer type, if T was a
// small type like int8_t, so we explicitly cast to T.
typename MakeUnsigned<T>::Type ux = aX;
typename MakeUnsigned<T>::Type uy = aY;
typename MakeUnsigned<T>::Type result = ux + uy;
return IsSigned<T>::value
? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY))))
: BinaryComplement(aX) >= aY;
}
template<typename T>
inline bool
IsSubValid(T aX, T aY)
{
// Subtraction is valid if either aX and aY have same sign, or aX-aY and aX
// have same sign. Since the value of aX-aY is undefined if we have a signed
// type, we compute it using the unsigned type of the same size.
typename MakeUnsigned<T>::Type ux = aX;
typename MakeUnsigned<T>::Type uy = aY;
typename MakeUnsigned<T>::Type result = ux - uy;
return IsSigned<T>::value
? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY))))
: aX >= aY;
}
template<typename T,
bool IsTSigned = IsSigned<T>::value,
bool TwiceBiggerTypeIsSupported =
IsSupported<typename TwiceBiggerType<T>::Type>::value>
struct IsMulValidImpl {};
template<typename T, bool IsTSigned>
struct IsMulValidImpl<T, IsTSigned, true>
{
static bool run(T aX, T aY)
{
typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY);
return IsInRange<T>(product);
}
};
template<typename T>
struct IsMulValidImpl<T, true, false>
{
static bool run(T aX, T aY)
{
const T max = MaxValue<T>::value;
const T min = MinValue<T>::value;
if (aX == 0 || aY == 0) {
return true;
}
if (aX > 0) {
return aY > 0
? aX <= max / aY
: aY >= min / aX;
}
// If we reach this point, we know that aX < 0.
return aY > 0
? aX >= min / aY
: aY >= max / aX;
}
};
template<typename T>
struct IsMulValidImpl<T, false, false>
{
static bool run(T aX, T aY)
{
return aY == 0 || aX <= MaxValue<T>::value / aY;
}
};
template<typename T>
inline bool
IsMulValid(T aX, T aY)
{
return IsMulValidImpl<T>::run(aX, aY);
}
template<typename T>
inline bool
IsDivValid(T aX, T aY)
{
// Keep in mind that in the signed case, min/-1 is invalid because
// abs(min)>max.
return aY != 0 &&
!(IsSigned<T>::value && aX == MinValue<T>::value && aY == T(-1));
}
template<typename T, bool IsTSigned = IsSigned<T>::value>
struct IsModValidImpl;
template<typename T>
inline bool
IsModValid(T aX, T aY)
{
return IsModValidImpl<T>::run(aX, aY);
}
/*
* Mod is pretty simple.
* For now, let's just use the ANSI C definition:
* If aX or aY are negative, the results are implementation defined.
* Consider these invalid.
* Undefined for aY=0.
* The result will never exceed either aX or aY.
*
* Checking that aX>=0 is a warning when T is unsigned.
*/
template<typename T>
struct IsModValidImpl<T, false>
{
static inline bool run(T aX, T aY)
{
return aY >= 1;
}
};
template<typename T>
struct IsModValidImpl<T, true>
{
static inline bool run(T aX, T aY)
{
if (aX < 0) {
return false;
}
return aY >= 1;
}
};
template<typename T, bool IsSigned = IsSigned<T>::value>
struct NegateImpl;
template<typename T>
struct NegateImpl<T, false>
{
static CheckedInt<T> negate(const CheckedInt<T>& aVal)
{
// Handle negation separately for signed/unsigned, for simpler code and to
// avoid an MSVC warning negating an unsigned value.
return CheckedInt<T>(0, aVal.isValid() && aVal.mValue == 0);
}
};
template<typename T>
struct NegateImpl<T, true>
{
static CheckedInt<T> negate(const CheckedInt<T>& aVal)
{
// Watch out for the min-value, which (with twos-complement) can't be
// negated as -min-value is then (max-value + 1).
if (!aVal.isValid() || aVal.mValue == MinValue<T>::value) {
return CheckedInt<T>(aVal.mValue, false);
}
return CheckedInt<T>(-aVal.mValue, true);
}
};
} // namespace detail
/*
* Step 3: Now define the CheckedInt class.
*/
/**
* @class CheckedInt
* @brief Integer wrapper class checking for integer overflow and other errors
* @param T the integer type to wrap. Can be any type among the following:
* - any basic integer type such as |int|
* - any stdint type such as |int8_t|
*
* This class implements guarded integer arithmetic. Do a computation, check
* that isValid() returns true, you then have a guarantee that no problem, such
* as integer overflow, happened during this computation, and you can call
* value() to get the plain integer value.
*
* The arithmetic operators in this class are guaranteed not to raise a signal
* (e.g. in case of a division by zero).
*
* For example, suppose that you want to implement a function that computes
* (aX+aY)/aZ, that doesn't crash if aZ==0, and that reports on error (divide by
* zero or integer overflow). You could code it as follows:
@code
bool computeXPlusYOverZ(int aX, int aY, int aZ, int* aResult)
{
CheckedInt<int> checkedResult = (CheckedInt<int>(aX) + aY) / aZ;
if (checkedResult.isValid()) {
*aResult = checkedResult.value();
return true;
} else {
return false;
}
}
@endcode
*
* Implicit conversion from plain integers to checked integers is allowed. The
* plain integer is checked to be in range before being casted to the
* destination type. This means that the following lines all compile, and the
* resulting CheckedInts are correctly detected as valid or invalid:
* @code
// 1 is of type int, is found to be in range for uint8_t, x is valid
CheckedInt<uint8_t> x(1);
// -1 is of type int, is found not to be in range for uint8_t, x is invalid
CheckedInt<uint8_t> x(-1);
// -1 is of type int, is found to be in range for int8_t, x is valid
CheckedInt<int8_t> x(-1);
// 1000 is of type int16_t, is found not to be in range for int8_t,
// x is invalid
CheckedInt<int8_t> x(int16_t(1000));
// 3123456789 is of type uint32_t, is found not to be in range for int32_t,
// x is invalid
CheckedInt<int32_t> x(uint32_t(3123456789));
* @endcode
* Implicit conversion from
* checked integers to plain integers is not allowed. As shown in the
* above example, to get the value of a checked integer as a normal integer,
* call value().
*
* Arithmetic operations between checked and plain integers is allowed; the
* result type is the type of the checked integer.
*
* Checked integers of different types cannot be used in the same arithmetic
* expression.
*
* There are convenience typedefs for all stdint types, of the following form
* (these are just 2 examples):
@code
typedef CheckedInt<int32_t> CheckedInt32;
typedef CheckedInt<uint16_t> CheckedUint16;
@endcode
*/
template<typename T>
class CheckedInt
{
protected:
T mValue;
bool mIsValid;
template<typename U>
CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid)
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
}
friend struct detail::NegateImpl<T>;
public:
/**
* Constructs a checked integer with given @a value. The checked integer is
* initialized as valid or invalid depending on whether the @a value
* is in range.
*
* This constructor is not explicit. Instead, the type of its argument is a
* separate template parameter, ensuring that no conversion is performed
* before this constructor is actually called. As explained in the above
* documentation for class CheckedInt, this constructor checks that its
* argument is valid.
*/
template<typename U>
MOZ_IMPLICIT CheckedInt(U aValue) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT
: mValue(T(aValue)),
mIsValid(detail::IsInRange<T>(aValue))
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
}
template<typename U>
friend class CheckedInt;
template<typename U>
CheckedInt<U> toChecked() const
{
CheckedInt<U> ret(mValue);
ret.mIsValid = ret.mIsValid && mIsValid;
return ret;
}
/** Constructs a valid checked integer with initial value 0 */
CheckedInt() : mValue(0), mIsValid(true)
{
static_assert(detail::IsSupported<T>::value,
"This type is not supported by CheckedInt");
}
/** @returns the actual value */
T value() const
{
MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
return mValue;
}
/**
* @returns true if the checked integer is valid, i.e. is not the result
* of an invalid operation or of an operation involving an invalid checked
* integer
*/
bool isValid() const
{
return mIsValid;
}
template<typename U>
friend CheckedInt<U> operator +(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator +=(U aRhs);
CheckedInt& operator +=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator -(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator -=(U aRhs);
CheckedInt& operator -=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator *(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator *=(U aRhs);
CheckedInt& operator *=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator /(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator /=(U aRhs);
CheckedInt& operator /=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator %(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator %=(U aRhs);
CheckedInt& operator %=(const CheckedInt<T>& aRhs);
CheckedInt operator -() const
{
return detail::NegateImpl<T>::negate(*this);
}
/**
* @returns true if the left and right hand sides are valid
* and have the same value.
*
* Note that these semantics are the reason why we don't offer
* a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
* but that would mean that whenever a or b is invalid, a!=b
* is always true, which would be very confusing.
*
* For similar reasons, operators <, >, <=, >= would be very tricky to
* specify, so we just avoid offering them.
*
* Notice that these == semantics are made more reasonable by these facts:
* 1. a==b implies equality at the raw data level
* (the converse is false, as a==b is never true among invalids)
* 2. This is similar to the behavior of IEEE floats, where a==b
* means that a and b have the same value *and* neither is NaN.
*/
bool operator ==(const CheckedInt& aOther) const
{
return mIsValid && aOther.mIsValid && mValue == aOther.mValue;
}
/** prefix ++ */
CheckedInt& operator++()
{
*this += 1;
return *this;
}
/** postfix ++ */
CheckedInt operator++(int)
{
CheckedInt tmp = *this;
*this += 1;
return tmp;
}
/** prefix -- */
CheckedInt& operator--()
{
*this -= 1;
return *this;
}
/** postfix -- */
CheckedInt operator--(int)
{
CheckedInt tmp = *this;
*this -= 1;
return tmp;
}
private:
/**
* The !=, <, <=, >, >= operators are disabled:
* see the comment on operator==.
*/
template<typename U> bool operator !=(U aOther) const = delete;
template<typename U> bool operator < (U aOther) const = delete;
template<typename U> bool operator <=(U aOther) const = delete;
template<typename U> bool operator > (U aOther) const = delete;
template<typename U> bool operator >=(U aOther) const = delete;
};
#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
template<typename T> \
inline CheckedInt<T> \
operator OP(const CheckedInt<T>& aLhs, const CheckedInt<T>& aRhs) \
{ \
if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \
return CheckedInt<T>(0, false); \
} \
return CheckedInt<T>(aLhs.mValue OP aRhs.mValue, \
aLhs.mIsValid && aRhs.mIsValid); \
}
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %)
#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
// Implement castToCheckedInt<T>(x), making sure that
// - it allows x to be either a CheckedInt<T> or any integer type
// that can be casted to T
// - if x is already a CheckedInt<T>, we just return a reference to it,
// instead of copying it (optimization)
namespace detail {
template<typename T, typename U>
struct CastToCheckedIntImpl
{
typedef CheckedInt<T> ReturnType;
static CheckedInt<T> run(U aU) { return aU; }
};
template<typename T>
struct CastToCheckedIntImpl<T, CheckedInt<T> >
{
typedef const CheckedInt<T>& ReturnType;
static const CheckedInt<T>& run(const CheckedInt<T>& aU) { return aU; }
};
} // namespace detail
template<typename T, typename U>
inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
castToCheckedInt(U aU)
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
return detail::CastToCheckedIntImpl<T, U>::run(aU);
}
#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
template<typename T> \
template<typename U> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U aRhs) \
{ \
*this = *this OP castToCheckedInt<T>(aRhs); \
return *this; \
} \
template<typename T> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const CheckedInt<T>& aRhs) \
{ \
*this = *this OP aRhs; \
return *this; \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(const CheckedInt<T>& aLhs, U aRhs) \
{ \
return aLhs OP castToCheckedInt<T>(aRhs); \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(U aLhs, const CheckedInt<T>& aRhs) \
{ \
return castToCheckedInt<T>(aLhs) OP aRhs; \
}
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
#undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
template<typename T, typename U>
inline bool
operator ==(const CheckedInt<T>& aLhs, U aRhs)
{
return aLhs == castToCheckedInt<T>(aRhs);
}
template<typename T, typename U>
inline bool
operator ==(U aLhs, const CheckedInt<T>& aRhs)
{
return castToCheckedInt<T>(aLhs) == aRhs;
}
// Convenience typedefs.
typedef CheckedInt<int8_t> CheckedInt8;
typedef CheckedInt<uint8_t> CheckedUint8;
typedef CheckedInt<int16_t> CheckedInt16;
typedef CheckedInt<uint16_t> CheckedUint16;
typedef CheckedInt<int32_t> CheckedInt32;
typedef CheckedInt<uint32_t> CheckedUint32;
typedef CheckedInt<int64_t> CheckedInt64;
typedef CheckedInt<uint64_t> CheckedUint64;
} // namespace mozilla
#endif /* mozilla_CheckedInt_h */

View File

@@ -0,0 +1,113 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Various compiler checks. */
#ifndef mozilla_Compiler_h
#define mozilla_Compiler_h
#define MOZ_IS_GCC 0
#define MOZ_IS_MSVC 0
#if !defined(__clang__) && defined(__GNUC__)
# undef MOZ_IS_GCC
# define MOZ_IS_GCC 1
/*
* These macros should simplify gcc version checking. For example, to check
* for gcc 4.7.1 or later, check `#if MOZ_GCC_VERSION_AT_LEAST(4, 7, 1)`.
*/
# define MOZ_GCC_VERSION_AT_LEAST(major, minor, patchlevel) \
((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \
>= ((major) * 10000 + (minor) * 100 + (patchlevel)))
# define MOZ_GCC_VERSION_AT_MOST(major, minor, patchlevel) \
((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \
<= ((major) * 10000 + (minor) * 100 + (patchlevel)))
# if !MOZ_GCC_VERSION_AT_LEAST(4, 8, 0)
# error "mfbt (and Gecko) require at least gcc 4.8 to build."
# endif
#elif defined(_MSC_VER)
# undef MOZ_IS_MSVC
# define MOZ_IS_MSVC 1
#endif
/*
* The situation with standard libraries is a lot worse than with compilers,
* particularly as clang and gcc could end up using one of three or so standard
* libraries, and they may not be up-to-snuff with newer C++11 versions. To
* detect the library, we're going to include cstddef (which is a small header
* which will be transitively included by everybody else at some point) to grab
* the version macros and deduce macros from there.
*/
#ifdef __cplusplus
# include <cstddef>
# ifdef _STLPORT_MAJOR
# define MOZ_USING_STLPORT 1
# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) \
(_STLPORT_VERSION >= ((major) << 8 | (minor) << 4 | (patch)))
# elif defined(_LIBCPP_VERSION)
/*
* libc++, unfortunately, doesn't appear to have useful versioning macros.
* Hopefully, the recommendations of N3694 with respect to standard libraries
* will get applied instead and we won't need to worry about version numbers
* here.
*/
# define MOZ_USING_LIBCXX 1
# elif defined(__GLIBCXX__)
# define MOZ_USING_LIBSTDCXX 1
/*
* libstdc++ is also annoying and doesn't give us useful versioning macros
* for the library. If we're using gcc, then assume that libstdc++ matches
* the compiler version. If we're using clang, we're going to have to fake
* major/minor combinations by looking for newly-defined config macros.
*/
# if MOZ_IS_GCC
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
MOZ_GCC_VERSION_AT_LEAST(major, minor, patch)
# elif defined(_GLIBCXX_THROW_OR_ABORT)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 8))
# elif defined(_GLIBCXX_NOEXCEPT)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 7))
# elif defined(_GLIBCXX_USE_DEPRECATED)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 6))
# elif defined(_GLIBCXX_PSEUDO_VISIBILITY)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 5))
# elif defined(_GLIBCXX_BEGIN_EXTERN_C)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 4))
# elif defined(_GLIBCXX_VISIBILITY_ATTR)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 3))
# elif defined(_GLIBCXX_VISIBILITY)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 2))
# else
# error "Your version of libstdc++ is unknown to us and is likely too old."
# endif
# endif
// Flesh out the defines for everyone else
# ifndef MOZ_USING_STLPORT
# define MOZ_USING_STLPORT 0
# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) 0
# endif
# ifndef MOZ_USING_LIBCXX
# define MOZ_USING_LIBCXX 0
# endif
# ifndef MOZ_USING_LIBSTDCXX
# define MOZ_USING_LIBSTDCXX 0
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) 0
# endif
#endif /* __cplusplus */
#endif /* mozilla_Compiler_h */

View File

@@ -0,0 +1,119 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Various simple compression/decompression functions. */
#ifndef mozilla_Compression_h_
#define mozilla_Compression_h_
#include "mozilla/Assertions.h"
#include "mozilla/Types.h"
namespace mozilla {
namespace Compression {
/**
* LZ4 is a very fast byte-wise compression algorithm.
*
* Compared to Google's Snappy it is faster to compress and decompress and
* generally produces output of about the same size.
*
* Compared to zlib it compresses at about 10x the speed, decompresses at about
* 4x the speed and produces output of about 1.5x the size.
*/
class LZ4
{
public:
/**
* Compresses |aInputSize| bytes from |aSource| into |aDest|. Destination
* buffer must be already allocated, and must be sized to handle worst cases
* situations (input data not compressible). Worst case size evaluation is
* provided by function maxCompressedSize()
*
* @param aInputSize is the input size. Max supported value is ~1.9GB
* @return the number of bytes written in buffer |aDest|
*/
static MFBT_API size_t
compress(const char* aSource, size_t aInputSize, char* aDest);
/**
* Compress |aInputSize| bytes from |aSource| into an output buffer
* |aDest| of maximum size |aMaxOutputSize|. If it cannot achieve it,
* compression will stop, and result of the function will be zero,
* |aDest| will still be written to, but since the number of input
* bytes consumed is not returned the result is not usable.
*
* This function never writes outside of provided output buffer.
*
* @param aInputSize is the input size. Max supported value is ~1.9GB
* @param aMaxOutputSize is the size of the destination buffer (which must
* be already allocated)
* @return the number of bytes written in buffer |aDest| or 0 if the
* compression fails
*/
static MFBT_API size_t
compressLimitedOutput(const char* aSource, size_t aInputSize, char* aDest,
size_t aMaxOutputSize);
/**
* If the source stream is malformed, the function will stop decoding
* and return false.
*
* This function never writes outside of provided buffers, and never
* modifies input buffer.
*
* Note: destination buffer must be already allocated, and its size must be a
* minimum of |aOutputSize| bytes.
*
* @param aOutputSize is the output size, therefore the original size
* @return true on success, false on failure
*/
static MFBT_API MOZ_MUST_USE bool
decompress(const char* aSource, char* aDest, size_t aOutputSize);
/**
* If the source stream is malformed, the function will stop decoding
* and return false.
*
* This function never writes beyond aDest + aMaxOutputSize, and is
* therefore protected against malicious data packets.
*
* Note: Destination buffer must be already allocated. This version is
* slightly slower than the decompress without the aMaxOutputSize.
*
* @param aInputSize is the length of the input compressed data
* @param aMaxOutputSize is the size of the destination buffer (which must be
* already allocated)
* @param aOutputSize the actual number of bytes decoded in the destination
* buffer (necessarily <= aMaxOutputSize)
* @return true on success, false on failure
*/
static MFBT_API MOZ_MUST_USE bool
decompress(const char* aSource, size_t aInputSize, char* aDest,
size_t aMaxOutputSize, size_t* aOutputSize);
/*
* Provides the maximum size that LZ4 may output in a "worst case"
* scenario (input data not compressible) primarily useful for memory
* allocation of output buffer.
* note : this function is limited by "int" range (2^31-1)
*
* @param aInputSize is the input size. Max supported value is ~1.9GB
* @return maximum output size in a "worst case" scenario
*/
static inline size_t maxCompressedSize(size_t aInputSize)
{
size_t max = (aInputSize + (aInputSize / 255) + 16);
MOZ_ASSERT(max > aInputSize);
return max;
}
};
} /* namespace Compression */
} /* namespace mozilla */
#endif /* mozilla_Compression_h_ */

View File

@@ -0,0 +1,92 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Provides DebugOnly, a type for variables used only in debug builds (i.e. by
* assertions).
*/
#ifndef mozilla_DebugOnly_h
#define mozilla_DebugOnly_h
#include "mozilla/Attributes.h"
namespace mozilla {
/**
* DebugOnly contains a value of type T, but only in debug builds. In release
* builds, it does not contain a value. This helper is intended to be used with
* MOZ_ASSERT()-style macros, allowing one to write:
*
* DebugOnly<bool> check = func();
* MOZ_ASSERT(check);
*
* more concisely than declaring |check| conditional on #ifdef DEBUG.
*
* DebugOnly instances can only be coerced to T in debug builds. In release
* builds they don't have a value, so type coercion is not well defined.
*
* NOTE: DebugOnly instances still take up one byte of space, plus padding, even
* in optimized, non-DEBUG builds (see bug 1253094 comment 37 for more info).
* For this reason the class is MOZ_STACK_CLASS to prevent consumers using
* DebugOnly for struct/class members and unwittingly inflating the size of
* their objects in release builds.
*/
template<typename T>
class MOZ_STACK_CLASS DebugOnly
{
public:
#ifdef DEBUG
T value;
DebugOnly() { }
MOZ_IMPLICIT DebugOnly(const T& aOther) : value(aOther) { }
DebugOnly(const DebugOnly& aOther) : value(aOther.value) { }
DebugOnly& operator=(const T& aRhs) {
value = aRhs;
return *this;
}
void operator++(int) { value++; }
void operator--(int) { value--; }
// Do not define operator+=(), etc. here. These will coerce via the
// implicit cast and built-in operators. Defining explicit methods here
// will create ambiguity the compiler can't deal with.
T* operator&() { return &value; }
operator T&() { return value; }
operator const T&() const { return value; }
T& operator->() { return value; }
const T& operator->() const { return value; }
#else
DebugOnly() { }
MOZ_IMPLICIT DebugOnly(const T&) { }
DebugOnly(const DebugOnly&) { }
DebugOnly& operator=(const T&) { return *this; }
void operator++(int) { }
void operator--(int) { }
DebugOnly& operator+=(const T&) { return *this; }
DebugOnly& operator-=(const T&) { return *this; }
DebugOnly& operator&=(const T&) { return *this; }
DebugOnly& operator|=(const T&) { return *this; }
DebugOnly& operator^=(const T&) { return *this; }
#endif
/*
* DebugOnly must always have a destructor or else it will
* generate "unused variable" warnings, exactly what it's intended
* to avoid!
*/
~DebugOnly() {}
};
} // namespace mozilla
#endif /* mozilla_DebugOnly_h */

View File

@@ -0,0 +1,221 @@
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Imported from:
* https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/platform/Decimal.h
* Check UPSTREAM-GIT-SHA for the commit ID of the last update from Blink core.
*/
#ifndef Decimal_h
#define Decimal_h
#include "mozilla/Assertions.h"
#include <stdint.h>
#include "mozilla/Types.h"
#include <string>
#ifndef ASSERT
#define DEFINED_ASSERT_FOR_DECIMAL_H 1
#define ASSERT MOZ_ASSERT
#endif
#define PLATFORM_EXPORT
// To use USING_FAST_MALLOC we'd need:
// https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/wtf/Allocator.h
// Since we don't allocate Decimal objects, no need.
#define USING_FAST_MALLOC(type) \
void ignore_this_dummy_method() = delete
#define DISALLOW_NEW() \
private: \
void* operator new(size_t) = delete; \
void* operator new(size_t, void*) = delete; \
public:
namespace blink {
namespace DecimalPrivate {
class SpecialValueHandler;
}
// This class represents decimal base floating point number.
//
// FIXME: Once all C++ compiler support decimal type, we should replace this
// class to compiler supported one. See below URI for current status of decimal
// type for C++: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1977.html
class PLATFORM_EXPORT Decimal {
USING_FAST_MALLOC(Decimal);
public:
enum Sign {
Positive,
Negative,
};
// You should not use EncodedData other than unit testing.
class EncodedData {
DISALLOW_NEW();
// For accessing FormatClass.
friend class Decimal;
friend class DecimalPrivate::SpecialValueHandler;
public:
EncodedData(Sign, int exponent, uint64_t coefficient);
bool operator==(const EncodedData&) const;
bool operator!=(const EncodedData& another) const { return !operator==(another); }
uint64_t coefficient() const { return m_coefficient; }
int countDigits() const;
int exponent() const { return m_exponent; }
bool isFinite() const { return !isSpecial(); }
bool isInfinity() const { return m_formatClass == ClassInfinity; }
bool isNaN() const { return m_formatClass == ClassNaN; }
bool isSpecial() const { return m_formatClass == ClassInfinity || m_formatClass == ClassNaN; }
bool isZero() const { return m_formatClass == ClassZero; }
Sign sign() const { return m_sign; }
void setSign(Sign sign) { m_sign = sign; }
private:
enum FormatClass {
ClassInfinity,
ClassNormal,
ClassNaN,
ClassZero,
};
EncodedData(Sign, FormatClass);
FormatClass formatClass() const { return m_formatClass; }
uint64_t m_coefficient;
int16_t m_exponent;
FormatClass m_formatClass;
Sign m_sign;
};
MFBT_API explicit Decimal(int32_t = 0);
MFBT_API Decimal(Sign, int exponent, uint64_t coefficient);
MFBT_API Decimal(const Decimal&);
MFBT_API Decimal& operator=(const Decimal&);
MFBT_API Decimal& operator+=(const Decimal&);
MFBT_API Decimal& operator-=(const Decimal&);
MFBT_API Decimal& operator*=(const Decimal&);
MFBT_API Decimal& operator/=(const Decimal&);
MFBT_API Decimal operator-() const;
MFBT_API bool operator==(const Decimal&) const;
MFBT_API bool operator!=(const Decimal&) const;
MFBT_API bool operator<(const Decimal&) const;
MFBT_API bool operator<=(const Decimal&) const;
MFBT_API bool operator>(const Decimal&) const;
MFBT_API bool operator>=(const Decimal&) const;
MFBT_API Decimal operator+(const Decimal&) const;
MFBT_API Decimal operator-(const Decimal&) const;
MFBT_API Decimal operator*(const Decimal&) const;
MFBT_API Decimal operator/(const Decimal&) const;
int exponent() const
{
ASSERT(isFinite());
return m_data.exponent();
}
bool isFinite() const { return m_data.isFinite(); }
bool isInfinity() const { return m_data.isInfinity(); }
bool isNaN() const { return m_data.isNaN(); }
bool isNegative() const { return sign() == Negative; }
bool isPositive() const { return sign() == Positive; }
bool isSpecial() const { return m_data.isSpecial(); }
bool isZero() const { return m_data.isZero(); }
MFBT_API Decimal abs() const;
MFBT_API Decimal ceil() const;
MFBT_API Decimal floor() const;
MFBT_API Decimal remainder(const Decimal&) const;
MFBT_API Decimal round() const;
MFBT_API double toDouble() const;
// Note: toString method supports infinity and nan but fromString not.
MFBT_API std::string toString() const;
MFBT_API bool toString(char* strBuf, size_t bufLength) const;
static MFBT_API Decimal fromDouble(double);
// fromString supports following syntax EBNF:
// number ::= sign? digit+ ('.' digit*) (exponent-marker sign? digit+)?
// | sign? '.' digit+ (exponent-marker sign? digit+)?
// sign ::= '+' | '-'
// exponent-marker ::= 'e' | 'E'
// digit ::= '0' | '1' | ... | '9'
// Note: fromString doesn't support "infinity" and "nan".
static MFBT_API Decimal fromString(const std::string& aValue);
static MFBT_API Decimal infinity(Sign);
static MFBT_API Decimal nan();
static MFBT_API Decimal zero(Sign);
// You should not use below methods. We expose them for unit testing.
MFBT_API explicit Decimal(const EncodedData&);
const EncodedData& value() const { return m_data; }
private:
struct AlignedOperands {
uint64_t lhsCoefficient;
uint64_t rhsCoefficient;
int exponent;
};
MFBT_API explicit Decimal(double);
MFBT_API Decimal compareTo(const Decimal&) const;
static MFBT_API AlignedOperands alignOperands(const Decimal& lhs, const Decimal& rhs);
static inline Sign invertSign(Sign sign) { return sign == Negative ? Positive : Negative; }
Sign sign() const { return m_data.sign(); }
EncodedData m_data;
};
} // namespace blink
namespace mozilla {
typedef blink::Decimal Decimal;
} // namespace mozilla
#undef USING_FAST_MALLOC
#ifdef DEFINED_ASSERT_FOR_DECIMAL_H
#undef DEFINED_ASSERT_FOR_DECIMAL_H
#undef ASSERT
#endif
#endif // Decimal_h

View File

@@ -0,0 +1,695 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Functions for reading and writing integers in various endiannesses. */
/*
* The classes LittleEndian and BigEndian expose static methods for
* reading and writing 16-, 32-, and 64-bit signed and unsigned integers
* in their respective endianness. The naming scheme is:
*
* {Little,Big}Endian::{read,write}{Uint,Int}<bitsize>
*
* For instance, LittleEndian::readInt32 will read a 32-bit signed
* integer from memory in little endian format. Similarly,
* BigEndian::writeUint16 will write a 16-bit unsigned integer to memory
* in big-endian format.
*
* The class NativeEndian exposes methods for conversion of existing
* data to and from the native endianness. These methods are intended
* for cases where data needs to be transferred, serialized, etc.
* swap{To,From}{Little,Big}Endian byteswap a single value if necessary.
* Bulk conversion functions are also provided which optimize the
* no-conversion-needed case:
*
* - copyAndSwap{To,From}{Little,Big}Endian;
* - swap{To,From}{Little,Big}EndianInPlace.
*
* The *From* variants are intended to be used for reading data and the
* *To* variants for writing data.
*
* Methods on NativeEndian work with integer data of any type.
* Floating-point data is not supported.
*
* For clarity in networking code, "Network" may be used as a synonym
* for "Big" in any of the above methods or class names.
*
* As an example, reading a file format header whose fields are stored
* in big-endian format might look like:
*
* class ExampleHeader
* {
* private:
* uint32_t mMagic;
* uint32_t mLength;
* uint32_t mTotalRecords;
* uint64_t mChecksum;
*
* public:
* ExampleHeader(const void* data)
* {
* const uint8_t* ptr = static_cast<const uint8_t*>(data);
* mMagic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
* mLength = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
* mTotalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
* mChecksum = BigEndian::readUint64(ptr);
* }
* ...
* };
*/
#ifndef mozilla_EndianUtils_h
#define mozilla_EndianUtils_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Compiler.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/TypeTraits.h"
#include <stdint.h>
#include <string.h>
#if defined(_MSC_VER)
# include <stdlib.h>
# pragma intrinsic(_byteswap_ushort)
# pragma intrinsic(_byteswap_ulong)
# pragma intrinsic(_byteswap_uint64)
#endif
#if defined(_WIN64)
# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)
# define MOZ_LITTLE_ENDIAN 1
# else
# error "CPU type is unknown"
# endif
#elif defined(_WIN32)
# if defined(_M_IX86)
# define MOZ_LITTLE_ENDIAN 1
# elif defined(_M_ARM)
# define MOZ_LITTLE_ENDIAN 1
# else
# error "CPU type is unknown"
# endif
#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__)
# if __LITTLE_ENDIAN__
# define MOZ_LITTLE_ENDIAN 1
# elif __BIG_ENDIAN__
# define MOZ_BIG_ENDIAN 1
# endif
#elif defined(__GNUC__) && \
defined(__BYTE_ORDER__) && \
defined(__ORDER_LITTLE_ENDIAN__) && \
defined(__ORDER_BIG_ENDIAN__)
/*
* Some versions of GCC provide architecture-independent macros for
* this. Yes, there are more than two values for __BYTE_ORDER__.
*/
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define MOZ_LITTLE_ENDIAN 1
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define MOZ_BIG_ENDIAN 1
# else
# error "Can't handle mixed-endian architectures"
# endif
/*
* We can't include useful headers like <endian.h> or <sys/isa_defs.h>
* here because they're not present on all platforms. Instead we have
* this big conditional that ideally will catch all the interesting
* cases.
*/
#elif defined(__sparc) || defined(__sparc__) || \
defined(_POWER) || defined(__hppa) || \
defined(_MIPSEB) || defined(__ARMEB__) || \
defined(__s390__) || defined(__AARCH64EB__) || \
(defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \
(defined(__ia64) && defined(__BIG_ENDIAN__))
# define MOZ_BIG_ENDIAN 1
#elif defined(__i386) || defined(__i386__) || \
defined(__x86_64) || defined(__x86_64__) || \
defined(_MIPSEL) || defined(__ARMEL__) || \
defined(__alpha__) || defined(__AARCH64EL__) || \
(defined(__sh__) && defined(__BIG_ENDIAN__)) || \
(defined(__ia64) && !defined(__BIG_ENDIAN__))
# define MOZ_LITTLE_ENDIAN 1
#endif
#if MOZ_BIG_ENDIAN
# define MOZ_LITTLE_ENDIAN 0
#elif MOZ_LITTLE_ENDIAN
# define MOZ_BIG_ENDIAN 0
#else
# error "Cannot determine endianness"
#endif
#if defined(__clang__)
# if __has_builtin(__builtin_bswap16)
# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
# endif
#elif defined(__GNUC__)
# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
#elif defined(_MSC_VER)
# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort
#endif
namespace mozilla {
namespace detail {
/*
* We need wrappers here because free functions with default template
* arguments and/or partial specialization of function templates are not
* supported by all the compilers we use.
*/
template<typename T, size_t Size = sizeof(T)>
struct Swapper;
template<typename T>
struct Swapper<T, 2>
{
static T swap(T aValue)
{
#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16)
return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue);
#else
return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8));
#endif
}
};
template<typename T>
struct Swapper<T, 4>
{
static T swap(T aValue)
{
#if defined(__clang__) || defined(__GNUC__)
return T(__builtin_bswap32(aValue));
#elif defined(_MSC_VER)
return T(_byteswap_ulong(aValue));
#else
return T(((aValue & 0x000000ffU) << 24) |
((aValue & 0x0000ff00U) << 8) |
((aValue & 0x00ff0000U) >> 8) |
((aValue & 0xff000000U) >> 24));
#endif
}
};
template<typename T>
struct Swapper<T, 8>
{
static inline T swap(T aValue)
{
#if defined(__clang__) || defined(__GNUC__)
return T(__builtin_bswap64(aValue));
#elif defined(_MSC_VER)
return T(_byteswap_uint64(aValue));
#else
return T(((aValue & 0x00000000000000ffULL) << 56) |
((aValue & 0x000000000000ff00ULL) << 40) |
((aValue & 0x0000000000ff0000ULL) << 24) |
((aValue & 0x00000000ff000000ULL) << 8) |
((aValue & 0x000000ff00000000ULL) >> 8) |
((aValue & 0x0000ff0000000000ULL) >> 24) |
((aValue & 0x00ff000000000000ULL) >> 40) |
((aValue & 0xff00000000000000ULL) >> 56));
#endif
}
};
enum Endianness { Little, Big };
#if MOZ_BIG_ENDIAN
# define MOZ_NATIVE_ENDIANNESS detail::Big
#else
# define MOZ_NATIVE_ENDIANNESS detail::Little
#endif
class EndianUtils
{
/**
* Assert that the memory regions [aDest, aDest+aCount) and
* [aSrc, aSrc+aCount] do not overlap. aCount is given in bytes.
*/
static void assertNoOverlap(const void* aDest, const void* aSrc,
size_t aCount)
{
DebugOnly<const uint8_t*> byteDestPtr = static_cast<const uint8_t*>(aDest);
DebugOnly<const uint8_t*> byteSrcPtr = static_cast<const uint8_t*>(aSrc);
MOZ_ASSERT((byteDestPtr <= byteSrcPtr &&
byteDestPtr + aCount <= byteSrcPtr) ||
(byteSrcPtr <= byteDestPtr &&
byteSrcPtr + aCount <= byteDestPtr));
}
template<typename T>
static void assertAligned(T* aPtr)
{
MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!");
}
protected:
/**
* Return |aValue| converted from SourceEndian encoding to DestEndian
* encoding.
*/
template<Endianness SourceEndian, Endianness DestEndian, typename T>
static inline T maybeSwap(T aValue)
{
if (SourceEndian == DestEndian) {
return aValue;
}
return Swapper<T>::swap(aValue);
}
/**
* Convert |aCount| elements at |aPtr| from SourceEndian encoding to
* DestEndian encoding.
*/
template<Endianness SourceEndian, Endianness DestEndian, typename T>
static inline void maybeSwapInPlace(T* aPtr, size_t aCount)
{
assertAligned(aPtr);
if (SourceEndian == DestEndian) {
return;
}
for (size_t i = 0; i < aCount; i++) {
aPtr[i] = Swapper<T>::swap(aPtr[i]);
}
}
/**
* Write |aCount| elements to the unaligned address |aDest| in DestEndian
* format, using elements found at |aSrc| in SourceEndian format.
*/
template<Endianness SourceEndian, Endianness DestEndian, typename T>
static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount)
{
assertNoOverlap(aDest, aSrc, aCount * sizeof(T));
assertAligned(aSrc);
if (SourceEndian == DestEndian) {
memcpy(aDest, aSrc, aCount * sizeof(T));
return;
}
uint8_t* byteDestPtr = static_cast<uint8_t*>(aDest);
for (size_t i = 0; i < aCount; ++i) {
union
{
T mVal;
uint8_t mBuffer[sizeof(T)];
} u;
u.mVal = maybeSwap<SourceEndian, DestEndian>(aSrc[i]);
memcpy(byteDestPtr, u.mBuffer, sizeof(T));
byteDestPtr += sizeof(T);
}
}
/**
* Write |aCount| elements to |aDest| in DestEndian format, using elements
* found at the unaligned address |aSrc| in SourceEndian format.
*/
template<Endianness SourceEndian, Endianness DestEndian, typename T>
static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount)
{
assertNoOverlap(aDest, aSrc, aCount * sizeof(T));
assertAligned(aDest);
if (SourceEndian == DestEndian) {
memcpy(aDest, aSrc, aCount * sizeof(T));
return;
}
const uint8_t* byteSrcPtr = static_cast<const uint8_t*>(aSrc);
for (size_t i = 0; i < aCount; ++i) {
union
{
T mVal;
uint8_t mBuffer[sizeof(T)];
} u;
memcpy(u.mBuffer, byteSrcPtr, sizeof(T));
aDest[i] = maybeSwap<SourceEndian, DestEndian>(u.mVal);
byteSrcPtr += sizeof(T);
}
}
};
template<Endianness ThisEndian>
class Endian : private EndianUtils
{
protected:
/** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_MUST_USE uint16_t readUint16(const void* aPtr)
{
return read<uint16_t>(aPtr);
}
/** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_MUST_USE uint32_t readUint32(const void* aPtr)
{
return read<uint32_t>(aPtr);
}
/** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_MUST_USE uint64_t readUint64(const void* aPtr)
{
return read<uint64_t>(aPtr);
}
/** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_MUST_USE int16_t readInt16(const void* aPtr)
{
return read<int16_t>(aPtr);
}
/** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_MUST_USE int32_t readInt32(const void* aPtr)
{
return read<uint32_t>(aPtr);
}
/** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_MUST_USE int64_t readInt64(const void* aPtr)
{
return read<int64_t>(aPtr);
}
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
static void writeUint16(void* aPtr, uint16_t aValue)
{
write(aPtr, aValue);
}
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
static void writeUint32(void* aPtr, uint32_t aValue)
{
write(aPtr, aValue);
}
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
static void writeUint64(void* aPtr, uint64_t aValue)
{
write(aPtr, aValue);
}
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
static void writeInt16(void* aPtr, int16_t aValue)
{
write(aPtr, aValue);
}
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
static void writeInt32(void* aPtr, int32_t aValue)
{
write(aPtr, aValue);
}
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
static void writeInt64(void* aPtr, int64_t aValue)
{
write(aPtr, aValue);
}
/*
* Converts a value of type T to little-endian format.
*
* This function is intended for cases where you have data in your
* native-endian format and you need it to appear in little-endian
* format for transmission.
*/
template<typename T>
MOZ_MUST_USE static T swapToLittleEndian(T aValue)
{
return maybeSwap<ThisEndian, Little>(aValue);
}
/*
* Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
* them to little-endian format if ThisEndian is Big.
* As with memcpy, |aDest| and |aSrc| must not overlap.
*/
template<typename T>
static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc,
size_t aCount)
{
copyAndSwapTo<ThisEndian, Little>(aDest, aSrc, aCount);
}
/*
* Likewise, but converts values in place.
*/
template<typename T>
static void swapToLittleEndianInPlace(T* aPtr, size_t aCount)
{
maybeSwapInPlace<ThisEndian, Little>(aPtr, aCount);
}
/*
* Converts a value of type T to big-endian format.
*/
template<typename T>
MOZ_MUST_USE static T swapToBigEndian(T aValue)
{
return maybeSwap<ThisEndian, Big>(aValue);
}
/*
* Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
* them to big-endian format if ThisEndian is Little.
* As with memcpy, |aDest| and |aSrc| must not overlap.
*/
template<typename T>
static void copyAndSwapToBigEndian(void* aDest, const T* aSrc,
size_t aCount)
{
copyAndSwapTo<ThisEndian, Big>(aDest, aSrc, aCount);
}
/*
* Likewise, but converts values in place.
*/
template<typename T>
static void swapToBigEndianInPlace(T* aPtr, size_t aCount)
{
maybeSwapInPlace<ThisEndian, Big>(aPtr, aCount);
}
/*
* Synonyms for the big-endian functions, for better readability
* in network code.
*/
template<typename T>
MOZ_MUST_USE static T swapToNetworkOrder(T aValue)
{
return swapToBigEndian(aValue);
}
template<typename T>
static void
copyAndSwapToNetworkOrder(void* aDest, const T* aSrc, size_t aCount)
{
copyAndSwapToBigEndian(aDest, aSrc, aCount);
}
template<typename T>
static void
swapToNetworkOrderInPlace(T* aPtr, size_t aCount)
{
swapToBigEndianInPlace(aPtr, aCount);
}
/*
* Converts a value of type T from little-endian format.
*/
template<typename T>
MOZ_MUST_USE static T swapFromLittleEndian(T aValue)
{
return maybeSwap<Little, ThisEndian>(aValue);
}
/*
* Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
* them to little-endian format if ThisEndian is Big.
* As with memcpy, |aDest| and |aSrc| must not overlap.
*/
template<typename T>
static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc,
size_t aCount)
{
copyAndSwapFrom<Little, ThisEndian>(aDest, aSrc, aCount);
}
/*
* Likewise, but converts values in place.
*/
template<typename T>
static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount)
{
maybeSwapInPlace<Little, ThisEndian>(aPtr, aCount);
}
/*
* Converts a value of type T from big-endian format.
*/
template<typename T>
MOZ_MUST_USE static T swapFromBigEndian(T aValue)
{
return maybeSwap<Big, ThisEndian>(aValue);
}
/*
* Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
* them to big-endian format if ThisEndian is Little.
* As with memcpy, |aDest| and |aSrc| must not overlap.
*/
template<typename T>
static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc,
size_t aCount)
{
copyAndSwapFrom<Big, ThisEndian>(aDest, aSrc, aCount);
}
/*
* Likewise, but converts values in place.
*/
template<typename T>
static void swapFromBigEndianInPlace(T* aPtr, size_t aCount)
{
maybeSwapInPlace<Big, ThisEndian>(aPtr, aCount);
}
/*
* Synonyms for the big-endian functions, for better readability
* in network code.
*/
template<typename T>
MOZ_MUST_USE static T swapFromNetworkOrder(T aValue)
{
return swapFromBigEndian(aValue);
}
template<typename T>
static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc,
size_t aCount)
{
copyAndSwapFromBigEndian(aDest, aSrc, aCount);
}
template<typename T>
static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount)
{
swapFromBigEndianInPlace(aPtr, aCount);
}
private:
/**
* Read a value of type T, encoded in endianness ThisEndian from |aPtr|.
* Return that value encoded in native endianness.
*/
template<typename T>
static T read(const void* aPtr)
{
union
{
T mVal;
uint8_t mBuffer[sizeof(T)];
} u;
memcpy(u.mBuffer, aPtr, sizeof(T));
return maybeSwap<ThisEndian, MOZ_NATIVE_ENDIANNESS>(u.mVal);
}
/**
* Write a value of type T, in native endianness, to |aPtr|, in ThisEndian
* endianness.
*/
template<typename T>
static void write(void* aPtr, T aValue)
{
T tmp = maybeSwap<MOZ_NATIVE_ENDIANNESS, ThisEndian>(aValue);
memcpy(aPtr, &tmp, sizeof(T));
}
Endian() = delete;
Endian(const Endian& aTther) = delete;
void operator=(const Endian& aOther) = delete;
};
template<Endianness ThisEndian>
class EndianReadWrite : public Endian<ThisEndian>
{
private:
typedef Endian<ThisEndian> super;
public:
using super::readUint16;
using super::readUint32;
using super::readUint64;
using super::readInt16;
using super::readInt32;
using super::readInt64;
using super::writeUint16;
using super::writeUint32;
using super::writeUint64;
using super::writeInt16;
using super::writeInt32;
using super::writeInt64;
};
} /* namespace detail */
class LittleEndian final : public detail::EndianReadWrite<detail::Little>
{};
class BigEndian final : public detail::EndianReadWrite<detail::Big>
{};
typedef BigEndian NetworkEndian;
class NativeEndian final : public detail::Endian<MOZ_NATIVE_ENDIANNESS>
{
private:
typedef detail::Endian<MOZ_NATIVE_ENDIANNESS> super;
public:
/*
* These functions are intended for cases where you have data in your
* native-endian format and you need the data to appear in the appropriate
* endianness for transmission, serialization, etc.
*/
using super::swapToLittleEndian;
using super::copyAndSwapToLittleEndian;
using super::swapToLittleEndianInPlace;
using super::swapToBigEndian;
using super::copyAndSwapToBigEndian;
using super::swapToBigEndianInPlace;
using super::swapToNetworkOrder;
using super::copyAndSwapToNetworkOrder;
using super::swapToNetworkOrderInPlace;
/*
* These functions are intended for cases where you have data in the
* given endianness (e.g. reading from disk or a file-format) and you
* need the data to appear in native-endian format for processing.
*/
using super::swapFromLittleEndian;
using super::copyAndSwapFromLittleEndian;
using super::swapFromLittleEndianInPlace;
using super::swapFromBigEndian;
using super::copyAndSwapFromBigEndian;
using super::swapFromBigEndianInPlace;
using super::swapFromNetworkOrder;
using super::copyAndSwapFromNetworkOrder;
using super::swapFromNetworkOrderInPlace;
};
#undef MOZ_NATIVE_ENDIANNESS
} /* namespace mozilla */
#endif /* mozilla_EndianUtils_h */

View File

@@ -0,0 +1,344 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A set abstraction for enumeration values. */
#ifndef mozilla_EnumSet_h
#define mozilla_EnumSet_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include <initializer_list>
#include <stdint.h>
namespace mozilla {
/**
* EnumSet<T> is a set of values defined by an enumeration. It is implemented
* using a 32 bit mask for each value so it will only work for enums with an int
* representation less than 32. It works both for enum and enum class types.
*/
template<typename T>
class EnumSet
{
public:
EnumSet()
: mBitField(0)
{
initVersion();
}
MOZ_IMPLICIT EnumSet(T aEnum)
: mBitField(bitFor(aEnum))
{ }
EnumSet(T aEnum1, T aEnum2)
: mBitField(bitFor(aEnum1) |
bitFor(aEnum2))
{
initVersion();
}
EnumSet(T aEnum1, T aEnum2, T aEnum3)
: mBitField(bitFor(aEnum1) |
bitFor(aEnum2) |
bitFor(aEnum3))
{
initVersion();
}
EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
: mBitField(bitFor(aEnum1) |
bitFor(aEnum2) |
bitFor(aEnum3) |
bitFor(aEnum4))
{
initVersion();
}
MOZ_IMPLICIT EnumSet(std::initializer_list<T> list)
: mBitField(0)
{
for (auto value : list) {
(*this) += value;
}
initVersion();
}
EnumSet(const EnumSet& aEnumSet)
: mBitField(aEnumSet.mBitField)
{
initVersion();
}
/**
* Add an element
*/
void operator+=(T aEnum)
{
incVersion();
mBitField |= bitFor(aEnum);
}
/**
* Add an element
*/
EnumSet<T> operator+(T aEnum) const
{
EnumSet<T> result(*this);
result += aEnum;
return result;
}
/**
* Union
*/
void operator+=(const EnumSet<T> aEnumSet)
{
incVersion();
mBitField |= aEnumSet.mBitField;
}
/**
* Union
*/
EnumSet<T> operator+(const EnumSet<T> aEnumSet) const
{
EnumSet<T> result(*this);
result += aEnumSet;
return result;
}
/**
* Remove an element
*/
void operator-=(T aEnum)
{
incVersion();
mBitField &= ~(bitFor(aEnum));
}
/**
* Remove an element
*/
EnumSet<T> operator-(T aEnum) const
{
EnumSet<T> result(*this);
result -= aEnum;
return result;
}
/**
* Remove a set of elements
*/
void operator-=(const EnumSet<T> aEnumSet)
{
incVersion();
mBitField &= ~(aEnumSet.mBitField);
}
/**
* Remove a set of elements
*/
EnumSet<T> operator-(const EnumSet<T> aEnumSet) const
{
EnumSet<T> result(*this);
result -= aEnumSet;
return result;
}
/**
* Clear
*/
void clear()
{
incVersion();
mBitField = 0;
}
/**
* Intersection
*/
void operator&=(const EnumSet<T> aEnumSet)
{
incVersion();
mBitField &= aEnumSet.mBitField;
}
/**
* Intersection
*/
EnumSet<T> operator&(const EnumSet<T> aEnumSet) const
{
EnumSet<T> result(*this);
result &= aEnumSet;
return result;
}
/**
* Equality
*/
bool operator==(const EnumSet<T> aEnumSet) const
{
return mBitField == aEnumSet.mBitField;
}
/**
* Test is an element is contained in the set.
*/
bool contains(T aEnum) const
{
return mBitField & bitFor(aEnum);
}
/**
* Return the number of elements in the set.
*/
uint8_t size() const
{
uint8_t count = 0;
for (uint32_t bitField = mBitField; bitField; bitField >>= 1) {
if (bitField & 1) {
count++;
}
}
return count;
}
bool isEmpty() const
{
return mBitField == 0;
}
uint32_t serialize() const
{
return mBitField;
}
void deserialize(uint32_t aValue)
{
incVersion();
mBitField = aValue;
}
class ConstIterator
{
const EnumSet<T>* mSet;
uint32_t mPos;
#ifdef DEBUG
uint64_t mVersion;
#endif
void checkVersion() {
// Check that the set has not been modified while being iterated.
MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion);
}
public:
ConstIterator(const EnumSet<T>& aSet, uint32_t aPos)
: mSet(&aSet), mPos(aPos)
{
#ifdef DEBUG
mVersion = mSet->mVersion;
#endif
MOZ_ASSERT(aPos <= kMaxBits);
if (aPos != kMaxBits && !mSet->contains(T(mPos)))
++*this;
}
ConstIterator(const ConstIterator& aOther)
: mSet(aOther.mSet), mPos(aOther.mPos)
{
#ifdef DEBUG
mVersion = aOther.mVersion;
checkVersion();
#endif
}
ConstIterator(ConstIterator&& aOther)
: mSet(aOther.mSet), mPos(aOther.mPos)
{
#ifdef DEBUG
mVersion = aOther.mVersion;
checkVersion();
#endif
aOther.mSet = nullptr;
}
~ConstIterator() {
checkVersion();
}
bool operator==(const ConstIterator& other) {
MOZ_ASSERT(mSet == other.mSet);
checkVersion();
return mPos == other.mPos;
}
bool operator!=(const ConstIterator& other) {
return !(*this == other);
}
T operator*() {
MOZ_ASSERT(mSet);
MOZ_ASSERT(mPos < kMaxBits);
MOZ_ASSERT(mSet->contains(T(mPos)));
checkVersion();
return T(mPos);
}
ConstIterator& operator++() {
MOZ_ASSERT(mSet);
MOZ_ASSERT(mPos < kMaxBits);
checkVersion();
do {
mPos++;
} while (mPos < kMaxBits && !mSet->contains(T(mPos)));
return *this;
}
};
ConstIterator begin() const {
return ConstIterator(*this, 0);
}
ConstIterator end() const {
return ConstIterator(*this, kMaxBits);
}
private:
static uint32_t bitFor(T aEnum)
{
uint32_t bitNumber = (uint32_t)aEnum;
MOZ_ASSERT(bitNumber < kMaxBits);
return 1U << bitNumber;
}
void initVersion() {
#ifdef DEBUG
mVersion = 0;
#endif
}
void incVersion() {
#ifdef DEBUG
mVersion++;
#endif
}
static const size_t kMaxBits = 32;
uint32_t mBitField;
#ifdef DEBUG
uint64_t mVersion;
#endif
};
} // namespace mozilla
#endif /* mozilla_EnumSet_h_*/

View File

@@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Type traits for enums. */
#ifndef mozilla_EnumTypeTraits_h
#define mozilla_EnumTypeTraits_h
#include <type_traits>
namespace mozilla {
namespace detail {
template<size_t EnumSize, bool EnumSigned, size_t StorageSize, bool StorageSigned>
struct EnumFitsWithinHelper;
// Signed enum, signed storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, true, StorageSize, true>
: public std::integral_constant<bool, (EnumSize <= StorageSize)>
{};
// Signed enum, unsigned storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, true, StorageSize, false>
: public std::integral_constant<bool, false>
{};
// Unsigned enum, signed storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, false, StorageSize, true>
: public std::integral_constant<bool, (EnumSize * 2 <= StorageSize)>
{};
// Unsigned enum, unsigned storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, false, StorageSize, false>
: public std::integral_constant<bool, (EnumSize <= StorageSize)>
{};
} // namespace detail
/*
* Type trait that determines whether the enum type T can fit within the
* integral type Storage without data loss. This trait should be used with
* caution with an enum type whose underlying type has not been explicitly
* specified: for such enums, the C++ implementation is free to choose a type
* no smaller than int whose range encompasses all possible values of the enum.
* So for an enum with only small non-negative values, the underlying type may
* be either int or unsigned int, depending on the whims of the implementation.
*/
template<typename T, typename Storage>
struct EnumTypeFitsWithin
: public detail::EnumFitsWithinHelper<
sizeof(T),
std::is_signed<typename std::underlying_type<T>::type>::value,
sizeof(Storage),
std::is_signed<Storage>::value
>
{
static_assert(std::is_enum<T>::value, "must provide an enum type");
static_assert(std::is_integral<Storage>::value, "must provide an integral type");
};
} // namespace mozilla
#endif /* mozilla_EnumTypeTraits_h */

View File

@@ -0,0 +1,110 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* EnumeratedArray is like Array, but indexed by a typed enum. */
#ifndef mozilla_EnumeratedArray_h
#define mozilla_EnumeratedArray_h
#include "mozilla/Array.h"
#include "mozilla/Move.h"
namespace mozilla {
/**
* EnumeratedArray is a fixed-size array container for use when an
* array is indexed by a specific enum class.
*
* This provides type safety by guarding at compile time against accidentally
* indexing such arrays with unrelated values. This also removes the need
* for manual casting when using a typed enum value to index arrays.
*
* Aside from the typing of indices, EnumeratedArray is similar to Array.
*
* Example:
*
* enum class AnimalSpecies {
* Cow,
* Sheep,
* Count
* };
*
* EnumeratedArray<AnimalSpecies, AnimalSpecies::Count, int> headCount;
*
* headCount[AnimalSpecies::Cow] = 17;
* headCount[AnimalSpecies::Sheep] = 30;
*
*/
template<typename IndexType,
IndexType SizeAsEnumValue,
typename ValueType>
class EnumeratedArray
{
public:
static const size_t kSize = size_t(SizeAsEnumValue);
private:
typedef Array<ValueType, kSize> ArrayType;
ArrayType mArray;
public:
EnumeratedArray() {}
template <typename... Args>
MOZ_IMPLICIT EnumeratedArray(Args&&... aArgs)
: mArray{mozilla::Forward<Args>(aArgs)...}
{}
explicit EnumeratedArray(const EnumeratedArray& aOther)
{
for (size_t i = 0; i < kSize; i++) {
mArray[i] = aOther.mArray[i];
}
}
EnumeratedArray(EnumeratedArray&& aOther)
{
for (size_t i = 0; i < kSize; i++) {
mArray[i] = Move(aOther.mArray[i]);
}
}
ValueType& operator[](IndexType aIndex)
{
return mArray[size_t(aIndex)];
}
const ValueType& operator[](IndexType aIndex) const
{
return mArray[size_t(aIndex)];
}
typedef typename ArrayType::iterator iterator;
typedef typename ArrayType::const_iterator const_iterator;
typedef typename ArrayType::reverse_iterator reverse_iterator;
typedef typename ArrayType::const_reverse_iterator const_reverse_iterator;
// Methods for range-based for loops.
iterator begin() { return mArray.begin(); }
const_iterator begin() const { return mArray.begin(); }
const_iterator cbegin() const { return mArray.cbegin(); }
iterator end() { return mArray.end(); }
const_iterator end() const { return mArray.end(); }
const_iterator cend() const { return mArray.cend(); }
// Methods for reverse iterating.
reverse_iterator rbegin() { return mArray.rbegin(); }
const_reverse_iterator rbegin() const { return mArray.rbegin(); }
const_reverse_iterator crbegin() const { return mArray.crbegin(); }
reverse_iterator rend() { return mArray.rend(); }
const_reverse_iterator rend() const { return mArray.rend(); }
const_reverse_iterator crend() const { return mArray.crend(); }
};
} // namespace mozilla
#endif // mozilla_EnumeratedArray_h

View File

@@ -0,0 +1,201 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Iterator over contiguous enum values */
/*
* Implements generator functions that create a range to iterate over the values
* of a scoped or unscoped enum. Unlike IntegerRange, which can only function on
* the underlying integral type, the elements of the generated sequence will
* have the type of the enum in question.
*
* Note that the enum values should be contiguous in the iterated range;
* unfortunately there exists no way for EnumeratedRange to enforce this
* either dynamically or at compile time.
*/
#ifndef mozilla_EnumeratedRange_h
#define mozilla_EnumeratedRange_h
#include <type_traits>
#include "mozilla/ReverseIterator.h"
namespace mozilla {
namespace detail {
template<typename EnumTypeT>
class EnumeratedIterator
{
public:
typedef typename std::underlying_type<EnumTypeT>::type IntTypeT;
template<typename EnumType>
explicit EnumeratedIterator(EnumType aCurrent)
: mCurrent(aCurrent) { }
template<typename EnumType>
explicit EnumeratedIterator(const EnumeratedIterator<EnumType>& aOther)
: mCurrent(aOther.mCurrent) { }
EnumTypeT operator*() const { return mCurrent; }
/* Increment and decrement operators */
EnumeratedIterator& operator++()
{
mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
return *this;
}
EnumeratedIterator& operator--()
{
mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
return *this;
}
EnumeratedIterator operator++(int)
{
auto ret = *this;
mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
return ret;
}
EnumeratedIterator operator--(int)
{
auto ret = *this;
mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
return ret;
}
/* Comparison operators */
template<typename EnumType>
friend bool operator==(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator!=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator<(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator<=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator>(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator>=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
private:
EnumTypeT mCurrent;
};
template<typename EnumType>
bool operator==(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent == aIter2.mCurrent;
}
template<typename EnumType>
bool operator!=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent != aIter2.mCurrent;
}
template<typename EnumType>
bool operator<(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent < aIter2.mCurrent;
}
template<typename EnumType>
bool operator<=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent <= aIter2.mCurrent;
}
template<typename EnumType>
bool operator>(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent > aIter2.mCurrent;
}
template<typename EnumType>
bool operator>=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent >= aIter2.mCurrent;
}
template<typename EnumTypeT>
class EnumeratedRange
{
public:
typedef EnumeratedIterator<EnumTypeT> iterator;
typedef EnumeratedIterator<EnumTypeT> const_iterator;
typedef ReverseIterator<iterator> reverse_iterator;
typedef ReverseIterator<const_iterator> const_reverse_iterator;
template<typename EnumType>
EnumeratedRange(EnumType aBegin, EnumType aEnd)
: mBegin(aBegin), mEnd(aEnd) { }
iterator begin() const { return iterator(mBegin); }
const_iterator cbegin() const { return begin(); }
iterator end() const { return iterator(mEnd); }
const_iterator cend() const { return end(); }
reverse_iterator rbegin() const { return reverse_iterator(mEnd); }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() const { return reverse_iterator(mBegin); }
const_reverse_iterator crend() const { return rend(); }
private:
EnumTypeT mBegin;
EnumTypeT mEnd;
};
} // namespace detail
#ifdef __GNUC__
// Enums can have an unsigned underlying type, which makes some of the
// comparisons below always true or always false. Temporarily disable
// -Wtype-limits to avoid breaking -Werror builds.
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
// Create a range to iterate from aBegin to aEnd, exclusive.
template<typename EnumType>
inline detail::EnumeratedRange<EnumType>
MakeEnumeratedRange(EnumType aBegin, EnumType aEnd)
{
MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!");
return detail::EnumeratedRange<EnumType>(aBegin, aEnd);
}
// Create a range to iterate from EnumType(0) to aEnd, exclusive. EnumType(0)
// should exist, but note that there is no way for us to ensure that it does!
template<typename EnumType>
inline detail::EnumeratedRange<EnumType>
MakeEnumeratedRange(EnumType aEnd)
{
return MakeEnumeratedRange(EnumType(0), aEnd);
}
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
} // namespace mozilla
#endif // mozilla_EnumeratedRange_h

View File

@@ -0,0 +1,379 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_FastBernoulliTrial_h
#define mozilla_FastBernoulliTrial_h
#include "mozilla/Assertions.h"
#include "mozilla/XorShift128PlusRNG.h"
#include <cmath>
#include <stdint.h>
namespace mozilla {
/**
* class FastBernoulliTrial: Efficient sampling with uniform probability
*
* When gathering statistics about a program's behavior, we may be observing
* events that occur very frequently (e.g., function calls or memory
* allocations) and we may be gathering information that is somewhat expensive
* to produce (e.g., call stacks). Sampling all the events could have a
* significant impact on the program's performance.
*
* Why not just sample every N'th event? This technique is called "systematic
* sampling"; it's simple and efficient, and it's fine if we imagine a
* patternless stream of events. But what if we're sampling allocations, and the
* program happens to have a loop where each iteration does exactly N
* allocations? You would end up sampling the same allocation every time through
* the loop; the entire rest of the loop becomes invisible to your measurements!
* More generally, if each iteration does M allocations, and M and N have any
* common divisor at all, most allocation sites will never be sampled. If
* they're both even, say, the odd-numbered allocations disappear from your
* results.
*
* Ideally, we'd like each event to have some probability P of being sampled,
* independent of its neighbors and of its position in the sequence. This is
* called "Bernoulli sampling", and it doesn't suffer from any of the problems
* mentioned above.
*
* One disadvantage of Bernoulli sampling is that you can't be sure exactly how
* many samples you'll get: technically, it's possible that you might sample
* none of them, or all of them. But if the number of events N is large, these
* aren't likely outcomes; you can generally expect somewhere around P * N
* events to be sampled.
*
* The other disadvantage of Bernoulli sampling is that you have to generate a
* random number for every event, which can be slow.
*
* [significant pause]
*
* BUT NOT WITH THIS CLASS! FastBernoulliTrial lets you do true Bernoulli
* sampling, while generating a fresh random number only when we do decide to
* sample an event, not on every trial. When it decides not to sample, a call to
* |FastBernoulliTrial::trial| is nothing but decrementing a counter and
* comparing it to zero. So the lower your sampling probability is, the less
* overhead FastBernoulliTrial imposes.
*
* Probabilities of 0 and 1 are handled efficiently. (In neither case need we
* ever generate a random number at all.)
*
* The essential API:
*
* - FastBernoulliTrial(double P)
* Construct an instance that selects events with probability P.
*
* - FastBernoulliTrial::trial()
* Return true with probability P. Call this each time an event occurs, to
* decide whether to sample it or not.
*
* - FastBernoulliTrial::trial(size_t n)
* Equivalent to calling trial() |n| times, and returning true if any of those
* calls do. However, like trial, this runs in fast constant time.
*
* What is this good for? In some applications, some events are "bigger" than
* others. For example, large allocations are more significant than small
* allocations. Perhaps we'd like to imagine that we're drawing allocations
* from a stream of bytes, and performing a separate Bernoulli trial on every
* byte from the stream. We can accomplish this by calling |t.trial(S)| for
* the number of bytes S, and sampling the event if that returns true.
*
* Of course, this style of sampling needs to be paired with analysis and
* presentation that makes the size of the event apparent, lest trials with
* large values for |n| appear to be indistinguishable from those with small
* values for |n|.
*/
class FastBernoulliTrial {
/*
* This comment should just read, "Generate skip counts with a geometric
* distribution", and leave everyone to go look that up and see why it's the
* right thing to do, if they don't know already.
*
* BUT IF YOU'RE CURIOUS, COMMENTS ARE FREE...
*
* Instead of generating a fresh random number for every trial, we can
* randomly generate a count of how many times we should return false before
* the next time we return true. We call this a "skip count". Once we've
* returned true, we generate a fresh skip count, and begin counting down
* again.
*
* Here's an awesome fact: by exercising a little care in the way we generate
* skip counts, we can produce results indistinguishable from those we would
* get "rolling the dice" afresh for every trial.
*
* In short, skip counts in Bernoulli trials of probability P obey a geometric
* distribution. If a random variable X is uniformly distributed from [0..1),
* then std::floor(std::log(X) / std::log(1-P)) has the appropriate geometric
* distribution for the skip counts.
*
* Why that formula?
*
* Suppose we're to return |true| with some probability P, say, 0.3. Spread
* all possible futures along a line segment of length 1. In portion P of
* those cases, we'll return true on the next call to |trial|; the skip count
* is 0. For the remaining portion 1-P of cases, the skip count is 1 or more.
*
* skip: 0 1 or more
* |------------------^-----------------------------------------|
* portion: 0.3 0.7
* P 1-P
*
* But the "1 or more" section of the line is subdivided the same way: *within
* that section*, in portion P the second call to |trial()| returns true, and in
* portion 1-P it returns false a second time; the skip count is two or more.
* So we return true on the second call in proportion 0.7 * 0.3, and skip at
* least the first two in proportion 0.7 * 0.7.
*
* skip: 0 1 2 or more
* |------------------^------------^----------------------------|
* portion: 0.3 0.7 * 0.3 0.7 * 0.7
* P (1-P)*P (1-P)^2
*
* We can continue to subdivide:
*
* skip >= 0: |------------------------------------------------- (1-P)^0 --|
* skip >= 1: | ------------------------------- (1-P)^1 --|
* skip >= 2: | ------------------ (1-P)^2 --|
* skip >= 3: | ^ ---------- (1-P)^3 --|
* skip >= 4: | . --- (1-P)^4 --|
* .
* ^X, see below
*
* In other words, the likelihood of the next n calls to |trial| returning
* false is (1-P)^n. The longer a run we require, the more the likelihood
* drops. Further calls may return false too, but this is the probability
* we'll skip at least n.
*
* This is interesting, because we can pick a point along this line segment
* and see which skip count's range it falls within; the point X above, for
* example, is within the ">= 2" range, but not within the ">= 3" range, so it
* designates a skip count of 2. So if we pick points on the line at random
* and use the skip counts they fall under, that will be indistinguishable
* from generating a fresh random number between 0 and 1 for each trial and
* comparing it to P.
*
* So to find the skip count for a point X, we must ask: To what whole power
* must we raise 1-P such that we include X, but the next power would exclude
* it? This is exactly std::floor(std::log(X) / std::log(1-P)).
*
* Our algorithm is then, simply: When constructed, compute an initial skip
* count. Return false from |trial| that many times, and then compute a new skip
* count.
*
* For a call to |trial(n)|, if the skip count is greater than n, return false
* and subtract n from the skip count. If the skip count is less than n,
* return true and compute a new skip count. Since each trial is independent,
* it doesn't matter by how much n overshoots the skip count; we can actually
* compute a new skip count at *any* time without affecting the distribution.
* This is really beautiful.
*/
public:
/**
* Construct a fast Bernoulli trial generator. Calls to |trial()| return true
* with probability |aProbability|. Use |aState0| and |aState1| to seed the
* random number generator; both may not be zero.
*/
FastBernoulliTrial(double aProbability, uint64_t aState0, uint64_t aState1)
: mProbability(0)
, mInvLogNotProbability(0)
, mGenerator(aState0, aState1)
, mSkipCount(0)
{
setProbability(aProbability);
}
/**
* Return true with probability |mProbability|. Call this each time an event
* occurs, to decide whether to sample it or not. The lower |mProbability| is,
* the faster this function runs.
*/
bool trial() {
if (mSkipCount) {
mSkipCount--;
return false;
}
return chooseSkipCount();
}
/**
* Equivalent to calling trial() |n| times, and returning true if any of those
* calls do. However, like trial, this runs in fast constant time.
*
* What is this good for? In some applications, some events are "bigger" than
* others. For example, large allocations are more significant than small
* allocations. Perhaps we'd like to imagine that we're drawing allocations
* from a stream of bytes, and performing a separate Bernoulli trial on every
* byte from the stream. We can accomplish this by calling |t.trial(S)| for
* the number of bytes S, and sampling the event if that returns true.
*
* Of course, this style of sampling needs to be paired with analysis and
* presentation that makes the "size" of the event apparent, lest trials with
* large values for |n| appear to be indistinguishable from those with small
* values for |n|, despite being potentially much more likely to be sampled.
*/
bool trial(size_t aCount) {
if (mSkipCount > aCount) {
mSkipCount -= aCount;
return false;
}
return chooseSkipCount();
}
void setRandomState(uint64_t aState0, uint64_t aState1) {
mGenerator.setState(aState0, aState1);
}
void setProbability(double aProbability) {
MOZ_ASSERT(0 <= aProbability && aProbability <= 1);
mProbability = aProbability;
if (0 < mProbability && mProbability < 1) {
/*
* Let's look carefully at how this calculation plays out in floating-
* point arithmetic. We'll assume IEEE, but the final C++ code we arrive
* at would still be fine if our numbers were mathematically perfect. So,
* while we've considered IEEE's edge cases, we haven't done anything that
* should be actively bad when using other representations.
*
* (In the below, read comparisons as exact mathematical comparisons: when
* we say something "equals 1", that means it's exactly equal to 1. We
* treat approximation using intervals with open boundaries: saying a
* value is in (0,1) doesn't specify how close to 0 or 1 the value gets.
* When we use closed boundaries like [2**-53, 1], we're careful to ensure
* the boundary values are actually representable.)
*
* - After the comparison above, we know mProbability is in (0,1).
*
* - The gaps below 1 are 2**-53, so that interval is (0, 1-2**-53].
*
* - Because the floating-point gaps near 1 are wider than those near
* zero, there are many small positive doubles ε such that 1-ε rounds to
* exactly 1. However, 2**-53 can be represented exactly. So
* 1-mProbability is in [2**-53, 1].
*
* - log(1 - mProbability) is thus in (-37, 0].
*
* That range includes zero, but when we use mInvLogNotProbability, it
* would be helpful if we could trust that it's negative. So when log(1
* - mProbability) is 0, we'll just set mProbability to 0, so that
* mInvLogNotProbability is not used in chooseSkipCount.
*
* - How much of the range of mProbability does this cause us to ignore?
* The only value for which log returns 0 is exactly 1; the slope of log
* at 1 is 1, so for small ε such that 1 - ε != 1, log(1 - ε) is -ε,
* never 0. The gaps near one are larger than the gaps near zero, so if
* 1 - ε wasn't 1, then -ε is representable. So if log(1 - mProbability)
* isn't 0, then 1 - mProbability isn't 1, which means that mProbability
* is at least 2**-53, as discussed earlier. This is a sampling
* likelihood of roughly one in ten trillion, which is unlikely to be
* distinguishable from zero in practice.
*
* So by forbidding zero, we've tightened our range to (-37, -2**-53].
*
* - Finally, 1 / log(1 - mProbability) is in [-2**53, -1/37). This all
* falls readily within the range of an IEEE double.
*
* ALL THAT HAVING BEEN SAID: here are the five lines of actual code:
*/
double logNotProbability = std::log(1 - mProbability);
if (logNotProbability == 0.0)
mProbability = 0.0;
else
mInvLogNotProbability = 1 / logNotProbability;
}
chooseSkipCount();
}
private:
/* The likelihood that any given call to |trial| should return true. */
double mProbability;
/*
* The value of 1/std::log(1 - mProbability), cached for repeated use.
*
* If mProbability is exactly 0 or exactly 1, we don't use this value.
* Otherwise, we guarantee this value is in the range [-2**53, -1/37), i.e.
* definitely negative, as required by chooseSkipCount. See setProbability for
* the details.
*/
double mInvLogNotProbability;
/* Our random number generator. */
non_crypto::XorShift128PlusRNG mGenerator;
/* The number of times |trial| should return false before next returning true. */
size_t mSkipCount;
/*
* Choose the next skip count. This also returns the value that |trial| should
* return, since we have to check for the extreme values for mProbability
* anyway, and |trial| should never return true at all when mProbability is 0.
*/
bool chooseSkipCount() {
/*
* If the probability is 1.0, every call to |trial| returns true. Make sure
* mSkipCount is 0.
*/
if (mProbability == 1.0) {
mSkipCount = 0;
return true;
}
/*
* If the probabilility is zero, |trial| never returns true. Don't bother us
* for a while.
*/
if (mProbability == 0.0) {
mSkipCount = SIZE_MAX;
return false;
}
/*
* What sorts of values can this call to std::floor produce?
*
* Since mGenerator.nextDouble returns a value in [0, 1-2**-53], std::log
* returns a value in the range [-infinity, -2**-53], all negative. Since
* mInvLogNotProbability is negative (see its comments), the product is
* positive and possibly infinite. std::floor returns +infinity unchanged.
* So the result will always be positive.
*
* Converting a double to an integer that is out of range for that integer
* is undefined behavior, so we must clamp our result to SIZE_MAX, to ensure
* we get an acceptable value for mSkipCount.
*
* The clamp is written carefully. Note that if we had said:
*
* if (skipCount > SIZE_MAX)
* skipCount = SIZE_MAX;
*
* that leads to undefined behavior 64-bit machines: SIZE_MAX coerced to
* double is 2^64, not 2^64-1, so this doesn't actually set skipCount to a
* value that can be safely assigned to mSkipCount.
*
* Jakub Oleson cleverly suggested flipping the sense of the comparison: if
* we require that skipCount < SIZE_MAX, then because of the gaps (2048)
* between doubles at that magnitude, the highest double less than 2^64 is
* 2^64 - 2048, which is fine to store in a size_t.
*
* (On 32-bit machines, all size_t values can be represented exactly in
* double, so all is well.)
*/
double skipCount = std::floor(std::log(mGenerator.nextDouble())
* mInvLogNotProbability);
if (skipCount < SIZE_MAX)
mSkipCount = skipCount;
else
mSkipCount = SIZE_MAX;
return true;
}
};
} /* namespace mozilla */
#endif /* mozilla_FastBernoulliTrial_h */

View File

@@ -0,0 +1,479 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Various predicates and operations on IEEE-754 floating point types. */
#ifndef mozilla_FloatingPoint_h
#define mozilla_FloatingPoint_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Casting.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Types.h"
#include <stdint.h>
namespace mozilla {
/*
* It's reasonable to ask why we have this header at all. Don't isnan,
* copysign, the built-in comparison operators, and the like solve these
* problems? Unfortunately, they don't. We've found that various compilers
* (MSVC, MSVC when compiling with PGO, and GCC on OS X, at least) miscompile
* the standard methods in various situations, so we can't use them. Some of
* these compilers even have problems compiling seemingly reasonable bitwise
* algorithms! But with some care we've found algorithms that seem to not
* trigger those compiler bugs.
*
* For the aforementioned reasons, be very wary of making changes to any of
* these algorithms. If you must make changes, keep a careful eye out for
* compiler bustage, particularly PGO-specific bustage.
*/
struct FloatTypeTraits
{
typedef uint32_t Bits;
static const unsigned kExponentBias = 127;
static const unsigned kExponentShift = 23;
static const Bits kSignBit = 0x80000000UL;
static const Bits kExponentBits = 0x7F800000UL;
static const Bits kSignificandBits = 0x007FFFFFUL;
};
struct DoubleTypeTraits
{
typedef uint64_t Bits;
static const unsigned kExponentBias = 1023;
static const unsigned kExponentShift = 52;
static const Bits kSignBit = 0x8000000000000000ULL;
static const Bits kExponentBits = 0x7ff0000000000000ULL;
static const Bits kSignificandBits = 0x000fffffffffffffULL;
};
template<typename T> struct SelectTrait;
template<> struct SelectTrait<float> : public FloatTypeTraits {};
template<> struct SelectTrait<double> : public DoubleTypeTraits {};
/*
* This struct contains details regarding the encoding of floating-point
* numbers that can be useful for direct bit manipulation. As of now, the
* template parameter has to be float or double.
*
* The nested typedef |Bits| is the unsigned integral type with the same size
* as T: uint32_t for float and uint64_t for double (static assertions
* double-check these assumptions).
*
* kExponentBias is the offset that is subtracted from the exponent when
* computing the value, i.e. one plus the opposite of the mininum possible
* exponent.
* kExponentShift is the shift that one needs to apply to retrieve the
* exponent component of the value.
*
* kSignBit contains a bits mask. Bit-and-ing with this mask will result in
* obtaining the sign bit.
* kExponentBits contains the mask needed for obtaining the exponent bits and
* kSignificandBits contains the mask needed for obtaining the significand
* bits.
*
* Full details of how floating point number formats are encoded are beyond
* the scope of this comment. For more information, see
* http://en.wikipedia.org/wiki/IEEE_floating_point
* http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers
*/
template<typename T>
struct FloatingPoint : public SelectTrait<T>
{
typedef SelectTrait<T> Base;
typedef typename Base::Bits Bits;
static_assert((Base::kSignBit & Base::kExponentBits) == 0,
"sign bit shouldn't overlap exponent bits");
static_assert((Base::kSignBit & Base::kSignificandBits) == 0,
"sign bit shouldn't overlap significand bits");
static_assert((Base::kExponentBits & Base::kSignificandBits) == 0,
"exponent bits shouldn't overlap significand bits");
static_assert((Base::kSignBit | Base::kExponentBits | Base::kSignificandBits) ==
~Bits(0),
"all bits accounted for");
/*
* These implementations assume float/double are 32/64-bit single/double
* format number types compatible with the IEEE-754 standard. C++ don't
* require this to be the case. But we required this in implementations of
* these algorithms that preceded this header, so we shouldn't break anything
* if we keep doing so.
*/
static_assert(sizeof(T) == sizeof(Bits), "Bits must be same size as T");
};
/** Determines whether a float/double is NaN. */
template<typename T>
static MOZ_ALWAYS_INLINE bool
IsNaN(T aValue)
{
/*
* A float/double is NaN if all exponent bits are 1 and the significand
* contains at least one non-zero bit.
*/
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
return (BitwiseCast<Bits>(aValue) & Traits::kExponentBits) == Traits::kExponentBits &&
(BitwiseCast<Bits>(aValue) & Traits::kSignificandBits) != 0;
}
/** Determines whether a float/double is +Infinity or -Infinity. */
template<typename T>
static MOZ_ALWAYS_INLINE bool
IsInfinite(T aValue)
{
/* Infinities have all exponent bits set to 1 and an all-0 significand. */
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
Bits bits = BitwiseCast<Bits>(aValue);
return (bits & ~Traits::kSignBit) == Traits::kExponentBits;
}
/** Determines whether a float/double is not NaN or infinite. */
template<typename T>
static MOZ_ALWAYS_INLINE bool
IsFinite(T aValue)
{
/*
* NaN and Infinities are the only non-finite floats/doubles, and both have
* all exponent bits set to 1.
*/
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
Bits bits = BitwiseCast<Bits>(aValue);
return (bits & Traits::kExponentBits) != Traits::kExponentBits;
}
/**
* Determines whether a float/double is negative or -0. It is an error
* to call this method on a float/double which is NaN.
*/
template<typename T>
static MOZ_ALWAYS_INLINE bool
IsNegative(T aValue)
{
MOZ_ASSERT(!IsNaN(aValue), "NaN does not have a sign");
/* The sign bit is set if the double is negative. */
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
Bits bits = BitwiseCast<Bits>(aValue);
return (bits & Traits::kSignBit) != 0;
}
/** Determines whether a float/double represents -0. */
template<typename T>
static MOZ_ALWAYS_INLINE bool
IsNegativeZero(T aValue)
{
/* Only the sign bit is set if the value is -0. */
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
Bits bits = BitwiseCast<Bits>(aValue);
return bits == Traits::kSignBit;
}
/** Determines wether a float/double represents +0. */
template<typename T>
static MOZ_ALWAYS_INLINE bool
IsPositiveZero(T aValue)
{
/* All bits are zero if the value is +0. */
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
Bits bits = BitwiseCast<Bits>(aValue);
return bits == 0;
}
/**
* Returns 0 if a float/double is NaN or infinite;
* otherwise, the float/double is returned.
*/
template<typename T>
static MOZ_ALWAYS_INLINE T
ToZeroIfNonfinite(T aValue)
{
return IsFinite(aValue) ? aValue : 0;
}
/**
* Returns the exponent portion of the float/double.
*
* Zero is not special-cased, so ExponentComponent(0.0) is
* -int_fast16_t(Traits::kExponentBias).
*/
template<typename T>
static MOZ_ALWAYS_INLINE int_fast16_t
ExponentComponent(T aValue)
{
/*
* The exponent component of a float/double is an unsigned number, biased
* from its actual value. Subtract the bias to retrieve the actual exponent.
*/
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
Bits bits = BitwiseCast<Bits>(aValue);
return int_fast16_t((bits & Traits::kExponentBits) >> Traits::kExponentShift) -
int_fast16_t(Traits::kExponentBias);
}
/** Returns +Infinity. */
template<typename T>
static MOZ_ALWAYS_INLINE T
PositiveInfinity()
{
/*
* Positive infinity has all exponent bits set, sign bit set to 0, and no
* significand.
*/
typedef FloatingPoint<T> Traits;
return BitwiseCast<T>(Traits::kExponentBits);
}
/** Returns -Infinity. */
template<typename T>
static MOZ_ALWAYS_INLINE T
NegativeInfinity()
{
/*
* Negative infinity has all exponent bits set, sign bit set to 1, and no
* significand.
*/
typedef FloatingPoint<T> Traits;
return BitwiseCast<T>(Traits::kSignBit | Traits::kExponentBits);
}
/**
* Computes the bit pattern for a NaN with the specified sign bit and
* significand bits.
*/
template<typename T,
int SignBit,
typename FloatingPoint<T>::Bits Significand>
struct SpecificNaNBits
{
using Traits = FloatingPoint<T>;
static_assert(SignBit == 0 || SignBit == 1, "bad sign bit");
static_assert((Significand & ~Traits::kSignificandBits) == 0,
"significand must only have significand bits set");
static_assert(Significand & Traits::kSignificandBits,
"significand must be nonzero");
static constexpr typename Traits::Bits value =
(SignBit * Traits::kSignBit) | Traits::kExponentBits | Significand;
};
/**
* Constructs a NaN value with the specified sign bit and significand bits.
*
* There is also a variant that returns the value directly. In most cases, the
* two variants should be identical. However, in the specific case of x86
* chips, the behavior differs: returning floating-point values directly is done
* through the x87 stack, and x87 loads and stores turn signaling NaNs into
* quiet NaNs... silently. Returning floating-point values via outparam,
* however, is done entirely within the SSE registers when SSE2 floating-point
* is enabled in the compiler, which has semantics-preserving behavior you would
* expect.
*
* If preserving the distinction between signaling NaNs and quiet NaNs is
* important to you, you should use the outparam version. In all other cases,
* you should use the direct return version.
*/
template<typename T>
static MOZ_ALWAYS_INLINE void
SpecificNaN(int signbit, typename FloatingPoint<T>::Bits significand, T* result)
{
typedef FloatingPoint<T> Traits;
MOZ_ASSERT(signbit == 0 || signbit == 1);
MOZ_ASSERT((significand & ~Traits::kSignificandBits) == 0);
MOZ_ASSERT(significand & Traits::kSignificandBits);
BitwiseCast<T>((signbit ? Traits::kSignBit : 0) |
Traits::kExponentBits |
significand,
result);
MOZ_ASSERT(IsNaN(*result));
}
template<typename T>
static MOZ_ALWAYS_INLINE T
SpecificNaN(int signbit, typename FloatingPoint<T>::Bits significand)
{
T t;
SpecificNaN(signbit, significand, &t);
return t;
}
/** Computes the smallest non-zero positive float/double value. */
template<typename T>
static MOZ_ALWAYS_INLINE T
MinNumberValue()
{
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
return BitwiseCast<T>(Bits(1));
}
/**
* If aValue is equal to some int32_t value, set *aInt32 to that value and
* return true; otherwise return false.
*
* Note that negative zero is "equal" to zero here. To test whether a value can
* be losslessly converted to int32_t and back, use NumberIsInt32 instead.
*/
template<typename T>
static MOZ_ALWAYS_INLINE bool
NumberEqualsInt32(T aValue, int32_t* aInt32)
{
/*
* XXX Casting a floating-point value that doesn't truncate to int32_t, to
* int32_t, induces undefined behavior. We should definitely fix this
* (bug 744965), but as apparently it "works" in practice, it's not a
* pressing concern now.
*/
return aValue == (*aInt32 = int32_t(aValue));
}
/**
* If d can be converted to int32_t and back to an identical double value,
* set *aInt32 to that value and return true; otherwise return false.
*
* The difference between this and NumberEqualsInt32 is that this method returns
* false for negative zero.
*/
template<typename T>
static MOZ_ALWAYS_INLINE bool
NumberIsInt32(T aValue, int32_t* aInt32)
{
return !IsNegativeZero(aValue) && NumberEqualsInt32(aValue, aInt32);
}
/**
* Computes a NaN value. Do not use this method if you depend upon a particular
* NaN value being returned.
*/
template<typename T>
static MOZ_ALWAYS_INLINE T
UnspecifiedNaN()
{
/*
* If we can use any quiet NaN, we might as well use the all-ones NaN,
* since it's cheap to materialize on common platforms (such as x64, where
* this value can be represented in a 32-bit signed immediate field, allowing
* it to be stored to memory in a single instruction).
*/
typedef FloatingPoint<T> Traits;
return SpecificNaN<T>(1, Traits::kSignificandBits);
}
/**
* Compare two doubles for equality, *without* equating -0 to +0, and equating
* any NaN value to any other NaN value. (The normal equality operators equate
* -0 with +0, and they equate NaN to no other value.)
*/
template<typename T>
static inline bool
NumbersAreIdentical(T aValue1, T aValue2)
{
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
if (IsNaN(aValue1)) {
return IsNaN(aValue2);
}
return BitwiseCast<Bits>(aValue1) == BitwiseCast<Bits>(aValue2);
}
namespace detail {
template<typename T>
struct FuzzyEqualsEpsilon;
template<>
struct FuzzyEqualsEpsilon<float>
{
// A number near 1e-5 that is exactly representable in a float.
static float value() { return 1.0f / (1 << 17); }
};
template<>
struct FuzzyEqualsEpsilon<double>
{
// A number near 1e-12 that is exactly representable in a double.
static double value() { return 1.0 / (1LL << 40); }
};
} // namespace detail
/**
* Compare two floating point values for equality, modulo rounding error. That
* is, the two values are considered equal if they are both not NaN and if they
* are less than or equal to aEpsilon apart. The default value of aEpsilon is
* near 1e-5.
*
* For most scenarios you will want to use FuzzyEqualsMultiplicative instead,
* as it is more reasonable over the entire range of floating point numbers.
* This additive version should only be used if you know the range of the
* numbers you are dealing with is bounded and stays around the same order of
* magnitude.
*/
template<typename T>
static MOZ_ALWAYS_INLINE bool
FuzzyEqualsAdditive(T aValue1, T aValue2,
T aEpsilon = detail::FuzzyEqualsEpsilon<T>::value())
{
static_assert(IsFloatingPoint<T>::value, "floating point type required");
return Abs(aValue1 - aValue2) <= aEpsilon;
}
/**
* Compare two floating point values for equality, allowing for rounding error
* relative to the magnitude of the values. That is, the two values are
* considered equal if they are both not NaN and they are less than or equal to
* some aEpsilon apart, where the aEpsilon is scaled by the smaller of the two
* argument values.
*
* In most cases you will want to use this rather than FuzzyEqualsAdditive, as
* this function effectively masks out differences in the bottom few bits of
* the floating point numbers being compared, regardless of what order of
* magnitude those numbers are at.
*/
template<typename T>
static MOZ_ALWAYS_INLINE bool
FuzzyEqualsMultiplicative(T aValue1, T aValue2,
T aEpsilon = detail::FuzzyEqualsEpsilon<T>::value())
{
static_assert(IsFloatingPoint<T>::value, "floating point type required");
// can't use std::min because of bug 965340
T smaller = Abs(aValue1) < Abs(aValue2) ? Abs(aValue1) : Abs(aValue2);
return Abs(aValue1 - aValue2) <= aEpsilon * smaller;
}
/**
* Returns true if the given value can be losslessly represented as an IEEE-754
* single format number, false otherwise. All NaN values are considered
* representable (notwithstanding that the exact bit pattern of a double format
* NaN value can't be exactly represented in single format).
*
* This function isn't inlined to avoid buggy optimizations by MSVC.
*/
MOZ_MUST_USE
extern MFBT_API bool
IsFloat32Representable(double aFloat32);
} /* namespace mozilla */
#endif /* mozilla_FloatingPoint_h */

View File

@@ -0,0 +1,223 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A type-erased callable wrapper. */
#ifndef mozilla_Function_h
#define mozilla_Function_h
#include "mozilla/Attributes.h" // for MOZ_IMPLICIT
#include "mozilla/Move.h"
#include "mozilla/RefCounted.h"
#include "mozilla/RefPtr.h"
// |function<Signature>| is a wrapper that can hold any type of callable
// object that can be invoked in a way that's compatible with |Signature|.
// The standard "type erasure" technique is used to avoid the type of the
// wrapper depending on the concrete type of the wrapped callable.
//
// Supported callable types include non-member functions, static member
// functions, and function objects (that is to say, objects with an overloaded
// call operator; this includes C++11 lambdas). Member functions aren't
// directly supported; they first need to be wrapped into a function object
// using |std::mem_fn()| or an equivalent.
//
// |Signature| is a type of the form |ReturnType(Arguments...)|. Syntactically,
// this is a function type; it's not used in any way other than serving as a
// vehicle to encode the return and argument types into a single type.
//
// |function| is default-constructible. A default-constructed instance is
// considered "empty". Invoking an empty instance is undefined behaviour.
// An empty instance can be populated with a callable by assigning to it.
//
// This class is intended to provide functionality similar to the C++11
// standard library class |std::function|.
namespace mozilla {
namespace detail {
template<typename ReturnType, typename... Arguments>
class FunctionImplBase : public mozilla::RefCounted<FunctionImplBase<ReturnType, Arguments...>>
{
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(FunctionImplBase)
virtual ~FunctionImplBase() {}
virtual ReturnType call(Arguments... aArguments) = 0;
};
// Normal Callable Object.
template <typename Callable, typename ReturnType, typename... Arguments>
class FunctionImpl : public FunctionImplBase<ReturnType, Arguments...>
{
public:
explicit FunctionImpl(const Callable& aCallable)
: mCallable(aCallable) {}
ReturnType call(Arguments... aArguments) override
{
return mCallable(Forward<Arguments>(aArguments)...);
}
private:
Callable mCallable;
};
// Base class for passing pointer to member function.
template <typename Callable, typename ReturnType, typename... Arguments>
class MemberFunctionImplBase : public FunctionImplBase<ReturnType, Arguments...>
{
public:
explicit MemberFunctionImplBase(const Callable& aCallable)
: mCallable(aCallable) {}
ReturnType call(Arguments... aArguments) override
{
return callInternal(Forward<Arguments>(aArguments)...);
}
private:
template<typename ThisType, typename... Args>
ReturnType callInternal(ThisType* aThis, Args&&... aArguments)
{
return (aThis->*mCallable)(Forward<Args>(aArguments)...);
}
template<typename ThisType, typename... Args>
ReturnType callInternal(ThisType&& aThis, Args&&... aArguments)
{
return (aThis.*mCallable)(Forward<Args>(aArguments)...);
}
Callable mCallable;
};
// For non-const member function specialization of FunctionImpl.
template <typename ThisType, typename... Args, typename ReturnType, typename... Arguments>
class FunctionImpl<ReturnType(ThisType::*)(Args...),
ReturnType, Arguments...>
: public MemberFunctionImplBase<ReturnType(ThisType::*)(Args...),
ReturnType, Arguments...>
{
public:
explicit FunctionImpl(ReturnType(ThisType::*aMemberFunc)(Args...))
: MemberFunctionImplBase<ReturnType(ThisType::*)(Args...),
ReturnType, Arguments...>(aMemberFunc)
{}
};
// For const member function specialization of FunctionImpl.
template <typename ThisType, typename... Args, typename ReturnType, typename... Arguments>
class FunctionImpl<ReturnType(ThisType::*)(Args...) const,
ReturnType, Arguments...>
: public MemberFunctionImplBase<ReturnType(ThisType::*)(Args...) const,
ReturnType, Arguments...>
{
public:
explicit FunctionImpl(ReturnType(ThisType::*aConstMemberFunc)(Args...) const)
: MemberFunctionImplBase<ReturnType(ThisType::*)(Args...) const,
ReturnType, Arguments...>(aConstMemberFunc)
{}
};
} // namespace detail
// The primary template is never defined. As |Signature| is required to be
// of the form |ReturnType(Arguments...)|, we only define a partial
// specialization that matches this form. This allows us to use |ReturnType|
// and |Arguments| in the definition of the specialization without having to
// introspect |Signature|.
template<typename Signature>
class function;
template<typename ReturnType, typename... Arguments>
class function<ReturnType(Arguments...)>
{
public:
function() {}
// This constructor is implicit to match the interface of |std::function|.
template <typename Callable>
MOZ_IMPLICIT function(const Callable& aCallable)
: mImpl(new detail::FunctionImpl<Callable, ReturnType, Arguments...>(aCallable))
{}
MOZ_IMPLICIT function(const function& aFunction)
: mImpl(aFunction.mImpl)
{}
MOZ_IMPLICIT function(decltype(nullptr))
{}
// Move constructor and move assingment operator.
// These should be generated automatically, but MSVC doesn't do that yet.
function(function&& aOther) : mImpl(Move(aOther.mImpl)) {}
function& operator=(function&& aOther) {
mImpl = Move(aOther.mImpl);
return *this;
}
template <typename Callable>
function& operator=(const Callable& aCallable)
{
mImpl = new detail::FunctionImpl<Callable, ReturnType, Arguments...>(aCallable);
return *this;
}
function& operator=(const function& aFunction)
{
mImpl = aFunction.mImpl;
return *this;
}
function& operator=(decltype(nullptr))
{
mImpl = nullptr;
return *this;
}
template<typename... Args>
ReturnType operator()(Args&&... aArguments) const
{
MOZ_ASSERT(mImpl);
return mImpl->call(Forward<Args>(aArguments)...);
}
explicit operator bool() const
{
return bool(mImpl);
}
private:
// TODO: Consider implementing a small object optimization.
RefPtr<detail::FunctionImplBase<ReturnType, Arguments...>> mImpl;
};
template<typename Signature>
bool
operator==(const function<Signature>& aX, decltype(nullptr))
{
return !aX;
}
template<typename Signature>
bool
operator==(decltype(nullptr), const function<Signature>& aX)
{
return !aX;
}
template<typename Signature>
bool
operator!=(const function<Signature>& aX, decltype(nullptr))
{
return bool(aX);
}
template<typename Signature>
bool
operator!=(decltype(nullptr), const function<Signature>& aX)
{
return bool(aX);
}
} // namespace mozilla
#endif /* mozilla_Function_h */

View File

@@ -0,0 +1,167 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implementation of macros to ensure correct use of RAII Auto* objects. */
#ifndef mozilla_GuardObjects_h
#define mozilla_GuardObjects_h
#include "mozilla/Assertions.h"
#include "mozilla/Move.h"
#include "mozilla/Types.h"
#ifdef __cplusplus
#ifdef DEBUG
/**
* A custom define is used rather than |mozPoisonValue()| due to cascading
* build failures relating to how mfbt is linked on different operating
* systems. See bug 1160253.
*/
#define MOZ_POISON uintptr_t(-1)
namespace mozilla {
namespace detail {
/*
* The following classes are designed to cause assertions to detect
* inadvertent use of guard objects as temporaries. In other words,
* when we have a guard object whose only purpose is its constructor and
* destructor (and is never otherwise referenced), the intended use
* might be:
*
* AutoRestore savePainting(mIsPainting);
*
* but is is easy to accidentally write:
*
* AutoRestore(mIsPainting);
*
* which compiles just fine, but runs the destructor well before the
* intended time.
*
* They work by adding (#ifdef DEBUG) an additional parameter to the
* guard object's constructor, with a default value, so that users of
* the guard object's API do not need to do anything. The default value
* of this parameter is a temporary object. C++ (ISO/IEC 14882:1998),
* section 12.2 [class.temporary], clauses 4 and 5 seem to assume a
* guarantee that temporaries are destroyed in the reverse of their
* construction order, but I actually can't find a statement that that
* is true in the general case (beyond the two specific cases mentioned
* there). However, it seems to be true.
*
* These classes are intended to be used only via the macros immediately
* below them:
*
* MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member
* variable, and should be put where a declaration of a private
* member variable would be placed.
* MOZ_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the
* parameters to each constructor of the guard object; it declares
* (ifdef DEBUG) an additional parameter. (But use the *_ONLY_PARAM
* variant for constructors that take no other parameters.)
* MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL should likewise be used in
* the implementation of such constructors when they are not inline.
* MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT should be used in
* the implementation of such constructors to pass the parameter to
* a base class that also uses these macros
* MOZ_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each
* constructor. It uses the parameter declared by
* MOZ_GUARD_OBJECT_NOTIFIER_PARAM.
*
* For more details, and examples of using these macros, see
* https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla
*/
class GuardObjectNotifier
{
private:
bool* mStatementDone;
public:
GuardObjectNotifier()
: mStatementDone(reinterpret_cast<bool*>(MOZ_POISON))
{
}
~GuardObjectNotifier()
{
// Assert that the GuardObjectNotifier has been properly initialized by
// using the |MOZ_GUARD_OBJECT_NOTIFIER_INIT| macro. A poison value is
// used rather than a null check to appease static analyzers that were
// (incorrectly) detecting null pointer dereferences.
MOZ_ASSERT(mStatementDone != reinterpret_cast<bool*>(MOZ_POISON));
*mStatementDone = true;
}
void setStatementDone(bool* aStatementIsDone)
{
mStatementDone = aStatementIsDone;
}
};
class GuardObjectNotificationReceiver
{
private:
bool mStatementDone;
public:
GuardObjectNotificationReceiver() : mStatementDone(false) { }
~GuardObjectNotificationReceiver() {
/*
* Assert that the guard object was not used as a temporary. (Note that
* this assert might also fire if init is not called because the guard
* object's implementation is not using the above macros correctly.)
*/
MOZ_ASSERT(mStatementDone);
}
void init(GuardObjectNotifier& aNotifier)
{
aNotifier.setStatementDone(&mStatementDone);
}
};
} /* namespace detail */
} /* namespace mozilla */
#undef MOZ_POISON
#endif /* DEBUG */
#ifdef DEBUG
# define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \
mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary;
# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \
, mozilla::detail::GuardObjectNotifier&& _notifier = \
mozilla::detail::GuardObjectNotifier()
# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \
mozilla::detail::GuardObjectNotifier&& _notifier = \
mozilla::detail::GuardObjectNotifier()
# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \
, mozilla::detail::GuardObjectNotifier&& _notifier
# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \
mozilla::detail::GuardObjectNotifier&& _notifier
# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \
, mozilla::Move(_notifier)
# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \
mozilla::Move(_notifier)
# define MOZ_GUARD_OBJECT_NOTIFIER_INIT \
do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0)
#else
# define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM
# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM
# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL
# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL
# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT
# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
# define MOZ_GUARD_OBJECT_NOTIFIER_INIT do { } while (0)
#endif
#endif /* __cplusplus */
#endif /* mozilla_GuardObjects_h */

View File

@@ -0,0 +1,389 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Utilities for hashing. */
/*
* This file exports functions for hashing data down to a 32-bit value,
* including:
*
* - HashString Hash a char* or char16_t/wchar_t* of known or unknown
* length.
*
* - HashBytes Hash a byte array of known length.
*
* - HashGeneric Hash one or more values. Currently, we support uint32_t,
* types which can be implicitly cast to uint32_t, data
* pointers, and function pointers.
*
* - AddToHash Add one or more values to the given hash. This supports the
* same list of types as HashGeneric.
*
*
* You can chain these functions together to hash complex objects. For example:
*
* class ComplexObject
* {
* char* mStr;
* uint32_t mUint1, mUint2;
* void (*mCallbackFn)();
*
* public:
* uint32_t hash()
* {
* uint32_t hash = HashString(mStr);
* hash = AddToHash(hash, mUint1, mUint2);
* return AddToHash(hash, mCallbackFn);
* }
* };
*
* If you want to hash an nsAString or nsACString, use the HashString functions
* in nsHashKeys.h.
*/
#ifndef mozilla_HashFunctions_h
#define mozilla_HashFunctions_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Char16.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Types.h"
#include <stdint.h>
#ifdef __cplusplus
namespace mozilla {
/**
* The golden ratio as a 32-bit fixed-point value.
*/
static const uint32_t kGoldenRatioU32 = 0x9E3779B9U;
inline uint32_t
RotateBitsLeft32(uint32_t aValue, uint8_t aBits)
{
MOZ_ASSERT(aBits < 32);
return (aValue << aBits) | (aValue >> (32 - aBits));
}
namespace detail {
inline uint32_t
AddU32ToHash(uint32_t aHash, uint32_t aValue)
{
/*
* This is the meat of all our hash routines. This hash function is not
* particularly sophisticated, but it seems to work well for our mostly
* plain-text inputs. Implementation notes follow.
*
* Our use of the golden ratio here is arbitrary; we could pick almost any
* number which:
*
* * is odd (because otherwise, all our hash values will be even)
*
* * has a reasonably-even mix of 1's and 0's (consider the extreme case
* where we multiply by 0x3 or 0xeffffff -- this will not produce good
* mixing across all bits of the hash).
*
* The rotation length of 5 is also arbitrary, although an odd number is again
* preferable so our hash explores the whole universe of possible rotations.
*
* Finally, we multiply by the golden ratio *after* xor'ing, not before.
* Otherwise, if |aHash| is 0 (as it often is for the beginning of a
* message), the expression
*
* (kGoldenRatioU32 * RotateBitsLeft(aHash, 5)) |xor| aValue
*
* evaluates to |aValue|.
*
* (Number-theoretic aside: Because any odd number |m| is relatively prime to
* our modulus (2^32), the list
*
* [x * m (mod 2^32) for 0 <= x < 2^32]
*
* has no duplicate elements. This means that multiplying by |m| does not
* cause us to skip any possible hash values.
*
* It's also nice if |m| has large-ish order mod 2^32 -- that is, if the
* smallest k such that m^k == 1 (mod 2^32) is large -- so we can safely
* multiply our hash value by |m| a few times without negating the
* multiplicative effect. Our golden ratio constant has order 2^29, which is
* more than enough for our purposes.)
*/
return kGoldenRatioU32 * (RotateBitsLeft32(aHash, 5) ^ aValue);
}
/**
* AddUintptrToHash takes sizeof(uintptr_t) as a template parameter.
*/
template<size_t PtrSize>
inline uint32_t
AddUintptrToHash(uint32_t aHash, uintptr_t aValue);
template<>
inline uint32_t
AddUintptrToHash<4>(uint32_t aHash, uintptr_t aValue)
{
return AddU32ToHash(aHash, static_cast<uint32_t>(aValue));
}
template<>
inline uint32_t
AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue)
{
/*
* The static cast to uint64_t below is necessary because this function
* sometimes gets compiled on 32-bit platforms (yes, even though it's a
* template and we never call this particular override in a 32-bit build). If
* we do aValue >> 32 on a 32-bit machine, we're shifting a 32-bit uintptr_t
* right 32 bits, and the compiler throws an error.
*/
uint32_t v1 = static_cast<uint32_t>(aValue);
uint32_t v2 = static_cast<uint32_t>(static_cast<uint64_t>(aValue) >> 32);
return AddU32ToHash(AddU32ToHash(aHash, v1), v2);
}
} /* namespace detail */
/**
* AddToHash takes a hash and some values and returns a new hash based on the
* inputs.
*
* Currently, we support hashing uint32_t's, values which we can implicitly
* convert to uint32_t, data pointers, and function pointers.
*/
template<typename A>
MOZ_MUST_USE inline uint32_t
AddToHash(uint32_t aHash, A aA)
{
/*
* Try to convert |A| to uint32_t implicitly. If this works, great. If not,
* we'll error out.
*/
return detail::AddU32ToHash(aHash, aA);
}
template<typename A>
MOZ_MUST_USE inline uint32_t
AddToHash(uint32_t aHash, A* aA)
{
/*
* You might think this function should just take a void*. But then we'd only
* catch data pointers and couldn't handle function pointers.
*/
static_assert(sizeof(aA) == sizeof(uintptr_t), "Strange pointer!");
return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, uintptr_t(aA));
}
template<>
MOZ_MUST_USE inline uint32_t
AddToHash(uint32_t aHash, uintptr_t aA)
{
return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, aA);
}
template<typename A, typename... Args>
MOZ_MUST_USE uint32_t
AddToHash(uint32_t aHash, A aArg, Args... aArgs)
{
return AddToHash(AddToHash(aHash, aArg), aArgs...);
}
/**
* The HashGeneric class of functions let you hash one or more values.
*
* If you want to hash together two values x and y, calling HashGeneric(x, y) is
* much better than calling AddToHash(x, y), because AddToHash(x, y) assumes
* that x has already been hashed.
*/
template<typename... Args>
MOZ_MUST_USE inline uint32_t
HashGeneric(Args... aArgs)
{
return AddToHash(0, aArgs...);
}
namespace detail {
template<typename T>
uint32_t
HashUntilZero(const T* aStr)
{
uint32_t hash = 0;
for (T c; (c = *aStr); aStr++) {
hash = AddToHash(hash, c);
}
return hash;
}
template<typename T>
uint32_t
HashKnownLength(const T* aStr, size_t aLength)
{
uint32_t hash = 0;
for (size_t i = 0; i < aLength; i++) {
hash = AddToHash(hash, aStr[i]);
}
return hash;
}
} /* namespace detail */
/**
* The HashString overloads below do just what you'd expect.
*
* If you have the string's length, you might as well call the overload which
* includes the length. It may be marginally faster.
*/
MOZ_MUST_USE inline uint32_t
HashString(const char* aStr)
{
return detail::HashUntilZero(reinterpret_cast<const unsigned char*>(aStr));
}
MOZ_MUST_USE inline uint32_t
HashString(const char* aStr, size_t aLength)
{
return detail::HashKnownLength(reinterpret_cast<const unsigned char*>(aStr), aLength);
}
MOZ_MUST_USE
inline uint32_t
HashString(const unsigned char* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
}
MOZ_MUST_USE inline uint32_t
HashString(const char16_t* aStr)
{
return detail::HashUntilZero(aStr);
}
MOZ_MUST_USE inline uint32_t
HashString(const char16_t* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
}
/*
* On Windows, wchar_t is not the same as char16_t, even though it's
* the same width!
*/
#ifdef WIN32
MOZ_MUST_USE inline uint32_t
HashString(const wchar_t* aStr)
{
return detail::HashUntilZero(aStr);
}
MOZ_MUST_USE inline uint32_t
HashString(const wchar_t* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
}
#endif
/**
* Hash some number of bytes.
*
* This hash walks word-by-word, rather than byte-by-byte, so you won't get the
* same result out of HashBytes as you would out of HashString.
*/
MOZ_MUST_USE extern MFBT_API uint32_t
HashBytes(const void* bytes, size_t aLength);
/**
* A pseudorandom function mapping 32-bit integers to 32-bit integers.
*
* This is for when you're feeding private data (like pointer values or credit
* card numbers) to a non-crypto hash function (like HashBytes) and then using
* the hash code for something that untrusted parties could observe (like a JS
* Map). Plug in a HashCodeScrambler before that last step to avoid leaking the
* private data.
*
* By itself, this does not prevent hash-flooding DoS attacks, because an
* attacker can still generate many values with exactly equal hash codes by
* attacking the non-crypto hash function alone. Equal hash codes will, of
* course, still be equal however much you scramble them.
*
* The algorithm is SipHash-1-3. See <https://131002.net/siphash/>.
*/
class HashCodeScrambler
{
struct SipHasher;
uint64_t mK0, mK1;
public:
/** Creates a new scrambler with the given 128-bit key. */
constexpr HashCodeScrambler(uint64_t aK0, uint64_t aK1) : mK0(aK0), mK1(aK1) {}
/**
* Scramble a hash code. Always produces the same result for the same
* combination of key and hash code.
*/
uint32_t scramble(uint32_t aHashCode) const
{
SipHasher hasher(mK0, mK1);
return uint32_t(hasher.sipHash(aHashCode));
}
private:
struct SipHasher
{
SipHasher(uint64_t aK0, uint64_t aK1)
{
// 1. Initialization.
mV0 = aK0 ^ UINT64_C(0x736f6d6570736575);
mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d);
mV2 = aK0 ^ UINT64_C(0x6c7967656e657261);
mV3 = aK1 ^ UINT64_C(0x7465646279746573);
}
uint64_t sipHash(uint64_t aM)
{
// 2. Compression.
mV3 ^= aM;
sipRound();
mV0 ^= aM;
// 3. Finalization.
mV2 ^= 0xff;
for (int i = 0; i < 3; i++)
sipRound();
return mV0 ^ mV1 ^ mV2 ^ mV3;
}
void sipRound()
{
mV0 += mV1;
mV1 = RotateLeft(mV1, 13);
mV1 ^= mV0;
mV0 = RotateLeft(mV0, 32);
mV2 += mV3;
mV3 = RotateLeft(mV3, 16);
mV3 ^= mV2;
mV0 += mV3;
mV3 = RotateLeft(mV3, 21);
mV3 ^= mV0;
mV2 += mV1;
mV1 = RotateLeft(mV1, 17);
mV1 ^= mV2;
mV2 = RotateLeft(mV2, 32);
}
uint64_t mV0, mV1, mV2, mV3;
};
};
} /* namespace mozilla */
#endif /* __cplusplus */
#endif /* mozilla_HashFunctions_h */

View File

@@ -0,0 +1,143 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A utility for expanding a tuple into a variadic argument list.
* Based on std::index_sequence. */
/**
* Example usage:
*
* Problem:
*
* You have a variadic function Foo:
*
* template <typename... Args> void Foo(Args...);
*
* And a variadic function Bar, which contains a tuple:
*
* template <typename... Args>
* void Bar() {
* // ...
* Tuple<Args...> t;
* }
*
* And inside Bar, you want to call Foo with the elements of the tuple as
* arguments to Foo.
*
* You want to write:
*
* Foo(Get<0>(t), Get<1>(t), ..., Get<N>(t))
*
* but you can't literally write that, because N is different for different
* instantiations of Bar.
*
* Solution:
*
* Write a helper function which takes the tuple, and an index sequence
* containing indices corresponding to the tuple indices.
*
* template <typename... Args, size_t... Indices>
* void Helper(const Tuple<Args...>& t, IndexSequence<Indices>)
* {
* Foo(Get<Indices>(t)...);
* }
*
* Assuming 'Indices...' are 0, 1, ..., N - 1, where N is the size of the
* tuple, pack expansion will expand the pack 'Get<Indices>(t)...' to
* 'Get<0>(t), Get<1>(t), ..., Get<N>(t)'.
*
* Finally, call the helper, creating the index sequence to pass in like so:
*
* template <typename... Args>
* void Bar() {
* // ...
* Tuple<Args...> t;
* Helper(t, typename IndexSequenceFor<Args...>::Type());
* }
*/
#ifndef mozilla_IndexSequence_h
#define mozilla_IndexSequence_h
#include "mozilla/Attributes.h"
#include <stddef.h>
namespace mozilla {
/**
* Represents a compile-time sequence of integer indices.
*/
template<size_t... Indices>
struct IndexSequence
{
static constexpr size_t Size() { return sizeof...(Indices); }
};
namespace detail {
// Helpers used by MakeIndexSequence.
template<size_t... Indices>
struct IndexTuple
{
typedef IndexTuple<Indices..., sizeof...(Indices)> Next;
};
// Builds IndexTuple<0, 1, ..., N - 1>.
template<size_t N>
struct BuildIndexTuple
{
typedef typename BuildIndexTuple<N - 1>::Type::Next Type;
};
template<>
struct BuildIndexTuple<0>
{
typedef IndexTuple<> Type;
};
template<size_t N, typename IndexTuple>
struct MakeIndexSequenceImpl;
template<size_t N, size_t... Indices>
struct MakeIndexSequenceImpl<N, IndexTuple<Indices...>>
{
typedef IndexSequence<Indices...> Type;
};
} // namespace detail
/**
* A utility for building an IndexSequence of consecutive indices.
* MakeIndexSequence<N>::Type evaluates to IndexSequence<0, 1, .., N - 1>.
* Note: unlike std::make_index_sequence, this is not an alias template
* to work around bugs in MSVC 2013.
*/
template<size_t N>
struct MakeIndexSequence
{
typedef typename detail::MakeIndexSequenceImpl<N,
typename detail::BuildIndexTuple<N>::Type>::Type Type;
};
/**
* A utility for building an IndexSequence of consecutive indices
* corresponding to a variadic argument list.
* IndexSequenceFor<Types...> evaluates to IndexSequence<0, 1, ..., N - 1>
* where N is the number of types in Types.
* Note: unlike std::index_sequence_for, this is not an alias template
* to work around bugs in MSVC 2013.
*/
template<typename... Types>
struct IndexSequenceFor
{
typedef typename MakeIndexSequence<sizeof...(Types)>::Type Type;
};
} // namespace mozilla
#endif /* mozilla_IndexSequence_h */

View File

@@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implements the C99 <inttypes.h> interface. */
#ifndef mozilla_IntegerPrintfMacros_h_
#define mozilla_IntegerPrintfMacros_h_
/*
* These macros should not be used with the NSPR printf-like functions or their
* users, e.g. mozilla/Logging.h. If you need to use NSPR's facilities, see the
* comment on supported formats at the top of nsprpub/pr/include/prprf.h.
*/
/*
* scanf is a footgun: if the input number exceeds the bounds of the target
* type, behavior is undefined (in the compiler sense: that is, this code
* could overwrite your hard drive with zeroes):
*
* uint8_t u;
* sscanf("256", "%" SCNu8, &u); // BAD
*
* For this reason, *never* use the SCN* macros provided by this header!
*/
#include <inttypes.h>
/*
* Fix up Android's broken [u]intptr_t inttype macros. Android's PRI*PTR
* macros are defined as "ld", but sizeof(long) is 8 and sizeof(intptr_t)
* is 4 on 32-bit Android. TestTypeTraits.cpp asserts that these new macro
* definitions match the actual type sizes seen at compile time.
*/
#if defined(ANDROID) && !defined(__LP64__)
# undef PRIdPTR /* intptr_t */
# define PRIdPTR "d" /* intptr_t */
# undef PRIiPTR /* intptr_t */
# define PRIiPTR "i" /* intptr_t */
# undef PRIoPTR /* uintptr_t */
# define PRIoPTR "o" /* uintptr_t */
# undef PRIuPTR /* uintptr_t */
# define PRIuPTR "u" /* uintptr_t */
# undef PRIxPTR /* uintptr_t */
# define PRIxPTR "x" /* uintptr_t */
# undef PRIXPTR /* uintptr_t */
# define PRIXPTR "X" /* uintptr_t */
#endif
#endif /* mozilla_IntegerPrintfMacros_h_ */

View File

@@ -0,0 +1,181 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Iterator over ranges of integers */
#ifndef mozilla_IntegerRange_h
#define mozilla_IntegerRange_h
#include "mozilla/Assertions.h"
#include "mozilla/ReverseIterator.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
namespace detail {
template<typename IntTypeT>
class IntegerIterator
{
public:
template<typename IntType>
explicit IntegerIterator(IntType aCurrent)
: mCurrent(aCurrent) { }
template<typename IntType>
explicit IntegerIterator(const IntegerIterator<IntType>& aOther)
: mCurrent(aOther.mCurrent) { }
IntTypeT operator*() const { return mCurrent; }
/* Increment and decrement operators */
IntegerIterator& operator++() { ++mCurrent; return *this; }
IntegerIterator& operator--() { --mCurrent; return *this; }
IntegerIterator operator++(int) { auto ret = *this; ++mCurrent; return ret; }
IntegerIterator operator--(int) { auto ret = *this; --mCurrent; return ret; }
/* Comparison operators */
template<typename IntType1, typename IntType2>
friend bool operator==(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator!=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator<(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator<=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator>(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator>=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
private:
IntTypeT mCurrent;
};
template<typename IntType1, typename IntType2>
bool operator==(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent == aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator!=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent != aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator<(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent < aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator<=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent <= aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator>(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent > aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator>=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent >= aIter2.mCurrent;
}
template<typename IntTypeT>
class IntegerRange
{
public:
typedef IntegerIterator<IntTypeT> iterator;
typedef IntegerIterator<IntTypeT> const_iterator;
typedef ReverseIterator<IntegerIterator<IntTypeT>> reverse_iterator;
typedef ReverseIterator<IntegerIterator<IntTypeT>> const_reverse_iterator;
template<typename IntType>
explicit IntegerRange(IntType aEnd)
: mBegin(0), mEnd(aEnd) { }
template<typename IntType1, typename IntType2>
IntegerRange(IntType1 aBegin, IntType2 aEnd)
: mBegin(aBegin), mEnd(aEnd) { }
iterator begin() const { return iterator(mBegin); }
const_iterator cbegin() const { return begin(); }
iterator end() const { return iterator(mEnd); }
const_iterator cend() const { return end(); }
reverse_iterator rbegin() const { return reverse_iterator(mEnd); }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() const { return reverse_iterator(mBegin); }
const_reverse_iterator crend() const { return rend(); }
private:
IntTypeT mBegin;
IntTypeT mEnd;
};
template<typename T, bool = IsUnsigned<T>::value>
struct GeqZero
{
static bool check(T t) {
return t >= 0;
}
};
template<typename T>
struct GeqZero<T, true>
{
static bool check(T t) {
return true;
}
};
} // namespace detail
template<typename IntType>
detail::IntegerRange<IntType>
MakeRange(IntType aEnd)
{
static_assert(IsIntegral<IntType>::value, "value must be integral");
MOZ_ASSERT(detail::GeqZero<IntType>::check(aEnd),
"Should never have negative value here");
return detail::IntegerRange<IntType>(aEnd);
}
template<typename IntType1, typename IntType2>
detail::IntegerRange<IntType2>
MakeRange(IntType1 aBegin, IntType2 aEnd)
{
static_assert(IsIntegral<IntType1>::value && IsIntegral<IntType2>::value,
"values must both be integral");
static_assert(IsSigned<IntType1>::value == IsSigned<IntType2>::value,
"signed/unsigned mismatch");
MOZ_ASSERT(aEnd >= aBegin, "End value should be larger than begin value");
return detail::IntegerRange<IntType2>(aBegin, aEnd);
}
} // namespace mozilla
#endif // mozilla_IntegerRange_h

View File

@@ -0,0 +1,143 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Helpers to manipulate integer types that don't fit in TypeTraits.h */
#ifndef mozilla_IntegerTypeTraits_h
#define mozilla_IntegerTypeTraits_h
#include "mozilla/TypeTraits.h"
#include <stdint.h>
namespace mozilla {
namespace detail {
/**
* StdintTypeForSizeAndSignedness returns the stdint integer type
* of given size (can be 1, 2, 4 or 8) and given signedness
* (false means unsigned, true means signed).
*/
template<size_t Size, bool Signedness>
struct StdintTypeForSizeAndSignedness;
template<>
struct StdintTypeForSizeAndSignedness<1, true>
{
typedef int8_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<1, false>
{
typedef uint8_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<2, true>
{
typedef int16_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<2, false>
{
typedef uint16_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<4, true>
{
typedef int32_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<4, false>
{
typedef uint32_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<8, true>
{
typedef int64_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<8, false>
{
typedef uint64_t Type;
};
} // namespace detail
template<size_t Size>
struct UnsignedStdintTypeForSize
: detail::StdintTypeForSizeAndSignedness<Size, false>
{};
template<size_t Size>
struct SignedStdintTypeForSize
: detail::StdintTypeForSizeAndSignedness<Size, true>
{};
template<typename IntegerType>
struct PositionOfSignBit
{
static_assert(IsIntegral<IntegerType>::value,
"PositionOfSignBit is only for integral types");
// 8 here should be CHAR_BIT from limits.h, but the world has moved on.
static const size_t value = 8 * sizeof(IntegerType) - 1;
};
/**
* MinValue returns the minimum value of the given integer type as a
* compile-time constant, which std::numeric_limits<IntegerType>::min()
* cannot do in c++98.
*/
template<typename IntegerType>
struct MinValue
{
private:
static_assert(IsIntegral<IntegerType>::value,
"MinValue is only for integral types");
typedef typename MakeUnsigned<IntegerType>::Type UnsignedIntegerType;
static const size_t PosOfSignBit = PositionOfSignBit<IntegerType>::value;
public:
// Bitwise ops may return a larger type, that's why we cast explicitly.
// In C++, left bit shifts on signed values is undefined by the standard
// unless the shifted value is representable.
// Notice that signed-to-unsigned conversions are always well-defined in
// the standard as the value congruent to 2**n, as expected. By contrast,
// unsigned-to-signed is only well-defined if the value is representable.
static const IntegerType value =
IsSigned<IntegerType>::value
? IntegerType(UnsignedIntegerType(1) << PosOfSignBit)
: IntegerType(0);
};
/**
* MaxValue returns the maximum value of the given integer type as a
* compile-time constant, which std::numeric_limits<IntegerType>::max()
* cannot do in c++98.
*/
template<typename IntegerType>
struct MaxValue
{
static_assert(IsIntegral<IntegerType>::value,
"MaxValue is only for integral types");
// Tricksy, but covered by the CheckedInt unit test.
// Relies on the type of MinValue<IntegerType>::value
// being IntegerType.
static const IntegerType value = ~MinValue<IntegerType>::value;
};
} // namespace mozilla
#endif // mozilla_IntegerTypeTraits_h

View File

@@ -0,0 +1,460 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A JSON pretty-printer class. */
// A typical JSON-writing library requires you to first build up a data
// structure that represents a JSON object and then serialize it (to file, or
// somewhere else). This approach makes for a clean API, but building the data
// structure takes up memory. Sometimes that isn't desirable, such as when the
// JSON data is produced for memory reporting.
//
// The JSONWriter class instead allows JSON data to be written out
// incrementally without building up large data structures.
//
// The API is slightly uglier than you would see in a typical JSON-writing
// library, but still fairly easy to use. It's possible to generate invalid
// JSON with JSONWriter, but typically the most basic testing will identify any
// such problems.
//
// Similarly, there are no RAII facilities for automatically closing objects
// and arrays. These would be nice if you are generating all your code within
// nested functions, but in other cases you'd have to maintain an explicit
// stack of RAII objects and manually unwind it, which is no better than just
// calling "end" functions. Furthermore, the consequences of forgetting to
// close an object or array are obvious and, again, will be identified via
// basic testing, unlike other cases where RAII is typically used (e.g. smart
// pointers) and the consequences of defects are more subtle.
//
// Importantly, the class does solve the two hard problems of JSON
// pretty-printing, which are (a) correctly escaping strings, and (b) adding
// appropriate indentation and commas between items.
//
// By default, every property is placed on its own line. However, it is
// possible to request that objects and arrays be placed entirely on a single
// line, which can reduce output size significantly in some cases.
//
// Strings used (for property names and string property values) are |const
// char*| throughout, and can be ASCII or UTF-8.
//
// EXAMPLE
// -------
// Assume that |MyWriteFunc| is a class that implements |JSONWriteFunc|. The
// following code:
//
// JSONWriter w(MakeUnique<MyWriteFunc>());
// w.Start();
// {
// w.NullProperty("null");
// w.BoolProperty("bool", true);
// w.IntProperty("int", 1);
// w.StartArrayProperty("array");
// {
// w.StringElement("string");
// w.StartObjectElement();
// {
// w.DoubleProperty("double", 3.4);
// w.StartArrayProperty("single-line array", w.SingleLineStyle);
// {
// w.IntElement(1);
// w.StartObjectElement(); // SingleLineStyle is inherited from
// w.EndObjectElement(); // above for this collection
// }
// w.EndArray();
// }
// w.EndObjectElement();
// }
// w.EndArrayProperty();
// }
// w.End();
//
// will produce pretty-printed output for the following JSON object:
//
// {
// "null": null,
// "bool": true,
// "int": 1,
// "array": [
// "string",
// {
// "double": 3.4,
// "single-line array": [1, {}]
// }
// ]
// }
//
// The nesting in the example code is obviously optional, but can aid
// readability.
#ifndef mozilla_JSONWriter_h
#define mozilla_JSONWriter_h
#include "mozilla/double-conversion.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Sprintf.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
#include <stdio.h>
namespace mozilla {
// A quasi-functor for JSONWriter. We don't use a true functor because that
// requires templatizing JSONWriter, and the templatization seeps to lots of
// places we don't want it to.
class JSONWriteFunc
{
public:
virtual void Write(const char* aStr) = 0;
virtual ~JSONWriteFunc() {}
};
// Ideally this would be within |EscapedString| but when compiling with GCC
// on Linux that caused link errors, whereas this formulation didn't.
namespace detail {
extern MFBT_DATA const char gTwoCharEscapes[256];
} // namespace detail
class JSONWriter
{
// From http://www.ietf.org/rfc/rfc4627.txt:
//
// "All Unicode characters may be placed within the quotation marks except
// for the characters that must be escaped: quotation mark, reverse
// solidus, and the control characters (U+0000 through U+001F)."
//
// This implementation uses two-char escape sequences where possible, namely:
//
// \", \\, \b, \f, \n, \r, \t
//
// All control characters not in the above list are represented with a
// six-char escape sequence, e.g. '\u000b' (a.k.a. '\v').
//
class EscapedString
{
// Only one of |mUnownedStr| and |mOwnedStr| are ever non-null. |mIsOwned|
// indicates which one is in use. They're not within a union because that
// wouldn't work with UniquePtr.
bool mIsOwned;
const char* mUnownedStr;
UniquePtr<char[]> mOwnedStr;
void SanityCheck() const
{
MOZ_ASSERT_IF( mIsOwned, mOwnedStr.get() && !mUnownedStr);
MOZ_ASSERT_IF(!mIsOwned, !mOwnedStr.get() && mUnownedStr);
}
static char hexDigitToAsciiChar(uint8_t u)
{
u = u & 0xf;
return u < 10 ? '0' + u : 'a' + (u - 10);
}
public:
explicit EscapedString(const char* aStr)
: mUnownedStr(nullptr)
, mOwnedStr(nullptr)
{
const char* p;
// First, see if we need to modify the string.
size_t nExtra = 0;
p = aStr;
while (true) {
uint8_t u = *p; // ensure it can't be interpreted as negative
if (u == 0) {
break;
}
if (detail::gTwoCharEscapes[u]) {
nExtra += 1;
} else if (u <= 0x1f) {
nExtra += 5;
}
p++;
}
if (nExtra == 0) {
// No escapes needed. Easy.
mIsOwned = false;
mUnownedStr = aStr;
return;
}
// Escapes are needed. We'll create a new string.
mIsOwned = true;
size_t len = (p - aStr) + nExtra;
mOwnedStr = MakeUnique<char[]>(len + 1);
p = aStr;
size_t i = 0;
while (true) {
uint8_t u = *p; // ensure it can't be interpreted as negative
if (u == 0) {
mOwnedStr[i] = 0;
break;
}
if (detail::gTwoCharEscapes[u]) {
mOwnedStr[i++] = '\\';
mOwnedStr[i++] = detail::gTwoCharEscapes[u];
} else if (u <= 0x1f) {
mOwnedStr[i++] = '\\';
mOwnedStr[i++] = 'u';
mOwnedStr[i++] = '0';
mOwnedStr[i++] = '0';
mOwnedStr[i++] = hexDigitToAsciiChar((u & 0x00f0) >> 4);
mOwnedStr[i++] = hexDigitToAsciiChar(u & 0x000f);
} else {
mOwnedStr[i++] = u;
}
p++;
}
}
~EscapedString()
{
SanityCheck();
}
const char* get() const
{
SanityCheck();
return mIsOwned ? mOwnedStr.get() : mUnownedStr;
}
};
public:
// Collections (objects and arrays) are printed in a multi-line style by
// default. This can be changed to a single-line style if SingleLineStyle is
// specified. If a collection is printed in single-line style, every nested
// collection within it is also printed in single-line style, even if
// multi-line style is requested.
enum CollectionStyle {
MultiLineStyle, // the default
SingleLineStyle
};
protected:
const UniquePtr<JSONWriteFunc> mWriter;
Vector<bool, 8> mNeedComma; // do we need a comma at depth N?
Vector<bool, 8> mNeedNewlines; // do we need newlines at depth N?
size_t mDepth; // the current nesting depth
void Indent()
{
for (size_t i = 0; i < mDepth; i++) {
mWriter->Write(" ");
}
}
// Adds whatever is necessary (maybe a comma, and then a newline and
// whitespace) to separate an item (property or element) from what's come
// before.
void Separator()
{
if (mNeedComma[mDepth]) {
mWriter->Write(",");
}
if (mDepth > 0 && mNeedNewlines[mDepth]) {
mWriter->Write("\n");
Indent();
} else if (mNeedComma[mDepth]) {
mWriter->Write(" ");
}
}
void PropertyNameAndColon(const char* aName)
{
EscapedString escapedName(aName);
mWriter->Write("\"");
mWriter->Write(escapedName.get());
mWriter->Write("\": ");
}
void Scalar(const char* aMaybePropertyName, const char* aStringValue)
{
Separator();
if (aMaybePropertyName) {
PropertyNameAndColon(aMaybePropertyName);
}
mWriter->Write(aStringValue);
mNeedComma[mDepth] = true;
}
void QuotedScalar(const char* aMaybePropertyName, const char* aStringValue)
{
Separator();
if (aMaybePropertyName) {
PropertyNameAndColon(aMaybePropertyName);
}
mWriter->Write("\"");
mWriter->Write(aStringValue);
mWriter->Write("\"");
mNeedComma[mDepth] = true;
}
void NewVectorEntries()
{
// If these tiny allocations OOM we might as well just crash because we
// must be in serious memory trouble.
MOZ_RELEASE_ASSERT(mNeedComma.resizeUninitialized(mDepth + 1));
MOZ_RELEASE_ASSERT(mNeedNewlines.resizeUninitialized(mDepth + 1));
mNeedComma[mDepth] = false;
mNeedNewlines[mDepth] = true;
}
void StartCollection(const char* aMaybePropertyName, const char* aStartChar,
CollectionStyle aStyle = MultiLineStyle)
{
Separator();
if (aMaybePropertyName) {
mWriter->Write("\"");
mWriter->Write(aMaybePropertyName);
mWriter->Write("\": ");
}
mWriter->Write(aStartChar);
mNeedComma[mDepth] = true;
mDepth++;
NewVectorEntries();
mNeedNewlines[mDepth] =
mNeedNewlines[mDepth - 1] && aStyle == MultiLineStyle;
}
// Adds the whitespace and closing char necessary to end a collection.
void EndCollection(const char* aEndChar)
{
if (mNeedNewlines[mDepth]) {
mWriter->Write("\n");
mDepth--;
Indent();
} else {
mDepth--;
}
mWriter->Write(aEndChar);
}
public:
explicit JSONWriter(UniquePtr<JSONWriteFunc> aWriter)
: mWriter(Move(aWriter))
, mNeedComma()
, mNeedNewlines()
, mDepth(0)
{
NewVectorEntries();
}
// Returns the JSONWriteFunc passed in at creation, for temporary use. The
// JSONWriter object still owns the JSONWriteFunc.
JSONWriteFunc* WriteFunc() const { return mWriter.get(); }
// For all the following functions, the "Prints:" comment indicates what the
// basic output looks like. However, it doesn't indicate the whitespace and
// trailing commas, which are automatically added as required.
//
// All property names and string properties are escaped as necessary.
// Prints: {
void Start(CollectionStyle aStyle = MultiLineStyle)
{
StartCollection(nullptr, "{", aStyle);
}
// Prints: }
void End() { EndCollection("}\n"); }
// Prints: "<aName>": null
void NullProperty(const char* aName)
{
Scalar(aName, "null");
}
// Prints: null
void NullElement() { NullProperty(nullptr); }
// Prints: "<aName>": <aBool>
void BoolProperty(const char* aName, bool aBool)
{
Scalar(aName, aBool ? "true" : "false");
}
// Prints: <aBool>
void BoolElement(bool aBool) { BoolProperty(nullptr, aBool); }
// Prints: "<aName>": <aInt>
void IntProperty(const char* aName, int64_t aInt)
{
char buf[64];
SprintfLiteral(buf, "%" PRId64, aInt);
Scalar(aName, buf);
}
// Prints: <aInt>
void IntElement(int64_t aInt) { IntProperty(nullptr, aInt); }
// Prints: "<aName>": <aDouble>
void DoubleProperty(const char* aName, double aDouble)
{
static const size_t buflen = 64;
char buf[buflen];
const double_conversion::DoubleToStringConverter &converter =
double_conversion::DoubleToStringConverter::EcmaScriptConverter();
double_conversion::StringBuilder builder(buf, buflen);
converter.ToShortest(aDouble, &builder);
Scalar(aName, builder.Finalize());
}
// Prints: <aDouble>
void DoubleElement(double aDouble) { DoubleProperty(nullptr, aDouble); }
// Prints: "<aName>": "<aStr>"
void StringProperty(const char* aName, const char* aStr)
{
EscapedString escapedStr(aStr);
QuotedScalar(aName, escapedStr.get());
}
// Prints: "<aStr>"
void StringElement(const char* aStr) { StringProperty(nullptr, aStr); }
// Prints: "<aName>": [
void StartArrayProperty(const char* aName,
CollectionStyle aStyle = MultiLineStyle)
{
StartCollection(aName, "[", aStyle);
}
// Prints: [
void StartArrayElement(CollectionStyle aStyle = MultiLineStyle)
{
StartArrayProperty(nullptr, aStyle);
}
// Prints: ]
void EndArray() { EndCollection("]"); }
// Prints: "<aName>": {
void StartObjectProperty(const char* aName,
CollectionStyle aStyle = MultiLineStyle)
{
StartCollection(aName, "{", aStyle);
}
// Prints: {
void StartObjectElement(CollectionStyle aStyle = MultiLineStyle)
{
StartObjectProperty(nullptr, aStyle);
}
// Prints: }
void EndObject() { EndCollection("}"); }
};
} // namespace mozilla
#endif /* mozilla_JSONWriter_h */

View File

@@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* MOZ_LIKELY and MOZ_UNLIKELY macros to hint to the compiler how a
* boolean predicate should be branch-predicted.
*/
#ifndef mozilla_Likely_h
#define mozilla_Likely_h
#if defined(__clang__) || defined(__GNUC__)
# define MOZ_LIKELY(x) (__builtin_expect(!!(x), 1))
# define MOZ_UNLIKELY(x) (__builtin_expect(!!(x), 0))
#else
# define MOZ_LIKELY(x) (!!(x))
# define MOZ_UNLIKELY(x) (!!(x))
#endif
#endif /* mozilla_Likely_h */

View File

@@ -0,0 +1,659 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A type-safe doubly-linked list class. */
/*
* The classes LinkedList<T> and LinkedListElement<T> together form a
* convenient, type-safe doubly-linked list implementation.
*
* The class T which will be inserted into the linked list must inherit from
* LinkedListElement<T>. A given object may be in only one linked list at a
* time.
*
* A LinkedListElement automatically removes itself from the list upon
* destruction, and a LinkedList will fatally assert in debug builds if it's
* non-empty when it's destructed.
*
* For example, you might use LinkedList in a simple observer list class as
* follows.
*
* class Observer : public LinkedListElement<Observer>
* {
* public:
* void observe(char* aTopic) { ... }
* };
*
* class ObserverContainer
* {
* private:
* LinkedList<Observer> list;
*
* public:
* void addObserver(Observer* aObserver)
* {
* // Will assert if |aObserver| is part of another list.
* list.insertBack(aObserver);
* }
*
* void removeObserver(Observer* aObserver)
* {
* // Will assert if |aObserver| is not part of some list.
* aObserver.remove();
* // Or, will assert if |aObserver| is not part of |list| specifically.
* // aObserver.removeFrom(list);
* }
*
* void notifyObservers(char* aTopic)
* {
* for (Observer* o = list.getFirst(); o != nullptr; o = o->getNext()) {
* o->observe(aTopic);
* }
* }
* };
*
* Additionally, the class AutoCleanLinkedList<T> is a LinkedList<T> that will
* remove and delete each element still within itself upon destruction. Note
* that because each element is deleted, elements must have been allocated
* using |new|.
*/
#ifndef mozilla_LinkedList_h
#define mozilla_LinkedList_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "mozilla/RefPtr.h"
#ifdef __cplusplus
namespace mozilla {
template<typename T>
class LinkedListElement;
namespace detail {
/**
* LinkedList supports refcounted elements using this adapter class. Clients
* using LinkedList<RefPtr<T>> will get a data structure that holds a strong
* reference to T as long as T is in the list.
*/
template<typename T>
struct LinkedListElementTraits
{
typedef T* RawType;
typedef const T* ConstRawType;
typedef T* ClientType;
typedef const T* ConstClientType;
// These static methods are called when an element is added to or removed from
// a linked list. It can be used to keep track ownership in lists that are
// supposed to own their elements. If elements are transferred from one list
// to another, no enter or exit calls happen since the elements still belong
// to a list.
static void enterList(LinkedListElement<T>* elt) {}
static void exitList(LinkedListElement<T>* elt) {}
};
template<typename T>
struct LinkedListElementTraits<RefPtr<T>>
{
typedef T* RawType;
typedef const T* ConstRawType;
typedef RefPtr<T> ClientType;
typedef RefPtr<const T> ConstClientType;
static void enterList(LinkedListElement<RefPtr<T>>* elt) { elt->asT()->AddRef(); }
static void exitList(LinkedListElement<RefPtr<T>>* elt) { elt->asT()->Release(); }
};
} /* namespace detail */
template<typename T>
class LinkedList;
template<typename T>
class LinkedListElement
{
typedef typename detail::LinkedListElementTraits<T> Traits;
typedef typename Traits::RawType RawType;
typedef typename Traits::ConstRawType ConstRawType;
typedef typename Traits::ClientType ClientType;
typedef typename Traits::ConstClientType ConstClientType;
/*
* It's convenient that we return nullptr when getNext() or getPrevious()
* hits the end of the list, but doing so costs an extra word of storage in
* each linked list node (to keep track of whether |this| is the sentinel
* node) and a branch on this value in getNext/getPrevious.
*
* We could get rid of the extra word of storage by shoving the "is
* sentinel" bit into one of the pointers, although this would, of course,
* have performance implications of its own.
*
* But the goal here isn't to win an award for the fastest or slimmest
* linked list; rather, we want a *convenient* linked list. So we won't
* waste time guessing which micro-optimization strategy is best.
*
*
* Speaking of unnecessary work, it's worth addressing here why we wrote
* mozilla::LinkedList in the first place, instead of using stl::list.
*
* The key difference between mozilla::LinkedList and stl::list is that
* mozilla::LinkedList stores the mPrev/mNext pointers in the object itself,
* while stl::list stores the mPrev/mNext pointers in a list element which
* itself points to the object being stored.
*
* mozilla::LinkedList's approach makes it harder to store an object in more
* than one list. But the upside is that you can call next() / prev() /
* remove() directly on the object. With stl::list, you'd need to store a
* pointer to its iterator in the object in order to accomplish this. Not
* only would this waste space, but you'd have to remember to update that
* pointer every time you added or removed the object from a list.
*
* In-place, constant-time removal is a killer feature of doubly-linked
* lists, and supporting this painlessly was a key design criterion.
*/
private:
LinkedListElement* mNext;
LinkedListElement* mPrev;
const bool mIsSentinel;
public:
LinkedListElement()
: mNext(this),
mPrev(this),
mIsSentinel(false)
{ }
/*
* Moves |aOther| into |*this|. If |aOther| is already in a list, then
* |aOther| is removed from the list and replaced by |*this|.
*/
LinkedListElement(LinkedListElement<T>&& aOther)
: mIsSentinel(aOther.mIsSentinel)
{
adjustLinkForMove(Move(aOther));
}
LinkedListElement& operator=(LinkedListElement<T>&& aOther)
{
MOZ_ASSERT(mIsSentinel == aOther.mIsSentinel, "Mismatch NodeKind!");
MOZ_ASSERT(!isInList(),
"Assigning to an element in a list messes up that list!");
adjustLinkForMove(Move(aOther));
return *this;
}
~LinkedListElement()
{
if (!mIsSentinel && isInList()) {
remove();
}
}
/*
* Get the next element in the list, or nullptr if this is the last element
* in the list.
*/
RawType getNext() { return mNext->asT(); }
ConstRawType getNext() const { return mNext->asT(); }
/*
* Get the previous element in the list, or nullptr if this is the first
* element in the list.
*/
RawType getPrevious() { return mPrev->asT(); }
ConstRawType getPrevious() const { return mPrev->asT(); }
/*
* Insert aElem after this element in the list. |this| must be part of a
* linked list when you call setNext(); otherwise, this method will assert.
*/
void setNext(RawType aElem)
{
MOZ_ASSERT(isInList());
setNextUnsafe(aElem);
}
/*
* Insert aElem before this element in the list. |this| must be part of a
* linked list when you call setPrevious(); otherwise, this method will
* assert.
*/
void setPrevious(RawType aElem)
{
MOZ_ASSERT(isInList());
setPreviousUnsafe(aElem);
}
/*
* Remove this element from the list which contains it. If this element is
* not currently part of a linked list, this method asserts.
*/
void remove()
{
MOZ_ASSERT(isInList());
mPrev->mNext = mNext;
mNext->mPrev = mPrev;
mNext = this;
mPrev = this;
Traits::exitList(this);
}
/*
* Remove this element from the list containing it. Returns a pointer to the
* element that follows this element (before it was removed). This method
* asserts if the element does not belong to a list.
*/
ClientType removeAndGetNext()
{
ClientType r = getNext();
remove();
return r;
}
/*
* Remove this element from the list containing it. Returns a pointer to the
* previous element in the containing list (before the removal). This method
* asserts if the element does not belong to a list.
*/
ClientType removeAndGetPrevious()
{
ClientType r = getPrevious();
remove();
return r;
}
/*
* Identical to remove(), but also asserts in debug builds that this element
* is in aList.
*/
void removeFrom(const LinkedList<T>& aList)
{
aList.assertContains(asT());
remove();
}
/*
* Return true if |this| part is of a linked list, and false otherwise.
*/
bool isInList() const
{
MOZ_ASSERT((mNext == this) == (mPrev == this));
return mNext != this;
}
private:
friend class LinkedList<T>;
friend struct detail::LinkedListElementTraits<T>;
enum class NodeKind {
Normal,
Sentinel
};
explicit LinkedListElement(NodeKind nodeKind)
: mNext(this),
mPrev(this),
mIsSentinel(nodeKind == NodeKind::Sentinel)
{ }
/*
* Return |this| cast to T* if we're a normal node, or return nullptr if
* we're a sentinel node.
*/
RawType asT()
{
return mIsSentinel ? nullptr : static_cast<RawType>(this);
}
ConstRawType asT() const
{
return mIsSentinel ? nullptr : static_cast<ConstRawType>(this);
}
/*
* Insert aElem after this element, but don't check that this element is in
* the list. This is called by LinkedList::insertFront().
*/
void setNextUnsafe(RawType aElem)
{
LinkedListElement *listElem = static_cast<LinkedListElement*>(aElem);
MOZ_ASSERT(!listElem->isInList());
listElem->mNext = this->mNext;
listElem->mPrev = this;
this->mNext->mPrev = listElem;
this->mNext = listElem;
Traits::enterList(aElem);
}
/*
* Insert aElem before this element, but don't check that this element is in
* the list. This is called by LinkedList::insertBack().
*/
void setPreviousUnsafe(RawType aElem)
{
LinkedListElement<T>* listElem = static_cast<LinkedListElement<T>*>(aElem);
MOZ_ASSERT(!listElem->isInList());
listElem->mNext = this;
listElem->mPrev = this->mPrev;
this->mPrev->mNext = listElem;
this->mPrev = listElem;
Traits::enterList(aElem);
}
/*
* Adjust mNext and mPrev for implementing move constructor and move
* assignment.
*/
void adjustLinkForMove(LinkedListElement<T>&& aOther)
{
if (!aOther.isInList()) {
mNext = this;
mPrev = this;
return;
}
if (!mIsSentinel) {
Traits::enterList(this);
}
MOZ_ASSERT(aOther.mNext->mPrev == &aOther);
MOZ_ASSERT(aOther.mPrev->mNext == &aOther);
/*
* Initialize |this| with |aOther|'s mPrev/mNext pointers, and adjust those
* element to point to this one.
*/
mNext = aOther.mNext;
mPrev = aOther.mPrev;
mNext->mPrev = this;
mPrev->mNext = this;
/*
* Adjust |aOther| so it doesn't think it's in a list. This makes it
* safely destructable.
*/
aOther.mNext = &aOther;
aOther.mPrev = &aOther;
if (!mIsSentinel) {
Traits::exitList(&aOther);
}
}
LinkedListElement& operator=(const LinkedListElement<T>& aOther) = delete;
LinkedListElement(const LinkedListElement<T>& aOther) = delete;
};
template<typename T>
class LinkedList
{
private:
typedef typename detail::LinkedListElementTraits<T> Traits;
typedef typename Traits::RawType RawType;
typedef typename Traits::ConstRawType ConstRawType;
typedef typename Traits::ClientType ClientType;
typedef typename Traits::ConstClientType ConstClientType;
LinkedListElement<T> sentinel;
public:
class Iterator {
RawType mCurrent;
public:
explicit Iterator(RawType aCurrent) : mCurrent(aCurrent) {}
RawType operator *() const {
return mCurrent;
}
const Iterator& operator++() {
mCurrent = mCurrent->getNext();
return *this;
}
bool operator!=(Iterator& aOther) const {
return mCurrent != aOther.mCurrent;
}
};
LinkedList() : sentinel(LinkedListElement<T>::NodeKind::Sentinel) { }
LinkedList(LinkedList<T>&& aOther)
: sentinel(mozilla::Move(aOther.sentinel))
{ }
LinkedList& operator=(LinkedList<T>&& aOther)
{
MOZ_ASSERT(isEmpty(), "Assigning to a non-empty list leaks elements in that list!");
sentinel = mozilla::Move(aOther.sentinel);
return *this;
}
~LinkedList() {
MOZ_ASSERT(isEmpty(),
"failing this assertion means this LinkedList's creator is "
"buggy: it should have removed all this list's elements before "
"the list's destruction");
}
/*
* Add aElem to the front of the list.
*/
void insertFront(RawType aElem)
{
/* Bypass setNext()'s this->isInList() assertion. */
sentinel.setNextUnsafe(aElem);
}
/*
* Add aElem to the back of the list.
*/
void insertBack(RawType aElem)
{
sentinel.setPreviousUnsafe(aElem);
}
/*
* Get the first element of the list, or nullptr if the list is empty.
*/
RawType getFirst() { return sentinel.getNext(); }
ConstRawType getFirst() const { return sentinel.getNext(); }
/*
* Get the last element of the list, or nullptr if the list is empty.
*/
RawType getLast() { return sentinel.getPrevious(); }
ConstRawType getLast() const { return sentinel.getPrevious(); }
/*
* Get and remove the first element of the list. If the list is empty,
* return nullptr.
*/
ClientType popFirst()
{
ClientType ret = sentinel.getNext();
if (ret) {
static_cast<LinkedListElement<T>*>(RawType(ret))->remove();
}
return ret;
}
/*
* Get and remove the last element of the list. If the list is empty,
* return nullptr.
*/
ClientType popLast()
{
ClientType ret = sentinel.getPrevious();
if (ret) {
static_cast<LinkedListElement<T>*>(RawType(ret))->remove();
}
return ret;
}
/*
* Return true if the list is empty, or false otherwise.
*/
bool isEmpty() const
{
return !sentinel.isInList();
}
/*
* Remove all the elements from the list.
*
* This runs in time linear to the list's length, because we have to mark
* each element as not in the list.
*/
void clear()
{
while (popFirst()) {
continue;
}
}
/*
* Allow range-based iteration:
*
* for (MyElementType* elt : myList) { ... }
*/
Iterator begin() {
return Iterator(getFirst());
}
Iterator end() {
return Iterator(nullptr);
}
/*
* Measures the memory consumption of the list excluding |this|. Note that
* it only measures the list elements themselves. If the list elements
* contain pointers to other memory blocks, those blocks must be measured
* separately during a subsequent iteration over the list.
*/
size_t sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = 0;
for (const T* t = getFirst(); t; t = t->getNext()) {
n += aMallocSizeOf(t);
}
return n;
}
/*
* Like sizeOfExcludingThis(), but measures |this| as well.
*/
size_t sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf);
}
/*
* In a debug build, make sure that the list is sane (no cycles, consistent
* mNext/mPrev pointers, only one sentinel). Has no effect in release builds.
*/
void debugAssertIsSane() const
{
#ifdef DEBUG
const LinkedListElement<T>* slow;
const LinkedListElement<T>* fast1;
const LinkedListElement<T>* fast2;
/*
* Check for cycles in the forward singly-linked list using the
* tortoise/hare algorithm.
*/
for (slow = sentinel.mNext,
fast1 = sentinel.mNext->mNext,
fast2 = sentinel.mNext->mNext->mNext;
slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel;
slow = slow->mNext, fast1 = fast2->mNext, fast2 = fast1->mNext) {
MOZ_ASSERT(slow != fast1);
MOZ_ASSERT(slow != fast2);
}
/* Check for cycles in the backward singly-linked list. */
for (slow = sentinel.mPrev,
fast1 = sentinel.mPrev->mPrev,
fast2 = sentinel.mPrev->mPrev->mPrev;
slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel;
slow = slow->mPrev, fast1 = fast2->mPrev, fast2 = fast1->mPrev) {
MOZ_ASSERT(slow != fast1);
MOZ_ASSERT(slow != fast2);
}
/*
* Check that |sentinel| is the only node in the list with
* mIsSentinel == true.
*/
for (const LinkedListElement<T>* elem = sentinel.mNext;
elem != &sentinel;
elem = elem->mNext) {
MOZ_ASSERT(!elem->mIsSentinel);
}
/* Check that the mNext/mPrev pointers match up. */
const LinkedListElement<T>* prev = &sentinel;
const LinkedListElement<T>* cur = sentinel.mNext;
do {
MOZ_ASSERT(cur->mPrev == prev);
MOZ_ASSERT(prev->mNext == cur);
prev = cur;
cur = cur->mNext;
} while (cur != &sentinel);
#endif /* ifdef DEBUG */
}
private:
friend class LinkedListElement<T>;
void assertContains(const RawType aValue) const
{
#ifdef DEBUG
for (ConstRawType elem = getFirst(); elem; elem = elem->getNext()) {
if (elem == aValue) {
return;
}
}
MOZ_CRASH("element wasn't found in this list!");
#endif
}
LinkedList& operator=(const LinkedList<T>& aOther) = delete;
LinkedList(const LinkedList<T>& aOther) = delete;
};
template <typename T>
class AutoCleanLinkedList : public LinkedList<T>
{
public:
~AutoCleanLinkedList()
{
while (T* element = this->popFirst()) {
delete element;
}
}
};
} /* namespace mozilla */
#endif /* __cplusplus */
#endif /* mozilla_LinkedList_h */

View File

@@ -0,0 +1,109 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implements various macros meant to ease the use of variadic macros.
*/
#ifndef mozilla_MacroArgs_h
#define mozilla_MacroArgs_h
// Concatenates pre-processor tokens in a way that can be used with __LINE__.
#define MOZ_CONCAT2(x, y) x ## y
#define MOZ_CONCAT(x, y) MOZ_CONCAT2(x, y)
/*
* MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic
* arguments and prefixes it with |aPrefix|. For example:
*
* MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2
* MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3
*
* You must pass in between 1 and 50 (inclusive) variadic arguments, past
* |aPrefix|. It is not legal to do
*
* MOZ_PASTE_PREFIX_AND_ARG_COUNT(prefix)
*
* (that is, pass in 0 variadic arguments). To ensure that a compile-time
* error occurs when these constraints are violated, use the
* MOZ_STATIC_ASSERT_VALID_ARG_COUNT macro with the same variaidc arguments
* wherever this macro is used.
*
* Passing (__VA_ARGS__, <rest of arguments>) rather than simply calling
* MOZ_MACROARGS_ARG_COUNT_HELPER2(__VA_ARGS__, <rest of arguments>) very
* carefully tiptoes around a MSVC bug where it improperly expands __VA_ARGS__
* as a single token in argument lists. For details, see:
*
* http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
* http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644
*/
#define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \
MOZ_MACROARGS_ARG_COUNT_HELPER((__VA_ARGS__, \
aPrefix##50, aPrefix##49, aPrefix##48, aPrefix##47, aPrefix##46, \
aPrefix##45, aPrefix##44, aPrefix##43, aPrefix##42, aPrefix##41, \
aPrefix##40, aPrefix##39, aPrefix##38, aPrefix##37, aPrefix##36, \
aPrefix##35, aPrefix##34, aPrefix##33, aPrefix##32, aPrefix##31, \
aPrefix##30, aPrefix##29, aPrefix##28, aPrefix##27, aPrefix##26, \
aPrefix##25, aPrefix##24, aPrefix##23, aPrefix##22, aPrefix##21, \
aPrefix##20, aPrefix##19, aPrefix##18, aPrefix##17, aPrefix##16, \
aPrefix##15, aPrefix##14, aPrefix##13, aPrefix##12, aPrefix##11, \
aPrefix##10, aPrefix##9, aPrefix##8, aPrefix##7, aPrefix##6, \
aPrefix##5, aPrefix##4, aPrefix##3, aPrefix##2, aPrefix##1, aPrefix##0))
#define MOZ_MACROARGS_ARG_COUNT_HELPER(aArgs) \
MOZ_MACROARGS_ARG_COUNT_HELPER2 aArgs
#define MOZ_MACROARGS_ARG_COUNT_HELPER2( \
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \
a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, \
a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, \
a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \
a51, ...) a51
/*
* MOZ_STATIC_ASSERT_VALID_ARG_COUNT ensures that a compile-time error occurs
* when the argument count constraints of MOZ_PASTE_PREFIX_AND_ARG_COUNT are
* violated. Use this macro wherever MOZ_PASTE_PREFIX_AND_ARG_COUNT is used
* and pass it the same variadic arguments.
*
* This macro employs a few dirty tricks to function. To detect the zero
* argument case, |(__VA_ARGS__)| is stringified, sizeof-ed, and compared to
* what it should be in the absence of arguments.
*
* Detecting too many arguments is a little trickier. With a valid argument
* count and a prefix of 1, MOZ_PASTE_PREFIX_AND_ARG_COUNT expands to e.g. 14.
* With a prefix of 0.0, it expands to e.g. 0.04. If there are too many
* arguments, it expands to the first argument over the limit. If this
* exceeding argument is a number, the assertion will fail as there is no
* number than can simultaneously be both > 10 and == 0. If the exceeding
* argument is not a number, a compile-time error should still occur due to
* the operations performed on it.
*/
#define MOZ_MACROARGS_STRINGIFY_HELPER(x) #x
#define MOZ_STATIC_ASSERT_VALID_ARG_COUNT(...) \
static_assert( \
sizeof(MOZ_MACROARGS_STRINGIFY_HELPER((__VA_ARGS__))) != sizeof("()") && \
(MOZ_PASTE_PREFIX_AND_ARG_COUNT(1, __VA_ARGS__)) > 10 && \
(int)(MOZ_PASTE_PREFIX_AND_ARG_COUNT(0.0, __VA_ARGS__)) == 0, \
"MOZ_STATIC_ASSERT_VALID_ARG_COUNT requires 1 to 50 arguments") /* ; */
/*
* MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N|
* arguments. For example:
*
* MOZ_ARGS_AFTER_2(a, b, c, d) expands to: c, d
*/
#define MOZ_ARGS_AFTER_1(a1, ...) __VA_ARGS__
#define MOZ_ARGS_AFTER_2(a1, a2, ...) __VA_ARGS__
/*
* MOZ_ARG_N expands to its |N|th argument.
*/
#define MOZ_ARG_1(a1, ...) a1
#define MOZ_ARG_2(a1, a2, ...) a2
#endif /* mozilla_MacroArgs_h */

View File

@@ -0,0 +1,158 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implements a higher-order macro for iteratively calling another macro with
* fixed leading arguments, plus a trailing element picked from a second list
* of arguments.
*/
#ifndef mozilla_MacroForEach_h
#define mozilla_MacroForEach_h
#include "mozilla/MacroArgs.h"
/*
* MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) expands to N calls to the macro
* |aMacro| where N is equal the number of items in the list |aArgs|. The
* arguments for each |aMacro| call are composed of *all* arguments in the list
* |aFixedArgs| as well as a single argument in the list |aArgs|. For example:
*
* #define MACRO_A(x) x +
* int a = MOZ_FOR_EACH(MACRO_A, (), (1, 2, 3)) 0;
* // Expands to: MACRO_A(1) MACRO_A(2) MACRO_A(3) 0;
* // And further to: 1 + 2 + 3 + 0;
*
* #define MACRO_B(k, x) (k + x) +
* int b = MOZ_FOR_EACH(MACRO_B, (5,), (1, 2)) 0;
* // Expands to: MACRO_B(5, 1) MACRO_B(5, 2) 0;
*
* #define MACRO_C(k1, k2, x) (k1 + k2 + x) +
* int c = MOZ_FOR_EACH(MACRO_C, (5, 8,), (1, 2)) 0;
* // Expands to: MACRO_B(5, 8, 1) MACRO_B(5, 8, 2) 0;
*
* If the |aFixedArgs| list is not empty, a trailing comma must be included.
*
* The |aArgs| list must be not be empty and may be up to 50 items long. Use
* MOZ_STATIC_ASSERT_VALID_ARG_COUNT to ensure that violating this constraint
* results in a compile-time error.
*/
#define MOZ_FOR_EACH_EXPAND_HELPER(...) __VA_ARGS__
#define MOZ_FOR_EACH_GLUE(a, b) a b
#define MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) \
MOZ_FOR_EACH_GLUE( \
MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_FOR_EACH_, \
MOZ_FOR_EACH_EXPAND_HELPER aArgs), \
(aMacro, aFixedArgs, aArgs))
#define MOZ_FOR_EACH_HELPER_GLUE(a, b) a b
#define MOZ_FOR_EACH_HELPER(aMacro, aFixedArgs, aArgs) \
MOZ_FOR_EACH_HELPER_GLUE( \
aMacro, \
(MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs))
#define MOZ_FOR_EACH_1(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a)
#define MOZ_FOR_EACH_2(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_1(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_3(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_2(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_4(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_3(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_5(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_4(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_6(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_5(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_7(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_6(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_8(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_7(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_9(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_8(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_10(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_9(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_11(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_10(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_12(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_11(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_13(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_12(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_14(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_13(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_15(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_14(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_16(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_15(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_17(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_16(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_18(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_17(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_19(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_18(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_20(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_19(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_21(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_20(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_22(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_21(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_23(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_22(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_24(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_23(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_25(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_24(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_26(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_25(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_27(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_26(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_28(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_27(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_29(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_28(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_30(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_29(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_31(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_30(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_32(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_31(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_33(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_32(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_34(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_33(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_35(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_34(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_36(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_35(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_37(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_36(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_38(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_37(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_39(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_38(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_40(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_39(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_41(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_40(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_42(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_41(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_43(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_42(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_44(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_43(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_45(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_44(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_46(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_45(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_47(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_46(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_48(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_47(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_49(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_48(m, fa, (MOZ_ARGS_AFTER_1 a))
#define MOZ_FOR_EACH_50(m, fa, a) \
MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_49(m, fa, (MOZ_ARGS_AFTER_1 a))
#endif /* mozilla_MacroForEach_h */

View File

@@ -0,0 +1,547 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* mfbt maths algorithms. */
#ifndef mozilla_MathAlgorithms_h
#define mozilla_MathAlgorithms_h
#include "mozilla/Assertions.h"
#include "mozilla/TypeTraits.h"
#include <cmath>
#include <limits.h>
#include <stdint.h>
namespace mozilla {
// Greatest Common Divisor
template<typename IntegerType>
MOZ_ALWAYS_INLINE IntegerType
EuclidGCD(IntegerType aA, IntegerType aB)
{
// Euclid's algorithm; O(N) in the worst case. (There are better
// ways, but we don't need them for the current use of this algo.)
MOZ_ASSERT(aA > IntegerType(0));
MOZ_ASSERT(aB > IntegerType(0));
while (aA != aB) {
if (aA > aB) {
aA = aA - aB;
} else {
aB = aB - aA;
}
}
return aA;
}
// Least Common Multiple
template<typename IntegerType>
MOZ_ALWAYS_INLINE IntegerType
EuclidLCM(IntegerType aA, IntegerType aB)
{
// Divide first to reduce overflow risk.
return (aA / EuclidGCD(aA, aB)) * aB;
}
namespace detail {
template<typename T>
struct AllowDeprecatedAbsFixed : FalseType {};
template<> struct AllowDeprecatedAbsFixed<int32_t> : TrueType {};
template<> struct AllowDeprecatedAbsFixed<int64_t> : TrueType {};
template<typename T>
struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed<T> {};
template<> struct AllowDeprecatedAbs<int> : TrueType {};
template<> struct AllowDeprecatedAbs<long> : TrueType {};
} // namespace detail
// DO NOT USE DeprecatedAbs. It exists only until its callers can be converted
// to Abs below, and it will be removed when all callers have been changed.
template<typename T>
inline typename mozilla::EnableIf<detail::AllowDeprecatedAbs<T>::value, T>::Type
DeprecatedAbs(const T aValue)
{
// The absolute value of the smallest possible value of a signed-integer type
// won't fit in that type (on twos-complement systems -- and we're blithely
// assuming we're on such systems, for the non-<stdint.h> types listed above),
// so assert that the input isn't that value.
//
// This is the case if: the value is non-negative; or if adding one (giving a
// value in the range [-maxvalue, 0]), then negating (giving a value in the
// range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement,
// (minvalue + 1) == -maxvalue).
MOZ_ASSERT(aValue >= 0 ||
-(aValue + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1),
"You can't negate the smallest possible negative integer!");
return aValue >= 0 ? aValue : -aValue;
}
namespace detail {
// For now mozilla::Abs only takes intN_T, the signed natural types, and
// float/double/long double. Feel free to add overloads for other standard,
// signed types if you need them.
template<typename T>
struct AbsReturnTypeFixed;
template<> struct AbsReturnTypeFixed<int8_t> { typedef uint8_t Type; };
template<> struct AbsReturnTypeFixed<int16_t> { typedef uint16_t Type; };
template<> struct AbsReturnTypeFixed<int32_t> { typedef uint32_t Type; };
template<> struct AbsReturnTypeFixed<int64_t> { typedef uint64_t Type; };
template<typename T>
struct AbsReturnType : AbsReturnTypeFixed<T> {};
template<> struct AbsReturnType<char> :
EnableIf<char(-1) < char(0), unsigned char> {};
template<> struct AbsReturnType<signed char> { typedef unsigned char Type; };
template<> struct AbsReturnType<short> { typedef unsigned short Type; };
template<> struct AbsReturnType<int> { typedef unsigned int Type; };
template<> struct AbsReturnType<long> { typedef unsigned long Type; };
template<> struct AbsReturnType<long long> { typedef unsigned long long Type; };
template<> struct AbsReturnType<float> { typedef float Type; };
template<> struct AbsReturnType<double> { typedef double Type; };
template<> struct AbsReturnType<long double> { typedef long double Type; };
} // namespace detail
template<typename T>
inline typename detail::AbsReturnType<T>::Type
Abs(const T aValue)
{
typedef typename detail::AbsReturnType<T>::Type ReturnType;
return aValue >= 0 ? ReturnType(aValue) : ~ReturnType(aValue) + 1;
}
template<>
inline float
Abs<float>(const float aFloat)
{
return std::fabs(aFloat);
}
template<>
inline double
Abs<double>(const double aDouble)
{
return std::fabs(aDouble);
}
template<>
inline long double
Abs<long double>(const long double aLongDouble)
{
return std::fabs(aLongDouble);
}
} // namespace mozilla
#if defined(_MSC_VER) && \
(defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
# define MOZ_BITSCAN_WINDOWS
# include <intrin.h>
# pragma intrinsic(_BitScanForward, _BitScanReverse)
# if defined(_M_AMD64) || defined(_M_X64)
# define MOZ_BITSCAN_WINDOWS64
# pragma intrinsic(_BitScanForward64, _BitScanReverse64)
# endif
#endif
namespace mozilla {
namespace detail {
#if defined(MOZ_BITSCAN_WINDOWS)
inline uint_fast8_t
CountLeadingZeroes32(uint32_t aValue)
{
unsigned long index;
if (!_BitScanReverse(&index, static_cast<unsigned long>(aValue)))
return 32;
return uint_fast8_t(31 - index);
}
inline uint_fast8_t
CountTrailingZeroes32(uint32_t aValue)
{
unsigned long index;
if (!_BitScanForward(&index, static_cast<unsigned long>(aValue)))
return 32;
return uint_fast8_t(index);
}
inline uint_fast8_t
CountPopulation32(uint32_t aValue)
{
uint32_t x = aValue - ((aValue >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
return (((x + (x >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
}
inline uint_fast8_t
CountPopulation64(uint64_t aValue)
{
return uint_fast8_t(CountPopulation32(aValue & 0xffffffff) +
CountPopulation32(aValue >> 32));
}
inline uint_fast8_t
CountLeadingZeroes64(uint64_t aValue)
{
#if defined(MOZ_BITSCAN_WINDOWS64)
unsigned long index;
if (!_BitScanReverse64(&index, static_cast<unsigned __int64>(aValue)))
return 64;
return uint_fast8_t(63 - index);
#else
uint32_t hi = uint32_t(aValue >> 32);
if (hi != 0) {
return CountLeadingZeroes32(hi);
}
return 32u + CountLeadingZeroes32(uint32_t(aValue));
#endif
}
inline uint_fast8_t
CountTrailingZeroes64(uint64_t aValue)
{
#if defined(MOZ_BITSCAN_WINDOWS64)
unsigned long index;
if (!_BitScanForward64(&index, static_cast<unsigned __int64>(aValue)))
return 64;
return uint_fast8_t(index);
#else
uint32_t lo = uint32_t(aValue);
if (lo != 0) {
return CountTrailingZeroes32(lo);
}
return 32u + CountTrailingZeroes32(uint32_t(aValue >> 32));
#endif
}
# ifdef MOZ_HAVE_BITSCAN64
# undef MOZ_HAVE_BITSCAN64
# endif
#elif defined(__clang__) || defined(__GNUC__)
# if defined(__clang__)
# if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz)
# error "A clang providing __builtin_c[lt]z is required to build"
# endif
# else
// gcc has had __builtin_clz and friends since 3.4: no need to check.
# endif
inline uint_fast8_t
CountLeadingZeroes32(uint32_t aValue)
{
return __builtin_clz(aValue);
}
inline uint_fast8_t
CountTrailingZeroes32(uint32_t aValue)
{
return __builtin_ctz(aValue);
}
inline uint_fast8_t
CountPopulation32(uint32_t aValue)
{
return __builtin_popcount(aValue);
}
inline uint_fast8_t
CountPopulation64(uint64_t aValue)
{
return __builtin_popcountll(aValue);
}
inline uint_fast8_t
CountLeadingZeroes64(uint64_t aValue)
{
return __builtin_clzll(aValue);
}
inline uint_fast8_t
CountTrailingZeroes64(uint64_t aValue)
{
return __builtin_ctzll(aValue);
}
#else
# error "Implement these!"
inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) = delete;
inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) = delete;
inline uint_fast8_t CountPopulation32(uint32_t aValue) = delete;
inline uint_fast8_t CountPopulation64(uint64_t aValue) = delete;
inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) = delete;
inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) = delete;
#endif
} // namespace detail
/**
* Compute the number of high-order zero bits in the NON-ZERO number |aValue|.
* That is, looking at the bitwise representation of the number, with the
* highest- valued bits at the start, return the number of zeroes before the
* first one is observed.
*
* CountLeadingZeroes32(0xF0FF1000) is 0;
* CountLeadingZeroes32(0x7F8F0001) is 1;
* CountLeadingZeroes32(0x3FFF0100) is 2;
* CountLeadingZeroes32(0x1FF50010) is 3; and so on.
*/
inline uint_fast8_t
CountLeadingZeroes32(uint32_t aValue)
{
MOZ_ASSERT(aValue != 0);
return detail::CountLeadingZeroes32(aValue);
}
/**
* Compute the number of low-order zero bits in the NON-ZERO number |aValue|.
* That is, looking at the bitwise representation of the number, with the
* lowest- valued bits at the start, return the number of zeroes before the
* first one is observed.
*
* CountTrailingZeroes32(0x0100FFFF) is 0;
* CountTrailingZeroes32(0x7000FFFE) is 1;
* CountTrailingZeroes32(0x0080FFFC) is 2;
* CountTrailingZeroes32(0x0080FFF8) is 3; and so on.
*/
inline uint_fast8_t
CountTrailingZeroes32(uint32_t aValue)
{
MOZ_ASSERT(aValue != 0);
return detail::CountTrailingZeroes32(aValue);
}
/**
* Compute the number of one bits in the number |aValue|,
*/
inline uint_fast8_t
CountPopulation32(uint32_t aValue)
{
return detail::CountPopulation32(aValue);
}
/** Analogous to CountPopulation32, but for 64-bit numbers */
inline uint_fast8_t
CountPopulation64(uint64_t aValue)
{
return detail::CountPopulation64(aValue);
}
/** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */
inline uint_fast8_t
CountLeadingZeroes64(uint64_t aValue)
{
MOZ_ASSERT(aValue != 0);
return detail::CountLeadingZeroes64(aValue);
}
/** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */
inline uint_fast8_t
CountTrailingZeroes64(uint64_t aValue)
{
MOZ_ASSERT(aValue != 0);
return detail::CountTrailingZeroes64(aValue);
}
namespace detail {
template<typename T, size_t Size = sizeof(T)>
class CeilingLog2;
template<typename T>
class CeilingLog2<T, 4>
{
public:
static uint_fast8_t compute(const T aValue)
{
// Check for <= 1 to avoid the == 0 undefined case.
return aValue <= 1 ? 0u : 32u - CountLeadingZeroes32(aValue - 1);
}
};
template<typename T>
class CeilingLog2<T, 8>
{
public:
static uint_fast8_t compute(const T aValue)
{
// Check for <= 1 to avoid the == 0 undefined case.
return aValue <= 1 ? 0u : 64u - CountLeadingZeroes64(aValue - 1);
}
};
} // namespace detail
/**
* Compute the log of the least power of 2 greater than or equal to |aValue|.
*
* CeilingLog2(0..1) is 0;
* CeilingLog2(2) is 1;
* CeilingLog2(3..4) is 2;
* CeilingLog2(5..8) is 3;
* CeilingLog2(9..16) is 4; and so on.
*/
template<typename T>
inline uint_fast8_t
CeilingLog2(const T aValue)
{
return detail::CeilingLog2<T>::compute(aValue);
}
/** A CeilingLog2 variant that accepts only size_t. */
inline uint_fast8_t
CeilingLog2Size(size_t aValue)
{
return CeilingLog2(aValue);
}
namespace detail {
template<typename T, size_t Size = sizeof(T)>
class FloorLog2;
template<typename T>
class FloorLog2<T, 4>
{
public:
static uint_fast8_t compute(const T aValue)
{
return 31u - CountLeadingZeroes32(aValue | 1);
}
};
template<typename T>
class FloorLog2<T, 8>
{
public:
static uint_fast8_t compute(const T aValue)
{
return 63u - CountLeadingZeroes64(aValue | 1);
}
};
} // namespace detail
/**
* Compute the log of the greatest power of 2 less than or equal to |aValue|.
*
* FloorLog2(0..1) is 0;
* FloorLog2(2..3) is 1;
* FloorLog2(4..7) is 2;
* FloorLog2(8..15) is 3; and so on.
*/
template<typename T>
inline uint_fast8_t
FloorLog2(const T aValue)
{
return detail::FloorLog2<T>::compute(aValue);
}
/** A FloorLog2 variant that accepts only size_t. */
inline uint_fast8_t
FloorLog2Size(size_t aValue)
{
return FloorLog2(aValue);
}
/*
* Compute the smallest power of 2 greater than or equal to |x|. |x| must not
* be so great that the computed value would overflow |size_t|.
*/
inline size_t
RoundUpPow2(size_t aValue)
{
MOZ_ASSERT(aValue <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)),
"can't round up -- will overflow!");
return size_t(1) << CeilingLog2(aValue);
}
/**
* Rotates the bits of the given value left by the amount of the shift width.
*/
template<typename T>
inline T
RotateLeft(const T aValue, uint_fast8_t aShift)
{
MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
MOZ_ASSERT(aShift > 0,
"Rotation by value length is undefined behavior, but compilers "
"do not currently fold a test into the rotate instruction. "
"Please remove this restriction when compilers optimize the "
"zero case (http://blog.regehr.org/archives/1063).");
static_assert(IsUnsigned<T>::value, "Rotates require unsigned values");
return (aValue << aShift) | (aValue >> (sizeof(T) * CHAR_BIT - aShift));
}
/**
* Rotates the bits of the given value right by the amount of the shift width.
*/
template<typename T>
inline T
RotateRight(const T aValue, uint_fast8_t aShift)
{
MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
MOZ_ASSERT(aShift > 0,
"Rotation by value length is undefined behavior, but compilers "
"do not currently fold a test into the rotate instruction. "
"Please remove this restriction when compilers optimize the "
"zero case (http://blog.regehr.org/archives/1063).");
static_assert(IsUnsigned<T>::value, "Rotates require unsigned values");
return (aValue >> aShift) | (aValue << (sizeof(T) * CHAR_BIT - aShift));
}
/**
* Returns true if |x| is a power of two.
* Zero is not an integer power of two. (-Inf is not an integer)
*/
template<typename T>
constexpr bool
IsPowerOfTwo(T x)
{
static_assert(IsUnsigned<T>::value,
"IsPowerOfTwo requires unsigned values");
return x && (x & (x - 1)) == 0;
}
template<typename T>
inline T
Clamp(const T aValue, const T aMin, const T aMax)
{
static_assert(IsIntegral<T>::value,
"Clamp accepts only integral types, so that it doesn't have"
" to distinguish differently-signed zeroes (which users may"
" or may not care to distinguish, likely at a perf cost) or"
" to decide how to clamp NaN or a range with a NaN"
" endpoint.");
MOZ_ASSERT(aMin <= aMax);
if (aValue <= aMin)
return aMin;
if (aValue >= aMax)
return aMax;
return aValue;
}
} /* namespace mozilla */
#endif /* mozilla_MathAlgorithms_h */

View File

@@ -0,0 +1,551 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A class for optional values and in-place lazy construction. */
#ifndef mozilla_Maybe_h
#define mozilla_Maybe_h
#include "mozilla/Alignment.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
#include <new> // for placement new
#include <type_traits>
namespace mozilla {
struct Nothing { };
/*
* Maybe is a container class which contains either zero or one elements. It
* serves two roles. It can represent values which are *semantically* optional,
* augmenting a type with an explicit 'Nothing' value. In this role, it provides
* methods that make it easy to work with values that may be missing, along with
* equality and comparison operators so that Maybe values can be stored in
* containers. Maybe values can be constructed conveniently in expressions using
* type inference, as follows:
*
* void doSomething(Maybe<Foo> aFoo) {
* if (aFoo) // Make sure that aFoo contains a value...
* aFoo->takeAction(); // and then use |aFoo->| to access it.
* } // |*aFoo| also works!
*
* doSomething(Nothing()); // Passes a Maybe<Foo> containing no value.
* doSomething(Some(Foo(100))); // Passes a Maybe<Foo> containing |Foo(100)|.
*
* You'll note that it's important to check whether a Maybe contains a value
* before using it, using conversion to bool, |isSome()|, or |isNothing()|. You
* can avoid these checks, and sometimes write more readable code, using
* |valueOr()|, |ptrOr()|, and |refOr()|, which allow you to retrieve the value
* in the Maybe and provide a default for the 'Nothing' case. You can also use
* |apply()| to call a function only if the Maybe holds a value, and |map()| to
* transform the value in the Maybe, returning another Maybe with a possibly
* different type.
*
* Maybe's other role is to support lazily constructing objects without using
* dynamic storage. A Maybe directly contains storage for a value, but it's
* empty by default. |emplace()|, as mentioned above, can be used to construct a
* value in Maybe's storage. The value a Maybe contains can be destroyed by
* calling |reset()|; this will happen automatically if a Maybe is destroyed
* while holding a value.
*
* It's a common idiom in C++ to use a pointer as a 'Maybe' type, with a null
* value meaning 'Nothing' and any other value meaning 'Some'. You can convert
* from such a pointer to a Maybe value using 'ToMaybe()'.
*
* Maybe is inspired by similar types in the standard library of many other
* languages (e.g. Haskell's Maybe and Rust's Option). In the C++ world it's
* very similar to std::optional, which was proposed for C++14 and originated in
* Boost. The most important differences between Maybe and std::optional are:
*
* - std::optional<T> may be compared with T. We deliberately forbid that.
* - std::optional allows in-place construction without a separate call to
* |emplace()| by using a dummy |in_place_t| value to tag the appropriate
* constructor.
* - std::optional has |valueOr()|, equivalent to Maybe's |valueOr()|, but
* lacks corresponding methods for |refOr()| and |ptrOr()|.
* - std::optional lacks |map()| and |apply()|, making it less suitable for
* functional-style code.
* - std::optional lacks many convenience functions that Maybe has. Most
* unfortunately, it lacks equivalents of the type-inferred constructor
* functions |Some()| and |Nothing()|.
*
* N.B. GCC has missed optimizations with Maybe in the past and may generate
* extra branches/loads/stores. Use with caution on hot paths; it's not known
* whether or not this is still a problem.
*/
template<class T>
class Maybe
{
bool mIsSome;
AlignedStorage2<T> mStorage;
public:
typedef T ValueType;
Maybe() : mIsSome(false) { }
~Maybe() { reset(); }
MOZ_IMPLICIT Maybe(Nothing) : mIsSome(false) { }
Maybe(const Maybe& aOther)
: mIsSome(false)
{
if (aOther.mIsSome) {
emplace(*aOther);
}
}
/**
* Maybe<T*> can be copy-constructed from a Maybe<U*> if U* and T* are
* compatible, or from Maybe<decltype(nullptr)>.
*/
template<typename U,
typename =
typename std::enable_if<std::is_pointer<T>::value &&
(std::is_same<U, decltype(nullptr)>::value ||
(std::is_pointer<U>::value &&
std::is_base_of<typename std::remove_pointer<T>::type,
typename std::remove_pointer<U>::type>::value))>::type>
MOZ_IMPLICIT
Maybe(const Maybe<U>& aOther)
: mIsSome(false)
{
if (aOther.isSome()) {
emplace(*aOther);
}
}
Maybe(Maybe&& aOther)
: mIsSome(false)
{
if (aOther.mIsSome) {
emplace(Move(*aOther));
aOther.reset();
}
}
/**
* Maybe<T*> can be move-constructed from a Maybe<U*> if U* and T* are
* compatible, or from Maybe<decltype(nullptr)>.
*/
template<typename U,
typename =
typename std::enable_if<std::is_pointer<T>::value &&
(std::is_same<U, decltype(nullptr)>::value ||
(std::is_pointer<U>::value &&
std::is_base_of<typename std::remove_pointer<T>::type,
typename std::remove_pointer<U>::type>::value))>::type>
MOZ_IMPLICIT
Maybe(Maybe<U>&& aOther)
: mIsSome(false)
{
if (aOther.isSome()) {
emplace(Move(*aOther));
aOther.reset();
}
}
Maybe& operator=(const Maybe& aOther)
{
if (&aOther != this) {
if (aOther.mIsSome) {
if (mIsSome) {
// XXX(seth): The correct code for this branch, below, can't be used
// due to a bug in Visual Studio 2010. See bug 1052940.
/*
ref() = aOther.ref();
*/
reset();
emplace(*aOther);
} else {
emplace(*aOther);
}
} else {
reset();
}
}
return *this;
}
Maybe& operator=(Maybe&& aOther)
{
MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
if (aOther.mIsSome) {
if (mIsSome) {
ref() = Move(aOther.ref());
} else {
emplace(Move(*aOther));
}
aOther.reset();
} else {
reset();
}
return *this;
}
/* Methods that check whether this Maybe contains a value */
explicit operator bool() const { return isSome(); }
bool isSome() const { return mIsSome; }
bool isNothing() const { return !mIsSome; }
/* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|. */
T value() const
{
MOZ_ASSERT(mIsSome);
return ref();
}
/*
* Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
* the default value provided.
*/
template<typename V>
T valueOr(V&& aDefault) const
{
if (isSome()) {
return ref();
}
return Forward<V>(aDefault);
}
/*
* Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
* the value returned from the function or functor provided.
*/
template<typename F>
T valueOrFrom(F&& aFunc) const
{
if (isSome()) {
return ref();
}
return aFunc();
}
/* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|. */
T* ptr()
{
MOZ_ASSERT(mIsSome);
return &ref();
}
const T* ptr() const
{
MOZ_ASSERT(mIsSome);
return &ref();
}
/*
* Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
* returns the default value provided.
*/
T* ptrOr(T* aDefault)
{
if (isSome()) {
return ptr();
}
return aDefault;
}
const T* ptrOr(const T* aDefault) const
{
if (isSome()) {
return ptr();
}
return aDefault;
}
/*
* Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
* returns the value returned from the function or functor provided.
*/
template<typename F>
T* ptrOrFrom(F&& aFunc)
{
if (isSome()) {
return ptr();
}
return aFunc();
}
template<typename F>
const T* ptrOrFrom(F&& aFunc) const
{
if (isSome()) {
return ptr();
}
return aFunc();
}
T* operator->()
{
MOZ_ASSERT(mIsSome);
return ptr();
}
const T* operator->() const
{
MOZ_ASSERT(mIsSome);
return ptr();
}
/* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
T& ref()
{
MOZ_ASSERT(mIsSome);
return *mStorage.addr();
}
const T& ref() const
{
MOZ_ASSERT(mIsSome);
return *mStorage.addr();
}
/*
* Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
* the default value provided.
*/
T& refOr(T& aDefault)
{
if (isSome()) {
return ref();
}
return aDefault;
}
const T& refOr(const T& aDefault) const
{
if (isSome()) {
return ref();
}
return aDefault;
}
/*
* Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns the
* value returned from the function or functor provided.
*/
template<typename F>
T& refOrFrom(F&& aFunc)
{
if (isSome()) {
return ref();
}
return aFunc();
}
template<typename F>
const T& refOrFrom(F&& aFunc) const
{
if (isSome()) {
return ref();
}
return aFunc();
}
T& operator*()
{
MOZ_ASSERT(mIsSome);
return ref();
}
const T& operator*() const
{
MOZ_ASSERT(mIsSome);
return ref();
}
/* If |isSome()|, runs the provided function or functor on the contents of
* this Maybe. */
template<typename Func>
Maybe& apply(Func aFunc)
{
if (isSome()) {
aFunc(ref());
}
return *this;
}
template<typename Func>
const Maybe& apply(Func aFunc) const
{
if (isSome()) {
aFunc(ref());
}
return *this;
}
/*
* If |isSome()|, runs the provided function and returns the result wrapped
* in a Maybe. If |isNothing()|, returns an empty Maybe value.
*/
template<typename Func>
auto map(Func aFunc) -> Maybe<decltype(aFunc(DeclVal<Maybe<T>>().ref()))>
{
using ReturnType = decltype(aFunc(ref()));
if (isSome()) {
Maybe<ReturnType> val;
val.emplace(aFunc(ref()));
return val;
}
return Maybe<ReturnType>();
}
template<typename Func>
auto map(Func aFunc) const -> Maybe<decltype(aFunc(DeclVal<Maybe<T>>().ref()))>
{
using ReturnType = decltype(aFunc(ref()));
if (isSome()) {
Maybe<ReturnType> val;
val.emplace(aFunc(ref()));
return val;
}
return Maybe<ReturnType>();
}
/* If |isSome()|, empties this Maybe and destroys its contents. */
void reset()
{
if (isSome()) {
ref().T::~T();
mIsSome = false;
}
}
/*
* Constructs a T value in-place in this empty Maybe<T>'s storage. The
* arguments to |emplace()| are the parameters to T's constructor.
*/
template<typename... Args>
void emplace(Args&&... aArgs)
{
MOZ_ASSERT(!mIsSome);
::new (mStorage.addr()) T(Forward<Args>(aArgs)...);
mIsSome = true;
}
};
/*
* Some() creates a Maybe<T> value containing the provided T value. If T has a
* move constructor, it's used to make this as efficient as possible.
*
* Some() selects the type of Maybe it returns by removing any const, volatile,
* or reference qualifiers from the type of the value you pass to it. This gives
* it more intuitive behavior when used in expressions, but it also means that
* if you need to construct a Maybe value that holds a const, volatile, or
* reference value, you need to use emplace() instead.
*/
template<typename T>
Maybe<typename RemoveCV<typename RemoveReference<T>::Type>::Type>
Some(T&& aValue)
{
typedef typename RemoveCV<typename RemoveReference<T>::Type>::Type U;
Maybe<U> value;
value.emplace(Forward<T>(aValue));
return value;
}
template<typename T>
Maybe<typename RemoveCV<typename RemoveReference<T>::Type>::Type>
ToMaybe(T* aPtr)
{
if (aPtr) {
return Some(*aPtr);
}
return Nothing();
}
/*
* Two Maybe<T> values are equal if
* - both are Nothing, or
* - both are Some, and the values they contain are equal.
*/
template<typename T> bool
operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS)
{
if (aLHS.isNothing() != aRHS.isNothing()) {
return false;
}
return aLHS.isNothing() || *aLHS == *aRHS;
}
template<typename T> bool
operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS)
{
return !(aLHS == aRHS);
}
/*
* We support comparison to Nothing to allow reasonable expressions like:
* if (maybeValue == Nothing()) { ... }
*/
template<typename T> bool
operator==(const Maybe<T>& aLHS, const Nothing& aRHS)
{
return aLHS.isNothing();
}
template<typename T> bool
operator!=(const Maybe<T>& aLHS, const Nothing& aRHS)
{
return !(aLHS == aRHS);
}
template<typename T> bool
operator==(const Nothing& aLHS, const Maybe<T>& aRHS)
{
return aRHS.isNothing();
}
template<typename T> bool
operator!=(const Nothing& aLHS, const Maybe<T>& aRHS)
{
return !(aLHS == aRHS);
}
/*
* Maybe<T> values are ordered in the same way T values are ordered, except that
* Nothing comes before anything else.
*/
template<typename T> bool
operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS)
{
if (aLHS.isNothing()) {
return aRHS.isSome();
}
if (aRHS.isNothing()) {
return false;
}
return *aLHS < *aRHS;
}
template<typename T> bool
operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS)
{
return !(aLHS < aRHS || aLHS == aRHS);
}
template<typename T> bool
operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS)
{
return aLHS < aRHS || aLHS == aRHS;
}
template<typename T> bool
operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS)
{
return !(aLHS < aRHS);
}
} // namespace mozilla
#endif /* mozilla_Maybe_h */

View File

@@ -0,0 +1,143 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_MaybeOneOf_h
#define mozilla_MaybeOneOf_h
#include "mozilla/Alignment.h"
#include "mozilla/Assertions.h"
#include "mozilla/Move.h"
#include "mozilla/TemplateLib.h"
#include <new> // For placement new
namespace mozilla {
/*
* MaybeOneOf<T1, T2> is like Maybe, but it supports constructing either T1
* or T2. When a MaybeOneOf<T1, T2> is constructed, it is |empty()|, i.e.,
* no value has been constructed and no destructor will be called when the
* MaybeOneOf<T1, T2> is destroyed. Upon calling |construct<T1>()| or
* |construct<T2>()|, a T1 or T2 object will be constructed with the given
* arguments and that object will be destroyed when the owning MaybeOneOf is
* destroyed.
*/
template<class T1, class T2>
class MaybeOneOf
{
AlignedStorage<tl::Max<sizeof(T1), sizeof(T2)>::value> storage;
enum State { None, SomeT1, SomeT2 } state;
template <class T, class Ignored = void> struct Type2State {};
template <class T>
T& as()
{
MOZ_ASSERT(state == Type2State<T>::result);
return *(T*)storage.addr();
}
template <class T>
const T& as() const
{
MOZ_ASSERT(state == Type2State<T>::result);
return *(T*)storage.addr();
}
public:
MaybeOneOf() : state(None) {}
~MaybeOneOf() { destroyIfConstructed(); }
MaybeOneOf(MaybeOneOf&& rhs)
: state(None)
{
if (!rhs.empty()) {
if (rhs.constructed<T1>()) {
construct<T1>(Move(rhs.as<T1>()));
rhs.as<T1>().~T1();
} else {
construct<T2>(Move(rhs.as<T2>()));
rhs.as<T2>().~T2();
}
rhs.state = None;
}
}
MaybeOneOf &operator=(MaybeOneOf&& rhs)
{
MOZ_ASSERT(this != &rhs, "Self-move is prohibited");
this->~MaybeOneOf();
new(this) MaybeOneOf(Move(rhs));
return *this;
}
bool empty() const { return state == None; }
template <class T>
bool constructed() const { return state == Type2State<T>::result; }
template <class T, class... Args>
void construct(Args&&... aArgs)
{
MOZ_ASSERT(state == None);
state = Type2State<T>::result;
::new (storage.addr()) T(Forward<Args>(aArgs)...);
}
template <class T>
T& ref()
{
return as<T>();
}
template <class T>
const T& ref() const
{
return as<T>();
}
void destroy()
{
MOZ_ASSERT(state == SomeT1 || state == SomeT2);
if (state == SomeT1) {
as<T1>().~T1();
} else if (state == SomeT2) {
as<T2>().~T2();
}
state = None;
}
void destroyIfConstructed()
{
if (!empty()) {
destroy();
}
}
private:
MaybeOneOf(const MaybeOneOf& aOther) = delete;
const MaybeOneOf& operator=(const MaybeOneOf& aOther) = delete;
};
template <class T1, class T2>
template <class Ignored>
struct MaybeOneOf<T1, T2>::Type2State<T1, Ignored>
{
typedef MaybeOneOf<T1, T2> Enclosing;
static const typename Enclosing::State result = Enclosing::SomeT1;
};
template <class T1, class T2>
template <class Ignored>
struct MaybeOneOf<T1, T2>::Type2State<T2, Ignored>
{
typedef MaybeOneOf<T1, T2> Enclosing;
static const typename Enclosing::State result = Enclosing::SomeT2;
};
} // namespace mozilla
#endif /* mozilla_MaybeOneOf_h */

View File

@@ -0,0 +1,129 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Provides a common interface to the ASan (AddressSanitizer) and Valgrind
* functions used to mark memory in certain ways. In detail, the following
* three macros are provided:
*
* MOZ_MAKE_MEM_NOACCESS - Mark memory as unsafe to access (e.g. freed)
* MOZ_MAKE_MEM_UNDEFINED - Mark memory as accessible, with content undefined
* MOZ_MAKE_MEM_DEFINED - Mark memory as accessible, with content defined
*
* With Valgrind in use, these directly map to the three respective Valgrind
* macros. With ASan in use, the NOACCESS macro maps to poisoning the memory,
* while the UNDEFINED/DEFINED macros unpoison memory.
*
* With no memory checker available, all macros expand to the empty statement.
*/
#ifndef mozilla_MemoryChecking_h
#define mozilla_MemoryChecking_h
#if defined(MOZ_VALGRIND)
#include "valgrind/memcheck.h"
#endif
#if defined(MOZ_ASAN) || defined(MOZ_VALGRIND)
#define MOZ_HAVE_MEM_CHECKS 1
#endif
#if defined(MOZ_ASAN)
#include <stddef.h>
#include "mozilla/Attributes.h"
#include "mozilla/Types.h"
#ifdef _MSC_VER
// In clang-cl based ASAN, we link against the memory poisoning functions
// statically.
#define MOZ_ASAN_VISIBILITY
#else
#define MOZ_ASAN_VISIBILITY MOZ_EXPORT
#endif
extern "C" {
/* These definitions are usually provided through the
* sanitizer/asan_interface.h header installed by ASan.
*/
void MOZ_ASAN_VISIBILITY
__asan_poison_memory_region(void const volatile *addr, size_t size);
void MOZ_ASAN_VISIBILITY
__asan_unpoison_memory_region(void const volatile *addr, size_t size);
#define MOZ_MAKE_MEM_NOACCESS(addr, size) \
__asan_poison_memory_region((addr), (size))
#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \
__asan_unpoison_memory_region((addr), (size))
#define MOZ_MAKE_MEM_DEFINED(addr, size) \
__asan_unpoison_memory_region((addr), (size))
/*
* These definitions are usually provided through the
* sanitizer/lsan_interface.h header installed by LSan.
*/
void MOZ_EXPORT
__lsan_ignore_object(const void *p);
}
#elif defined(MOZ_MSAN)
#include <stddef.h>
#include "mozilla/Types.h"
extern "C" {
/* These definitions are usually provided through the
* sanitizer/msan_interface.h header installed by MSan.
*/
void MOZ_EXPORT
__msan_poison(void const volatile *addr, size_t size);
void MOZ_EXPORT
__msan_unpoison(void const volatile *addr, size_t size);
#define MOZ_MAKE_MEM_NOACCESS(addr, size) \
__msan_poison((addr), (size))
#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \
__msan_poison((addr), (size))
#define MOZ_MAKE_MEM_DEFINED(addr, size) \
__msan_unpoison((addr), (size))
}
#elif defined(MOZ_VALGRIND)
#define MOZ_MAKE_MEM_NOACCESS(addr, size) \
VALGRIND_MAKE_MEM_NOACCESS((addr), (size))
#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \
VALGRIND_MAKE_MEM_UNDEFINED((addr), (size))
#define MOZ_MAKE_MEM_DEFINED(addr, size) \
VALGRIND_MAKE_MEM_DEFINED((addr), (size))
#else
#define MOZ_MAKE_MEM_NOACCESS(addr, size) do {} while (0)
#define MOZ_MAKE_MEM_UNDEFINED(addr, size) do {} while (0)
#define MOZ_MAKE_MEM_DEFINED(addr, size) do {} while (0)
#endif
/*
* MOZ_LSAN_INTENTIONAL_LEAK(X) is a macro to tell LeakSanitizer that X
* points to a value that will intentionally never be deallocated during
* the execution of the process.
*
* Additional uses of this macro should be reviewed by people
* conversant in leak-checking and/or MFBT peers.
*/
#if defined(MOZ_ASAN)
# define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) __lsan_ignore_object(X)
#else
# define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) /* nothing */
#endif // defined(MOZ_ASAN)
#endif /* mozilla_MemoryChecking_h */

View File

@@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Memory reporting infrastructure. */
#ifndef mozilla_MemoryReporting_h
#define mozilla_MemoryReporting_h
#include <stddef.h>
#ifdef __cplusplus
namespace mozilla {
/*
* This is for functions that are like malloc_usable_size. Such functions are
* used for measuring the size of data structures.
*/
typedef size_t (*MallocSizeOf)(const void* p);
} /* namespace mozilla */
#endif /* __cplusplus */
typedef size_t (*MozMallocSizeOf)(const void* p);
#endif /* mozilla_MemoryReporting_h */

View File

@@ -0,0 +1,238 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* C++11-style, but C++98-usable, "move references" implementation. */
#ifndef mozilla_Move_h
#define mozilla_Move_h
#include "mozilla/TypeTraits.h"
namespace mozilla {
/*
* "Move" References
*
* Some types can be copied much more efficiently if we know the original's
* value need not be preserved --- that is, if we are doing a "move", not a
* "copy". For example, if we have:
*
* Vector<T> u;
* Vector<T> v(u);
*
* the constructor for v must apply a copy constructor to each element of u ---
* taking time linear in the length of u. However, if we know we will not need u
* any more once v has been initialized, then we could initialize v very
* efficiently simply by stealing u's dynamically allocated buffer and giving it
* to v --- a constant-time operation, regardless of the size of u.
*
* Moves often appear in container implementations. For example, when we append
* to a vector, we may need to resize its buffer. This entails moving each of
* its extant elements from the old, smaller buffer to the new, larger buffer.
* But once the elements have been migrated, we're just going to throw away the
* old buffer; we don't care if they still have their values. So if the vector's
* element type can implement "move" more efficiently than "copy", the vector
* resizing should by all means use a "move" operation. Hash tables should also
* use moves when resizing their internal array as entries are added and
* removed.
*
* The details of the optimization, and whether it's worth applying, vary
* from one type to the next: copying an 'int' is as cheap as moving it, so
* there's no benefit in distinguishing 'int' moves from copies. And while
* some constructor calls for complex types are moves, many really have to
* be copies, and can't be optimized this way. So we need:
*
* 1) a way for a type (like Vector) to announce that it can be moved more
* efficiently than it can be copied, and provide an implementation of that
* move operation; and
*
* 2) a way for a particular invocation of a copy constructor to say that it's
* really a move, not a copy, and that the value of the original isn't
* important afterwards (although it must still be safe to destroy).
*
* If a constructor has a single argument of type 'T&&' (an 'rvalue reference
* to T'), that indicates that it is a 'move constructor'. That's 1). It should
* move, not copy, its argument into the object being constructed. It may leave
* the original in any safely-destructible state.
*
* If a constructor's argument is an rvalue, as in 'C(f(x))' or 'C(x + y)', as
* opposed to an lvalue, as in 'C(x)', then overload resolution will prefer the
* move constructor, if there is one. The 'mozilla::Move' function, defined in
* this file, is an identity function you can use in a constructor invocation to
* make any argument into an rvalue, like this: C(Move(x)). That's 2). (You
* could use any function that works, but 'Move' indicates your intention
* clearly.)
*
* Where we might define a copy constructor for a class C like this:
*
* C(const C& rhs) { ... copy rhs to this ... }
*
* we would declare a move constructor like this:
*
* C(C&& rhs) { .. move rhs to this ... }
*
* And where we might perform a copy like this:
*
* C c2(c1);
*
* we would perform a move like this:
*
* C c2(Move(c1));
*
* Note that 'T&&' implicitly converts to 'T&'. So you can pass a 'T&&' to an
* ordinary copy constructor for a type that doesn't support a special move
* constructor, and you'll just get a copy. This means that templates can use
* Move whenever they know they won't use the original value any more, even if
* they're not sure whether the type at hand has a specialized move constructor.
* If it doesn't, the 'T&&' will just convert to a 'T&', and the ordinary copy
* constructor will apply.
*
* A class with a move constructor can also provide a move assignment operator.
* A generic definition would run this's destructor, and then apply the move
* constructor to *this's memory. A typical definition:
*
* C& operator=(C&& rhs) {
* MOZ_ASSERT(&rhs != this, "self-moves are prohibited");
* this->~C();
* new(this) C(Move(rhs));
* return *this;
* }
*
* With that in place, one can write move assignments like this:
*
* c2 = Move(c1);
*
* This destroys c2, moves c1's value to c2, and leaves c1 in an undefined but
* destructible state.
*
* As we say, a move must leave the original in a "destructible" state. The
* original's destructor will still be called, so if a move doesn't
* actually steal all its resources, that's fine. We require only that the
* move destination must take on the original's value; and that destructing
* the original must not break the move destination.
*
* (Opinions differ on whether move assignment operators should deal with move
* assignment of an object onto itself. It seems wise to either handle that
* case, or assert that it does not occur.)
*
* Forwarding:
*
* Sometimes we want copy construction or assignment if we're passed an ordinary
* value, but move construction if passed an rvalue reference. For example, if
* our constructor takes two arguments and either could usefully be a move, it
* seems silly to write out all four combinations:
*
* C::C(X& x, Y& y) : x(x), y(y) { }
* C::C(X& x, Y&& y) : x(x), y(Move(y)) { }
* C::C(X&& x, Y& y) : x(Move(x)), y(y) { }
* C::C(X&& x, Y&& y) : x(Move(x)), y(Move(y)) { }
*
* To avoid this, C++11 has tweaks to make it possible to write what you mean.
* The four constructor overloads above can be written as one constructor
* template like so[0]:
*
* template <typename XArg, typename YArg>
* C::C(XArg&& x, YArg&& y) : x(Forward<XArg>(x)), y(Forward<YArg>(y)) { }
*
* ("'Don't Repeat Yourself'? What's that?")
*
* This takes advantage of two new rules in C++11:
*
* - First, when a function template takes an argument that is an rvalue
* reference to a template argument (like 'XArg&& x' and 'YArg&& y' above),
* then when the argument is applied to an lvalue, the template argument
* resolves to 'T&'; and when it is applied to an rvalue, the template
* argument resolves to 'T'. Thus, in a call to C::C like:
*
* X foo(int);
* Y yy;
*
* C(foo(5), yy)
*
* XArg would resolve to 'X', and YArg would resolve to 'Y&'.
*
* - Second, Whereas C++ used to forbid references to references, C++11 defines
* 'collapsing rules': 'T& &', 'T&& &', and 'T& &&' (that is, any combination
* involving an lvalue reference) now collapse to simply 'T&'; and 'T&& &&'
* collapses to 'T&&'.
*
* Thus, in the call above, 'XArg&&' is 'X&&'; and 'YArg&&' is 'Y& &&', which
* collapses to 'Y&'. Because the arguments are declared as rvalue references
* to template arguments, the lvalue-ness "shines through" where present.
*
* Then, the 'Forward<T>' function --- you must invoke 'Forward' with its type
* argument --- returns an lvalue reference or an rvalue reference to its
* argument, depending on what T is. In our unified constructor definition, that
* means that we'll invoke either the copy or move constructors for x and y,
* depending on what we gave C's constructor. In our call, we'll move 'foo()'
* into 'x', but copy 'yy' into 'y'.
*
* This header file defines Move and Forward in the mozilla namespace. It's up
* to individual containers to annotate moves as such, by calling Move; and it's
* up to individual types to define move constructors and assignment operators
* when valuable.
*
* (C++11 says that the <utility> header file should define 'std::move' and
* 'std::forward', which are just like our 'Move' and 'Forward'; but those
* definitions aren't available in that header on all our platforms, so we
* define them ourselves here.)
*
* 0. This pattern is known as "perfect forwarding". Interestingly, it is not
* actually perfect, and it can't forward all possible argument expressions!
* There is a C++11 issue: you can't form a reference to a bit-field. As a
* workaround, assign the bit-field to a local variable and use that:
*
* // C is as above
* struct S { int x : 1; } s;
* C(s.x, 0); // BAD: s.x is a reference to a bit-field, can't form those
* int tmp = s.x;
* C(tmp, 0); // OK: tmp not a bit-field
*/
/**
* Identical to std::Move(); this is necessary until our stlport supports
* std::move().
*/
template<typename T>
inline typename RemoveReference<T>::Type&&
Move(T&& aX)
{
return static_cast<typename RemoveReference<T>::Type&&>(aX);
}
/**
* These two overloads are identical to std::forward(); they are necessary until
* our stlport supports std::forward().
*/
template<typename T>
inline T&&
Forward(typename RemoveReference<T>::Type& aX)
{
return static_cast<T&&>(aX);
}
template<typename T>
inline T&&
Forward(typename RemoveReference<T>::Type&& aX)
{
static_assert(!IsLvalueReference<T>::value,
"misuse of Forward detected! try the other overload");
return static_cast<T&&>(aX);
}
/** Swap |aX| and |aY| using move-construction if possible. */
template<typename T>
inline void
Swap(T& aX, T& aY)
{
T tmp(Move(aX));
aX = Move(aY);
aY = Move(tmp);
}
} // namespace mozilla
#endif /* mozilla_Move_h */

View File

@@ -0,0 +1,209 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_NotNull_h
#define mozilla_NotNull_h
// It's often unclear if a particular pointer, be it raw (T*) or smart
// (RefPtr<T>, nsCOMPtr<T>, etc.) can be null. This leads to missing null
// checks (which can cause crashes) and unnecessary null checks (which clutter
// the code).
//
// C++ has a built-in alternative that avoids these problems: references. This
// module defines another alternative, NotNull, which can be used in cases
// where references are not suitable.
//
// In the comments below we use the word "handle" to cover all varieties of
// pointers and references.
//
// References
// ----------
// References are always non-null. (You can do |T& r = *p;| where |p| is null,
// but that's undefined behaviour. C++ doesn't provide any built-in, ironclad
// guarantee of non-nullness.)
//
// A reference works well when you need a temporary handle to an existing
// single object, e.g. for passing a handle to a function, or as a local handle
// within another object. (In Rust parlance, this is a "borrow".)
//
// A reference is less appropriate in the following cases.
//
// - As a primary handle to an object. E.g. code such as this is possible but
// strange: |T& t = *new T(); ...; delete &t;|
//
// - As a handle to an array. It's common for |T*| to refer to either a single
// |T| or an array of |T|, but |T&| cannot refer to an array of |T| because
// you can't index off a reference (at least, not without first converting it
// to a pointer).
//
// - When the handle identity is meaningful, e.g. if you have a hashtable of
// handles, because you have to use |&| on the reference to convert it to a
// pointer.
//
// - Some people don't like using non-const references as function parameters,
// because it is not clear at the call site that the argument might be
// modified.
//
// - When you need "smart" behaviour. E.g. we lack reference equivalents to
// RefPtr and nsCOMPtr.
//
// - When interfacing with code that uses pointers a lot, sometimes using a
// reference just feels like an odd fit.
//
// Furthermore, a reference is impossible in the following cases.
//
// - When the handle is rebound to another object. References don't allow this.
//
// - When the handle has type |void|. |void&| is not allowed.
//
// NotNull is an alternative that can be used in any of the above cases except
// for the last one, where the handle type is |void|. See below.
#include "mozilla/Assertions.h"
namespace mozilla {
// NotNull can be used to wrap a "base" pointer (raw or smart) to indicate it
// is not null. Some examples:
//
// - NotNull<char*>
// - NotNull<RefPtr<Event>>
// - NotNull<nsCOMPtr<Event>>
//
// NotNull has the following notable properties.
//
// - It has zero space overhead.
//
// - It must be initialized explicitly. There is no default initialization.
//
// - It auto-converts to the base pointer type.
//
// - It does not auto-convert from a base pointer. Implicit conversion from a
// less-constrained type (e.g. T*) to a more-constrained type (e.g.
// NotNull<T*>) is dangerous. Creation and assignment from a base pointer can
// only be done with WrapNotNull(), which makes them impossible to overlook,
// both when writing and reading code.
//
// - When initialized (or assigned) it is checked, and if it is null we abort.
// This guarantees that it cannot be null.
//
// - |operator bool()| is deleted. This means you cannot check a NotNull in a
// boolean context, which eliminates the possibility of unnecessary null
// checks.
//
// NotNull currently doesn't work with UniquePtr. See
// https://github.com/Microsoft/GSL/issues/89 for some discussion.
//
template <typename T>
class NotNull
{
template <typename U> friend NotNull<U> WrapNotNull(U aBasePtr);
T mBasePtr;
// This constructor is only used by WrapNotNull().
template <typename U>
explicit NotNull(U aBasePtr) : mBasePtr(aBasePtr) {}
public:
// Disallow default construction.
NotNull() = delete;
// Construct/assign from another NotNull with a compatible base pointer type.
template <typename U>
MOZ_IMPLICIT NotNull(const NotNull<U>& aOther) : mBasePtr(aOther.get()) {}
// Default copy/move construction and assignment.
NotNull(const NotNull<T>&) = default;
NotNull<T>& operator=(const NotNull<T>&) = default;
NotNull(NotNull<T>&&) = default;
NotNull<T>& operator=(NotNull<T>&&) = default;
// Disallow null checks, which are unnecessary for this type.
explicit operator bool() const = delete;
// Explicit conversion to a base pointer. Use only to resolve ambiguity or to
// get a castable pointer.
const T& get() const { return mBasePtr; }
// Implicit conversion to a base pointer. Preferable to get().
operator const T&() const { return get(); }
// Dereference operators.
const T& operator->() const { return get(); }
decltype(*mBasePtr) operator*() const { return *mBasePtr; }
};
template <typename T>
NotNull<T>
WrapNotNull(const T aBasePtr)
{
NotNull<T> notNull(aBasePtr);
MOZ_RELEASE_ASSERT(aBasePtr);
return notNull;
}
// Compare two NotNulls.
template <typename T, typename U>
inline bool
operator==(const NotNull<T>& aLhs, const NotNull<U>& aRhs)
{
return aLhs.get() == aRhs.get();
}
template <typename T, typename U>
inline bool
operator!=(const NotNull<T>& aLhs, const NotNull<U>& aRhs)
{
return aLhs.get() != aRhs.get();
}
// Compare a NotNull to a base pointer.
template <typename T, typename U>
inline bool
operator==(const NotNull<T>& aLhs, const U& aRhs)
{
return aLhs.get() == aRhs;
}
template <typename T, typename U>
inline bool
operator!=(const NotNull<T>& aLhs, const U& aRhs)
{
return aLhs.get() != aRhs;
}
// Compare a base pointer to a NotNull.
template <typename T, typename U>
inline bool
operator==(const T& aLhs, const NotNull<U>& aRhs)
{
return aLhs == aRhs.get();
}
template <typename T, typename U>
inline bool
operator!=(const T& aLhs, const NotNull<U>& aRhs)
{
return aLhs != aRhs.get();
}
// Disallow comparing a NotNull to a nullptr.
template <typename T>
bool
operator==(const NotNull<T>&, decltype(nullptr)) = delete;
template <typename T>
bool
operator!=(const NotNull<T>&, decltype(nullptr)) = delete;
// Disallow comparing a nullptr to a NotNull.
template <typename T>
bool
operator==(decltype(nullptr), const NotNull<T>&) = delete;
template <typename T>
bool
operator!=(decltype(nullptr), const NotNull<T>&) = delete;
} // namespace mozilla
#endif /* mozilla_NotNull_h */

View File

@@ -0,0 +1,31 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implements a mozilla::IsNullPointer<T> type trait. */
#ifndef mozilla_NullPtr_h
#define mozilla_NullPtr_h
#include "mozilla/TypeTraits.h"
namespace mozilla {
/**
* IsNullPointer<T>::value is true iff T is decltype(nullptr).
*
* Ideally this would be in TypeTraits.h, but C++11 omitted std::is_null_pointer
* (fixed in C++14), so in the interests of easing a switch to <type_traits>,
* this trait lives elsewhere.
*/
template<typename T>
struct IsNullPointer : FalseType {};
template<>
struct IsNullPointer<decltype(nullptr)> : TrueType {};
} // namespace mozilla
#endif /* mozilla_NullPtr_h */

View File

@@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* An opaque integral type supporting only comparison operators. */
#ifndef mozilla_Opaque_h
#define mozilla_Opaque_h
#include "mozilla/TypeTraits.h"
namespace mozilla {
/**
* Opaque<T> is a replacement for integral T in cases where only comparisons
* must be supported, and it's desirable to prevent accidental dependency on
* exact values.
*/
template<typename T>
class Opaque final
{
static_assert(mozilla::IsIntegral<T>::value,
"mozilla::Opaque only supports integral types");
T mValue;
public:
Opaque() {}
explicit Opaque(T aValue) : mValue(aValue) {}
bool operator==(const Opaque& aOther) const {
return mValue == aOther.mValue;
}
bool operator!=(const Opaque& aOther) const {
return !(*this == aOther);
}
};
} // namespace mozilla
#endif /* mozilla_Opaque_h */

View File

@@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A version of |operator new| that eschews mandatory null-checks. */
#ifndef mozilla_OperatorNewExtensions_h
#define mozilla_OperatorNewExtensions_h
#include "mozilla/Assertions.h"
// Credit goes to WebKit for this implementation, cf.
// https://bugs.webkit.org/show_bug.cgi?id=74676
namespace mozilla {
enum NotNullTag {
KnownNotNull,
};
} // namespace mozilla
/*
* The logic here is a little subtle. [expr.new] states that if the allocation
* function being called returns null, then object initialization must not be
* done, and the entirety of the new expression must return null. Non-throwing
* (noexcept) functions are defined to return null to indicate failure. The
* standard placement operator new is defined in such a way, and so it requires
* a null check, even when that null check would be extraneous. Functions
* declared without such a specification are defined to throw std::bad_alloc if
* they fail, and return a non-null pointer otherwise. We compile without
* exceptions, so any placement new overload we define that doesn't declare
* itself as noexcept must therefore avoid generating a null check. Below is
* just such an overload.
*
* You might think that MOZ_NONNULL might perform the same function, but
* MOZ_NONNULL isn't supported on all of our compilers, and even when it is
* supported, doesn't work on all the versions we support. And even keeping
* those limitations in mind, we can't put MOZ_NONNULL on the global,
* standardized placement new function in any event.
*
* We deliberately don't add MOZ_NONNULL(3) to tag |p| as non-null, to benefit
* hypothetical static analyzers. Doing so makes |MOZ_ASSERT(p)|'s internal
* test vacuous, and some compilers warn about such vacuous tests.
*/
inline void*
operator new(size_t, mozilla::NotNullTag, void* p)
{
MOZ_ASSERT(p);
return p;
}
#endif // mozilla_OperatorNewExtensions_h

View File

@@ -0,0 +1,219 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A class holding a pair of objects that tries to conserve storage space. */
#ifndef mozilla_Pair_h
#define mozilla_Pair_h
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
namespace detail {
enum StorageType { AsBase, AsMember };
// Optimize storage using the Empty Base Optimization -- that empty base classes
// don't take up space -- to optimize size when one or the other class is
// stateless and can be used as a base class.
//
// The extra conditions on storage for B are necessary so that PairHelper won't
// ambiguously inherit from either A or B, such that one or the other base class
// would be inaccessible.
template<typename A, typename B,
detail::StorageType =
IsEmpty<A>::value ? detail::AsBase : detail::AsMember,
detail::StorageType =
IsEmpty<B>::value && !IsBaseOf<A, B>::value && !IsBaseOf<B, A>::value
? detail::AsBase
: detail::AsMember>
struct PairHelper;
template<typename A, typename B>
struct PairHelper<A, B, AsMember, AsMember>
{
protected:
template<typename AArg, typename BArg>
PairHelper(AArg&& aA, BArg&& aB)
: mFirstA(Forward<AArg>(aA)),
mSecondB(Forward<BArg>(aB))
{}
A& first() { return mFirstA; }
const A& first() const { return mFirstA; }
B& second() { return mSecondB; }
const B& second() const { return mSecondB; }
void swap(PairHelper& aOther)
{
Swap(mFirstA, aOther.mFirstA);
Swap(mSecondB, aOther.mSecondB);
}
private:
A mFirstA;
B mSecondB;
};
template<typename A, typename B>
struct PairHelper<A, B, AsMember, AsBase> : private B
{
protected:
template<typename AArg, typename BArg>
PairHelper(AArg&& aA, BArg&& aB)
: B(Forward<BArg>(aB)),
mFirstA(Forward<AArg>(aA))
{}
A& first() { return mFirstA; }
const A& first() const { return mFirstA; }
B& second() { return *this; }
const B& second() const { return *this; }
void swap(PairHelper& aOther)
{
Swap(mFirstA, aOther.mFirstA);
Swap(static_cast<B&>(*this), static_cast<B&>(aOther));
}
private:
A mFirstA;
};
template<typename A, typename B>
struct PairHelper<A, B, AsBase, AsMember> : private A
{
protected:
template<typename AArg, typename BArg>
PairHelper(AArg&& aA, BArg&& aB)
: A(Forward<AArg>(aA)),
mSecondB(Forward<BArg>(aB))
{}
A& first() { return *this; }
const A& first() const { return *this; }
B& second() { return mSecondB; }
const B& second() const { return mSecondB; }
void swap(PairHelper& aOther)
{
Swap(static_cast<A&>(*this), static_cast<A&>(aOther));
Swap(mSecondB, aOther.mSecondB);
}
private:
B mSecondB;
};
template<typename A, typename B>
struct PairHelper<A, B, AsBase, AsBase> : private A, private B
{
protected:
template<typename AArg, typename BArg>
PairHelper(AArg&& aA, BArg&& aB)
: A(Forward<AArg>(aA)),
B(Forward<BArg>(aB))
{}
A& first() { return static_cast<A&>(*this); }
const A& first() const { return static_cast<A&>(*this); }
B& second() { return static_cast<B&>(*this); }
const B& second() const { return static_cast<B&>(*this); }
void swap(PairHelper& aOther)
{
Swap(static_cast<A&>(*this), static_cast<A&>(aOther));
Swap(static_cast<B&>(*this), static_cast<B&>(aOther));
}
};
} // namespace detail
/**
* Pair is the logical concatenation of an instance of A with an instance B.
* Space is conserved when possible. Neither A nor B may be a final class.
*
* It's typically clearer to have individual A and B member fields. Except if
* you want the space-conserving qualities of Pair, you're probably better off
* not using this!
*
* No guarantees are provided about the memory layout of A and B, the order of
* initialization or destruction of A and B, and so on. (This is approximately
* required to optimize space usage.) The first/second names are merely
* conceptual!
*/
template<typename A, typename B>
struct Pair
: private detail::PairHelper<A, B>
{
typedef typename detail::PairHelper<A, B> Base;
public:
template<typename AArg, typename BArg>
Pair(AArg&& aA, BArg&& aB)
: Base(Forward<AArg>(aA), Forward<BArg>(aB))
{}
Pair(Pair&& aOther)
: Base(Move(aOther.first()), Move(aOther.second()))
{ }
Pair(const Pair& aOther) = default;
Pair& operator=(Pair&& aOther)
{
MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
first() = Move(aOther.first());
second() = Move(aOther.second());
return *this;
}
Pair& operator=(const Pair& aOther) = default;
/** The A instance. */
using Base::first;
/** The B instance. */
using Base::second;
/** Swap this pair with another pair. */
void swap(Pair& aOther) { Base::swap(aOther); }
};
template<typename A, class B>
void
Swap(Pair<A, B>& aX, Pair<A, B>& aY)
{
aX.swap(aY);
}
/**
* MakePair allows you to construct a Pair instance using type inference. A call
* like this:
*
* MakePair(Foo(), Bar())
*
* will return a Pair<Foo, Bar>.
*/
template<typename A, typename B>
Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type,
typename RemoveCV<typename RemoveReference<B>::Type>::Type>
MakePair(A&& aA, B&& aB)
{
return
Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type,
typename RemoveCV<typename RemoveReference<B>::Type>::Type>(
Forward<A>(aA),
Forward<B>(aB));
}
} // namespace mozilla
#endif /* mozilla_Pair_h */

View File

@@ -0,0 +1,196 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Operations for zeroing POD types, arrays, and so on.
*
* These operations are preferable to memset, memcmp, and the like because they
* don't require remembering to multiply by sizeof(T), array lengths, and so on
* everywhere.
*/
#ifndef mozilla_PodOperations_h
#define mozilla_PodOperations_h
#include "mozilla/Array.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include <stdint.h>
#include <string.h>
namespace mozilla {
/** Set the contents of |aT| to 0. */
template<typename T>
static MOZ_ALWAYS_INLINE void
PodZero(T* aT)
{
memset(aT, 0, sizeof(T));
}
/** Set the contents of |aNElem| elements starting at |aT| to 0. */
template<typename T>
static MOZ_ALWAYS_INLINE void
PodZero(T* aT, size_t aNElem)
{
/*
* This function is often called with 'aNElem' small; we use an inline loop
* instead of calling 'memset' with a non-constant length. The compiler
* should inline the memset call with constant size, though.
*/
for (T* end = aT + aNElem; aT < end; aT++) {
memset(aT, 0, sizeof(T));
}
}
/*
* Arrays implicitly convert to pointers to their first element, which is
* dangerous when combined with the above PodZero definitions. Adding an
* overload for arrays is ambiguous, so we need another identifier. The
* ambiguous overload is left to catch mistaken uses of PodZero; if you get a
* compile error involving PodZero and array types, use PodArrayZero instead.
*/
template<typename T, size_t N>
static void PodZero(T (&aT)[N]) = delete;
template<typename T, size_t N>
static void PodZero(T (&aT)[N], size_t aNElem) = delete;
/** Set the contents of the array |aT| to zero. */
template <class T, size_t N>
static MOZ_ALWAYS_INLINE void
PodArrayZero(T (&aT)[N])
{
memset(aT, 0, N * sizeof(T));
}
template <typename T, size_t N>
static MOZ_ALWAYS_INLINE void
PodArrayZero(Array<T, N>& aArr)
{
memset(&aArr[0], 0, N * sizeof(T));
}
/**
* Assign |*aSrc| to |*aDst|. The locations must not be the same and must not
* overlap.
*/
template<typename T>
static MOZ_ALWAYS_INLINE void
PodAssign(T* aDst, const T* aSrc)
{
MOZ_ASSERT(aDst + 1 <= aSrc || aSrc + 1 <= aDst,
"destination and source must not overlap");
memcpy(reinterpret_cast<char*>(aDst), reinterpret_cast<const char*>(aSrc),
sizeof(T));
}
/**
* Copy |aNElem| T elements from |aSrc| to |aDst|. The two memory ranges must
* not overlap!
*/
template<typename T>
static MOZ_ALWAYS_INLINE void
PodCopy(T* aDst, const T* aSrc, size_t aNElem)
{
MOZ_ASSERT(aDst + aNElem <= aSrc || aSrc + aNElem <= aDst,
"destination and source must not overlap");
if (aNElem < 128) {
/*
* Avoid using operator= in this loop, as it may have been
* intentionally deleted by the POD type.
*/
for (const T* srcend = aSrc + aNElem; aSrc < srcend; aSrc++, aDst++) {
PodAssign(aDst, aSrc);
}
} else {
memcpy(aDst, aSrc, aNElem * sizeof(T));
}
}
template<typename T>
static MOZ_ALWAYS_INLINE void
PodCopy(volatile T* aDst, const volatile T* aSrc, size_t aNElem)
{
MOZ_ASSERT(aDst + aNElem <= aSrc || aSrc + aNElem <= aDst,
"destination and source must not overlap");
/*
* Volatile |aDst| requires extra work, because it's undefined behavior to
* modify volatile objects using the mem* functions. Just write out the
* loops manually, using operator= rather than memcpy for the same reason,
* and let the compiler optimize to the extent it can.
*/
for (const volatile T* srcend = aSrc + aNElem;
aSrc < srcend;
aSrc++, aDst++) {
*aDst = *aSrc;
}
}
/*
* Copy the contents of the array |aSrc| into the array |aDst|, both of size N.
* The arrays must not overlap!
*/
template <class T, size_t N>
static MOZ_ALWAYS_INLINE void
PodArrayCopy(T (&aDst)[N], const T (&aSrc)[N])
{
PodCopy(aDst, aSrc, N);
}
/**
* Copy the memory for |aNElem| T elements from |aSrc| to |aDst|. If the two
* memory ranges overlap, then the effect is as if the |aNElem| elements are
* first copied from |aSrc| to a temporary array, and then from the temporary
* array to |aDst|.
*/
template<typename T>
static MOZ_ALWAYS_INLINE void
PodMove(T* aDst, const T* aSrc, size_t aNElem)
{
MOZ_ASSERT(aNElem <= SIZE_MAX / sizeof(T),
"trying to move an impossible number of elements");
memmove(aDst, aSrc, aNElem * sizeof(T));
}
/**
* Determine whether the |len| elements at |one| are memory-identical to the
* |len| elements at |two|.
*/
template<typename T>
static MOZ_ALWAYS_INLINE bool
PodEqual(const T* one, const T* two, size_t len)
{
if (len < 128) {
const T* p1end = one + len;
const T* p1 = one;
const T* p2 = two;
for (; p1 < p1end; p1++, p2++) {
if (*p1 != *p2) {
return false;
}
}
return true;
}
return !memcmp(one, two, len * sizeof(T));
}
/*
* Determine whether the |N| elements at |one| are memory-identical to the
* |N| elements at |two|.
*/
template <class T, size_t N>
static MOZ_ALWAYS_INLINE bool
PodEqual(const T (&one)[N], const T (&two)[N])
{
return PodEqual(one, two, N);
}
} // namespace mozilla
#endif /* mozilla_PodOperations_h */

View File

@@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* A poison value that can be used to fill a memory space with
* an address that leads to a safe crash when dereferenced.
*/
#ifndef mozilla_Poison_h
#define mozilla_Poison_h
#include "mozilla/Assertions.h"
#include "mozilla/Types.h"
#include <stdint.h>
MOZ_BEGIN_EXTERN_C
extern MFBT_DATA uintptr_t gMozillaPoisonValue;
/**
* @return the poison value.
*/
inline uintptr_t mozPoisonValue()
{
return gMozillaPoisonValue;
}
/**
* Overwrite the memory block of aSize bytes at aPtr with the poison value.
* aPtr MUST be aligned at a sizeof(uintptr_t) boundary.
* Only an even number of sizeof(uintptr_t) bytes are overwritten, the last
* few bytes (if any) is not overwritten.
*/
inline void mozWritePoison(void* aPtr, size_t aSize)
{
const uintptr_t POISON = mozPoisonValue();
char* p = (char*)aPtr;
char* limit = p + aSize;
MOZ_ASSERT((uintptr_t)aPtr % sizeof(uintptr_t) == 0, "bad alignment");
MOZ_ASSERT(aSize >= sizeof(uintptr_t), "poisoning this object has no effect");
for (; p < limit; p += sizeof(uintptr_t)) {
*((uintptr_t*)p) = POISON;
}
}
/**
* Initialize the poison value.
* This should only be called once.
*/
extern MFBT_API void mozPoisonValueInit();
/* Values annotated by CrashReporter */
extern MFBT_DATA uintptr_t gMozillaPoisonBase;
extern MFBT_DATA uintptr_t gMozillaPoisonSize;
MOZ_END_EXTERN_C
#if defined(__cplusplus)
namespace mozilla {
/**
* This class is designed to cause crashes when various kinds of memory
* corruption are observed. For instance, let's say we have a class C where we
* suspect out-of-bounds writes to some members. We can insert a member of type
* Poison near the members we suspect are being corrupted by out-of-bounds
* writes. Or perhaps we have a class K we suspect is subject to use-after-free
* violations, in which case it doesn't particularly matter where in the class
* we add the member of type Poison.
*
* In either case, we then insert calls to Check() throughout the code. Doing
* so enables us to narrow down the location where the corruption is occurring.
* A pleasant side-effect of these additional Check() calls is that crash
* signatures may become more regular, as crashes will ideally occur
* consolidated at the point of a Check(), rather than scattered about at
* various uses of the corrupted memory.
*/
class CorruptionCanary {
public:
CorruptionCanary() {
mValue = kCanarySet;
}
~CorruptionCanary() {
Check();
mValue = mozPoisonValue();
}
void Check() const {
if (mValue != kCanarySet) {
MOZ_CRASH("Canary check failed, check lifetime");
}
}
private:
static const uintptr_t kCanarySet = 0x0f0b0f0b;
uintptr_t mValue;
};
} // mozilla
#endif
#endif /* mozilla_Poison_h */

View File

@@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_Range_h
#define mozilla_Range_h
#include "mozilla/RangedPtr.h"
#include "mozilla/TypeTraits.h"
#include <stddef.h>
namespace mozilla {
// Range<T> is a tuple containing a pointer and a length.
template <typename T>
class Range
{
const RangedPtr<T> mStart;
const RangedPtr<T> mEnd;
public:
Range() : mStart(nullptr, 0), mEnd(nullptr, 0) {}
Range(T* aPtr, size_t aLength)
: mStart(aPtr, aPtr, aPtr + aLength),
mEnd(aPtr + aLength, aPtr, aPtr + aLength)
{}
Range(const RangedPtr<T>& aStart, const RangedPtr<T>& aEnd)
: mStart(aStart.get(), aStart.get(), aEnd.get()),
mEnd(aEnd.get(), aStart.get(), aEnd.get())
{
// Only accept two RangedPtrs within the same range.
aStart.checkIdenticalRange(aEnd);
MOZ_ASSERT(aStart <= aEnd);
}
template<typename U,
class = typename EnableIf<IsConvertible<U (*)[], T (*)[]>::value,
int>::Type>
MOZ_IMPLICIT Range(const Range<U>& aOther)
: mStart(aOther.mStart),
mEnd(aOther.mEnd)
{}
RangedPtr<T> begin() const { return mStart; }
RangedPtr<T> end() const { return mEnd; }
size_t length() const { return mEnd - mStart; }
T& operator[](size_t aOffset) const { return mStart[aOffset]; }
explicit operator bool() const { return mStart != nullptr; }
};
} // namespace mozilla
#endif /* mozilla_Range_h */

View File

@@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* A compile-time constant-length array, with bounds-checking assertions -- but
* unlike mozilla::Array, with indexes biased by a constant.
*
* Thus where mozilla::Array<int, 3> is a three-element array indexed by [0, 3),
* mozilla::RangedArray<int, 8, 3> is a three-element array indexed by [8, 11).
*/
#ifndef mozilla_RangedArray_h
#define mozilla_RangedArray_h
#include "mozilla/Array.h"
namespace mozilla {
template<typename T, size_t MinIndex, size_t Length>
class RangedArray
{
private:
typedef Array<T, Length> ArrayType;
ArrayType mArr;
public:
T& operator[](size_t aIndex)
{
MOZ_ASSERT(aIndex == MinIndex || aIndex > MinIndex);
return mArr[aIndex - MinIndex];
}
const T& operator[](size_t aIndex) const
{
MOZ_ASSERT(aIndex == MinIndex || aIndex > MinIndex);
return mArr[aIndex - MinIndex];
}
typedef typename ArrayType::iterator iterator;
typedef typename ArrayType::const_iterator const_iterator;
typedef typename ArrayType::reverse_iterator reverse_iterator;
typedef typename ArrayType::const_reverse_iterator const_reverse_iterator;
// Methods for range-based for loops.
iterator begin() { return mArr.begin(); }
const_iterator begin() const { return mArr.begin(); }
const_iterator cbegin() const { return mArr.cbegin(); }
iterator end() { return mArr.end(); }
const_iterator end() const { return mArr.end(); }
const_iterator cend() const { return mArr.cend(); }
// Methods for reverse iterating.
reverse_iterator rbegin() { return mArr.rbegin(); }
const_reverse_iterator rbegin() const { return mArr.rbegin(); }
const_reverse_iterator crbegin() const { return mArr.crbegin(); }
reverse_iterator rend() { return mArr.rend(); }
const_reverse_iterator rend() const { return mArr.rend(); }
const_reverse_iterator crend() const { return mArr.crend(); }
};
} // namespace mozilla
#endif // mozilla_RangedArray_h

View File

@@ -0,0 +1,292 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implements a smart pointer asserted to remain within a range specified at
* construction.
*/
#ifndef mozilla_RangedPtr_h
#define mozilla_RangedPtr_h
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include <stdint.h>
namespace mozilla {
/*
* RangedPtr is a smart pointer restricted to an address range specified at
* creation. The pointer (and any smart pointers derived from it) must remain
* within the range [start, end] (inclusive of end to facilitate use as
* sentinels). Dereferencing or indexing into the pointer (or pointers derived
* from it) must remain within the range [start, end). All the standard pointer
* operators are defined on it; in debug builds these operations assert that the
* range specified at construction is respected.
*
* In theory passing a smart pointer instance as an argument can be slightly
* slower than passing a T* (due to ABI requirements for passing structs versus
* passing pointers), if the method being called isn't inlined. If you are in
* extremely performance-critical code, you may want to be careful using this
* smart pointer as an argument type.
*
* RangedPtr<T> intentionally does not implicitly convert to T*. Use get() to
* explicitly convert to T*. Keep in mind that the raw pointer of course won't
* implement bounds checking in debug builds.
*/
template<typename T>
class RangedPtr
{
T* mPtr;
#ifdef DEBUG
T* const mRangeStart;
T* const mRangeEnd;
#endif
void checkSanity()
{
MOZ_ASSERT(mRangeStart <= mPtr);
MOZ_ASSERT(mPtr <= mRangeEnd);
}
/* Creates a new pointer for |aPtr|, restricted to this pointer's range. */
RangedPtr<T> create(T* aPtr) const
{
#ifdef DEBUG
return RangedPtr<T>(aPtr, mRangeStart, mRangeEnd);
#else
return RangedPtr<T>(aPtr, nullptr, size_t(0));
#endif
}
uintptr_t asUintptr() const { return reinterpret_cast<uintptr_t>(mPtr); }
public:
RangedPtr(T* aPtr, T* aStart, T* aEnd)
: mPtr(aPtr)
#ifdef DEBUG
, mRangeStart(aStart), mRangeEnd(aEnd)
#endif
{
MOZ_ASSERT(mRangeStart <= mRangeEnd);
checkSanity();
}
RangedPtr(T* aPtr, T* aStart, size_t aLength)
: mPtr(aPtr)
#ifdef DEBUG
, mRangeStart(aStart), mRangeEnd(aStart + aLength)
#endif
{
MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T));
MOZ_ASSERT(reinterpret_cast<uintptr_t>(mRangeStart) + aLength * sizeof(T) >=
reinterpret_cast<uintptr_t>(mRangeStart));
checkSanity();
}
/* Equivalent to RangedPtr(aPtr, aPtr, aLength). */
RangedPtr(T* aPtr, size_t aLength)
: mPtr(aPtr)
#ifdef DEBUG
, mRangeStart(aPtr), mRangeEnd(aPtr + aLength)
#endif
{
MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T));
MOZ_ASSERT(reinterpret_cast<uintptr_t>(mRangeStart) + aLength * sizeof(T) >=
reinterpret_cast<uintptr_t>(mRangeStart));
checkSanity();
}
/* Equivalent to RangedPtr(aArr, aArr, N). */
template<size_t N>
explicit RangedPtr(T (&aArr)[N])
: mPtr(aArr)
#ifdef DEBUG
, mRangeStart(aArr), mRangeEnd(aArr + N)
#endif
{
checkSanity();
}
T* get() const { return mPtr; }
explicit operator bool() const { return mPtr != nullptr; }
void checkIdenticalRange(const RangedPtr<T>& aOther) const
{
MOZ_ASSERT(mRangeStart == aOther.mRangeStart);
MOZ_ASSERT(mRangeEnd == aOther.mRangeEnd);
}
/*
* You can only assign one RangedPtr into another if the two pointers have
* the same valid range:
*
* char arr1[] = "hi";
* char arr2[] = "bye";
* RangedPtr<char> p1(arr1, 2);
* p1 = RangedPtr<char>(arr1 + 1, arr1, arr1 + 2); // works
* p1 = RangedPtr<char>(arr2, 3); // asserts
*/
RangedPtr<T>& operator=(const RangedPtr<T>& aOther)
{
checkIdenticalRange(aOther);
mPtr = aOther.mPtr;
checkSanity();
return *this;
}
RangedPtr<T> operator+(size_t aInc) const
{
MOZ_ASSERT(aInc <= size_t(-1) / sizeof(T));
MOZ_ASSERT(asUintptr() + aInc * sizeof(T) >= asUintptr());
return create(mPtr + aInc);
}
RangedPtr<T> operator-(size_t aDec) const
{
MOZ_ASSERT(aDec <= size_t(-1) / sizeof(T));
MOZ_ASSERT(asUintptr() - aDec * sizeof(T) <= asUintptr());
return create(mPtr - aDec);
}
/*
* You can assign a raw pointer into a RangedPtr if the raw pointer is
* within the range specified at creation.
*/
template <typename U>
RangedPtr<T>& operator=(U* aPtr)
{
*this = create(aPtr);
return *this;
}
template <typename U>
RangedPtr<T>& operator=(const RangedPtr<U>& aPtr)
{
MOZ_ASSERT(mRangeStart <= aPtr.mPtr);
MOZ_ASSERT(aPtr.mPtr <= mRangeEnd);
mPtr = aPtr.mPtr;
checkSanity();
return *this;
}
RangedPtr<T>& operator++()
{
return (*this += 1);
}
RangedPtr<T> operator++(int)
{
RangedPtr<T> rcp = *this;
++*this;
return rcp;
}
RangedPtr<T>& operator--()
{
return (*this -= 1);
}
RangedPtr<T> operator--(int)
{
RangedPtr<T> rcp = *this;
--*this;
return rcp;
}
RangedPtr<T>& operator+=(size_t aInc)
{
*this = *this + aInc;
return *this;
}
RangedPtr<T>& operator-=(size_t aDec)
{
*this = *this - aDec;
return *this;
}
T& operator[](int aIndex) const
{
MOZ_ASSERT(size_t(aIndex > 0 ? aIndex : -aIndex) <= size_t(-1) / sizeof(T));
return *create(mPtr + aIndex);
}
T& operator*() const
{
MOZ_ASSERT(mPtr >= mRangeStart);
MOZ_ASSERT(mPtr < mRangeEnd);
return *mPtr;
}
T* operator->() const
{
MOZ_ASSERT(mPtr >= mRangeStart);
MOZ_ASSERT(mPtr < mRangeEnd);
return mPtr;
}
template <typename U>
bool operator==(const RangedPtr<U>& aOther) const
{
return mPtr == aOther.mPtr;
}
template <typename U>
bool operator!=(const RangedPtr<U>& aOther) const
{
return !(*this == aOther);
}
template<typename U>
bool operator==(const U* u) const
{
return mPtr == u;
}
template<typename U>
bool operator!=(const U* u) const
{
return !(*this == u);
}
template <typename U>
bool operator<(const RangedPtr<U>& aOther) const
{
return mPtr < aOther.mPtr;
}
template <typename U>
bool operator<=(const RangedPtr<U>& aOther) const
{
return mPtr <= aOther.mPtr;
}
template <typename U>
bool operator>(const RangedPtr<U>& aOther) const
{
return mPtr > aOther.mPtr;
}
template <typename U>
bool operator>=(const RangedPtr<U>& aOther) const
{
return mPtr >= aOther.mPtr;
}
size_t operator-(const RangedPtr<T>& aOther) const
{
MOZ_ASSERT(mPtr >= aOther.mPtr);
return PointerRangeSize(aOther.mPtr, mPtr);
}
private:
RangedPtr() = delete;
T* operator&() = delete;
};
} /* namespace mozilla */
#endif /* mozilla_RangedPtr_h */

View File

@@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Small helper class for asserting uses of a class are non-reentrant. */
#ifndef mozilla_ReentrancyGuard_h
#define mozilla_ReentrancyGuard_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/GuardObjects.h"
namespace mozilla {
/* Useful for implementing containers that assert non-reentrancy */
class MOZ_RAII ReentrancyGuard
{
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
#ifdef DEBUG
bool& mEntered;
#endif
public:
template<class T>
#ifdef DEBUG
explicit ReentrancyGuard(T& aObj
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mEntered(aObj.mEntered)
#else
explicit ReentrancyGuard(T&
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
#endif
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
#ifdef DEBUG
MOZ_ASSERT(!mEntered);
mEntered = true;
#endif
}
~ReentrancyGuard()
{
#ifdef DEBUG
mEntered = false;
#endif
}
private:
ReentrancyGuard(const ReentrancyGuard&) = delete;
void operator=(const ReentrancyGuard&) = delete;
};
} // namespace mozilla
#endif /* mozilla_ReentrancyGuard_h */

View File

@@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_RefCountType_h
#define mozilla_RefCountType_h
#include <stdint.h>
/**
* MozRefCountType is Mozilla's reference count type.
*
* We use the same type to represent the refcount of RefCounted objects
* as well, in order to be able to use the leak detection facilities
* that are implemented by XPCOM.
*
* Note that this type is not in the mozilla namespace so that it is
* usable for both C and C++ code.
*/
typedef uintptr_t MozRefCountType;
/*
* This is the return type for AddRef() and Release() in nsISupports.
* IUnknown of COM returns an unsigned long from equivalent functions.
*
* The following ifdef exists to maintain binary compatibility with
* IUnknown, the base interface in Microsoft COM.
*/
#ifdef XP_WIN
typedef unsigned long MozExternalRefCountType;
#else
typedef uint32_t MozExternalRefCountType;
#endif
#endif

View File

@@ -0,0 +1,210 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* CRTP refcounting templates. Do not use unless you are an Expert. */
#ifndef mozilla_RefCounted_h
#define mozilla_RefCounted_h
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/RefCountType.h"
#include "mozilla/TypeTraits.h"
#if defined(MOZILLA_INTERNAL_API)
#include "nsXPCOM.h"
#endif
#if defined(MOZILLA_INTERNAL_API) && \
(defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
#define MOZ_REFCOUNTED_LEAK_CHECKING
#endif
namespace mozilla {
/**
* RefCounted<T> is a sort of a "mixin" for a class T. RefCounted
* manages, well, refcounting for T, and because RefCounted is
* parameterized on T, RefCounted<T> can call T's destructor directly.
* This means T doesn't need to have a virtual dtor and so doesn't
* need a vtable.
*
* RefCounted<T> is created with refcount == 0. Newly-allocated
* RefCounted<T> must immediately be assigned to a RefPtr to make the
* refcount > 0. It's an error to allocate and free a bare
* RefCounted<T>, i.e. outside of the RefPtr machinery. Attempts to
* do so will abort DEBUG builds.
*
* Live RefCounted<T> have refcount > 0. The lifetime (refcounts) of
* live RefCounted<T> are controlled by RefPtr<T> and
* RefPtr<super/subclass of T>. Upon a transition from refcounted==1
* to 0, the RefCounted<T> "dies" and is destroyed. The "destroyed"
* state is represented in DEBUG builds by refcount==0xffffdead. This
* state distinguishes use-before-ref (refcount==0) from
* use-after-destroy (refcount==0xffffdead).
*
* Note that when deriving from RefCounted or AtomicRefCounted, you
* should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public
* section of your class, where ClassName is the name of your class.
*/
namespace detail {
const MozRefCountType DEAD = 0xffffdead;
// When building code that gets compiled into Gecko, try to use the
// trace-refcount leak logging facilities.
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
class RefCountLogger
{
public:
static void logAddRef(const void* aPointer, MozRefCountType aRefCount,
const char* aTypeName, uint32_t aInstanceSize)
{
MOZ_ASSERT(aRefCount != DEAD);
NS_LogAddRef(const_cast<void*>(aPointer), aRefCount, aTypeName,
aInstanceSize);
}
static void logRelease(const void* aPointer, MozRefCountType aRefCount,
const char* aTypeName)
{
MOZ_ASSERT(aRefCount != DEAD);
NS_LogRelease(const_cast<void*>(aPointer), aRefCount, aTypeName);
}
};
#endif
// This is used WeakPtr.h as well as this file.
enum RefCountAtomicity
{
AtomicRefCount,
NonAtomicRefCount
};
template<typename T, RefCountAtomicity Atomicity>
class RefCounted
{
protected:
RefCounted() : mRefCnt(0) {}
~RefCounted() { MOZ_ASSERT(mRefCnt == detail::DEAD); }
public:
// Compatibility with nsRefPtr.
void AddRef() const
{
// Note: this method must be thread safe for AtomicRefCounted.
MOZ_ASSERT(int32_t(mRefCnt) >= 0);
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
++mRefCnt;
#else
const char* type = static_cast<const T*>(this)->typeName();
uint32_t size = static_cast<const T*>(this)->typeSize();
const void* ptr = static_cast<const T*>(this);
MozRefCountType cnt = ++mRefCnt;
detail::RefCountLogger::logAddRef(ptr, cnt, type, size);
#endif
}
void Release() const
{
// Note: this method must be thread safe for AtomicRefCounted.
MOZ_ASSERT(int32_t(mRefCnt) > 0);
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
MozRefCountType cnt = --mRefCnt;
#else
const char* type = static_cast<const T*>(this)->typeName();
const void* ptr = static_cast<const T*>(this);
MozRefCountType cnt = --mRefCnt;
// Note: it's not safe to touch |this| after decrementing the refcount,
// except for below.
detail::RefCountLogger::logRelease(ptr, cnt, type);
#endif
if (0 == cnt) {
// Because we have atomically decremented the refcount above, only
// one thread can get a 0 count here, so as long as we can assume that
// everything else in the system is accessing this object through
// RefPtrs, it's safe to access |this| here.
#ifdef DEBUG
mRefCnt = detail::DEAD;
#endif
delete static_cast<const T*>(this);
}
}
// Compatibility with wtf::RefPtr.
void ref() { AddRef(); }
void deref() { Release(); }
MozRefCountType refCount() const { return mRefCnt; }
bool hasOneRef() const
{
MOZ_ASSERT(mRefCnt > 0);
return mRefCnt == 1;
}
private:
mutable typename Conditional<Atomicity == AtomicRefCount,
Atomic<MozRefCountType>,
MozRefCountType>::Type mRefCnt;
};
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
// Passing override for the optional argument marks the typeName and
// typeSize functions defined by this macro as overrides.
#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...) \
virtual const char* typeName() const __VA_ARGS__ { return #T; } \
virtual size_t typeSize() const __VA_ARGS__ { return sizeof(*this); }
#else
#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...)
#endif
// Note that this macro is expanded unconditionally because it declares only
// two small inline functions which will hopefully get eliminated by the linker
// in non-leak-checking builds.
#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \
const char* typeName() const { return #T; } \
size_t typeSize() const { return sizeof(*this); }
} // namespace detail
template<typename T>
class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount>
{
public:
~RefCounted()
{
static_assert(IsBaseOf<RefCounted, T>::value,
"T must derive from RefCounted<T>");
}
};
namespace external {
/**
* AtomicRefCounted<T> is like RefCounted<T>, with an atomically updated
* reference counter.
*
* NOTE: Please do not use this class, use NS_INLINE_DECL_THREADSAFE_REFCOUNTING
* instead.
*/
template<typename T>
class AtomicRefCounted :
public mozilla::detail::RefCounted<T, mozilla::detail::AtomicRefCount>
{
public:
~AtomicRefCounted()
{
static_assert(IsBaseOf<AtomicRefCounted, T>::value,
"T must derive from AtomicRefCounted<T>");
}
};
} // namespace external
} // namespace mozilla
#endif // mozilla_RefCounted_h

View File

@@ -0,0 +1,656 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_RefPtr_h
#define mozilla_RefPtr_h
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
/*****************************************************************************/
// template <class T> class RefPtrGetterAddRefs;
class nsCOMPtr_helper;
namespace mozilla {
template<class T> class OwningNonNull;
template<class T> class StaticRefPtr;
// Traditionally, RefPtr supports automatic refcounting of any pointer type
// with AddRef() and Release() methods that follow the traditional semantics.
//
// This traits class can be specialized to operate on other pointer types. For
// example, we specialize this trait for opaque FFI types that represent
// refcounted objects in Rust.
//
// Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
// qualified type.
template<class U>
struct RefPtrTraits
{
static void AddRef(U* aPtr) {
aPtr->AddRef();
}
static void Release(U* aPtr) {
aPtr->Release();
}
};
} // namespace mozilla
template <class T>
class RefPtr
{
private:
void
assign_with_AddRef(T* aRawPtr)
{
if (aRawPtr) {
ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
}
assign_assuming_AddRef(aRawPtr);
}
void
assign_assuming_AddRef(T* aNewPtr)
{
T* oldPtr = mRawPtr;
mRawPtr = aNewPtr;
if (oldPtr) {
ConstRemovingRefPtrTraits<T>::Release(oldPtr);
}
}
private:
T* MOZ_OWNING_REF mRawPtr;
public:
typedef T element_type;
~RefPtr()
{
if (mRawPtr) {
ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
}
}
// Constructors
RefPtr()
: mRawPtr(nullptr)
// default constructor
{
}
RefPtr(const RefPtr<T>& aSmartPtr)
: mRawPtr(aSmartPtr.mRawPtr)
// copy-constructor
{
if (mRawPtr) {
ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
}
}
RefPtr(RefPtr<T>&& aRefPtr)
: mRawPtr(aRefPtr.mRawPtr)
{
aRefPtr.mRawPtr = nullptr;
}
// construct from a raw pointer (of the right type)
MOZ_IMPLICIT RefPtr(T* aRawPtr)
: mRawPtr(aRawPtr)
{
if (mRawPtr) {
ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
}
}
MOZ_IMPLICIT RefPtr(decltype(nullptr))
: mRawPtr(nullptr)
{
}
template <typename I>
MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
: mRawPtr(aSmartPtr.take())
// construct from |already_AddRefed|
{
}
template <typename I>
MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr)
: mRawPtr(aSmartPtr.take())
// construct from |otherRefPtr.forget()|
{
}
template <typename I>
MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr)
: mRawPtr(aSmartPtr.get())
// copy-construct from a smart pointer with a related pointer type
{
if (mRawPtr) {
ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
}
}
template <typename I>
MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
: mRawPtr(aSmartPtr.forget().take())
// construct from |Move(RefPtr<SomeSubclassOfT>)|.
{
}
MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
// Defined in OwningNonNull.h
template<class U>
MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
// Defined in StaticPtr.h
template<class U>
MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
// Assignment operators
RefPtr<T>&
operator=(decltype(nullptr))
{
assign_assuming_AddRef(nullptr);
return *this;
}
RefPtr<T>&
operator=(const RefPtr<T>& aRhs)
// copy assignment operator
{
assign_with_AddRef(aRhs.mRawPtr);
return *this;
}
template <typename I>
RefPtr<T>&
operator=(const RefPtr<I>& aRhs)
// assign from an RefPtr of a related pointer type
{
assign_with_AddRef(aRhs.get());
return *this;
}
RefPtr<T>&
operator=(T* aRhs)
// assign from a raw pointer (of the right type)
{
assign_with_AddRef(aRhs);
return *this;
}
template <typename I>
RefPtr<T>&
operator=(already_AddRefed<I>& aRhs)
// assign from |already_AddRefed|
{
assign_assuming_AddRef(aRhs.take());
return *this;
}
template <typename I>
RefPtr<T>&
operator=(already_AddRefed<I> && aRhs)
// assign from |otherRefPtr.forget()|
{
assign_assuming_AddRef(aRhs.take());
return *this;
}
RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
RefPtr<T>&
operator=(RefPtr<T> && aRefPtr)
{
assign_assuming_AddRef(aRefPtr.mRawPtr);
aRefPtr.mRawPtr = nullptr;
return *this;
}
// Defined in OwningNonNull.h
template<class U>
RefPtr<T>&
operator=(const mozilla::OwningNonNull<U>& aOther);
// Defined in StaticPtr.h
template<class U>
RefPtr<T>&
operator=(const mozilla::StaticRefPtr<U>& aOther);
// Other pointer operators
void
swap(RefPtr<T>& aRhs)
// ...exchange ownership with |aRhs|; can save a pair of refcount operations
{
T* temp = aRhs.mRawPtr;
aRhs.mRawPtr = mRawPtr;
mRawPtr = temp;
}
void
swap(T*& aRhs)
// ...exchange ownership with |aRhs|; can save a pair of refcount operations
{
T* temp = aRhs;
aRhs = mRawPtr;
mRawPtr = temp;
}
already_AddRefed<T>
forget()
// return the value of mRawPtr and null out mRawPtr. Useful for
// already_AddRefed return values.
{
T* temp = nullptr;
swap(temp);
return already_AddRefed<T>(temp);
}
template <typename I>
void
forget(I** aRhs)
// Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
// Useful to avoid unnecessary AddRef/Release pairs with "out"
// parameters where aRhs bay be a T** or an I** where I is a base class
// of T.
{
MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
*aRhs = mRawPtr;
mRawPtr = nullptr;
}
T*
get() const
/*
Prefer the implicit conversion provided automatically by |operator T*() const|.
Use |get()| to resolve ambiguity or to get a castable pointer.
*/
{
return const_cast<T*>(mRawPtr);
}
operator T*() const
#ifdef MOZ_HAVE_REF_QUALIFIERS
&
#endif
/*
...makes an |RefPtr| act like its underlying raw pointer type whenever it
is used in a context where a raw pointer is expected. It is this operator
that makes an |RefPtr| substitutable for a raw pointer.
Prefer the implicit use of this operator to calling |get()|, except where
necessary to resolve ambiguity.
*/
{
return get();
}
#ifdef MOZ_HAVE_REF_QUALIFIERS
// Don't allow implicit conversion of temporary RefPtr to raw pointer,
// because the refcount might be one and the pointer will immediately become
// invalid.
operator T*() const && = delete;
// These are needed to avoid the deleted operator above. XXX Why is operator!
// needed separately? Shouldn't the compiler prefer using the non-deleted
// operator bool instead of the deleted operator T*?
explicit operator bool() const { return !!mRawPtr; }
bool operator!() const { return !mRawPtr; }
#endif
T*
operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
{
MOZ_ASSERT(mRawPtr != nullptr,
"You can't dereference a NULL RefPtr with operator->().");
return get();
}
template <typename R, typename... Args>
class Proxy
{
typedef R (T::*member_function)(Args...);
T* mRawPtr;
member_function mFunction;
public:
Proxy(T* aRawPtr, member_function aFunction)
: mRawPtr(aRawPtr),
mFunction(aFunction)
{
}
template<typename... ActualArgs>
R operator()(ActualArgs&&... aArgs)
{
return ((*mRawPtr).*mFunction)(mozilla::Forward<ActualArgs>(aArgs)...);
}
};
template <typename R, typename... Args>
Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const
{
MOZ_ASSERT(mRawPtr != nullptr,
"You can't dereference a NULL RefPtr with operator->*().");
return Proxy<R, Args...>(get(), aFptr);
}
RefPtr<T>*
get_address()
// This is not intended to be used by clients. See |address_of|
// below.
{
return this;
}
const RefPtr<T>*
get_address() const
// This is not intended to be used by clients. See |address_of|
// below.
{
return this;
}
public:
T&
operator*() const
{
MOZ_ASSERT(mRawPtr != nullptr,
"You can't dereference a NULL RefPtr with operator*().");
return *get();
}
T**
StartAssignment()
{
assign_assuming_AddRef(nullptr);
return reinterpret_cast<T**>(&mRawPtr);
}
private:
// This helper class makes |RefPtr<const T>| possible by casting away
// the constness from the pointer when calling AddRef() and Release().
//
// This is necessary because AddRef() and Release() implementations can't
// generally expected to be const themselves (without heavy use of |mutable|
// and |const_cast| in their own implementations).
//
// This should be sound because while |RefPtr<const T>| provides a
// const view of an object, the object itself should not be const (it
// would have to be allocated as |new const T| or similar to be const).
template<class U>
struct ConstRemovingRefPtrTraits
{
static void AddRef(U* aPtr) {
mozilla::RefPtrTraits<U>::AddRef(aPtr);
}
static void Release(U* aPtr) {
mozilla::RefPtrTraits<U>::Release(aPtr);
}
};
template<class U>
struct ConstRemovingRefPtrTraits<const U>
{
static void AddRef(const U* aPtr) {
mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
}
static void Release(const U* aPtr) {
mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
}
};
};
class nsCycleCollectionTraversalCallback;
template <typename T>
void
CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback,
T* aChild, const char* aName, uint32_t aFlags);
template <typename T>
inline void
ImplCycleCollectionUnlink(RefPtr<T>& aField)
{
aField = nullptr;
}
template <typename T>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
RefPtr<T>& aField,
const char* aName,
uint32_t aFlags = 0)
{
CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
}
template <class T>
inline RefPtr<T>*
address_of(RefPtr<T>& aPtr)
{
return aPtr.get_address();
}
template <class T>
inline const RefPtr<T>*
address_of(const RefPtr<T>& aPtr)
{
return aPtr.get_address();
}
template <class T>
class RefPtrGetterAddRefs
/*
...
This class is designed to be used for anonymous temporary objects in the
argument list of calls that return COM interface pointers, e.g.,
RefPtr<IFoo> fooP;
...->GetAddRefedPointer(getter_AddRefs(fooP))
DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
When initialized with a |RefPtr|, as in the example above, it returns
a |void**|, a |T**|, or an |nsISupports**| as needed, that the
outer call (|GetAddRefedPointer| in this case) can fill in.
This type should be a nested class inside |RefPtr<T>|.
*/
{
public:
explicit
RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
: mTargetSmartPtr(aSmartPtr)
{
// nothing else to do
}
operator void**()
{
return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
}
operator T**()
{
return mTargetSmartPtr.StartAssignment();
}
T*&
operator*()
{
return *(mTargetSmartPtr.StartAssignment());
}
private:
RefPtr<T>& mTargetSmartPtr;
};
template <class T>
inline RefPtrGetterAddRefs<T>
getter_AddRefs(RefPtr<T>& aSmartPtr)
/*
Used around a |RefPtr| when
...makes the class |RefPtrGetterAddRefs<T>| invisible.
*/
{
return RefPtrGetterAddRefs<T>(aSmartPtr);
}
// Comparing two |RefPtr|s
template <class T, class U>
inline bool
operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs)
{
return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
}
template <class T, class U>
inline bool
operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs)
{
return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
}
// Comparing an |RefPtr| to a raw pointer
template <class T, class U>
inline bool
operator==(const RefPtr<T>& aLhs, const U* aRhs)
{
return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs);
}
template <class T, class U>
inline bool
operator==(const U* aLhs, const RefPtr<T>& aRhs)
{
return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
}
template <class T, class U>
inline bool
operator!=(const RefPtr<T>& aLhs, const U* aRhs)
{
return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs);
}
template <class T, class U>
inline bool
operator!=(const U* aLhs, const RefPtr<T>& aRhs)
{
return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
}
template <class T, class U>
inline bool
operator==(const RefPtr<T>& aLhs, U* aRhs)
{
return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
}
template <class T, class U>
inline bool
operator==(U* aLhs, const RefPtr<T>& aRhs)
{
return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
}
template <class T, class U>
inline bool
operator!=(const RefPtr<T>& aLhs, U* aRhs)
{
return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
}
template <class T, class U>
inline bool
operator!=(U* aLhs, const RefPtr<T>& aRhs)
{
return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
}
// Comparing an |RefPtr| to |nullptr|
template <class T>
inline bool
operator==(const RefPtr<T>& aLhs, decltype(nullptr))
{
return aLhs.get() == nullptr;
}
template <class T>
inline bool
operator==(decltype(nullptr), const RefPtr<T>& aRhs)
{
return nullptr == aRhs.get();
}
template <class T>
inline bool
operator!=(const RefPtr<T>& aLhs, decltype(nullptr))
{
return aLhs.get() != nullptr;
}
template <class T>
inline bool
operator!=(decltype(nullptr), const RefPtr<T>& aRhs)
{
return nullptr != aRhs.get();
}
/*****************************************************************************/
template <class T>
inline already_AddRefed<T>
do_AddRef(T* aObj)
{
RefPtr<T> ref(aObj);
return ref.forget();
}
template <class T>
inline already_AddRefed<T>
do_AddRef(const RefPtr<T>& aObj)
{
RefPtr<T> ref(aObj);
return ref.forget();
}
namespace mozilla {
/**
* Helper function to be able to conveniently write things like:
*
* already_AddRefed<T>
* f(...)
* {
* return MakeAndAddRef<T>(...);
* }
*/
template<typename T, typename... Args>
already_AddRefed<T>
MakeAndAddRef(Args&&... aArgs)
{
RefPtr<T> p(new T(Forward<Args>(aArgs)...));
return p.forget();
}
} // namespace mozilla
#endif /* mozilla_RefPtr_h */

View File

@@ -0,0 +1,168 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* An iterator that acts like another iterator, but iterating in
* the negative direction. (Note that not all iterators can iterate
* in the negative direction.) */
#ifndef mozilla_ReverseIterator_h
#define mozilla_ReverseIterator_h
#include "mozilla/Attributes.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
template<typename IteratorT>
class ReverseIterator
{
public:
template<typename Iterator>
explicit ReverseIterator(Iterator aIter)
: mCurrent(aIter) { }
template<typename Iterator>
MOZ_IMPLICIT ReverseIterator(const ReverseIterator<Iterator>& aOther)
: mCurrent(aOther.mCurrent) { }
decltype(*DeclVal<IteratorT>()) operator*() const
{
IteratorT tmp = mCurrent;
return *--tmp;
}
/* Increments and decrements operators */
ReverseIterator& operator++() { --mCurrent; return *this; }
ReverseIterator& operator--() { ++mCurrent; return *this; }
ReverseIterator operator++(int) { auto ret = *this; mCurrent--; return ret; }
ReverseIterator operator--(int) { auto ret = *this; mCurrent++; return ret; }
/* Comparison operators */
template<typename Iterator1, typename Iterator2>
friend bool operator==(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2);
template<typename Iterator1, typename Iterator2>
friend bool operator!=(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2);
template<typename Iterator1, typename Iterator2>
friend bool operator<(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2);
template<typename Iterator1, typename Iterator2>
friend bool operator<=(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2);
template<typename Iterator1, typename Iterator2>
friend bool operator>(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2);
template<typename Iterator1, typename Iterator2>
friend bool operator>=(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2);
private:
IteratorT mCurrent;
};
template<typename Iterator1, typename Iterator2>
bool
operator==(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2)
{
return aIter1.mCurrent == aIter2.mCurrent;
}
template<typename Iterator1, typename Iterator2>
bool
operator!=(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2)
{
return aIter1.mCurrent != aIter2.mCurrent;
}
template<typename Iterator1, typename Iterator2>
bool
operator<(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2)
{
return aIter1.mCurrent > aIter2.mCurrent;
}
template<typename Iterator1, typename Iterator2>
bool
operator<=(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2)
{
return aIter1.mCurrent >= aIter2.mCurrent;
}
template<typename Iterator1, typename Iterator2>
bool
operator>(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2)
{
return aIter1.mCurrent < aIter2.mCurrent;
}
template<typename Iterator1, typename Iterator2>
bool
operator>=(const ReverseIterator<Iterator1>& aIter1,
const ReverseIterator<Iterator2>& aIter2)
{
return aIter1.mCurrent <= aIter2.mCurrent;
}
namespace detail {
template<typename IteratorT>
class IteratorRange
{
public:
typedef IteratorT iterator;
typedef IteratorT const_iterator;
typedef ReverseIterator<IteratorT> reverse_iterator;
typedef ReverseIterator<IteratorT> const_reverse_iterator;
template<typename Iterator1, typename Iterator2>
MOZ_IMPLICIT IteratorRange(Iterator1 aIterBegin, Iterator2 aIterEnd)
: mIterBegin(aIterBegin), mIterEnd(aIterEnd) { }
template<typename Iterator>
MOZ_IMPLICIT IteratorRange(const IteratorRange<Iterator>& aOther)
: mIterBegin(aOther.mIterBegin), mIterEnd(aOther.mIterEnd) { }
iterator begin() const { return mIterBegin; }
const_iterator cbegin() const { return begin(); }
iterator end() const { return mIterEnd; }
const_iterator cend() const { return end(); }
reverse_iterator rbegin() const { return reverse_iterator(mIterEnd); }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() const { return reverse_iterator(mIterBegin); }
const_reverse_iterator crend() const { return rend(); }
private:
IteratorT mIterBegin;
IteratorT mIterEnd;
};
} // namespace detail
template<typename Range>
detail::IteratorRange<typename Range::reverse_iterator>
Reversed(Range& aRange)
{
return {aRange.rbegin(), aRange.rend()};
}
template<typename Range>
detail::IteratorRange<typename Range::const_reverse_iterator>
Reversed(const Range& aRange)
{
return {aRange.rbegin(), aRange.rend()};
}
} // namespace mozilla
#endif // mozilla_ReverseIterator_h

View File

@@ -0,0 +1,115 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A set abstraction for enumeration values. */
#ifndef mozilla_RollingMean_h_
#define mozilla_RollingMean_h_
#include "mozilla/Assertions.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/Vector.h"
#include <stddef.h>
namespace mozilla {
/**
* RollingMean<T> calculates a rolling mean of the values it is given. It
* accumulates the total as values are added and removed. The second type
* argument S specifies the type of the total. This may need to be a bigger
* type in order to maintain that the sum of all values in the average doesn't
* exceed the maximum input value.
*
* WARNING: Float types are not supported due to rounding errors.
*/
template<typename T, typename S>
class RollingMean
{
private:
size_t mInsertIndex;
size_t mMaxValues;
Vector<T> mValues;
S mTotal;
public:
static_assert(!IsFloatingPoint<T>::value,
"floating-point types are unsupported due to rounding "
"errors");
explicit RollingMean(size_t aMaxValues)
: mInsertIndex(0),
mMaxValues(aMaxValues),
mTotal(0)
{
MOZ_ASSERT(aMaxValues > 0);
}
RollingMean& operator=(RollingMean&& aOther)
{
MOZ_ASSERT(this != &aOther, "self-assignment is forbidden");
this->~RollingMean();
new(this) RollingMean(aOther.mMaxValues);
mInsertIndex = aOther.mInsertIndex;
mTotal = aOther.mTotal;
mValues.swap(aOther.mValues);
return *this;
}
/**
* Insert a value into the rolling mean.
*/
bool insert(T aValue)
{
MOZ_ASSERT(mValues.length() <= mMaxValues);
if (mValues.length() == mMaxValues) {
mTotal = mTotal - mValues[mInsertIndex] + aValue;
mValues[mInsertIndex] = aValue;
} else {
if (!mValues.append(aValue)) {
return false;
}
mTotal = mTotal + aValue;
}
mInsertIndex = (mInsertIndex + 1) % mMaxValues;
return true;
}
/**
* Calculate the rolling mean.
*/
T mean()
{
MOZ_ASSERT(!empty());
return T(mTotal / int64_t(mValues.length()));
}
bool empty()
{
return mValues.empty();
}
/**
* Remove all values from the rolling mean.
*/
void clear()
{
mValues.clear();
mInsertIndex = 0;
mTotal = T(0);
}
size_t maxValues()
{
return mMaxValues;
}
};
} // namespace mozilla
#endif // mozilla_RollingMean_h_

View File

@@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Simple class for computing SHA1. */
#ifndef mozilla_SHA1_h
#define mozilla_SHA1_h
#include "mozilla/Types.h"
#include <stddef.h>
#include <stdint.h>
namespace mozilla {
/**
* This class computes the SHA1 hash of a byte sequence, or of the concatenation
* of multiple sequences. For example, computing the SHA1 of two sequences of
* bytes could be done as follows:
*
* void SHA1(const uint8_t* buf1, uint32_t size1,
* const uint8_t* buf2, uint32_t size2,
* SHA1Sum::Hash& hash)
* {
* SHA1Sum s;
* s.update(buf1, size1);
* s.update(buf2, size2);
* s.finish(hash);
* }
*
* The finish method may only be called once and cannot be followed by calls
* to update.
*/
class SHA1Sum
{
union
{
uint32_t mW[16]; /* input buffer */
uint8_t mB[64];
} mU;
uint64_t mSize; /* count of hashed bytes. */
unsigned mH[22]; /* 5 state variables, 16 tmp values, 1 extra */
bool mDone;
public:
MFBT_API SHA1Sum();
static const size_t kHashSize = 20;
typedef uint8_t Hash[kHashSize];
/* Add len bytes of dataIn to the data sequence being hashed. */
MFBT_API void update(const void* aData, uint32_t aLength);
/* Compute the final hash of all data into hashOut. */
MFBT_API void finish(SHA1Sum::Hash& aHashOut);
};
} /* namespace mozilla */
#endif /* mozilla_SHA1_h */

View File

@@ -0,0 +1,288 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Provides saturation arithmetics for scalar types. */
#ifndef mozilla_Saturate_h
#define mozilla_Saturate_h
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
#include <limits>
namespace mozilla {
namespace detail {
/**
* |SaturateOp<T>| wraps scalar values for saturation arithmetics. Usage:
*
* uint32_t value = 1;
*
* ++SaturateOp<uint32_t>(value); // value is 2
* --SaturateOp<uint32_t>(value); // value is 1
* --SaturateOp<uint32_t>(value); // value is 0
* --SaturateOp<uint32_t>(value); // value is still 0
*
* Please add new operators when required.
*
* |SaturateOp<T>| will saturate at the minimum and maximum values of
* type T. If you need other bounds, implement a clamped-type class and
* specialize the type traits accordingly.
*/
template <typename T>
class SaturateOp
{
public:
explicit SaturateOp(T& aValue)
: mValue(aValue)
{
// We should actually check for |std::is_scalar<T>::value| to be
// true, but this type trait is not available everywhere. Relax
// this assertion if you want to use floating point values as well.
static_assert(IsIntegral<T>::value,
"Integral type required in instantiation");
}
// Add and subtract operators
T operator+(const T& aRhs) const
{
return T(mValue) += aRhs;
}
T operator-(const T& aRhs) const
{
return T(mValue) -= aRhs;
}
// Compound operators
const T& operator+=(const T& aRhs) const
{
const T min = std::numeric_limits<T>::min();
const T max = std::numeric_limits<T>::max();
if (aRhs > static_cast<T>(0)) {
mValue = (max - aRhs) < mValue ? max : mValue + aRhs;
} else {
mValue = (min - aRhs) > mValue ? min : mValue + aRhs;
}
return mValue;
}
const T& operator-=(const T& aRhs) const
{
const T min = std::numeric_limits<T>::min();
const T max = std::numeric_limits<T>::max();
if (aRhs > static_cast<T>(0)) {
mValue = (min + aRhs) > mValue ? min : mValue - aRhs;
} else {
mValue = (max + aRhs) < mValue ? max : mValue - aRhs;
}
return mValue;
}
// Increment and decrement operators
const T& operator++() const // prefix
{
return operator+=(static_cast<T>(1));
}
T operator++(int) const // postfix
{
const T value(mValue);
operator++();
return value;
}
const T& operator--() const // prefix
{
return operator-=(static_cast<T>(1));
}
T operator--(int) const // postfix
{
const T value(mValue);
operator--();
return value;
}
private:
SaturateOp(const SaturateOp<T>&) = delete;
SaturateOp(SaturateOp<T>&&) = delete;
SaturateOp& operator=(const SaturateOp<T>&) = delete;
SaturateOp& operator=(SaturateOp<T>&&) = delete;
T& mValue;
};
/**
* |Saturate<T>| is a value type for saturation arithmetics. It's
* build on top of |SaturateOp<T>|.
*/
template <typename T>
class Saturate
{
public:
Saturate() = default;
MOZ_IMPLICIT Saturate(const Saturate<T>&) = default;
MOZ_IMPLICIT Saturate(Saturate<T>&& aValue)
{
mValue = Move(aValue.mValue);
}
explicit Saturate(const T& aValue)
: mValue(aValue)
{ }
const T& value() const
{
return mValue;
}
// Compare operators
bool operator==(const Saturate<T>& aRhs) const
{
return mValue == aRhs.mValue;
}
bool operator!=(const Saturate<T>& aRhs) const
{
return !operator==(aRhs);
}
bool operator==(const T& aRhs) const
{
return mValue == aRhs;
}
bool operator!=(const T& aRhs) const
{
return !operator==(aRhs);
}
// Assignment operators
Saturate<T>& operator=(const Saturate<T>&) = default;
Saturate<T>& operator=(Saturate<T>&& aRhs)
{
mValue = Move(aRhs.mValue);
return *this;
}
// Add and subtract operators
Saturate<T> operator+(const Saturate<T>& aRhs) const
{
Saturate<T> lhs(mValue);
return lhs += aRhs.mValue;
}
Saturate<T> operator+(const T& aRhs) const
{
Saturate<T> lhs(mValue);
return lhs += aRhs;
}
Saturate<T> operator-(const Saturate<T>& aRhs) const
{
Saturate<T> lhs(mValue);
return lhs -= aRhs.mValue;
}
Saturate<T> operator-(const T& aRhs) const
{
Saturate<T> lhs(mValue);
return lhs -= aRhs;
}
// Compound operators
Saturate<T>& operator+=(const Saturate<T>& aRhs)
{
SaturateOp<T>(mValue) += aRhs.mValue;
return *this;
}
Saturate<T>& operator+=(const T& aRhs)
{
SaturateOp<T>(mValue) += aRhs;
return *this;
}
Saturate<T>& operator-=(const Saturate<T>& aRhs)
{
SaturateOp<T>(mValue) -= aRhs.mValue;
return *this;
}
Saturate<T>& operator-=(const T& aRhs)
{
SaturateOp<T>(mValue) -= aRhs;
return *this;
}
// Increment and decrement operators
Saturate<T>& operator++() // prefix
{
++SaturateOp<T>(mValue);
return *this;
}
Saturate<T> operator++(int) // postfix
{
return Saturate<T>(SaturateOp<T>(mValue)++);
}
Saturate<T>& operator--() // prefix
{
--SaturateOp<T>(mValue);
return *this;
}
Saturate<T> operator--(int) // postfix
{
return Saturate<T>(SaturateOp<T>(mValue)--);
}
private:
T mValue;
};
} // namespace detail
typedef detail::Saturate<int8_t> SaturateInt8;
typedef detail::Saturate<int16_t> SaturateInt16;
typedef detail::Saturate<int32_t> SaturateInt32;
typedef detail::Saturate<uint8_t> SaturateUint8;
typedef detail::Saturate<uint16_t> SaturateUint16;
typedef detail::Saturate<uint32_t> SaturateUint32;
} // namespace mozilla
template<typename LhsT, typename RhsT>
bool
operator==(LhsT aLhs, const mozilla::detail::Saturate<RhsT>& aRhs)
{
return aRhs.operator==(static_cast<RhsT>(aLhs));
}
template<typename LhsT, typename RhsT>
bool
operator!=(LhsT aLhs, const mozilla::detail::Saturate<RhsT>& aRhs)
{
return !(aLhs == aRhs);
}
#endif // mozilla_Saturate_h

View File

@@ -0,0 +1,135 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* RAII class for executing arbitrary actions at scope end. */
#ifndef mozilla_ScopeExit_h
#define mozilla_ScopeExit_h
/*
* See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189.pdf for a
* standards-track version of this.
*
* Error handling can be complex when various actions need to be performed that
* need to be undone if an error occurs midway. This can be handled with a
* collection of boolean state variables and gotos, which can get clunky and
* error-prone:
*
* {
* if (!a.setup())
* goto fail;
* isASetup = true;
*
* if (!b.setup())
* goto fail;
* isBSetup = true;
*
* ...
* return true;
*
* fail:
* if (isASetup)
* a.teardown();
* if (isBSetup)
* b.teardown();
* return false;
* }
*
* ScopeExit is a mechanism to simplify this pattern by keeping an RAII guard
* class that will perform the teardown on destruction, unless released. So the
* above would become:
*
* {
* if (!a.setup()) {
* return false;
* }
* auto guardA = MakeScopeExit([&] {
* a.teardown();
* });
*
* if (!b.setup()) {
* return false;
* }
* auto guardB = MakeScopeExit([&] {
* b.teardown();
* });
*
* ...
* guardA.release();
* guardB.release();
* return true;
* }
*
* This header provides:
*
* - |ScopeExit| - a container for a cleanup call, automically called at the
* end of the scope;
* - |MakeScopeExit| - a convenience function for constructing a |ScopeExit|
* with a given cleanup routine, commonly used with a lambda function.
*
* Note that the RAII classes defined in this header do _not_ perform any form
* of reference-counting or garbage-collection. These classes have exactly two
* behaviors:
*
* - if |release()| has not been called, the cleanup is always performed at
* the end of the scope;
* - if |release()| has been called, nothing will happen at the end of the
* scope.
*/
#include "mozilla/GuardObjects.h"
#include "mozilla/Move.h"
namespace mozilla {
template <typename ExitFunction>
class MOZ_STACK_CLASS ScopeExit {
ExitFunction mExitFunction;
bool mExecuteOnDestruction;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
public:
explicit ScopeExit(ExitFunction&& cleanup
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mExitFunction(cleanup)
, mExecuteOnDestruction(true)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
ScopeExit(ScopeExit&& rhs)
: mExitFunction(mozilla::Move(rhs.mExitFunction))
, mExecuteOnDestruction(rhs.mExecuteOnDestruction)
{
rhs.release();
}
~ScopeExit() {
if (mExecuteOnDestruction) {
mExitFunction();
}
}
void release() {
mExecuteOnDestruction = false;
}
private:
explicit ScopeExit(const ScopeExit&) = delete;
ScopeExit& operator=(const ScopeExit&) = delete;
ScopeExit& operator=(ScopeExit&&) = delete;
};
template <typename ExitFunction>
ScopeExit<ExitFunction>
MakeScopeExit(ExitFunction&& exitFunction)
{
return ScopeExit<ExitFunction>(mozilla::Move(exitFunction));
}
} /* namespace mozilla */
#endif /* mozilla_ScopeExit_h */

View File

@@ -0,0 +1,255 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* DEPRECATED: Use UniquePtr.h instead. */
#ifndef mozilla_Scoped_h
#define mozilla_Scoped_h
/*
* DEPRECATED: Use UniquePtr.h instead.
*
* Resource Acquisition Is Initialization is a programming idiom used
* to write robust code that is able to deallocate resources properly,
* even in presence of execution errors or exceptions that need to be
* propagated. The Scoped* classes defined via the |SCOPED_TEMPLATE|
* and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLTE| macros perform the
* deallocation of the resource they hold once program execution
* reaches the end of the scope for which they have been defined.
* These macros have been used to automatically close file
* descriptors/file handles when reaching the end of the scope,
* graphics contexts, etc.
*
* The general scenario for RAII classes created by the above macros
* is the following:
*
* ScopedClass foo(create_value());
* // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()|
* to access the value.
* // ... In case of |return| or |throw|, |foo| is deallocated automatically.
* // ... If |foo| needs to be returned or stored, use |foo.forget()|
*
* Note that the RAII classes defined in this header do _not_ perform any form
* of reference-counting or garbage-collection. These classes have exactly two
* behaviors:
*
* - if |forget()| has not been called, the resource is always deallocated at
* the end of the scope;
* - if |forget()| has been called, any control on the resource is unbound
* and the resource is not deallocated by the class.
*/
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/GuardObjects.h"
#include "mozilla/Move.h"
namespace mozilla {
/*
* Scoped is a helper to create RAII wrappers
* Type argument |Traits| is expected to have the following structure:
*
* struct Traits
* {
* // Define the type of the value stored in the wrapper
* typedef value_type type;
* // Returns the value corresponding to the uninitialized or freed state
* const static type empty();
* // Release resources corresponding to the wrapped value
* // This function is responsible for not releasing an |empty| value
* const static void release(type);
* }
*/
template<typename Traits>
class MOZ_NON_TEMPORARY_CLASS Scoped
{
public:
typedef typename Traits::type Resource;
explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
: mValue(Traits::empty())
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
explicit Scoped(const Resource& aValue
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mValue(aValue)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
/* Move constructor. */
Scoped(Scoped&& aOther
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mValue(Move(aOther.mValue))
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
aOther.mValue = Traits::empty();
}
~Scoped() { Traits::release(mValue); }
// Constant getter
operator const Resource&() const { return mValue; }
const Resource& operator->() const { return mValue; }
const Resource& get() const { return mValue; }
// Non-constant getter.
Resource& rwget() { return mValue; }
/*
* Forget the resource.
*
* Once |forget| has been called, the |Scoped| is neutralized, i.e. it will
* have no effect at destruction (unless it is reset to another resource by
* |operator=|).
*
* @return The original resource.
*/
Resource forget()
{
Resource tmp = mValue;
mValue = Traits::empty();
return tmp;
}
/*
* Perform immediate clean-up of this |Scoped|.
*
* If this |Scoped| is currently empty, this method has no effect.
*/
void dispose()
{
Traits::release(mValue);
mValue = Traits::empty();
}
bool operator==(const Resource& aOther) const { return mValue == aOther; }
/*
* Replace the resource with another resource.
*
* Calling |operator=| has the side-effect of triggering clean-up. If you do
* not want to trigger clean-up, you should first invoke |forget|.
*
* @return this
*/
Scoped& operator=(const Resource& aOther) { return reset(aOther); }
Scoped& reset(const Resource& aOther)
{
Traits::release(mValue);
mValue = aOther;
return *this;
}
/* Move assignment operator. */
Scoped& operator=(Scoped&& aRhs)
{
MOZ_ASSERT(&aRhs != this, "self-move-assignment not allowed");
this->~Scoped();
new(this) Scoped(Move(aRhs));
return *this;
}
private:
explicit Scoped(const Scoped& aValue) = delete;
Scoped& operator=(const Scoped& aValue) = delete;
private:
Resource mValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/*
* SCOPED_TEMPLATE defines a templated class derived from Scoped
* This allows to implement templates such as ScopedFreePtr.
*
* @param name The name of the class to define.
* @param Traits A struct implementing clean-up. See the implementations
* for more details.
*/
#define SCOPED_TEMPLATE(name, Traits) \
template<typename Type> \
struct MOZ_NON_TEMPORARY_CLASS name : public mozilla::Scoped<Traits<Type> > \
{ \
typedef mozilla::Scoped<Traits<Type> > Super; \
typedef typename Super::Resource Resource; \
name& operator=(Resource aRhs) \
{ \
Super::operator=(aRhs); \
return *this; \
} \
name& operator=(name&& aRhs) \
{ \
Super::operator=(Move(aRhs)); \
return *this; \
} \
explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \
: Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) \
{} \
explicit name(Resource aRhs \
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \
: Super(aRhs \
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \
{} \
name(name&& aRhs \
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \
: Super(Move(aRhs) \
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \
{} \
private: \
explicit name(name&) = delete; \
name& operator=(name&) = delete; \
};
/*
* MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped
* pointers for types with custom deleters; just overload
* TypeSpecificDelete(T*) in the same namespace as T to call the deleter for
* type T.
*
* @param name The name of the class to define.
* @param Type A struct implementing clean-up. See the implementations
* for more details.
* *param Deleter The function that is used to delete/destroy/free a
* non-null value of Type*.
*
* Example:
*
* MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, \
* PR_Close)
* ...
* {
* ScopedPRFileDesc file(PR_OpenFile(...));
* ...
* } // file is closed with PR_Close here
*/
#define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \
template <> inline void TypeSpecificDelete(Type* aValue) { Deleter(aValue); } \
typedef ::mozilla::TypeSpecificScopedPointer<Type> name;
template <typename T> void TypeSpecificDelete(T* aValue);
template <typename T>
struct TypeSpecificScopedPointerTraits
{
typedef T* type;
static type empty() { return nullptr; }
static void release(type aValue)
{
if (aValue) {
TypeSpecificDelete(aValue);
}
}
};
SCOPED_TEMPLATE(TypeSpecificScopedPointer, TypeSpecificScopedPointerTraits)
} /* namespace mozilla */
#endif /* mozilla_Scoped_h */

View File

@@ -0,0 +1,339 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// A simple segmented vector class.
//
// This class should be used in preference to mozilla::Vector or nsTArray when
// you are simply gathering items in order to later iterate over them.
//
// - In the case where you don't know the final size in advance, using
// SegmentedVector avoids the need to repeatedly allocate increasingly large
// buffers and copy the data into them.
//
// - In the case where you know the final size in advance and so can set the
// capacity appropriately, using SegmentedVector still avoids the need for
// large allocations (which can trigger OOMs).
#ifndef mozilla_SegmentedVector_h
#define mozilla_SegmentedVector_h
#include "mozilla/Alignment.h"
#include "mozilla/AllocPolicy.h"
#include "mozilla/Array.h"
#include "mozilla/LinkedList.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
#include <new> // for placement new
namespace mozilla {
// |IdealSegmentSize| specifies how big each segment will be in bytes (or as
// close as is possible). Use the following guidelines to choose a size.
//
// - It should be a power-of-two, to avoid slop.
//
// - It should not be too small, so that segment allocations are infrequent,
// and so that per-segment bookkeeping overhead is low. Typically each
// segment should be able to hold hundreds of elements, at least.
//
// - It should not be too large, so that OOMs are unlikely when allocating
// segments, and so that not too much space is wasted when the final segment
// is not full.
//
// The ideal size depends on how the SegmentedVector is used and the size of
// |T|, but reasonable sizes include 1024, 4096 (the default), 8192, and 16384.
//
template<typename T,
size_t IdealSegmentSize = 4096,
typename AllocPolicy = MallocAllocPolicy>
class SegmentedVector : private AllocPolicy
{
template<size_t SegmentCapacity>
struct SegmentImpl
: public mozilla::LinkedListElement<SegmentImpl<SegmentCapacity>>
{
SegmentImpl() : mLength(0) {}
~SegmentImpl()
{
for (uint32_t i = 0; i < mLength; i++) {
(*this)[i].~T();
}
}
uint32_t Length() const { return mLength; }
T* Elems() { return reinterpret_cast<T*>(&mStorage.mBuf); }
T& operator[](size_t aIndex)
{
MOZ_ASSERT(aIndex < mLength);
return Elems()[aIndex];
}
const T& operator[](size_t aIndex) const
{
MOZ_ASSERT(aIndex < mLength);
return Elems()[aIndex];
}
template<typename U>
void Append(U&& aU)
{
MOZ_ASSERT(mLength < SegmentCapacity);
// Pre-increment mLength so that the bounds-check in operator[] passes.
mLength++;
T* elem = &(*this)[mLength - 1];
new (elem) T(mozilla::Forward<U>(aU));
}
void PopLast()
{
MOZ_ASSERT(mLength > 0);
(*this)[mLength - 1].~T();
mLength--;
}
uint32_t mLength;
// The union ensures that the elements are appropriately aligned.
union Storage
{
char mBuf[sizeof(T) * SegmentCapacity];
mozilla::AlignedElem<MOZ_ALIGNOF(T)> mAlign;
} mStorage;
static_assert(MOZ_ALIGNOF(T) == MOZ_ALIGNOF(Storage),
"SegmentedVector provides incorrect alignment");
};
// See how many we elements we can fit in a segment of IdealSegmentSize. If
// IdealSegmentSize is too small, it'll be just one. The +1 is because
// kSingleElementSegmentSize already accounts for one element.
static const size_t kSingleElementSegmentSize = sizeof(SegmentImpl<1>);
static const size_t kSegmentCapacity =
kSingleElementSegmentSize <= IdealSegmentSize
? (IdealSegmentSize - kSingleElementSegmentSize) / sizeof(T) + 1
: 1;
typedef SegmentImpl<kSegmentCapacity> Segment;
public:
// The |aIdealSegmentSize| is only for sanity checking. If it's specified, we
// check that the actual segment size is as close as possible to it. This
// serves as a sanity check for SegmentedVectorCapacity's capacity
// computation.
explicit SegmentedVector(size_t aIdealSegmentSize = 0)
{
// The difference between the actual segment size and the ideal segment
// size should be less than the size of a single element... unless the
// ideal size was too small, in which case the capacity should be one.
MOZ_ASSERT_IF(
aIdealSegmentSize != 0,
(sizeof(Segment) > aIdealSegmentSize && kSegmentCapacity == 1) ||
aIdealSegmentSize - sizeof(Segment) < sizeof(T));
}
~SegmentedVector() { Clear(); }
bool IsEmpty() const { return !mSegments.getFirst(); }
// Note that this is O(n) rather than O(1), but the constant factor is very
// small because it only has to do one addition per segment.
size_t Length() const
{
size_t n = 0;
for (auto segment = mSegments.getFirst();
segment;
segment = segment->getNext()) {
n += segment->Length();
}
return n;
}
// Returns false if the allocation failed. (If you are using an infallible
// allocation policy, use InfallibleAppend() instead.)
template<typename U>
MOZ_MUST_USE bool Append(U&& aU)
{
Segment* last = mSegments.getLast();
if (!last || last->Length() == kSegmentCapacity) {
last = this->template pod_malloc<Segment>(1);
if (!last) {
return false;
}
new (last) Segment();
mSegments.insertBack(last);
}
last->Append(mozilla::Forward<U>(aU));
return true;
}
// You should probably only use this instead of Append() if you are using an
// infallible allocation policy. It will crash if the allocation fails.
template<typename U>
void InfallibleAppend(U&& aU)
{
bool ok = Append(mozilla::Forward<U>(aU));
MOZ_RELEASE_ASSERT(ok);
}
void Clear()
{
Segment* segment;
while ((segment = mSegments.popFirst())) {
segment->~Segment();
this->free_(segment);
}
}
T& GetLast()
{
MOZ_ASSERT(!IsEmpty());
Segment* last = mSegments.getLast();
return (*last)[last->Length() - 1];
}
const T& GetLast() const
{
MOZ_ASSERT(!IsEmpty());
Segment* last = mSegments.getLast();
return (*last)[last->Length() - 1];
}
void PopLast()
{
MOZ_ASSERT(!IsEmpty());
Segment* last = mSegments.getLast();
last->PopLast();
if (!last->Length()) {
mSegments.popLast();
last->~Segment();
this->free_(last);
}
}
// Equivalent to calling |PopLast| |aNumElements| times, but potentially
// more efficient.
void PopLastN(uint32_t aNumElements)
{
MOZ_ASSERT(aNumElements <= Length());
Segment* last;
// Pop full segments for as long as we can. Note that this loop
// cleanly handles the case when the initial last segment is not
// full and we are popping more elements than said segment contains.
do {
last = mSegments.getLast();
// The list is empty. We're all done.
if (!last) {
return;
}
// Check to see if the list contains too many elements. Handle
// that in the epilogue.
uint32_t segmentLen = last->Length();
if (segmentLen > aNumElements) {
break;
}
// Destroying the segment destroys all elements contained therein.
mSegments.popLast();
last->~Segment();
this->free_(last);
MOZ_ASSERT(aNumElements >= segmentLen);
aNumElements -= segmentLen;
if (aNumElements == 0) {
return;
}
} while (true);
// Handle the case where the last segment contains more elements
// than we want to pop.
MOZ_ASSERT(last);
MOZ_ASSERT(last == mSegments.getLast());
MOZ_ASSERT(aNumElements != 0);
MOZ_ASSERT(aNumElements < last->Length());
for (uint32_t i = 0; i < aNumElements; ++i) {
last->PopLast();
}
MOZ_ASSERT(last->Length() != 0);
}
// Use this class to iterate over a SegmentedVector, like so:
//
// for (auto iter = v.Iter(); !iter.Done(); iter.Next()) {
// MyElem& elem = iter.Get();
// f(elem);
// }
//
class IterImpl
{
friend class SegmentedVector;
Segment* mSegment;
size_t mIndex;
explicit IterImpl(SegmentedVector* aVector)
: mSegment(aVector->mSegments.getFirst())
, mIndex(0)
{}
public:
bool Done() const { return !mSegment; }
T& Get()
{
MOZ_ASSERT(!Done());
return (*mSegment)[mIndex];
}
const T& Get() const
{
MOZ_ASSERT(!Done());
return (*mSegment)[mIndex];
}
void Next()
{
MOZ_ASSERT(!Done());
mIndex++;
if (mIndex == mSegment->Length()) {
mSegment = mSegment->getNext();
mIndex = 0;
}
}
};
IterImpl Iter() { return IterImpl(this); }
// Measure the memory consumption of the vector excluding |this|. Note that
// it only measures the vector itself. If the vector elements contain
// pointers to other memory blocks, those blocks must be measured separately
// during a subsequent iteration over the vector.
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
return mSegments.sizeOfExcludingThis(aMallocSizeOf);
}
// Like sizeOfExcludingThis(), but measures |this| as well.
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
private:
mozilla::LinkedList<Segment> mSegments;
};
} // namespace mozilla
#endif /* mozilla_SegmentedVector_h */

View File

@@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implements (nonstandard) PRI{ouxX}SIZE format macros for size_t types. */
#ifndef mozilla_SizePrintfMacros_h_
#define mozilla_SizePrintfMacros_h_
/*
* MSVC's libc does not support C99's %z format length modifier for size_t
* types. Instead, we use Microsoft's nonstandard %I modifier for size_t, which
* is unsigned __int32 on 32-bit platforms and unsigned __int64 on 64-bit
* platforms:
*
* http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx
*/
#if defined(XP_WIN)
# define PRIoSIZE "Io"
# define PRIuSIZE "Iu"
# define PRIxSIZE "Ix"
# define PRIXSIZE "IX"
#else
# define PRIoSIZE "zo"
# define PRIuSIZE "zu"
# define PRIxSIZE "zx"
# define PRIXSIZE "zX"
#endif
#endif /* mozilla_SizePrintfMacros_h_ */

View File

@@ -0,0 +1,330 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* A sorted tree with optimal access times, where recently-accessed elements
* are faster to access again.
*/
#ifndef mozilla_SplayTree_h
#define mozilla_SplayTree_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
namespace mozilla {
template<class T, class C>
class SplayTree;
template<typename T>
class SplayTreeNode
{
public:
template<class A, class B>
friend class SplayTree;
SplayTreeNode()
: mLeft(nullptr)
, mRight(nullptr)
, mParent(nullptr)
{}
private:
T* mLeft;
T* mRight;
T* mParent;
};
/**
* Class which represents a splay tree.
* Splay trees are balanced binary search trees for which search, insert and
* remove are all amortized O(log n), but where accessing a node makes it
* faster to access that node in the future.
*
* T indicates the type of tree elements, Comparator must have a static
* compare(const T&, const T&) method ordering the elements. The compare
* method must be free from side effects.
*/
template<typename T, class Comparator>
class SplayTree
{
T* mRoot;
public:
constexpr SplayTree()
: mRoot(nullptr)
{}
bool empty() const
{
return !mRoot;
}
T* find(const T& aValue)
{
if (empty()) {
return nullptr;
}
T* last = lookup(aValue);
splay(last);
return Comparator::compare(aValue, *last) == 0 ? last : nullptr;
}
void insert(T* aValue)
{
MOZ_ASSERT(!find(*aValue), "Duplicate elements are not allowed.");
if (!mRoot) {
mRoot = aValue;
return;
}
T* last = lookup(*aValue);
int cmp = Comparator::compare(*aValue, *last);
finishInsertion(last, cmp, aValue);
return;
}
T* findOrInsert(const T& aValue);
T* remove(const T& aValue)
{
T* last = lookup(aValue);
MOZ_ASSERT(last, "This tree must contain the element being removed.");
MOZ_ASSERT(Comparator::compare(aValue, *last) == 0);
// Splay the tree so that the item to remove is the root.
splay(last);
MOZ_ASSERT(last == mRoot);
// Find another node which can be swapped in for the root: either the
// rightmost child of the root's left, or the leftmost child of the
// root's right.
T* swap;
T* swapChild;
if (mRoot->mLeft) {
swap = mRoot->mLeft;
while (swap->mRight) {
swap = swap->mRight;
}
swapChild = swap->mLeft;
} else if (mRoot->mRight) {
swap = mRoot->mRight;
while (swap->mLeft) {
swap = swap->mLeft;
}
swapChild = swap->mRight;
} else {
T* result = mRoot;
mRoot = nullptr;
return result;
}
// The selected node has at most one child, in swapChild. Detach it
// from the subtree by replacing it with that child.
if (swap == swap->mParent->mLeft) {
swap->mParent->mLeft = swapChild;
} else {
swap->mParent->mRight = swapChild;
}
if (swapChild) {
swapChild->mParent = swap->mParent;
}
// Make the selected node the new root.
mRoot = swap;
mRoot->mParent = nullptr;
mRoot->mLeft = last->mLeft;
mRoot->mRight = last->mRight;
if (mRoot->mLeft) {
mRoot->mLeft->mParent = mRoot;
}
if (mRoot->mRight) {
mRoot->mRight->mParent = mRoot;
}
return last;
}
T* removeMin()
{
MOZ_ASSERT(mRoot, "No min to remove!");
T* min = mRoot;
while (min->mLeft) {
min = min->mLeft;
}
return remove(*min);
}
// For testing purposes only.
void checkCoherency()
{
checkCoherency(mRoot, nullptr);
}
private:
/**
* Returns the node in this comparing equal to |aValue|, or a node just
* greater or just less than |aValue| if there is no such node.
*/
T* lookup(const T& aValue)
{
MOZ_ASSERT(!empty());
T* node = mRoot;
T* parent;
do {
parent = node;
int c = Comparator::compare(aValue, *node);
if (c == 0) {
return node;
} else if (c < 0) {
node = node->mLeft;
} else {
node = node->mRight;
}
} while (node);
return parent;
}
void finishInsertion(T* aLast, int32_t aCmp, T* aNew)
{
MOZ_ASSERT(aCmp, "Nodes shouldn't be equal!");
T** parentPointer = (aCmp < 0) ? &aLast->mLeft : &aLast->mRight;
MOZ_ASSERT(!*parentPointer);
*parentPointer = aNew;
aNew->mParent = aLast;
splay(aNew);
}
/**
* Rotate the tree until |node| is at the root of the tree. Performing
* the rotations in this fashion preserves the amortized balancing of
* the tree.
*/
void splay(T* aNode)
{
MOZ_ASSERT(aNode);
while (aNode != mRoot) {
T* parent = aNode->mParent;
if (parent == mRoot) {
// Zig rotation.
rotate(aNode);
MOZ_ASSERT(aNode == mRoot);
return;
}
T* grandparent = parent->mParent;
if ((parent->mLeft == aNode) == (grandparent->mLeft == parent)) {
// Zig-zig rotation.
rotate(parent);
rotate(aNode);
} else {
// Zig-zag rotation.
rotate(aNode);
rotate(aNode);
}
}
}
void rotate(T* aNode)
{
// Rearrange nodes so that aNode becomes the parent of its current
// parent, while preserving the sortedness of the tree.
T* parent = aNode->mParent;
if (parent->mLeft == aNode) {
// x y
// y c ==> a x
// a b b c
parent->mLeft = aNode->mRight;
if (aNode->mRight) {
aNode->mRight->mParent = parent;
}
aNode->mRight = parent;
} else {
MOZ_ASSERT(parent->mRight == aNode);
// x y
// a y ==> x c
// b c a b
parent->mRight = aNode->mLeft;
if (aNode->mLeft) {
aNode->mLeft->mParent = parent;
}
aNode->mLeft = parent;
}
aNode->mParent = parent->mParent;
parent->mParent = aNode;
if (T* grandparent = aNode->mParent) {
if (grandparent->mLeft == parent) {
grandparent->mLeft = aNode;
} else {
grandparent->mRight = aNode;
}
} else {
mRoot = aNode;
}
}
T* checkCoherency(T* aNode, T* aMinimum)
{
if (mRoot) {
MOZ_RELEASE_ASSERT(!mRoot->mParent);
}
if (!aNode) {
MOZ_RELEASE_ASSERT(!mRoot);
return nullptr;
}
if (!aNode->mParent) {
MOZ_RELEASE_ASSERT(aNode == mRoot);
}
if (aMinimum) {
MOZ_RELEASE_ASSERT(Comparator::compare(*aMinimum, *aNode) < 0);
}
if (aNode->mLeft) {
MOZ_RELEASE_ASSERT(aNode->mLeft->mParent == aNode);
T* leftMaximum = checkCoherency(aNode->mLeft, aMinimum);
MOZ_RELEASE_ASSERT(Comparator::compare(*leftMaximum, *aNode) < 0);
}
if (aNode->mRight) {
MOZ_RELEASE_ASSERT(aNode->mRight->mParent == aNode);
return checkCoherency(aNode->mRight, aNode);
}
return aNode;
}
SplayTree(const SplayTree&) = delete;
void operator=(const SplayTree&) = delete;
};
template<typename T, class Comparator>
T*
SplayTree<T, Comparator>::findOrInsert(const T& aValue)
{
if (!mRoot) {
mRoot = new T(aValue);
return mRoot;
}
T* last = lookup(aValue);
int cmp = Comparator::compare(aValue, *last);
if (!cmp) {
return last;
}
T* t = new T(aValue);
finishInsertion(last, cmp, t);
return t;
}
} /* namespace mozilla */
#endif /* mozilla_SplayTree_h */

View File

@@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Provides a safer sprintf for printing to fixed-size character arrays. */
#ifndef mozilla_Sprintf_h_
#define mozilla_Sprintf_h_
#include <stdio.h>
#include <stdarg.h>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#ifdef __cplusplus
template <size_t N>
int VsprintfLiteral(char (&buffer)[N], const char* format, va_list args)
{
MOZ_ASSERT(format != buffer);
int result = vsnprintf(buffer, N, format, args);
buffer[N - 1] = '\0';
return result;
}
template <size_t N>
MOZ_FORMAT_PRINTF(2, 3)
int SprintfLiteral(char (&buffer)[N], const char* format, ...)
{
va_list args;
va_start(args, format);
int result = VsprintfLiteral(buffer, format, args);
va_end(args);
return result;
}
#endif
#endif /* mozilla_Sprintf_h_ */

View File

@@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* API for getting a stack trace of the C/C++ stack on the current thread */
#ifndef mozilla_StackWalk_h
#define mozilla_StackWalk_h
/* WARNING: This file is intended to be included from C or C++ files. */
#include "mozilla/Types.h"
#include <stdint.h>
/**
* The callback for MozStackWalk.
*
* @param aFrameNumber The frame number (starts at 1, not 0).
* @param aPC The program counter value.
* @param aSP The best approximation possible of what the stack
* pointer will be pointing to when the execution returns
* to executing that at aPC. If no approximation can
* be made it will be nullptr.
* @param aClosure Extra data passed in via MozStackWalk().
*/
typedef void
(*MozWalkStackCallback)(uint32_t aFrameNumber, void* aPC, void* aSP,
void* aClosure);
/**
* Call aCallback for the C/C++ stack frames on the current thread, from
* the caller of MozStackWalk to main (or above).
*
* @param aCallback Callback function, called once per frame.
* @param aSkipFrames Number of initial frames to skip. 0 means that
* the first callback will be for the caller of
* MozStackWalk.
* @param aMaxFrames Maximum number of frames to trace. 0 means no limit.
* @param aClosure Caller-supplied data passed through to aCallback.
* @param aThread The thread for which the stack is to be retrieved.
* Passing null causes us to walk the stack of the
* current thread. On Windows, this is a thread HANDLE.
* It is currently not supported on any other platform.
* @param aPlatformData Platform specific data that can help in walking the
* stack, this should be nullptr unless you really know
* what you're doing! This needs to be a pointer to a
* CONTEXT on Windows and should not be passed on other
* platforms.
*
* May skip some stack frames due to compiler optimizations or code
* generation.
*
*/
MFBT_API bool
MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
uint32_t aMaxFrames, void* aClosure, uintptr_t aThread,
void* aPlatformData);
typedef struct
{
/*
* The name of the shared library or executable containing an
* address and the address's offset within that library, or empty
* string and zero if unknown.
*/
char library[256];
ptrdiff_t loffset;
/*
* The name of the file name and line number of the code
* corresponding to the address, or empty string and zero if
* unknown.
*/
char filename[256];
unsigned long lineno;
/*
* The name of the function containing an address and the address's
* offset within that function, or empty string and zero if unknown.
*/
char function[256];
ptrdiff_t foffset;
} MozCodeAddressDetails;
/**
* For a given pointer to code, fill in the pieces of information used
* when printing a stack trace.
*
* @param aPC The code address.
* @param aDetails A structure to be filled in with the result.
*/
MFBT_API bool
MozDescribeCodeAddress(void* aPC, MozCodeAddressDetails* aDetails);
/**
* Format the information about a code address in a format suitable for
* stack traces on the current platform. When available, this string
* should contain the function name, source file, and line number. When
* these are not available, library and offset should be reported, if
* possible.
*
* Note that this output is parsed by several scripts including the fix*.py and
* make-tree.pl scripts in tools/rb/. It should only be change with care, and
* in conjunction with those scripts.
*
* @param aBuffer A string to be filled in with the description.
* The string will always be null-terminated.
* @param aBufferSize The size, in bytes, of aBuffer, including
* room for the terminating null. If the information
* to be printed would be larger than aBuffer, it
* will be truncated so that aBuffer[aBufferSize-1]
* is the terminating null.
* @param aFrameNumber The frame number.
* @param aPC The code address.
* @param aFunction The function name. Possibly null or the empty string.
* @param aLibrary The library name. Possibly null or the empty string.
* @param aLOffset The library offset.
* @param aFileName The filename. Possibly null or the empty string.
* @param aLineNo The line number. Possibly zero.
*/
MFBT_API void
MozFormatCodeAddress(char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber,
const void* aPC, const char* aFunction,
const char* aLibrary, ptrdiff_t aLOffset,
const char* aFileName, uint32_t aLineNo);
/**
* Format the information about a code address in the same fashion as
* MozFormatCodeAddress.
*
* @param aBuffer A string to be filled in with the description.
* The string will always be null-terminated.
* @param aBufferSize The size, in bytes, of aBuffer, including
* room for the terminating null. If the information
* to be printed would be larger than aBuffer, it
* will be truncated so that aBuffer[aBufferSize-1]
* is the terminating null.
* @param aFrameNumber The frame number.
* @param aPC The code address.
* @param aDetails The value filled in by MozDescribeCodeAddress(aPC).
*/
MFBT_API void
MozFormatCodeAddressDetails(char* aBuffer, uint32_t aBufferSize,
uint32_t aFrameNumber, void* aPC,
const MozCodeAddressDetails* aDetails);
namespace mozilla {
MFBT_API bool
FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
uint32_t aMaxFrames, void* aClosure, void** aBp,
void* aStackEnd);
} // namespace mozilla
/**
* Initialize the critical sections for this platform so that we can
* abort stack walks when needed.
*/
MFBT_API void
StackWalkInitCriticalAddress(void);
#endif

View File

@@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_StaticAnalysisFunctions_h
#define mozilla_StaticAnalysisFunctions_h
#ifndef __cplusplus
#ifndef bool
#include <stdbool.h>
#endif
#endif
/*
* Functions that are used as markers in Gecko code for static analysis. Their
* purpose is to have different AST nodes generated during compile time and to
* match them based on different checkers implemented in build/clang-plugin
*/
#ifdef MOZ_CLANG_PLUGIN
#ifdef __cplusplus
extern "C" {
#endif
/*
* MOZ_AssertAssignmentTest - used in MOZ_ASSERT in order to test the possible
* presence of assignment instead of logical comparisons.
*
* Example:
* MOZ_ASSERT(retVal = true);
*/
static MOZ_ALWAYS_INLINE bool MOZ_AssertAssignmentTest(bool exprResult) {
return exprResult;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) MOZ_AssertAssignmentTest(!!(expr))
#else
#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) (!!(expr))
#endif /* MOZ_CLANG_PLUGIN */
#endif /* StaticAnalysisFunctions_h */

View File

@@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Some Linux kernels -- specifically, newer versions of Android and
// some B2G devices -- have a feature for assigning names to ranges of
// anonymous memory (i.e., memory that doesn't have a "name" in the
// form of an underlying mapped file). These names are reported in
// /proc/<pid>/smaps alongside system-level memory usage information
// such as Proportional Set Size (memory usage adjusted for sharing
// between processes), which allows reporting this information at a
// finer granularity than would otherwise be possible (e.g.,
// separating malloc() heap from JS heap).
//
// Existing memory can be tagged with MozTagAnonymousMemory(); it will
// tag the range of complete pages containing the given interval, so
// the results may be inexact if the range isn't page-aligned.
// MozTaggedAnonymousMmap() can be used like mmap() with an extra
// parameter, and will tag the returned memory if the mapping was
// successful (and if it was in fact anonymous).
//
// NOTE: The pointer given as the "tag" argument MUST remain valid as
// long as the mapping exists. The referenced string is read when
// /proc/<pid>/smaps or /proc/<pid>/maps is read, not when the tag is
// established, so freeing it or changing its contents will have
// unexpected results. Using a static string is probably best.
//
// Also note that this header can be used by both C and C++ code.
#ifndef mozilla_TaggedAnonymousMemory_h
#define mozilla_TaggedAnonymousMemory_h
#ifndef XP_WIN
#include <sys/types.h>
#include <sys/mman.h>
#include "mozilla/Types.h"
#ifdef ANDROID
#ifdef __cplusplus
extern "C" {
#endif
MFBT_API void
MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag);
MFBT_API void*
MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, int aFlags,
int aFd, off_t aOffset, const char* aTag);
MFBT_API int
MozTaggedMemoryIsSupported(void);
#ifdef __cplusplus
} // extern "C"
#endif
#else // ANDROID
static inline void
MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag)
{
}
static inline void*
MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, int aFlags,
int aFd, off_t aOffset, const char* aTag)
{
return mmap(aAddr, aLength, aProt, aFlags, aFd, aOffset);
}
static inline int
MozTaggedMemoryIsSupported(void)
{
return 0;
}
#endif // ANDROID
#endif // !XP_WIN
#endif // mozilla_TaggedAnonymousMemory_h

View File

@@ -0,0 +1,133 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Reusable template meta-functions on types and compile-time values. Meta-
* functions are placed inside the 'tl' namespace to avoid conflict with non-
* meta functions of the same name (e.g., mozilla::tl::FloorLog2 vs.
* mozilla::FloorLog2).
*
* When constexpr support becomes universal, we should probably use that instead
* of some of these templates, for simplicity.
*/
#ifndef mozilla_TemplateLib_h
#define mozilla_TemplateLib_h
#include <limits.h>
#include <stddef.h>
#include "mozilla/TypeTraits.h"
namespace mozilla {
namespace tl {
/** Compute min/max. */
template<size_t I, size_t J>
struct Min
{
static const size_t value = I < J ? I : J;
};
template<size_t I, size_t J>
struct Max
{
static const size_t value = I > J ? I : J;
};
/** Compute floor(log2(i)). */
template<size_t I>
struct FloorLog2
{
static const size_t value = 1 + FloorLog2<I / 2>::value;
};
template<> struct FloorLog2<0> { /* Error */ };
template<> struct FloorLog2<1> { static const size_t value = 0; };
/** Compute ceiling(log2(i)). */
template<size_t I>
struct CeilingLog2
{
static const size_t value = FloorLog2<2 * I - 1>::value;
};
/** Round up to the nearest power of 2. */
template<size_t I>
struct RoundUpPow2
{
static const size_t value = size_t(1) << CeilingLog2<I>::value;
};
template<>
struct RoundUpPow2<0>
{
static const size_t value = 1;
};
/** Compute the number of bits in the given unsigned type. */
template<typename T>
struct BitSize
{
static const size_t value = sizeof(T) * CHAR_BIT;
};
/**
* Produce an N-bit mask, where N <= BitSize<size_t>::value. Handle the
* language-undefined edge case when N = BitSize<size_t>::value.
*/
template<size_t N>
struct NBitMask
{
// Assert the precondition. On success this evaluates to 0. Otherwise it
// triggers divide-by-zero at compile time: a guaranteed compile error in
// C++11, and usually one in C++98. Add this value to |value| to assure
// its computation.
static const size_t checkPrecondition =
0 / size_t(N < BitSize<size_t>::value);
static const size_t value = (size_t(1) << N) - 1 + checkPrecondition;
};
template<>
struct NBitMask<BitSize<size_t>::value>
{
static const size_t value = size_t(-1);
};
/**
* For the unsigned integral type size_t, compute a mask M for N such that
* for all X, !(X & M) implies X * N will not overflow (w.r.t size_t)
*/
template<size_t N>
struct MulOverflowMask
{
static const size_t value =
~NBitMask<BitSize<size_t>::value - CeilingLog2<N>::value>::value;
};
template<> struct MulOverflowMask<0> { /* Error */ };
template<> struct MulOverflowMask<1> { static const size_t value = 0; };
/**
* And<bool...> computes the logical 'and' of its argument booleans.
*
* Examples:
* mozilla::t1::And<true, true>::value is true.
* mozilla::t1::And<true, false>::value is false.
* mozilla::t1::And<>::value is true.
*/
template<bool...>
struct And;
template<>
struct And<> : public TrueType { };
template<bool C1, bool... Cn>
struct And<C1, Cn...>
: public Conditional<C1, And<Cn...>, FalseType>::Type { };
} // namespace tl
} // namespace mozilla
#endif /* mozilla_TemplateLib_h */

View File

@@ -0,0 +1,222 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Cross-platform lightweight thread local data wrappers. */
#ifndef mozilla_ThreadLocal_h
#define mozilla_ThreadLocal_h
#if defined(XP_WIN)
// This file will get included in any file that wants to add a profiler mark.
// In order to not bring <windows.h> together we could include windef.h and
// winbase.h which are sufficient to get the prototypes for the Tls* functions.
// # include <windef.h>
// # include <winbase.h>
// Unfortunately, even including these headers causes us to add a bunch of ugly
// stuff to our namespace e.g #define CreateEvent CreateEventW
extern "C" {
__declspec(dllimport) void* __stdcall TlsGetValue(unsigned long);
__declspec(dllimport) int __stdcall TlsSetValue(unsigned long, void*);
__declspec(dllimport) unsigned long __stdcall TlsAlloc();
}
#else
# include <pthread.h>
# include <signal.h>
#endif
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
// sig_safe_t denotes an atomic type which can be read or stored in a single
// instruction. This means that data of this type is safe to be manipulated
// from a signal handler, or other similar asynchronous execution contexts.
#if defined(XP_WIN)
typedef unsigned long sig_safe_t;
#else
typedef sig_atomic_t sig_safe_t;
#endif
namespace detail {
#if defined(HAVE_THREAD_TLS_KEYWORD)
#define MOZ_HAS_THREAD_LOCAL
#endif
/*
* Thread Local Storage helpers.
*
* Usage:
*
* Do not directly instantiate this class. Instead, use the
* MOZ_THREAD_LOCAL macro to declare or define instances. The macro
* takes a type name as its argument.
*
* Declare like this:
* extern MOZ_THREAD_LOCAL(int) tlsInt;
* Define like this:
* MOZ_THREAD_LOCAL(int) tlsInt;
* or:
* static MOZ_THREAD_LOCAL(int) tlsInt;
*
* Only static-storage-duration (e.g. global variables, or static class members)
* objects of this class should be instantiated. This class relies on
* zero-initialization, which is implicit for static-storage-duration objects.
* It doesn't have a custom default constructor, to avoid static initializers.
*
* API usage:
*
* // Create a TLS item.
* //
* // Note that init() should be invoked before the first use of set()
* // or get(). It is ok to call it multiple times. This must be
* // called in a way that avoids possible races with other threads.
* MOZ_THREAD_LOCAL(int) tlsKey;
* if (!tlsKey.init()) {
* // deal with the error
* }
*
* // Set the TLS value
* tlsKey.set(123);
*
* // Get the TLS value
* int value = tlsKey.get();
*/
template<typename T>
class ThreadLocal
{
#ifndef MOZ_HAS_THREAD_LOCAL
#if defined(XP_WIN)
typedef unsigned long key_t;
#else
typedef pthread_key_t key_t;
#endif
// Integral types narrower than void* must be extended to avoid
// warnings from valgrind on some platforms. This helper type
// achieves that without penalizing the common case of ThreadLocals
// instantiated using a pointer type.
template<typename S>
struct Helper
{
typedef uintptr_t Type;
};
template<typename S>
struct Helper<S *>
{
typedef S *Type;
};
#endif
bool initialized() const {
#ifdef MOZ_HAS_THREAD_LOCAL
return true;
#else
return mInited;
#endif
}
public:
// __thread does not allow non-trivial constructors, but we can
// instead rely on zero-initialization.
#ifndef MOZ_HAS_THREAD_LOCAL
ThreadLocal()
: mKey(0), mInited(false)
{}
#endif
MOZ_MUST_USE inline bool init();
inline T get() const;
inline void set(const T aValue);
private:
#ifdef MOZ_HAS_THREAD_LOCAL
T mValue;
#else
key_t mKey;
bool mInited;
#endif
};
template<typename T>
inline bool
ThreadLocal<T>::init()
{
static_assert(mozilla::IsPointer<T>::value || mozilla::IsIntegral<T>::value,
"mozilla::ThreadLocal must be used with a pointer or "
"integral type");
static_assert(sizeof(T) <= sizeof(void*),
"mozilla::ThreadLocal can't be used for types larger than "
"a pointer");
#ifdef MOZ_HAS_THREAD_LOCAL
return true;
#else
if (!initialized()) {
#ifdef XP_WIN
mKey = TlsAlloc();
mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES
#else
mInited = !pthread_key_create(&mKey, nullptr);
#endif
}
return mInited;
#endif
}
template<typename T>
inline T
ThreadLocal<T>::get() const
{
#ifdef MOZ_HAS_THREAD_LOCAL
return mValue;
#else
MOZ_ASSERT(initialized());
void* h;
#ifdef XP_WIN
h = TlsGetValue(mKey);
#else
h = pthread_getspecific(mKey);
#endif
return static_cast<T>(reinterpret_cast<typename Helper<T>::Type>(h));
#endif
}
template<typename T>
inline void
ThreadLocal<T>::set(const T aValue)
{
#ifdef MOZ_HAS_THREAD_LOCAL
mValue = aValue;
#else
MOZ_ASSERT(initialized());
void* h = reinterpret_cast<void*>(static_cast<typename Helper<T>::Type>(aValue));
#ifdef XP_WIN
bool succeeded = TlsSetValue(mKey, h);
#else
bool succeeded = !pthread_setspecific(mKey, h);
#endif
if (!succeeded) {
MOZ_CRASH();
}
#endif
}
#ifdef MOZ_HAS_THREAD_LOCAL
#define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal<TYPE>
#else
#define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal<TYPE>
#endif
} // namespace detail
} // namespace mozilla
#endif /* mozilla_ThreadLocal_h */

View File

@@ -0,0 +1,609 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_TimeStamp_h
#define mozilla_TimeStamp_h
#include <stdint.h>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/Types.h"
namespace IPC {
template<typename T> struct ParamTraits;
} // namespace IPC
#ifdef XP_WIN
// defines TimeStampValue as a complex value keeping both
// GetTickCount and QueryPerformanceCounter values
#include "TimeStamp_windows.h"
#endif
namespace mozilla {
#ifndef XP_WIN
typedef uint64_t TimeStampValue;
#endif
class TimeStamp;
/**
* Platform-specific implementation details of BaseTimeDuration.
*/
class BaseTimeDurationPlatformUtils
{
public:
static MFBT_API double ToSeconds(int64_t aTicks);
static MFBT_API double ToSecondsSigDigits(int64_t aTicks);
static MFBT_API int64_t TicksFromMilliseconds(double aMilliseconds);
static MFBT_API int64_t ResolutionInTicks();
};
/**
* Instances of this class represent the length of an interval of time.
* Negative durations are allowed, meaning the end is before the start.
*
* Internally the duration is stored as a int64_t in units of
* PR_TicksPerSecond() when building with NSPR interval timers, or a
* system-dependent unit when building with system clocks. The
* system-dependent unit must be constant, otherwise the semantics of
* this class would be broken.
*
* The ValueCalculator template parameter determines how arithmetic
* operations are performed on the integer count of ticks (mValue).
*/
template <typename ValueCalculator>
class BaseTimeDuration
{
public:
// The default duration is 0.
constexpr BaseTimeDuration() : mValue(0) {}
// Allow construction using '0' as the initial value, for readability,
// but no other numbers (so we don't have any implicit unit conversions).
struct _SomethingVeryRandomHere;
MOZ_IMPLICIT BaseTimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0)
{
MOZ_ASSERT(!aZero, "Who's playing funny games here?");
}
// Default copy-constructor and assignment are OK
// Converting copy-constructor and assignment operator
template <typename E>
explicit BaseTimeDuration(const BaseTimeDuration<E>& aOther)
: mValue(aOther.mValue)
{ }
template <typename E>
BaseTimeDuration& operator=(const BaseTimeDuration<E>& aOther)
{
mValue = aOther.mValue;
return *this;
}
double ToSeconds() const
{
if (mValue == INT64_MAX) {
return PositiveInfinity<double>();
}
if (mValue == INT64_MIN) {
return NegativeInfinity<double>();
}
return BaseTimeDurationPlatformUtils::ToSeconds(mValue);
}
// Return a duration value that includes digits of time we think to
// be significant. This method should be used when displaying a
// time to humans.
double ToSecondsSigDigits() const
{
if (mValue == INT64_MAX) {
return PositiveInfinity<double>();
}
if (mValue == INT64_MIN) {
return NegativeInfinity<double>();
}
return BaseTimeDurationPlatformUtils::ToSecondsSigDigits(mValue);
}
double ToMilliseconds() const { return ToSeconds() * 1000.0; }
double ToMicroseconds() const { return ToMilliseconds() * 1000.0; }
// Using a double here is safe enough; with 53 bits we can represent
// durations up to over 280,000 years exactly. If the units of
// mValue do not allow us to represent durations of that length,
// long durations are clamped to the max/min representable value
// instead of overflowing.
static inline BaseTimeDuration FromSeconds(double aSeconds)
{
return FromMilliseconds(aSeconds * 1000.0);
}
static BaseTimeDuration FromMilliseconds(double aMilliseconds)
{
if (aMilliseconds == PositiveInfinity<double>()) {
return Forever();
}
if (aMilliseconds == NegativeInfinity<double>()) {
return FromTicks(INT64_MIN);
}
return FromTicks(
BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds));
}
static inline BaseTimeDuration FromMicroseconds(double aMicroseconds)
{
return FromMilliseconds(aMicroseconds / 1000.0);
}
static BaseTimeDuration Forever()
{
return FromTicks(INT64_MAX);
}
BaseTimeDuration operator+(const BaseTimeDuration& aOther) const
{
return FromTicks(ValueCalculator::Add(mValue, aOther.mValue));
}
BaseTimeDuration operator-(const BaseTimeDuration& aOther) const
{
return FromTicks(ValueCalculator::Subtract(mValue, aOther.mValue));
}
BaseTimeDuration& operator+=(const BaseTimeDuration& aOther)
{
mValue = ValueCalculator::Add(mValue, aOther.mValue);
return *this;
}
BaseTimeDuration& operator-=(const BaseTimeDuration& aOther)
{
mValue = ValueCalculator::Subtract(mValue, aOther.mValue);
return *this;
}
BaseTimeDuration operator-() const
{
// We don't just use FromTicks(ValueCalculator::Subtract(0, mValue))
// since that won't give the correct result for -TimeDuration::Forever().
int64_t ticks;
if (mValue == INT64_MAX) {
ticks = INT64_MIN;
} else if (mValue == INT64_MIN) {
ticks = INT64_MAX;
} else {
ticks = -mValue;
}
return FromTicks(ticks);
}
private:
// Block double multiplier (slower, imprecise if long duration) - Bug 853398.
// If required, use MultDouble explicitly and with care.
BaseTimeDuration operator*(const double aMultiplier) const = delete;
// Block double divisor (for the same reason, and because dividing by
// fractional values would otherwise invoke the int64_t variant, and rounding
// the passed argument can then cause divide-by-zero) - Bug 1147491.
BaseTimeDuration operator/(const double aDivisor) const = delete;
public:
BaseTimeDuration MultDouble(double aMultiplier) const
{
return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
}
BaseTimeDuration operator*(const int32_t aMultiplier) const
{
return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
}
BaseTimeDuration operator*(const uint32_t aMultiplier) const
{
return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
}
BaseTimeDuration operator*(const int64_t aMultiplier) const
{
return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
}
BaseTimeDuration operator*(const uint64_t aMultiplier) const
{
if (aMultiplier > INT64_MAX) {
return Forever();
}
return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
}
BaseTimeDuration operator/(const int64_t aDivisor) const
{
MOZ_ASSERT(aDivisor != 0, "Division by zero");
return FromTicks(ValueCalculator::Divide(mValue, aDivisor));
}
double operator/(const BaseTimeDuration& aOther) const
{
#ifndef MOZ_B2G
// Bug 1066388 - This fails on B2G ICS Emulator
MOZ_ASSERT(aOther.mValue != 0, "Division by zero");
#endif
return ValueCalculator::DivideDouble(mValue, aOther.mValue);
}
BaseTimeDuration operator%(const BaseTimeDuration& aOther) const
{
MOZ_ASSERT(aOther.mValue != 0, "Division by zero");
return FromTicks(ValueCalculator::Modulo(mValue, aOther.mValue));
}
template<typename E>
bool operator<(const BaseTimeDuration<E>& aOther) const
{
return mValue < aOther.mValue;
}
template<typename E>
bool operator<=(const BaseTimeDuration<E>& aOther) const
{
return mValue <= aOther.mValue;
}
template<typename E>
bool operator>=(const BaseTimeDuration<E>& aOther) const
{
return mValue >= aOther.mValue;
}
template<typename E>
bool operator>(const BaseTimeDuration<E>& aOther) const
{
return mValue > aOther.mValue;
}
template<typename E>
bool operator==(const BaseTimeDuration<E>& aOther) const
{
return mValue == aOther.mValue;
}
template<typename E>
bool operator!=(const BaseTimeDuration<E>& aOther) const
{
return mValue != aOther.mValue;
}
bool IsZero() const
{
return mValue == 0;
}
explicit operator bool() const
{
return mValue != 0;
}
// Return a best guess at the system's current timing resolution,
// which might be variable. BaseTimeDurations below this order of
// magnitude are meaningless, and those at the same order of
// magnitude or just above are suspect.
static BaseTimeDuration Resolution() {
return FromTicks(BaseTimeDurationPlatformUtils::ResolutionInTicks());
}
// We could define additional operators here:
// -- convert to/from other time units
// -- scale duration by a float
// but let's do that on demand.
// Comparing durations for equality will only lead to bugs on
// platforms with high-resolution timers.
private:
friend class TimeStamp;
friend struct IPC::ParamTraits<mozilla::BaseTimeDuration<ValueCalculator>>;
template <typename>
friend class BaseTimeDuration;
static BaseTimeDuration FromTicks(int64_t aTicks)
{
BaseTimeDuration t;
t.mValue = aTicks;
return t;
}
static BaseTimeDuration FromTicks(double aTicks)
{
// NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX))
// overflows and gives INT64_MIN.
if (aTicks >= double(INT64_MAX)) {
return FromTicks(INT64_MAX);
}
// This MUST be a <= test.
if (aTicks <= double(INT64_MIN)) {
return FromTicks(INT64_MIN);
}
return FromTicks(int64_t(aTicks));
}
// Duration, result is implementation-specific difference of two TimeStamps
int64_t mValue;
};
/**
* Perform arithmetic operations on the value of a BaseTimeDuration without
* doing strict checks on the range of values.
*/
class TimeDurationValueCalculator
{
public:
static int64_t Add(int64_t aA, int64_t aB) { return aA + aB; }
static int64_t Subtract(int64_t aA, int64_t aB) { return aA - aB; }
template <typename T>
static int64_t Multiply(int64_t aA, T aB)
{
static_assert(IsIntegral<T>::value,
"Using integer multiplication routine with non-integer type."
" Further specialization required");
return aA * static_cast<int64_t>(aB);
}
static int64_t Divide(int64_t aA, int64_t aB) { return aA / aB; }
static double DivideDouble(int64_t aA, int64_t aB)
{
return static_cast<double>(aA) / aB;
}
static int64_t Modulo(int64_t aA, int64_t aB) { return aA % aB; }
};
template <>
inline int64_t
TimeDurationValueCalculator::Multiply<double>(int64_t aA, double aB)
{
return static_cast<int64_t>(aA * aB);
}
/**
* Specialization of BaseTimeDuration that uses TimeDurationValueCalculator for
* arithmetic on the mValue member.
*
* Use this class for time durations that are *not* expected to hold values of
* Forever (or the negative equivalent) or when such time duration are *not*
* expected to be used in arithmetic operations.
*/
typedef BaseTimeDuration<TimeDurationValueCalculator> TimeDuration;
/**
* Instances of this class represent moments in time, or a special
* "null" moment. We do not use the non-monotonic system clock or
* local time, since they can be reset, causing apparent backward
* travel in time, which can confuse algorithms. Instead we measure
* elapsed time according to the system. This time can never go
* backwards (i.e. it never wraps around, at least not in less than
* five million years of system elapsed time). It might not advance
* while the system is sleeping. If TimeStamp::SetNow() is not called
* at all for hours or days, we might not notice the passage of some
* of that time.
*
* We deliberately do not expose a way to convert TimeStamps to some
* particular unit. All you can do is compute a difference between two
* TimeStamps to get a TimeDuration. You can also add a TimeDuration
* to a TimeStamp to get a new TimeStamp. You can't do something
* meaningless like add two TimeStamps.
*
* Internally this is implemented as either a wrapper around
* - high-resolution, monotonic, system clocks if they exist on this
* platform
* - PRIntervalTime otherwise. We detect wraparounds of
* PRIntervalTime and work around them.
*
* This class is similar to C++11's time_point, however it is
* explicitly nullable and provides an IsNull() method. time_point
* is initialized to the clock's epoch and provides a
* time_since_epoch() method that functions similiarly. i.e.
* t.IsNull() is equivalent to t.time_since_epoch() == decltype(t)::duration::zero();
*/
class TimeStamp
{
public:
/**
* Initialize to the "null" moment
*/
constexpr TimeStamp() : mValue(0) {}
// Default copy-constructor and assignment are OK
/**
* The system timestamps are the same as the TimeStamp
* retrieved by mozilla::TimeStamp. Since we need this for
* vsync timestamps, we enable the creation of mozilla::TimeStamps
* on platforms that support vsync aligned refresh drivers / compositors
* Verified true as of Jan 31, 2015: B2G and OS X
* False on Windows 7
* UNTESTED ON OTHER PLATFORMS
*/
#if defined(MOZ_WIDGET_GONK) || defined(XP_DARWIN)
static TimeStamp FromSystemTime(int64_t aSystemTime)
{
static_assert(sizeof(aSystemTime) == sizeof(TimeStampValue),
"System timestamp should be same units as TimeStampValue");
return TimeStamp(aSystemTime);
}
#endif
/**
* Return true if this is the "null" moment
*/
bool IsNull() const { return mValue == 0; }
/**
* Return true if this is not the "null" moment, may be used in tests, e.g.:
* |if (timestamp) { ... }|
*/
explicit operator bool() const
{
return mValue != 0;
}
/**
* Return a timestamp reflecting the current elapsed system time. This
* is monotonically increasing (i.e., does not decrease) over the
* lifetime of this process' XPCOM session.
*
* Now() is trying to ensure the best possible precision on each platform,
* at least one millisecond.
*
* NowLoRes() has been introduced to workaround performance problems of
* QueryPerformanceCounter on the Windows platform. NowLoRes() is giving
* lower precision, usually 15.6 ms, but with very good performance benefit.
* Use it for measurements of longer times, like >200ms timeouts.
*/
static TimeStamp Now() { return Now(true); }
static TimeStamp NowLoRes() { return Now(false); }
/**
* Return a timestamp representing the time when the current process was
* created which will be comparable with other timestamps taken with this
* class. If the actual process creation time is detected to be inconsistent
* the @a aIsInconsistent parameter will be set to true, the returned
* timestamp however will still be valid though inaccurate.
*
* @param aIsInconsistent Set to true if an inconsistency was detected in the
* process creation time
* @returns A timestamp representing the time when the process was created,
* this timestamp is always valid even when errors are reported
*/
static MFBT_API TimeStamp ProcessCreation(bool& aIsInconsistent);
/**
* Records a process restart. After this call ProcessCreation() will return
* the time when the browser was restarted instead of the actual time when
* the process was created.
*/
static MFBT_API void RecordProcessRestart();
/**
* Compute the difference between two timestamps. Both must be non-null.
*/
TimeDuration operator-(const TimeStamp& aOther) const
{
MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
static_assert(-INT64_MAX > INT64_MIN, "int64_t sanity check");
int64_t ticks = int64_t(mValue - aOther.mValue);
// Check for overflow.
if (mValue > aOther.mValue) {
if (ticks < 0) {
ticks = INT64_MAX;
}
} else {
if (ticks > 0) {
ticks = INT64_MIN;
}
}
return TimeDuration::FromTicks(ticks);
}
TimeStamp operator+(const TimeDuration& aOther) const
{
TimeStamp result = *this;
result += aOther;
return result;
}
TimeStamp operator-(const TimeDuration& aOther) const
{
TimeStamp result = *this;
result -= aOther;
return result;
}
TimeStamp& operator+=(const TimeDuration& aOther)
{
MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
TimeStampValue value = mValue + aOther.mValue;
// Check for underflow.
// (We don't check for overflow because it's not obvious what the error
// behavior should be in that case.)
if (aOther.mValue < 0 && value > mValue) {
value = 0;
}
mValue = value;
return *this;
}
TimeStamp& operator-=(const TimeDuration& aOther)
{
MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
TimeStampValue value = mValue - aOther.mValue;
// Check for underflow.
// (We don't check for overflow because it's not obvious what the error
// behavior should be in that case.)
if (aOther.mValue > 0 && value > mValue) {
value = 0;
}
mValue = value;
return *this;
}
bool operator<(const TimeStamp& aOther) const
{
MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
return mValue < aOther.mValue;
}
bool operator<=(const TimeStamp& aOther) const
{
MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
return mValue <= aOther.mValue;
}
bool operator>=(const TimeStamp& aOther) const
{
MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
return mValue >= aOther.mValue;
}
bool operator>(const TimeStamp& aOther) const
{
MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
return mValue > aOther.mValue;
}
bool operator==(const TimeStamp& aOther) const
{
return IsNull()
? aOther.IsNull()
: !aOther.IsNull() && mValue == aOther.mValue;
}
bool operator!=(const TimeStamp& aOther) const
{
return !(*this == aOther);
}
// Comparing TimeStamps for equality should be discouraged. Adding
// two TimeStamps, or scaling TimeStamps, is nonsense and must never
// be allowed.
static MFBT_API void Startup();
static MFBT_API void Shutdown();
private:
friend struct IPC::ParamTraits<mozilla::TimeStamp>;
friend void StartupTimelineRecordExternal(int, uint64_t);
MOZ_IMPLICIT TimeStamp(TimeStampValue aValue) : mValue(aValue) {}
static MFBT_API TimeStamp Now(bool aHighResolution);
/**
* Computes the uptime of the current process in microseconds. The result
* is platform-dependent and needs to be checked against existing timestamps
* for consistency.
*
* @returns The number of microseconds since the calling process was started
* or 0 if an error was encountered while computing the uptime
*/
static MFBT_API uint64_t ComputeProcessUptime();
/**
* When built with PRIntervalTime, a value of 0 means this instance
* is "null". Otherwise, the low 32 bits represent a PRIntervalTime,
* and the high 32 bits represent a counter of the number of
* rollovers of PRIntervalTime that we've seen. This counter starts
* at 1 to avoid a real time colliding with the "null" value.
*
* PR_INTERVAL_MAX is set at 100,000 ticks per second. So the minimum
* time to wrap around is about 2^64/100000 seconds, i.e. about
* 5,849,424 years.
*
* When using a system clock, a value is system dependent.
*/
TimeStampValue mValue;
};
} // namespace mozilla
#endif /* mozilla_TimeStamp_h */

View File

@@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Utilities for converting an object to a string representation. */
#ifndef mozilla_ToString_h
#define mozilla_ToString_h
#include <string>
#include <sstream>
namespace mozilla {
/**
* A convenience function for converting an object to a string representation.
* Supports any object which can be streamed to an std::ostream.
*/
template<typename T>
std::string
ToString(const T& aValue)
{
std::ostringstream stream;
stream << aValue;
return stream.str();
}
} // namespace mozilla
#endif /* mozilla_ToString_h */

View File

@@ -0,0 +1,461 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A variadic tuple class. */
#ifndef mozilla_Tuple_h
#define mozilla_Tuple_h
#include "mozilla/Move.h"
#include "mozilla/Pair.h"
#include "mozilla/TemplateLib.h"
#include "mozilla/TypeTraits.h"
#include <stddef.h>
#include <utility>
namespace mozilla {
namespace detail {
/*
* A helper class that allows passing around multiple variadic argument lists
* by grouping them.
*/
template<typename... Ts>
struct Group;
/*
* CheckConvertibility checks whether each type in a source pack of types
* is convertible to the corresponding type in a target pack of types.
*
* It is intended to be invoked like this:
* CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>>
* 'Group' is used to separate types in the two packs (otherwise if we just
* wrote 'CheckConvertibility<SourceTypes..., TargetTypes...', it couldn't
* know where the first pack ends and the second begins).
*
* Note that we need to check explicitly that the two packs are of the same
* size, because attempting to simultaneously expand two parameter packs
* is an error (and it would be a hard error, because it wouldn't be in the
* immediate context of the caller).
*/
template<typename Source, typename Target, bool SameSize>
struct CheckConvertibilityImpl;
template<typename Source, typename Target>
struct CheckConvertibilityImpl<Source, Target, false>
: FalseType {};
template<typename... SourceTypes, typename... TargetTypes>
struct CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>, true>
: IntegralConstant<bool, tl::And<IsConvertible<SourceTypes, TargetTypes>::value...>::value> { };
template<typename Source, typename Target>
struct CheckConvertibility;
template<typename... SourceTypes, typename... TargetTypes>
struct CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>>
: CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>,
sizeof...(SourceTypes) == sizeof...(TargetTypes)> { };
/*
* TupleImpl is a helper class used to implement mozilla::Tuple.
* It represents one node in a recursive inheritance hierarchy.
* 'Index' is the 0-based index of the tuple element stored in this node;
* 'Elements...' are the types of the elements stored in this node and its
* base classes.
*
* Example:
* Tuple<int, float, char> inherits from
* TupleImpl<0, int, float, char>, which stores the 'int' and inherits from
* TupleImpl<1, float, char>, which stores the 'float' and inherits from
* TupleImpl<2, char>, which stores the 'char' and inherits from
* TupleImpl<3>, which stores nothing and terminates the recursion.
*
* The purpose of the 'Index' parameter is to allow efficient index-based
* access to a tuple element: given a tuple, and an index 'I' that we wish to
* access, we can cast the tuple to the base which stores the I'th element
* by performing template argument deduction against 'TupleImpl<I, E...>',
* where 'I' is specified explicitly and 'E...' is deduced (this is what the
* non-member 'Get<N>(t)' function does).
*
* This implementation strategy is borrowed from libstdc++'s std::tuple
* implementation.
*/
template<std::size_t Index, typename... Elements>
struct TupleImpl;
/*
* The base case of the inheritance recursion (and also the implementation
* of an empty tuple).
*/
template<std::size_t Index>
struct TupleImpl<Index> {
bool operator==(const TupleImpl<Index>& aOther) const
{
return true;
}
};
/*
* One node of the recursive inheritance hierarchy. It stores the element at
* index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes
* that store the remaining elements, of types 'TailT...'.
*/
template<std::size_t Index, typename HeadT, typename... TailT>
struct TupleImpl<Index, HeadT, TailT...>
: public TupleImpl<Index + 1, TailT...>
{
typedef TupleImpl<Index + 1, TailT...> Base;
// Accessors for the head and the tail.
// These are static, because the intended usage is for the caller to,
// given a tuple, obtain the type B of the base class which stores the
// element of interest, and then call B::Head(tuple) to access it.
// (Tail() is mostly for internal use, but is exposed for consistency.)
static HeadT& Head(TupleImpl& aTuple) { return aTuple.mHead; }
static const HeadT& Head(const TupleImpl& aTuple) { return aTuple.mHead; }
static Base& Tail(TupleImpl& aTuple) { return aTuple; }
static const Base& Tail(const TupleImpl& aTuple) { return aTuple; }
TupleImpl() : Base(), mHead() { }
// Construct from const references to the elements.
explicit TupleImpl(const HeadT& aHead, const TailT&... aTail)
: Base(aTail...), mHead(aHead) { }
// Construct from objects that are convertible to the elements.
// This constructor is enabled only when the argument types are actually
// convertible to the element types, otherwise it could become a better
// match for certain invocations than the copy constructor.
template <typename OtherHeadT, typename... OtherTailT,
typename = typename EnableIf<
CheckConvertibility<
Group<OtherHeadT, OtherTailT...>,
Group<HeadT, TailT...>>::value>::Type>
explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail)
: Base(Forward<OtherTailT>(aTail)...), mHead(Forward<OtherHeadT>(aHead)) { }
// Copy and move constructors.
// We'd like to use '= default' to implement these, but MSVC 2013's support
// for '= default' is incomplete and this doesn't work.
TupleImpl(const TupleImpl& aOther)
: Base(Tail(aOther))
, mHead(Head(aOther)) {}
TupleImpl(TupleImpl&& aOther)
: Base(Move(Tail(aOther)))
, mHead(Forward<HeadT>(Head(aOther))) {}
// Assign from a tuple whose elements are convertible to the elements
// of this tuple.
template <typename... OtherElements,
typename = typename EnableIf<
sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type>
TupleImpl& operator=(const TupleImpl<Index, OtherElements...>& aOther)
{
typedef TupleImpl<Index, OtherElements...> OtherT;
Head(*this) = OtherT::Head(aOther);
Tail(*this) = OtherT::Tail(aOther);
return *this;
}
template <typename... OtherElements,
typename = typename EnableIf<
sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type>
TupleImpl& operator=(TupleImpl<Index, OtherElements...>&& aOther)
{
typedef TupleImpl<Index, OtherElements...> OtherT;
Head(*this) = Move(OtherT::Head(aOther));
Tail(*this) = Move(OtherT::Tail(aOther));
return *this;
}
// Copy and move assignment operators.
TupleImpl& operator=(const TupleImpl& aOther)
{
Head(*this) = Head(aOther);
Tail(*this) = Tail(aOther);
return *this;
}
TupleImpl& operator=(TupleImpl&& aOther)
{
Head(*this) = Move(Head(aOther));
Tail(*this) = Move(Tail(aOther));
return *this;
}
bool operator==(const TupleImpl& aOther) const
{
return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther);
}
private:
HeadT mHead; // The element stored at this index in the tuple.
};
} // namespace detail
/**
* Tuple is a class that stores zero or more objects, whose types are specified
* as template parameters. It can be thought of as a generalization of Pair,
* (which can be thought of as a 2-tuple).
*
* Tuple allows index-based access to its elements (with the index having to be
* known at compile time) via the non-member function 'Get<N>(tuple)'.
*/
template<typename... Elements>
class Tuple : public detail::TupleImpl<0, Elements...>
{
typedef detail::TupleImpl<0, Elements...> Impl;
public:
// The constructors and assignment operators here are simple wrappers
// around those in TupleImpl.
Tuple() : Impl() { }
explicit Tuple(const Elements&... aElements) : Impl(aElements...) { }
// Here, we can't just use 'typename... OtherElements' because MSVC will give
// a warning "C4520: multiple default constructors specified" (even if no one
// actually instantiates the constructor with an empty parameter pack -
// that's probably a bug) and we compile with warnings-as-errors.
template <typename OtherHead, typename... OtherTail,
typename = typename EnableIf<
detail::CheckConvertibility<
detail::Group<OtherHead, OtherTail...>,
detail::Group<Elements...>>::value>::Type>
explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail)
: Impl(Forward<OtherHead>(aHead), Forward<OtherTail>(aTail)...) { }
Tuple(const Tuple& aOther) : Impl(aOther) { }
Tuple(Tuple&& aOther) : Impl(Move(aOther)) { }
template <typename... OtherElements,
typename = typename EnableIf<
sizeof...(OtherElements) == sizeof...(Elements)>::Type>
Tuple& operator=(const Tuple<OtherElements...>& aOther)
{
static_cast<Impl&>(*this) = aOther;
return *this;
}
template <typename... OtherElements,
typename = typename EnableIf<
sizeof...(OtherElements) == sizeof...(Elements)>::Type>
Tuple& operator=(Tuple<OtherElements...>&& aOther)
{
static_cast<Impl&>(*this) = Move(aOther);
return *this;
}
Tuple& operator=(const Tuple& aOther)
{
static_cast<Impl&>(*this) = aOther;
return *this;
}
Tuple& operator=(Tuple&& aOther)
{
static_cast<Impl&>(*this) = Move(aOther);
return *this;
}
bool operator==(const Tuple& aOther) const
{
return static_cast<const Impl&>(*this) == static_cast<const Impl&>(aOther);
}
};
/**
* Specialization of Tuple for two elements.
* This is created to support construction and assignment from a Pair or std::pair.
*/
template <typename A, typename B>
class Tuple<A, B> : public detail::TupleImpl<0, A, B>
{
typedef detail::TupleImpl<0, A, B> Impl;
public:
// The constructors and assignment operators here are simple wrappers
// around those in TupleImpl.
Tuple() : Impl() { }
explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) { }
template <typename AArg, typename BArg,
typename = typename EnableIf<
detail::CheckConvertibility<
detail::Group<AArg, BArg>,
detail::Group<A, B>>::value>::Type>
explicit Tuple(AArg&& aA, BArg&& aB)
: Impl(Forward<AArg>(aA), Forward<BArg>(aB)) { }
Tuple(const Tuple& aOther) : Impl(aOther) { }
Tuple(Tuple&& aOther) : Impl(Move(aOther)) { }
explicit Tuple(const Pair<A, B>& aOther)
: Impl(aOther.first(), aOther.second()) { }
explicit Tuple(Pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first()),
Forward<B>(aOther.second())) { }
explicit Tuple(const std::pair<A, B>& aOther)
: Impl(aOther.first, aOther.second) { }
explicit Tuple(std::pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first),
Forward<B>(aOther.second)) { }
template <typename AArg, typename BArg>
Tuple& operator=(const Tuple<AArg, BArg>& aOther)
{
static_cast<Impl&>(*this) = aOther;
return *this;
}
template <typename AArg, typename BArg>
Tuple& operator=(Tuple<AArg, BArg>&& aOther)
{
static_cast<Impl&>(*this) = Move(aOther);
return *this;
}
Tuple& operator=(const Tuple& aOther)
{
static_cast<Impl&>(*this) = aOther;
return *this;
}
Tuple& operator=(Tuple&& aOther)
{
static_cast<Impl&>(*this) = Move(aOther);
return *this;
}
template <typename AArg, typename BArg>
Tuple& operator=(const Pair<AArg, BArg>& aOther)
{
Impl::Head(*this) = aOther.first();
Impl::Tail(*this).Head(*this) = aOther.second();
return *this;
}
template <typename AArg, typename BArg>
Tuple& operator=(Pair<AArg, BArg>&& aOther)
{
Impl::Head(*this) = Forward<AArg>(aOther.first());
Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second());
return *this;
}
template <typename AArg, typename BArg>
Tuple& operator=(const std::pair<AArg, BArg>& aOther)
{
Impl::Head(*this) = aOther.first;
Impl::Tail(*this).Head(*this) = aOther.second;
return *this;
}
template <typename AArg, typename BArg>
Tuple& operator=(std::pair<AArg, BArg>&& aOther)
{
Impl::Head(*this) = Forward<AArg>(aOther.first);
Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second);
return *this;
}
};
/**
* Specialization of Tuple for zero arguments.
* This is necessary because if the primary template were instantiated with
* an empty parameter pack, the 'Tuple(Elements...)' constructors would
* become illegal overloads of the default constructor.
*/
template <>
class Tuple<> {};
namespace detail {
/*
* Helper functions for implementing Get<N>(tuple).
* These functions take a TupleImpl<Index, Elements...>, with Index being
* explicitly specified, and Elements being deduced. By passing a Tuple
* object as argument, template argument deduction will do its magic and
* cast the tuple to the base class which stores the element at Index.
*/
// Const reference version.
template<std::size_t Index, typename... Elements>
auto TupleGetHelper(TupleImpl<Index, Elements...>& aTuple)
-> decltype(TupleImpl<Index, Elements...>::Head(aTuple))
{
return TupleImpl<Index, Elements...>::Head(aTuple);
}
// Non-const reference version.
template<std::size_t Index, typename... Elements>
auto TupleGetHelper(const TupleImpl<Index, Elements...>& aTuple)
-> decltype(TupleImpl<Index, Elements...>::Head(aTuple))
{
return TupleImpl<Index, Elements...>::Head(aTuple);
}
} // namespace detail
/**
* Index-based access to an element of a tuple.
* The syntax is Get<Index>(tuple). The index is zero-based.
*
* Example:
*
* Tuple<int, float, char> t;
* ...
* float f = Get<1>(t);
*/
// Non-const reference version.
template<std::size_t Index, typename... Elements>
auto Get(Tuple<Elements...>& aTuple)
-> decltype(detail::TupleGetHelper<Index>(aTuple))
{
return detail::TupleGetHelper<Index>(aTuple);
}
// Const reference version.
template<std::size_t Index, typename... Elements>
auto Get(const Tuple<Elements...>& aTuple)
-> decltype(detail::TupleGetHelper<Index>(aTuple))
{
return detail::TupleGetHelper<Index>(aTuple);
}
// Rvalue reference version.
template<std::size_t Index, typename... Elements>
auto Get(Tuple<Elements...>&& aTuple)
-> decltype(Move(mozilla::Get<Index>(aTuple)))
{
// We need a 'mozilla::' qualification here to avoid
// name lookup only finding the current function.
return Move(mozilla::Get<Index>(aTuple));
}
/**
* A convenience function for constructing a tuple out of a sequence of
* values without specifying the type of the tuple.
* The type of the tuple is deduced from the types of its elements.
*
* Example:
*
* auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple<int, float, char>
*/
template<typename... Elements>
inline Tuple<typename Decay<Elements>::Type...>
MakeTuple(Elements&&... aElements)
{
return Tuple<typename Decay<Elements>::Type...>(Forward<Elements>(aElements)...);
}
/**
* A convenience function for constructing a tuple of references to a
* sequence of variables. Since assignments to the elements of the tuple
* "go through" to the referenced variables, this can be used to "unpack"
* a tuple into individual variables.
*
* Example:
*
* int i;
* float f;
* char c;
* Tie(i, f, c) = FunctionThatReturnsATuple();
*/
template<typename... Elements>
inline Tuple<Elements&...>
Tie(Elements&... aVariables)
{
return Tuple<Elements&...>(aVariables...);
}
} // namespace mozilla
#endif /* mozilla_Tuple_h */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS allows using a typed enum as bit flags.
*/
#ifndef mozilla_TypedEnumBits_h
#define mozilla_TypedEnumBits_h
#include "mozilla/Attributes.h"
#include "mozilla/IntegerTypeTraits.h"
namespace mozilla {
/*
* The problem that CastableTypedEnumResult aims to solve is that
* typed enums are not convertible to bool, and there is no way to make them
* be, yet user code wants to be able to write
*
* if (myFlags & Flags::SOME_PARTICULAR_FLAG) (1)
*
* There are different approaches to solving this. Most of them require
* adapting user code. For example, we could implement operator! and have
* the user write
*
* if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG)) (2)
*
* Or we could supply a IsNonZero() or Any() function returning whether
* an enum value is nonzero, and have the user write
*
* if (Any(Flags & Flags::SOME_PARTICULAR_FLAG)) (3)
*
* But instead, we choose to preserve the original user syntax (1) as it
* is inherently more readable, and to ease porting existing code to typed
* enums. We achieve this by having operator& and other binary bitwise
* operators have as return type a class, CastableTypedEnumResult,
* that wraps a typed enum but adds bool convertibility.
*/
template<typename E>
class CastableTypedEnumResult
{
private:
const E mValue;
public:
explicit constexpr CastableTypedEnumResult(E aValue)
: mValue(aValue)
{}
constexpr operator E() const { return mValue; }
template<typename DestinationType>
explicit constexpr
operator DestinationType() const { return DestinationType(mValue); }
constexpr bool operator !() const { return !bool(mValue); }
};
#define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \
template<typename E> \
constexpr ReturnType \
operator Op(const OtherType& aE, const CastableTypedEnumResult<E>& aR) \
{ \
return ReturnType(aE Op OtherType(aR)); \
} \
template<typename E> \
constexpr ReturnType \
operator Op(const CastableTypedEnumResult<E>& aR, const OtherType& aE) \
{ \
return ReturnType(OtherType(aR) Op aE); \
} \
template<typename E> \
constexpr ReturnType \
operator Op(const CastableTypedEnumResult<E>& aR1, \
const CastableTypedEnumResult<E>& aR2) \
{ \
return ReturnType(OtherType(aR1) Op OtherType(aR2)); \
}
MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult<E>)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult<E>)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult<E>)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(||, bool, bool)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(&&, bool, bool)
template <typename E>
constexpr CastableTypedEnumResult<E>
operator ~(const CastableTypedEnumResult<E>& aR)
{
return CastableTypedEnumResult<E>(~(E(aR)));
}
#define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \
template<typename E> \
E& \
operator Op(E& aR1, \
const CastableTypedEnumResult<E>& aR2) \
{ \
return aR1 Op E(aR2); \
}
MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=)
MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=)
MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(^=)
#undef MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP
#undef MOZ_CASTABLETYPEDENUMRESULT_BINOP
namespace detail {
template<typename E>
struct UnsignedIntegerTypeForEnum
: UnsignedStdintTypeForSize<sizeof(E)>
{};
} // namespace detail
} // namespace mozilla
#define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \
inline constexpr mozilla::CastableTypedEnumResult<Name> \
operator Op(Name a, Name b) \
{ \
typedef mozilla::CastableTypedEnumResult<Name> Result; \
typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
return Result(Name(U(a) Op U(b))); \
} \
\
inline Name& \
operator Op##=(Name& a, Name b) \
{ \
return a = a Op b; \
}
/**
* MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators
* for the given enum type. Use this to enable using an enum type as bit-field.
*/
#define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \
MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \
MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \
MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \
inline constexpr mozilla::CastableTypedEnumResult<Name> \
operator~(Name a) \
{ \
typedef mozilla::CastableTypedEnumResult<Name> Result; \
typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
return Result(Name(~(U(a)))); \
}
#endif // mozilla_TypedEnumBits_h

View File

@@ -0,0 +1,134 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* mfbt foundational types and macros. */
#ifndef mozilla_Types_h
#define mozilla_Types_h
/*
* This header must be valid C and C++, includable by code embedding either
* SpiderMonkey or Gecko.
*/
/* Expose all <stdint.h> types and size_t. */
#include <stddef.h>
#include <stdint.h>
/* Implement compiler and linker macros needed for APIs. */
/*
* MOZ_EXPORT is used to declare and define a symbol or type which is externally
* visible to users of the current library. It encapsulates various decorations
* needed to properly export the method's symbol.
*
* api.h:
* extern MOZ_EXPORT int MeaningOfLife(void);
* extern MOZ_EXPORT int LuggageCombination;
*
* api.c:
* int MeaningOfLife(void) { return 42; }
* int LuggageCombination = 12345;
*
* If you are merely sharing a method across files, just use plain |extern|.
* These macros are designed for use by library interfaces -- not for normal
* methods or data used cross-file.
*/
#if defined(WIN32)
# define MOZ_EXPORT __declspec(dllexport)
#else /* Unix */
# ifdef HAVE_VISIBILITY_ATTRIBUTE
# define MOZ_EXPORT __attribute__((visibility("default")))
# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
# define MOZ_EXPORT __global
# else
# define MOZ_EXPORT /* nothing */
# endif
#endif
/*
* Whereas implementers use MOZ_EXPORT to declare and define library symbols,
* users use MOZ_IMPORT_API and MOZ_IMPORT_DATA to access them. Most often the
* implementer of the library will expose an API macro which expands to either
* the export or import version of the macro, depending upon the compilation
* mode.
*/
#ifdef _WIN32
# if defined(__MWERKS__)
# define MOZ_IMPORT_API /* nothing */
# else
# define MOZ_IMPORT_API __declspec(dllimport)
# endif
#else
# define MOZ_IMPORT_API MOZ_EXPORT
#endif
#if defined(_WIN32) && !defined(__MWERKS__)
# define MOZ_IMPORT_DATA __declspec(dllimport)
#else
# define MOZ_IMPORT_DATA MOZ_EXPORT
#endif
/*
* Consistent with the above comment, the MFBT_API and MFBT_DATA macros expose
* export mfbt declarations when building mfbt, and they expose import mfbt
* declarations when using mfbt.
*/
#if defined(IMPL_MFBT)
# define MFBT_API MOZ_EXPORT
# define MFBT_DATA MOZ_EXPORT
#else
/*
* On linux mozglue is linked in the program and we link libxul.so with
* -z,defs. Normally that causes the linker to reject undefined references in
* libxul.so, but as a loophole it allows undefined references to weak
* symbols. We add the weak attribute to the import version of the MFBT API
* macros to exploit this.
*/
# if defined(MOZ_GLUE_IN_PROGRAM)
# define MFBT_API __attribute__((weak)) MOZ_IMPORT_API
# define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA
# else
# define MFBT_API MOZ_IMPORT_API
# define MFBT_DATA MOZ_IMPORT_DATA
# endif
#endif
/*
* C symbols in C++ code must be declared immediately within |extern "C"|
* blocks. However, in C code, they need not be declared specially. This
* difference is abstracted behind the MOZ_BEGIN_EXTERN_C and MOZ_END_EXTERN_C
* macros, so that the user need not know whether he is being used in C or C++
* code.
*
* MOZ_BEGIN_EXTERN_C
*
* extern MOZ_EXPORT int MostRandomNumber(void);
* ...other declarations...
*
* MOZ_END_EXTERN_C
*
* This said, it is preferable to just use |extern "C"| in C++ header files for
* its greater clarity.
*/
#ifdef __cplusplus
# define MOZ_BEGIN_EXTERN_C extern "C" {
# define MOZ_END_EXTERN_C }
#else
# define MOZ_BEGIN_EXTERN_C
# define MOZ_END_EXTERN_C
#endif
/*
* GCC's typeof is available when decltype is not.
*/
#if defined(__GNUC__) && defined(__cplusplus) && \
!defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L
# define decltype __typeof__
#endif
#endif /* mozilla_Types_h */

View File

@@ -0,0 +1,697 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Smart pointer managing sole ownership of a resource. */
#ifndef mozilla_UniquePtr_h
#define mozilla_UniquePtr_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Compiler.h"
#include "mozilla/Move.h"
#include "mozilla/Pair.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
template<typename T> class DefaultDelete;
template<typename T, class D = DefaultDelete<T>> class UniquePtr;
} // namespace mozilla
namespace mozilla {
namespace detail {
struct HasPointerTypeHelper
{
template <class U> static double Test(...);
template <class U> static char Test(typename U::pointer* = 0);
};
template <class T>
class HasPointerType : public IntegralConstant<bool, sizeof(HasPointerTypeHelper::Test<T>(0)) == 1>
{
};
template <class T, class D, bool = HasPointerType<D>::value>
struct PointerTypeImpl
{
typedef typename D::pointer Type;
};
template <class T, class D>
struct PointerTypeImpl<T, D, false>
{
typedef T* Type;
};
template <class T, class D>
struct PointerType
{
typedef typename PointerTypeImpl<T, typename RemoveReference<D>::Type>::Type Type;
};
} // namespace detail
/**
* UniquePtr is a smart pointer that wholly owns a resource. Ownership may be
* transferred out of a UniquePtr through explicit action, but otherwise the
* resource is destroyed when the UniquePtr is destroyed.
*
* UniquePtr is similar to C++98's std::auto_ptr, but it improves upon auto_ptr
* in one crucial way: it's impossible to copy a UniquePtr. Copying an auto_ptr
* obviously *can't* copy ownership of its singly-owned resource. So what
* happens if you try to copy one? Bizarrely, ownership is implicitly
* *transferred*, preserving single ownership but breaking code that assumes a
* copy of an object is identical to the original. (This is why auto_ptr is
* prohibited in STL containers.)
*
* UniquePtr solves this problem by being *movable* rather than copyable.
* Instead of passing a |UniquePtr u| directly to the constructor or assignment
* operator, you pass |Move(u)|. In doing so you indicate that you're *moving*
* ownership out of |u|, into the target of the construction/assignment. After
* the transfer completes, |u| contains |nullptr| and may be safely destroyed.
* This preserves single ownership but also allows UniquePtr to be moved by
* algorithms that have been made move-safe. (Note: if |u| is instead a
* temporary expression, don't use |Move()|: just pass the expression, because
* it's already move-ready. For more information see Move.h.)
*
* UniquePtr is also better than std::auto_ptr in that the deletion operation is
* customizable. An optional second template parameter specifies a class that
* (through its operator()(T*)) implements the desired deletion policy. If no
* policy is specified, mozilla::DefaultDelete<T> is used -- which will either
* |delete| or |delete[]| the resource, depending whether the resource is an
* array. Custom deletion policies ideally should be empty classes (no member
* fields, no member fields in base classes, no virtual methods/inheritance),
* because then UniquePtr can be just as efficient as a raw pointer.
*
* Use of UniquePtr proceeds like so:
*
* UniquePtr<int> g1; // initializes to nullptr
* g1.reset(new int); // switch resources using reset()
* g1 = nullptr; // clears g1, deletes the int
*
* UniquePtr<int> g2(new int); // owns that int
* int* p = g2.release(); // g2 leaks its int -- still requires deletion
* delete p; // now freed
*
* struct S { int x; S(int x) : x(x) {} };
* UniquePtr<S> g3, g4(new S(5));
* g3 = Move(g4); // g3 owns the S, g4 cleared
* S* p = g3.get(); // g3 still owns |p|
* assert(g3->x == 5); // operator-> works (if .get() != nullptr)
* assert((*g3).x == 5); // also operator* (again, if not cleared)
* Swap(g3, g4); // g4 now owns the S, g3 cleared
* g3.swap(g4); // g3 now owns the S, g4 cleared
* UniquePtr<S> g5(Move(g3)); // g5 owns the S, g3 cleared
* g5.reset(); // deletes the S, g5 cleared
*
* struct FreePolicy { void operator()(void* p) { free(p); } };
* UniquePtr<int, FreePolicy> g6(static_cast<int*>(malloc(sizeof(int))));
* int* ptr = g6.get();
* g6 = nullptr; // calls free(ptr)
*
* Now, carefully note a few things you *can't* do:
*
* UniquePtr<int> b1;
* b1 = new int; // BAD: can only assign another UniquePtr
* int* ptr = b1; // BAD: no auto-conversion to pointer, use get()
*
* UniquePtr<int> b2(b1); // BAD: can't copy a UniquePtr
* UniquePtr<int> b3 = b1; // BAD: can't copy-assign a UniquePtr
*
* (Note that changing a UniquePtr to store a direct |new| expression is
* permitted, but usually you should use MakeUnique, defined at the end of this
* header.)
*
* A few miscellaneous notes:
*
* UniquePtr, when not instantiated for an array type, can be move-constructed
* and move-assigned, not only from itself but from "derived" UniquePtr<U, E>
* instantiations where U converts to T and E converts to D. If you want to use
* this, you're going to have to specify a deletion policy for both UniquePtr
* instantations, and T pretty much has to have a virtual destructor. In other
* words, this doesn't work:
*
* struct Base { virtual ~Base() {} };
* struct Derived : Base {};
*
* UniquePtr<Base> b1;
* // BAD: DefaultDelete<Base> and DefaultDelete<Derived> don't interconvert
* UniquePtr<Derived> d1(Move(b));
*
* UniquePtr<Base> b2;
* UniquePtr<Derived, DefaultDelete<Base>> d2(Move(b2)); // okay
*
* UniquePtr is specialized for array types. Specializing with an array type
* creates a smart-pointer version of that array -- not a pointer to such an
* array.
*
* UniquePtr<int[]> arr(new int[5]);
* arr[0] = 4;
*
* What else is different? Deletion of course uses |delete[]|. An operator[]
* is provided. Functionality that doesn't make sense for arrays is removed.
* The constructors and mutating methods only accept array pointers (not T*, U*
* that converts to T*, or UniquePtr<U[]> or UniquePtr<U>) or |nullptr|.
*
* It's perfectly okay for a function to return a UniquePtr. This transfers
* the UniquePtr's sole ownership of the data, to the fresh UniquePtr created
* in the calling function, that will then solely own that data. Such functions
* can return a local variable UniquePtr, |nullptr|, |UniquePtr(ptr)| where
* |ptr| is a |T*|, or a UniquePtr |Move()|'d from elsewhere.
*
* UniquePtr will commonly be a member of a class, with lifetime equivalent to
* that of that class. If you want to expose the related resource, you could
* expose a raw pointer via |get()|, but ownership of a raw pointer is
* inherently unclear. So it's better to expose a |const UniquePtr&| instead.
* This prohibits mutation but still allows use of |get()| when needed (but
* operator-> is preferred). Of course, you can only use this smart pointer as
* long as the enclosing class instance remains live -- no different than if you
* exposed the |get()| raw pointer.
*
* To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&|
* argument. To specify an inout parameter (where the method may or may not
* take ownership of the resource, or reset it), or to specify an out parameter
* (where simply returning a |UniquePtr| isn't possible), use a |UniquePtr&|
* argument. To unconditionally transfer ownership of a UniquePtr
* into a method, use a |UniquePtr| argument. To conditionally transfer
* ownership of a resource into a method, should the method want it, use a
* |UniquePtr&&| argument.
*/
template<typename T, class D>
class UniquePtr
{
public:
typedef T ElementType;
typedef D DeleterType;
typedef typename detail::PointerType<T, DeleterType>::Type Pointer;
private:
Pair<Pointer, DeleterType> mTuple;
Pointer& ptr() { return mTuple.first(); }
const Pointer& ptr() const { return mTuple.first(); }
DeleterType& del() { return mTuple.second(); }
const DeleterType& del() const { return mTuple.second(); }
public:
/**
* Construct a UniquePtr containing |nullptr|.
*/
constexpr UniquePtr()
: mTuple(static_cast<Pointer>(nullptr), DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
/**
* Construct a UniquePtr containing |aPtr|.
*/
explicit UniquePtr(Pointer aPtr)
: mTuple(aPtr, DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
UniquePtr(Pointer aPtr,
typename Conditional<IsReference<D>::value,
D,
const D&>::Type aD1)
: mTuple(aPtr, aD1)
{}
// If you encounter an error with MSVC10 about RemoveReference below, along
// the lines that "more than one partial specialization matches the template
// argument list": don't use UniquePtr<T, reference to function>! Ideally
// you should make deletion use the same function every time, using a
// deleter policy:
//
// // BAD, won't compile with MSVC10, deleter doesn't need to be a
// // variable at all
// typedef void (&FreeSignature)(void*);
// UniquePtr<int, FreeSignature> ptr((int*) malloc(sizeof(int)), free);
//
// // GOOD, compiles with MSVC10, deletion behavior statically known and
// // optimizable
// struct DeleteByFreeing
// {
// void operator()(void* aPtr) { free(aPtr); }
// };
//
// If deletion really, truly, must be a variable: you might be able to work
// around this with a deleter class that contains the function reference.
// But this workaround is untried and untested, because variable deletion
// behavior really isn't something you should use.
UniquePtr(Pointer aPtr,
typename RemoveReference<D>::Type&& aD2)
: mTuple(aPtr, Move(aD2))
{
static_assert(!IsReference<D>::value,
"rvalue deleter can't be stored by reference");
}
UniquePtr(UniquePtr&& aOther)
: mTuple(aOther.release(), Forward<DeleterType>(aOther.get_deleter()))
{}
MOZ_IMPLICIT
UniquePtr(decltype(nullptr))
: mTuple(nullptr, DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
template<typename U, class E>
MOZ_IMPLICIT
UniquePtr(UniquePtr<U, E>&& aOther,
typename EnableIf<IsConvertible<typename UniquePtr<U, E>::Pointer,
Pointer>::value &&
!IsArray<U>::value &&
(IsReference<D>::value
? IsSame<D, E>::value
: IsConvertible<E, D>::value),
int>::Type aDummy = 0)
: mTuple(aOther.release(), Forward<E>(aOther.get_deleter()))
{
}
~UniquePtr() { reset(nullptr); }
UniquePtr& operator=(UniquePtr&& aOther)
{
reset(aOther.release());
get_deleter() = Forward<DeleterType>(aOther.get_deleter());
return *this;
}
template<typename U, typename E>
UniquePtr& operator=(UniquePtr<U, E>&& aOther)
{
static_assert(IsConvertible<typename UniquePtr<U, E>::Pointer,
Pointer>::value,
"incompatible UniquePtr pointees");
static_assert(!IsArray<U>::value,
"can't assign from UniquePtr holding an array");
reset(aOther.release());
get_deleter() = Forward<E>(aOther.get_deleter());
return *this;
}
UniquePtr& operator=(decltype(nullptr))
{
reset(nullptr);
return *this;
}
T& operator*() const { return *get(); }
Pointer operator->() const
{
MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr");
return get();
}
explicit operator bool() const { return get() != nullptr; }
Pointer get() const { return ptr(); }
DeleterType& get_deleter() { return del(); }
const DeleterType& get_deleter() const { return del(); }
MOZ_MUST_USE Pointer release()
{
Pointer p = ptr();
ptr() = nullptr;
return p;
}
void reset(Pointer aPtr = Pointer())
{
Pointer old = ptr();
ptr() = aPtr;
if (old != nullptr) {
get_deleter()(old);
}
}
void swap(UniquePtr& aOther)
{
mTuple.swap(aOther.mTuple);
}
UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()!
void operator=(const UniquePtr& aOther) = delete; // assign using Move()!
};
// In case you didn't read the comment by the main definition (you should!): the
// UniquePtr<T[]> specialization exists to manage array pointers. It deletes
// such pointers using delete[], it will reject construction and modification
// attempts using U* or U[]. Otherwise it works like the normal UniquePtr.
template<typename T, class D>
class UniquePtr<T[], D>
{
public:
typedef T* Pointer;
typedef T ElementType;
typedef D DeleterType;
private:
Pair<Pointer, DeleterType> mTuple;
public:
/**
* Construct a UniquePtr containing nullptr.
*/
constexpr UniquePtr()
: mTuple(static_cast<Pointer>(nullptr), DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
/**
* Construct a UniquePtr containing |aPtr|.
*/
explicit UniquePtr(Pointer aPtr)
: mTuple(aPtr, DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
// delete[] knows how to handle *only* an array of a single class type. For
// delete[] to work correctly, it must know the size of each element, the
// fields and base classes of each element requiring destruction, and so on.
// So forbid all overloads which would end up invoking delete[] on a pointer
// of the wrong type.
template<typename U>
UniquePtr(U&& aU,
typename EnableIf<IsPointer<U>::value &&
IsConvertible<U, Pointer>::value,
int>::Type aDummy = 0)
= delete;
UniquePtr(Pointer aPtr,
typename Conditional<IsReference<D>::value,
D,
const D&>::Type aD1)
: mTuple(aPtr, aD1)
{}
// If you encounter an error with MSVC10 about RemoveReference below, along
// the lines that "more than one partial specialization matches the template
// argument list": don't use UniquePtr<T[], reference to function>! See the
// comment by this constructor in the non-T[] specialization above.
UniquePtr(Pointer aPtr,
typename RemoveReference<D>::Type&& aD2)
: mTuple(aPtr, Move(aD2))
{
static_assert(!IsReference<D>::value,
"rvalue deleter can't be stored by reference");
}
// Forbidden for the same reasons as stated above.
template<typename U, typename V>
UniquePtr(U&& aU, V&& aV,
typename EnableIf<IsPointer<U>::value &&
IsConvertible<U, Pointer>::value,
int>::Type aDummy = 0)
= delete;
UniquePtr(UniquePtr&& aOther)
: mTuple(aOther.release(), Forward<DeleterType>(aOther.get_deleter()))
{}
MOZ_IMPLICIT
UniquePtr(decltype(nullptr))
: mTuple(nullptr, DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
~UniquePtr() { reset(nullptr); }
UniquePtr& operator=(UniquePtr&& aOther)
{
reset(aOther.release());
get_deleter() = Forward<DeleterType>(aOther.get_deleter());
return *this;
}
UniquePtr& operator=(decltype(nullptr))
{
reset();
return *this;
}
explicit operator bool() const { return get() != nullptr; }
T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; }
Pointer get() const { return mTuple.first(); }
DeleterType& get_deleter() { return mTuple.second(); }
const DeleterType& get_deleter() const { return mTuple.second(); }
MOZ_MUST_USE Pointer release()
{
Pointer p = mTuple.first();
mTuple.first() = nullptr;
return p;
}
void reset(Pointer aPtr = Pointer())
{
Pointer old = mTuple.first();
mTuple.first() = aPtr;
if (old != nullptr) {
mTuple.second()(old);
}
}
void reset(decltype(nullptr))
{
Pointer old = mTuple.first();
mTuple.first() = nullptr;
if (old != nullptr) {
mTuple.second()(old);
}
}
template<typename U>
void reset(U) = delete;
void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); }
UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()!
void operator=(const UniquePtr& aOther) = delete; // assign using Move()!
};
/**
* A default deletion policy using plain old operator delete.
*
* Note that this type can be specialized, but authors should beware of the risk
* that the specialization may at some point cease to match (either because it
* gets moved to a different compilation unit or the signature changes). If the
* non-specialized (|delete|-based) version compiles for that type but does the
* wrong thing, bad things could happen.
*
* This is a non-issue for types which are always incomplete (i.e. opaque handle
* types), since |delete|-ing such a type will always trigger a compilation
* error.
*/
template<typename T>
class DefaultDelete
{
public:
constexpr DefaultDelete() {}
template<typename U>
MOZ_IMPLICIT DefaultDelete(const DefaultDelete<U>& aOther,
typename EnableIf<mozilla::IsConvertible<U*, T*>::value,
int>::Type aDummy = 0)
{}
void operator()(T* aPtr) const
{
static_assert(sizeof(T) > 0, "T must be complete");
delete aPtr;
}
};
/** A default deletion policy using operator delete[]. */
template<typename T>
class DefaultDelete<T[]>
{
public:
constexpr DefaultDelete() {}
void operator()(T* aPtr) const
{
static_assert(sizeof(T) > 0, "T must be complete");
delete[] aPtr;
}
template<typename U>
void operator()(U* aPtr) const = delete;
};
template<typename T, class D>
void
Swap(UniquePtr<T, D>& aX, UniquePtr<T, D>& aY)
{
aX.swap(aY);
}
template<typename T, class D, typename U, class E>
bool
operator==(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY)
{
return aX.get() == aY.get();
}
template<typename T, class D, typename U, class E>
bool
operator!=(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY)
{
return aX.get() != aY.get();
}
template<typename T, class D>
bool
operator==(const UniquePtr<T, D>& aX, decltype(nullptr))
{
return !aX;
}
template<typename T, class D>
bool
operator==(decltype(nullptr), const UniquePtr<T, D>& aX)
{
return !aX;
}
template<typename T, class D>
bool
operator!=(const UniquePtr<T, D>& aX, decltype(nullptr))
{
return bool(aX);
}
template<typename T, class D>
bool
operator!=(decltype(nullptr), const UniquePtr<T, D>& aX)
{
return bool(aX);
}
// No operator<, operator>, operator<=, operator>= for now because simplicity.
namespace detail {
template<typename T>
struct UniqueSelector
{
typedef UniquePtr<T> SingleObject;
};
template<typename T>
struct UniqueSelector<T[]>
{
typedef UniquePtr<T[]> UnknownBound;
};
template<typename T, decltype(sizeof(int)) N>
struct UniqueSelector<T[N]>
{
typedef UniquePtr<T[N]> KnownBound;
};
} // namespace detail
/**
* MakeUnique is a helper function for allocating new'd objects and arrays,
* returning a UniquePtr containing the resulting pointer. The semantics of
* MakeUnique<Type>(...) are as follows.
*
* If Type is an array T[n]:
* Disallowed, deleted, no overload for you!
* If Type is an array T[]:
* MakeUnique<T[]>(size_t) is the only valid overload. The pointer returned
* is as if by |new T[n]()|, which value-initializes each element. (If T
* isn't a class type, this will zero each element. If T is a class type,
* then roughly speaking, each element will be constructed using its default
* constructor. See C++11 [dcl.init]p7 for the full gory details.)
* If Type is non-array T:
* The arguments passed to MakeUnique<T>(...) are forwarded into a
* |new T(...)| call, initializing the T as would happen if executing
* |T(...)|.
*
* There are various benefits to using MakeUnique instead of |new| expressions.
*
* First, MakeUnique eliminates use of |new| from code entirely. If objects are
* only created through UniquePtr, then (assuming all explicit release() calls
* are safe, including transitively, and no type-safety casting funniness)
* correctly maintained ownership of the UniquePtr guarantees no leaks are
* possible. (This pays off best if a class is only ever created through a
* factory method on the class, using a private constructor.)
*
* Second, initializing a UniquePtr using a |new| expression requires repeating
* the name of the new'd type, whereas MakeUnique in concert with the |auto|
* keyword names it only once:
*
* UniquePtr<char> ptr1(new char()); // repetitive
* auto ptr2 = MakeUnique<char>(); // shorter
*
* Of course this assumes the reader understands the operation MakeUnique
* performs. In the long run this is probably a reasonable assumption. In the
* short run you'll have to use your judgment about what readers can be expected
* to know, or to quickly look up.
*
* Third, a call to MakeUnique can be assigned directly to a UniquePtr. In
* contrast you can't assign a pointer into a UniquePtr without using the
* cumbersome reset().
*
* UniquePtr<char> p;
* p = new char; // ERROR
* p.reset(new char); // works, but fugly
* p = MakeUnique<char>(); // preferred
*
* (And third, although not relevant to Mozilla: MakeUnique is exception-safe.
* An exception thrown after |new T| succeeds will leak that memory, unless the
* pointer is assigned to an object that will manage its ownership. UniquePtr
* ably serves this function.)
*/
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::SingleObject
MakeUnique(Args&&... aArgs)
{
return UniquePtr<T>(new T(Forward<Args>(aArgs)...));
}
template<typename T>
typename detail::UniqueSelector<T>::UnknownBound
MakeUnique(decltype(sizeof(int)) aN)
{
typedef typename RemoveExtent<T>::Type ArrayType;
return UniquePtr<T>(new ArrayType[aN]());
}
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::KnownBound
MakeUnique(Args&&... aArgs) = delete;
} // namespace mozilla
#endif /* mozilla_UniquePtr_h */

View File

@@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Useful extensions to UniquePtr. */
#ifndef mozilla_UniquePtrExtensions_h
#define mozilla_UniquePtrExtensions_h
#include "mozilla/fallible.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
/**
* MakeUniqueFallible works exactly like MakeUnique, except that the memory
* allocation performed is done fallibly, i.e. it can return nullptr.
*/
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::SingleObject
MakeUniqueFallible(Args&&... aArgs)
{
return UniquePtr<T>(new (fallible) T(Forward<Args>(aArgs)...));
}
template<typename T>
typename detail::UniqueSelector<T>::UnknownBound
MakeUniqueFallible(decltype(sizeof(int)) aN)
{
typedef typename RemoveExtent<T>::Type ArrayType;
return UniquePtr<T>(new (fallible) ArrayType[aN]());
}
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::KnownBound
MakeUniqueFallible(Args&&... aArgs) = delete;
namespace detail {
template<typename T>
struct FreePolicy
{
void operator()(const void* ptr) {
free(const_cast<void*>(ptr));
}
};
} // namespace detail
template<typename T>
using UniqueFreePtr = UniquePtr<T, detail::FreePolicy<T>>;
} // namespace mozilla
#endif // mozilla_UniquePtrExtensions_h

View File

@@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_unused_h
#define mozilla_unused_h
#include "mozilla/Types.h"
#ifdef __cplusplus
namespace mozilla {
//
// Suppress GCC warnings about unused return values with
// Unused << SomeFuncDeclaredWarnUnusedReturnValue();
//
struct unused_t
{
template<typename T>
inline void
operator<<(const T& /*unused*/) const {}
};
extern MFBT_DATA const unused_t Unused;
} // namespace mozilla
#endif // __cplusplus
// An alternative to mozilla::Unused for use in (a) C code and (b) code where
// linking with unused.o is difficult.
#define MOZ_UNUSED(expr) \
do { if (expr) { (void)0; } } while (0)
#endif // mozilla_unused_h

View File

@@ -0,0 +1,625 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A template class for tagged unions. */
#include <new>
#include <stdint.h>
#include "mozilla/Alignment.h"
#include "mozilla/Assertions.h"
#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
#ifndef mozilla_Variant_h
#define mozilla_Variant_h
namespace mozilla {
template<typename... Ts>
class Variant;
namespace detail {
// MaxSizeOf computes the maximum sizeof(T) for each T in Ts.
template<typename T, typename... Ts>
struct MaxSizeOf
{
static const size_t size = sizeof(T) > MaxSizeOf<Ts...>::size
? sizeof(T)
: MaxSizeOf<Ts...>::size;
};
template<typename T>
struct MaxSizeOf<T>
{
static const size_t size = sizeof(T);
};
// The `IsVariant` helper is used in conjunction with static_assert and
// `mozilla::EnableIf` to catch passing non-variant types to `Variant::is<T>()`
// and friends at compile time, rather than at runtime. It ensures that the
// given type `Needle` is one of the types in the set of types `Haystack`.
template<typename Needle, typename... Haystack>
struct IsVariant;
template<typename Needle>
struct IsVariant<Needle>
{
static const bool value = false;
};
template<typename Needle, typename... Haystack>
struct IsVariant<Needle, Needle, Haystack...>
{
static const bool value = true;
};
template<typename Needle, typename T, typename... Haystack>
struct IsVariant<Needle, T, Haystack...> : public IsVariant<Needle, Haystack...> { };
/// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
template<typename T, typename... Variants>
struct SelectVariantTypeHelper;
template<typename T>
struct SelectVariantTypeHelper<T>
{ };
template<typename T, typename... Variants>
struct SelectVariantTypeHelper<T, T, Variants...>
{
typedef T Type;
};
template<typename T, typename... Variants>
struct SelectVariantTypeHelper<T, const T, Variants...>
{
typedef const T Type;
};
template<typename T, typename... Variants>
struct SelectVariantTypeHelper<T, const T&, Variants...>
{
typedef const T& Type;
};
template<typename T, typename... Variants>
struct SelectVariantTypeHelper<T, T&&, Variants...>
{
typedef T&& Type;
};
template<typename T, typename Head, typename... Variants>
struct SelectVariantTypeHelper<T, Head, Variants...>
: public SelectVariantTypeHelper<T, Variants...>
{ };
/**
* SelectVariantType takes a type T and a list of variant types Variants and
* yields a type Type, selected from Variants, that can store a value of type T
* or a reference to type T. If no such type was found, Type is not defined.
*/
template <typename T, typename... Variants>
struct SelectVariantType
: public SelectVariantTypeHelper<typename RemoveConst<typename RemoveReference<T>::Type>::Type,
Variants...>
{ };
// Compute a fast, compact type that can be used to hold integral values that
// distinctly map to every type in Ts.
template<typename... Ts>
struct VariantTag
{
private:
static const size_t TypeCount = sizeof...(Ts);
public:
using Type =
typename Conditional<TypeCount < 3,
bool,
typename Conditional<TypeCount < (1 << 8),
uint_fast8_t,
size_t // stop caring past a certain point :-)
>::Type
>::Type;
};
// TagHelper gets the given sentinel tag value for the given type T. This has to
// be split out from VariantImplementation because you can't nest a partial
// template specialization within a template class.
template<typename Tag, size_t N, typename T, typename U, typename Next, bool isMatch>
struct TagHelper;
// In the case where T != U, we continue recursion.
template<typename Tag, size_t N, typename T, typename U, typename Next>
struct TagHelper<Tag, N, T, U, Next, false>
{
static Tag tag() { return Next::template tag<U>(); }
};
// In the case where T == U, return the tag number.
template<typename Tag, size_t N, typename T, typename U, typename Next>
struct TagHelper<Tag, N, T, U, Next, true>
{
static Tag tag() { return Tag(N); }
};
// The VariantImplementation template provides the guts of mozilla::Variant. We
// create a VariantImplementation for each T in Ts... which handles
// construction, destruction, etc for when the Variant's type is T. If the
// Variant's type isn't T, it punts the request on to the next
// VariantImplementation.
template<typename Tag, size_t N, typename... Ts>
struct VariantImplementation;
// The singly typed Variant / recursion base case.
template<typename Tag, size_t N, typename T>
struct VariantImplementation<Tag, N, T>
{
template<typename U>
static Tag tag() {
static_assert(mozilla::IsSame<T, U>::value,
"mozilla::Variant: tag: bad type!");
return Tag(N);
}
template<typename Variant>
static void copyConstruct(void* aLhs, const Variant& aRhs) {
new (aLhs) T(aRhs.template as<T>());
}
template<typename Variant>
static void moveConstruct(void* aLhs, Variant&& aRhs) {
new (aLhs) T(aRhs.template extract<T>());
}
template<typename Variant>
static void destroy(Variant& aV) {
aV.template as<T>().~T();
}
template<typename Variant>
static bool
equal(const Variant& aLhs, const Variant& aRhs) {
return aLhs.template as<T>() == aRhs.template as<T>();
}
template<typename Matcher, typename ConcreteVariant>
static auto
match(Matcher&& aMatcher, ConcreteVariant& aV)
-> decltype(aMatcher.match(aV.template as<T>()))
{
return aMatcher.match(aV.template as<T>());
}
};
// VariantImplementation for some variant type T.
template<typename Tag, size_t N, typename T, typename... Ts>
struct VariantImplementation<Tag, N, T, Ts...>
{
// The next recursive VariantImplementation.
using Next = VariantImplementation<Tag, N + 1, Ts...>;
template<typename U>
static Tag tag() {
return TagHelper<Tag, N, T, U, Next, IsSame<T, U>::value>::tag();
}
template<typename Variant>
static void copyConstruct(void* aLhs, const Variant& aRhs) {
if (aRhs.template is<T>()) {
new (aLhs) T(aRhs.template as<T>());
} else {
Next::copyConstruct(aLhs, aRhs);
}
}
template<typename Variant>
static void moveConstruct(void* aLhs, Variant&& aRhs) {
if (aRhs.template is<T>()) {
new (aLhs) T(aRhs.template extract<T>());
} else {
Next::moveConstruct(aLhs, aRhs);
}
}
template<typename Variant>
static void destroy(Variant& aV) {
if (aV.template is<T>()) {
aV.template as<T>().~T();
} else {
Next::destroy(aV);
}
}
template<typename Variant>
static bool equal(const Variant& aLhs, const Variant& aRhs) {
if (aLhs.template is<T>()) {
MOZ_ASSERT(aRhs.template is<T>());
return aLhs.template as<T>() == aRhs.template as<T>();
} else {
return Next::equal(aLhs, aRhs);
}
}
template<typename Matcher, typename ConcreteVariant>
static auto
match(Matcher&& aMatcher, ConcreteVariant& aV)
-> decltype(aMatcher.match(aV.template as<T>()))
{
if (aV.template is<T>()) {
return aMatcher.match(aV.template as<T>());
} else {
// If you're seeing compilation errors here like "no matching
// function for call to 'match'" then that means that the
// Matcher doesn't exhaust all variant types. There must exist a
// Matcher::match(T&) for every variant type T.
//
// If you're seeing compilation errors here like "cannot
// initialize return object of type <...> with an rvalue of type
// <...>" then that means that the Matcher::match(T&) overloads
// are returning different types. They must all return the same
// Matcher::ReturnType type.
return Next::match(aMatcher, aV);
}
}
};
/**
* AsVariantTemporary stores a value of type T to allow construction of a
* Variant value via type inference. Because T is copied and there's no
* guarantee that the copy can be elided, AsVariantTemporary is best used with
* primitive or very small types.
*/
template <typename T>
struct AsVariantTemporary
{
explicit AsVariantTemporary(const T& aValue)
: mValue(aValue)
{}
template<typename U>
explicit AsVariantTemporary(U&& aValue)
: mValue(Forward<U>(aValue))
{}
AsVariantTemporary(const AsVariantTemporary& aOther)
: mValue(aOther.mValue)
{}
AsVariantTemporary(AsVariantTemporary&& aOther)
: mValue(Move(aOther.mValue))
{}
AsVariantTemporary() = delete;
void operator=(const AsVariantTemporary&) = delete;
void operator=(AsVariantTemporary&&) = delete;
typename RemoveConst<typename RemoveReference<T>::Type>::Type mValue;
};
} // namespace detail
/**
* # mozilla::Variant
*
* A variant / tagged union / heterogenous disjoint union / sum-type template
* class. Similar in concept to (but not derived from) `boost::variant`.
*
* Sometimes, you may wish to use a C union with non-POD types. However, this is
* forbidden in C++ because it is not clear which type in the union should have
* its constructor and destructor run on creation and deletion
* respectively. This is the problem that `mozilla::Variant` solves.
*
* ## Usage
*
* A `mozilla::Variant` instance is constructed (via move or copy) from one of
* its variant types (ignoring const and references). It does *not* support
* construction from subclasses of variant types or types that coerce to one of
* the variant types.
*
* Variant<char, uint32_t> v1('a');
* Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
*
* Because specifying the full type of a Variant value is often verbose,
* AsVariant() can be used to construct a Variant value using type inference in
* contexts such as expressions or when returning values from functions. Because
* AsVariant() must copy or move the value into a temporary and this cannot
* necessarily be elided by the compiler, it's mostly appropriate only for use
* with primitive or very small types.
*
*
* Variant<char, uint32_t> Foo() { return AsVariant('x'); }
* // ...
* Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
*
* All access to the contained value goes through type-safe accessors.
*
* void
* Foo(Variant<A, B, C> v)
* {
* if (v.is<A>()) {
* A& ref = v.as<A>();
* ...
* } else {
* ...
* }
* }
*
* Attempting to use the contained value as type `T1` when the `Variant`
* instance contains a value of type `T2` causes an assertion failure.
*
* A a;
* Variant<A, B, C> v(a);
* v.as<B>(); // <--- Assertion failure!
*
* Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
* member of the set of `Ts...` is a compiler error.
*
* A a;
* Variant<A, B, C> v(a);
* v.as<SomeRandomType>(); // <--- Compiler error!
*
* Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
* out of the containing `Variant` instance with the `extract<T>` method:
*
* Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
* auto ptr = v.extract<UniquePtr<A>>();
*
* Finally, you can exhaustively match on the contained variant and branch into
* different code paths depending which type is contained. This is preferred to
* manually checking every variant type T with is<T>() because it provides
* compile-time checking that you handled every type, rather than runtime
* assertion failures.
*
* // Bad!
* char* foo(Variant<A, B, C, D>& v) {
* if (v.is<A>()) {
* return ...;
* } else if (v.is<B>()) {
* return ...;
* } else {
* return doSomething(v.as<C>()); // Forgot about case D!
* }
* }
*
* // Good!
* struct FooMatcher
* {
* // The return type of all matchers must be identical.
* char* match(A& a) { ... }
* char* match(B& b) { ... }
* char* match(C& c) { ... }
* char* match(D& d) { ... } // Compile-time error to forget D!
* }
* char* foo(Variant<A, B, C, D>& v) {
* return v.match(FooMatcher());
* }
*
* ## Examples
*
* A tree is either an empty leaf, or a node with a value and two children:
*
* struct Leaf { };
*
* template<typename T>
* struct Node
* {
* T value;
* Tree<T>* left;
* Tree<T>* right;
* };
*
* template<typename T>
* using Tree = Variant<Leaf, Node<T>>;
*
* A copy-on-write string is either a non-owning reference to some existing
* string, or an owning reference to our copy:
*
* class CopyOnWriteString
* {
* Variant<const char*, UniquePtr<char[]>> string;
*
* ...
* };
*/
template<typename... Ts>
class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Variant
{
using Tag = typename detail::VariantTag<Ts...>::Type;
using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
using RawData = AlignedStorage<detail::MaxSizeOf<Ts...>::size>;
// Raw storage for the contained variant value.
RawData raw;
// Each type is given a unique tag value that lets us keep track of the
// contained variant value's type.
Tag tag;
void* ptr() {
return reinterpret_cast<void*>(&raw);
}
public:
/** Perfect forwarding construction for some variant type T. */
template<typename RefT,
// RefT captures both const& as well as && (as intended, to support
// perfect forwarding), so we have to remove those qualifiers here
// when ensuring that T is a variant of this type, and getting T's
// tag, etc.
typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
explicit Variant(RefT&& aT)
: tag(Impl::template tag<T>())
{
new (ptr()) T(Forward<RefT>(aT));
}
/**
* Constructs this Variant from an AsVariantTemporary<T> such that T can be
* stored in one of the types allowable in this Variant. This is used in the
* implementation of AsVariant().
*/
template<typename RefT,
typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue)
: tag(Impl::template tag<T>())
{
new (ptr()) T(Move(aValue.mValue));
}
/** Copy construction. */
Variant(const Variant& aRhs)
: tag(aRhs.tag)
{
Impl::copyConstruct(ptr(), aRhs);
}
/** Move construction. */
Variant(Variant&& aRhs)
: tag(aRhs.tag)
{
Impl::moveConstruct(ptr(), Move(aRhs));
}
/** Copy assignment. */
Variant& operator=(const Variant& aRhs) {
MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
this->~Variant();
new (this) Variant(aRhs);
return *this;
}
/** Move assignment. */
Variant& operator=(Variant&& aRhs) {
MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
this->~Variant();
new (this) Variant(Move(aRhs));
return *this;
}
/** Move assignment from AsVariant(). */
template <typename T>
Variant& operator=(detail::AsVariantTemporary<T>&& aValue)
{
this->~Variant();
new (this) Variant(Move(aValue));
return *this;
}
~Variant()
{
Impl::destroy(*this);
}
/** Check which variant type is currently contained. */
template<typename T>
bool is() const {
static_assert(detail::IsVariant<T, Ts...>::value,
"provided a type not found in this Variant's type list");
return Impl::template tag<T>() == tag;
}
/**
* Operator == overload that defers to the variant type's operator==
* implementation if the rhs is tagged as the same type as this one.
*/
bool operator==(const Variant& aRhs) const {
return tag == aRhs.tag && Impl::equal(*this, aRhs);
}
/**
* Operator != overload that defers to the negation of the variant type's
* operator== implementation if the rhs is tagged as the same type as this
* one.
*/
bool operator!=(const Variant& aRhs) const {
return !(*this == aRhs);
}
// Accessors for working with the contained variant value.
/** Mutable reference. */
template<typename T>
T& as() {
static_assert(detail::IsVariant<T, Ts...>::value,
"provided a type not found in this Variant's type list");
MOZ_ASSERT(is<T>());
return *reinterpret_cast<T*>(&raw);
}
/** Immutable const reference. */
template<typename T>
const T& as() const {
static_assert(detail::IsVariant<T, Ts...>::value,
"provided a type not found in this Variant's type list");
MOZ_ASSERT(is<T>());
return *reinterpret_cast<const T*>(&raw);
}
/**
* Extract the contained variant value from this container into a temporary
* value. On completion, the value in the variant will be in a
* safely-destructible state, as determined by the behavior of T's move
* constructor when provided the variant's internal value.
*/
template<typename T>
T extract() {
static_assert(detail::IsVariant<T, Ts...>::value,
"provided a type not found in this Variant's type list");
MOZ_ASSERT(is<T>());
return T(Move(as<T>()));
}
// Exhaustive matching of all variant types on the contained value.
/** Match on an immutable const reference. */
template<typename Matcher>
auto
match(Matcher&& aMatcher) const
-> decltype(Impl::match(aMatcher, *this))
{
return Impl::match(aMatcher, *this);
}
/** Match on a mutable non-const reference. */
template<typename Matcher>
auto
match(Matcher&& aMatcher)
-> decltype(Impl::match(aMatcher, *this))
{
return Impl::match(aMatcher, *this);
}
};
/*
* AsVariant() is used to construct a Variant<T,...> value containing the
* provided T value using type inference. It can be used to construct Variant
* values in expressions or return them from functions without specifying the
* entire Variant type.
*
* Because AsVariant() must copy or move the value into a temporary and this
* cannot necessarily be elided by the compiler, it's mostly appropriate only
* for use with primitive or very small types.
*
* AsVariant() returns a AsVariantTemporary value which is implicitly
* convertible to any Variant that can hold a value of type T.
*/
template<typename T>
detail::AsVariantTemporary<T>
AsVariant(T&& aValue)
{
return detail::AsVariantTemporary<T>(Forward<T>(aValue));
}
} // namespace mozilla
#endif /* mozilla_Variant_h */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,283 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Weak pointer functionality, implemented as a mixin for use with any class. */
/**
* SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting
* its lifetime. It works by creating a single shared reference counted object
* (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo'
* clear the pointer in the WeakReference without having to know about all of
* the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
* of 'Foo'.
*
* PLEASE NOTE: This weak pointer implementation is not thread-safe.
*
* Note that when deriving from SupportsWeakPtr you should add
* MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ClassName) to the public section of your
* class, where ClassName is the name of your class.
*
* The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
* dereference, and an additional heap allocated pointer sized object shared
* between all of the WeakPtrs.
*
* Example of usage:
*
* // To have a class C support weak pointers, inherit from
* // SupportsWeakPtr<C>.
* class C : public SupportsWeakPtr<C>
* {
* public:
* MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C)
* int mNum;
* void act();
* };
*
* C* ptr = new C();
*
* // Get weak pointers to ptr. The first time a weak pointer
* // is obtained, a reference counted WeakReference object is created that
* // can live beyond the lifetime of 'ptr'. The WeakReference
* // object will be notified of 'ptr's destruction.
* WeakPtr<C> weak = ptr;
* WeakPtr<C> other = ptr;
*
* // Test a weak pointer for validity before using it.
* if (weak) {
* weak->mNum = 17;
* weak->act();
* }
*
* // Destroying the underlying object clears weak pointers to it.
* delete ptr;
*
* MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
* MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
*
* WeakPtr is typesafe and may be used with any class. It is not required that
* the class be reference-counted or allocated in any particular way.
*
* The API was loosely inspired by Chromium's weak_ptr.h:
* http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
*/
#ifndef mozilla_WeakPtr_h
#define mozilla_WeakPtr_h
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/RefCounted.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TypeTraits.h"
#include <string.h>
// Weak referencing is not implemeted as thread safe. When a WeakPtr
// is created or dereferenced on thread A but the real object is just
// being Released() on thread B, there is a possibility of a race
// when the proxy object (detail::WeakReference) is notified about
// the real object destruction just between when thread A is storing
// the object pointer locally and is about to add a reference to it.
//
// Hence, a non-null weak proxy object is considered to have a single
// "owning thread". It means that each query for a weak reference,
// its dereference, and destruction of the real object must all happen
// on a single thread. The following macros implement assertions for
// checking these conditions.
//
// We disable this on MinGW. MinGW has two threading models: win32
// API based, which disables std::thread; and POSIX based which
// enables it but requires an emulation library (winpthreads).
// Rather than attempting to switch to pthread emulation at this point,
// we are disabling the std::thread based assertion checking.
//
// In the future, to enable it we could
// a. have libgcc/stdc++ support win32 threads natively
// b. switch to POSIX-based threading in MinGW with pthread emulation
// c. refactor it to not use std::thread
#if !defined(__MINGW32__) && (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING)))
#include <thread>
#define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \
std::thread::id _owningThread; \
bool _empty; // If it was initialized as a placeholder with mPtr = nullptr.
#define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
do { \
_owningThread = std::this_thread::get_id(); \
_empty = !p; \
} while (false)
#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
MOZ_DIAGNOSTIC_ASSERT(_empty || _owningThread == std::this_thread::get_id(), \
"WeakPtr used on multiple threads")
#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
(that)->AssertThreadSafety();
#define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
#else
#define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
#define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() do { } while (false)
#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() do { } while (false)
#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) do { } while (false)
#endif
namespace mozilla {
template <typename T> class WeakPtr;
template <typename T> class SupportsWeakPtr;
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
#define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \
static const char* weakReferenceTypeName() { return "WeakReference<" #T ">"; }
#else
#define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T)
#endif
namespace detail {
// This can live beyond the lifetime of the class derived from
// SupportsWeakPtr.
template<class T>
class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
{
public:
explicit WeakReference(T* p) : mPtr(p)
{
MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
}
T* get() const {
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
return mPtr;
}
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
const char* typeName() const
{
// The first time this is called mPtr is null, so don't
// invoke any methods on mPtr.
return T::weakReferenceTypeName();
}
size_t typeSize() const { return sizeof(*this); }
#endif
#ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
#endif
private:
friend class mozilla::SupportsWeakPtr<T>;
void detach() {
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
mPtr = nullptr;
}
T* MOZ_NON_OWNING_REF mPtr;
MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
};
} // namespace detail
template <typename T>
class SupportsWeakPtr
{
protected:
~SupportsWeakPtr()
{
static_assert(IsBaseOf<SupportsWeakPtr<T>, T>::value,
"T must derive from SupportsWeakPtr<T>");
if (mSelfReferencingWeakPtr) {
mSelfReferencingWeakPtr.mRef->detach();
}
}
private:
const WeakPtr<T>& SelfReferencingWeakPtr()
{
if (!mSelfReferencingWeakPtr) {
mSelfReferencingWeakPtr.mRef = new detail::WeakReference<T>(static_cast<T*>(this));
} else {
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef);
}
return mSelfReferencingWeakPtr;
}
const WeakPtr<const T>& SelfReferencingWeakPtr() const
{
const WeakPtr<T>& p = const_cast<SupportsWeakPtr*>(this)->SelfReferencingWeakPtr();
return reinterpret_cast<const WeakPtr<const T>&>(p);
}
friend class WeakPtr<T>;
friend class WeakPtr<const T>;
WeakPtr<T> mSelfReferencingWeakPtr;
};
template <typename T>
class WeakPtr
{
typedef detail::WeakReference<T> WeakReference;
public:
WeakPtr& operator=(const WeakPtr& aOther)
{
mRef = aOther.mRef;
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
return *this;
}
WeakPtr(const WeakPtr& aOther)
{
// The thread safety check is performed inside of the operator= method.
*this = aOther;
}
WeakPtr& operator=(T* aOther)
{
if (aOther) {
*this = aOther->SelfReferencingWeakPtr();
} else if (!mRef || mRef->get()) {
// Ensure that mRef is dereferenceable in the uninitialized state.
mRef = new WeakReference(nullptr);
}
// The thread safety check happens inside SelfReferencingWeakPtr
// or is initialized in the WeakReference constructor.
return *this;
}
MOZ_IMPLICIT WeakPtr(T* aOther)
{
*this = aOther;
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
}
// Ensure that mRef is dereferenceable in the uninitialized state.
WeakPtr() : mRef(new WeakReference(nullptr)) {}
operator T*() const { return mRef->get(); }
T& operator*() const { return *mRef->get(); }
T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mRef->get(); }
T* get() const { return mRef->get(); }
private:
friend class SupportsWeakPtr<T>;
explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {}
RefPtr<WeakReference> mRef;
};
} // namespace mozilla
#endif /* mozilla_WeakPtr_h */

View File

@@ -0,0 +1,121 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* The xorshift128+ pseudo-random number generator. */
#ifndef mozilla_XorShift128Plus_h
#define mozilla_XorShift128Plus_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
#include <inttypes.h>
namespace mozilla {
namespace non_crypto {
/*
* A stream of pseudo-random numbers generated using the xorshift+ technique
* described here:
*
* Vigna, Sebastiano (2014). "Further scramblings of Marsaglia's xorshift
* generators". arXiv:1404.0390 (http://arxiv.org/abs/1404.0390)
*
* That paper says:
*
* In particular, we propose a tightly coded xorshift128+ generator that
* does not fail systematically any test from the BigCrush suite of TestU01
* (even reversed) and generates 64 pseudorandom bits in 1.10 ns on an
* Intel(R) Core(TM) i7-4770 CPU @3.40GHz (Haswell). It is the fastest
* generator we are aware of with such empirical statistical properties.
*
* The stream of numbers produced by this method repeats every 2**128 - 1 calls
* (i.e. never, for all practical purposes). Zero appears 2**64 - 1 times in
* this period; all other numbers appear 2**64 times. Additionally, each *bit*
* in the produced numbers repeats every 2**128 - 1 calls.
*
* This generator is not suitable as a cryptographically secure random number
* generator.
*/
class XorShift128PlusRNG {
uint64_t mState[2];
public:
/*
* Construct a xorshift128+ pseudo-random number stream using |aInitial0| and
* |aInitial1| as the initial state. These MUST NOT both be zero.
*
* If the initial states contain many zeros, for a few iterations you'll see
* many zeroes in the generated numbers. It's suggested to seed a SplitMix64
* generator <http://xorshift.di.unimi.it/splitmix64.c> and use its first two
* outputs to seed xorshift128+.
*/
XorShift128PlusRNG(uint64_t aInitial0, uint64_t aInitial1) {
setState(aInitial0, aInitial1);
}
/**
* Return a pseudo-random 64-bit number.
*/
uint64_t next() {
/*
* The offsetOfState*() methods below are provided so that exceedingly-rare
* callers that want to observe or poke at RNG state in C++ type-system-
* ignoring means can do so. Don't change the next() or nextDouble()
* algorithms without altering code that uses offsetOfState*()!
*/
uint64_t s1 = mState[0];
const uint64_t s0 = mState[1];
mState[0] = s0;
s1 ^= s1 << 23;
mState[1] = s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26);
return mState[1] + s0;
}
/*
* Return a pseudo-random floating-point value in the range [0, 1). More
* precisely, choose an integer in the range [0, 2**53) and divide it by
* 2**53. Given the 2**128 - 1 period noted above, the produced doubles are
* all but uniformly distributed in this range.
*/
double nextDouble() {
/*
* Because the IEEE 64-bit floating point format stores the leading '1' bit
* of the mantissa implicitly, it effectively represents a mantissa in the
* range [0, 2**53) in only 52 bits. FloatingPoint<double>::kExponentShift
* is the width of the bitfield in the in-memory format, so we must add one
* to get the mantissa's range.
*/
static constexpr int kMantissaBits =
mozilla::FloatingPoint<double>::kExponentShift + 1;
uint64_t mantissa = next() & ((UINT64_C(1) << kMantissaBits) - 1);
return double(mantissa) / (UINT64_C(1) << kMantissaBits);
}
/*
* Set the stream's current state to |aState0| and |aState1|. These must not
* both be zero; ideally, they should have an almost even mix of zero and one
* bits.
*/
void setState(uint64_t aState0, uint64_t aState1) {
MOZ_ASSERT(aState0 || aState1);
mState[0] = aState0;
mState[1] = aState1;
}
static size_t offsetOfState0() {
return offsetof(XorShift128PlusRNG, mState[0]);
}
static size_t offsetOfState1() {
return offsetof(XorShift128PlusRNG, mState[1]);
}
};
} // namespace non_crypto
} // namespace mozilla
#endif // mozilla_XorShift128Plus_h

View File

@@ -0,0 +1,538 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
#include "mozilla/Types.h"
#include "utils.h"
namespace double_conversion {
class DoubleToStringConverter {
public:
// When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint
// or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the
// function returns false.
static const int kMaxFixedDigitsBeforePoint = 60;
static const int kMaxFixedDigitsAfterPoint = 60;
// When calling ToExponential with a requested_digits
// parameter > kMaxExponentialDigits then the function returns false.
static const int kMaxExponentialDigits = 120;
// When calling ToPrecision with a requested_digits
// parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits
// then the function returns false.
static const int kMinPrecisionDigits = 1;
static const int kMaxPrecisionDigits = 120;
enum Flags {
NO_FLAGS = 0,
EMIT_POSITIVE_EXPONENT_SIGN = 1,
EMIT_TRAILING_DECIMAL_POINT = 2,
EMIT_TRAILING_ZERO_AFTER_POINT = 4,
UNIQUE_ZERO = 8
};
// Flags should be a bit-or combination of the possible Flags-enum.
// - NO_FLAGS: no special flags.
// - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent
// form, emits a '+' for positive exponents. Example: 1.2e+2.
// - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is
// converted into decimal format then a trailing decimal point is appended.
// Example: 2345.0 is converted to "2345.".
// - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point
// emits a trailing '0'-character. This flag requires the
// EXMIT_TRAILING_DECIMAL_POINT flag.
// Example: 2345.0 is converted to "2345.0".
// - UNIQUE_ZERO: "-0.0" is converted to "0.0".
//
// Infinity symbol and nan_symbol provide the string representation for these
// special values. If the string is NULL and the special value is encountered
// then the conversion functions return false.
//
// The exponent_character is used in exponential representations. It is
// usually 'e' or 'E'.
//
// When converting to the shortest representation the converter will
// represent input numbers in decimal format if they are in the interval
// [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[
// (lower boundary included, greater boundary excluded).
// Example: with decimal_in_shortest_low = -6 and
// decimal_in_shortest_high = 21:
// ToShortest(0.000001) -> "0.000001"
// ToShortest(0.0000001) -> "1e-7"
// ToShortest(111111111111111111111.0) -> "111111111111111110000"
// ToShortest(100000000000000000000.0) -> "100000000000000000000"
// ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
//
// When converting to precision mode the converter may add
// max_leading_padding_zeroes before returning the number in exponential
// format.
// Example with max_leading_padding_zeroes_in_precision_mode = 6.
// ToPrecision(0.0000012345, 2) -> "0.0000012"
// ToPrecision(0.00000012345, 2) -> "1.2e-7"
// Similarily the converter may add up to
// max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
// returning an exponential representation. A zero added by the
// EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
// Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
// ToPrecision(230.0, 2) -> "230"
// ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
// ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
DoubleToStringConverter(int flags,
const char* infinity_symbol,
const char* nan_symbol,
char exponent_character,
int decimal_in_shortest_low,
int decimal_in_shortest_high,
int max_leading_padding_zeroes_in_precision_mode,
int max_trailing_padding_zeroes_in_precision_mode)
: flags_(flags),
infinity_symbol_(infinity_symbol),
nan_symbol_(nan_symbol),
exponent_character_(exponent_character),
decimal_in_shortest_low_(decimal_in_shortest_low),
decimal_in_shortest_high_(decimal_in_shortest_high),
max_leading_padding_zeroes_in_precision_mode_(
max_leading_padding_zeroes_in_precision_mode),
max_trailing_padding_zeroes_in_precision_mode_(
max_trailing_padding_zeroes_in_precision_mode) {
// When 'trailing zero after the point' is set, then 'trailing point'
// must be set too.
ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) ||
!((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0));
}
// Returns a converter following the EcmaScript specification.
static MFBT_API const DoubleToStringConverter& EcmaScriptConverter();
// Computes the shortest string of digits that correctly represent the input
// number. Depending on decimal_in_shortest_low and decimal_in_shortest_high
// (see constructor) it then either returns a decimal representation, or an
// exponential representation.
// Example with decimal_in_shortest_low = -6,
// decimal_in_shortest_high = 21,
// EMIT_POSITIVE_EXPONENT_SIGN activated, and
// EMIT_TRAILING_DECIMAL_POINT deactived:
// ToShortest(0.000001) -> "0.000001"
// ToShortest(0.0000001) -> "1e-7"
// ToShortest(111111111111111111111.0) -> "111111111111111110000"
// ToShortest(100000000000000000000.0) -> "100000000000000000000"
// ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
//
// Note: the conversion may round the output if the returned string
// is accurate enough to uniquely identify the input-number.
// For example the most precise representation of the double 9e59 equals
// "899999999999999918767229449717619953810131273674690656206848", but
// the converter will return the shorter (but still correct) "9e59".
//
// Returns true if the conversion succeeds. The conversion always succeeds
// except when the input value is special and no infinity_symbol or
// nan_symbol has been given to the constructor.
bool ToShortest(double value, StringBuilder* result_builder) const {
return ToShortestIeeeNumber(value, result_builder, SHORTEST);
}
// Same as ToShortest, but for single-precision floats.
bool ToShortestSingle(float value, StringBuilder* result_builder) const {
return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE);
}
// Computes a decimal representation with a fixed number of digits after the
// decimal point. The last emitted digit is rounded.
//
// Examples:
// ToFixed(3.12, 1) -> "3.1"
// ToFixed(3.1415, 3) -> "3.142"
// ToFixed(1234.56789, 4) -> "1234.5679"
// ToFixed(1.23, 5) -> "1.23000"
// ToFixed(0.1, 4) -> "0.1000"
// ToFixed(1e30, 2) -> "1000000000000000019884624838656.00"
// ToFixed(0.1, 30) -> "0.100000000000000005551115123126"
// ToFixed(0.1, 17) -> "0.10000000000000001"
//
// If requested_digits equals 0, then the tail of the result depends on
// the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT.
// Examples, for requested_digits == 0,
// let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be
// - false and false: then 123.45 -> 123
// 0.678 -> 1
// - true and false: then 123.45 -> 123.
// 0.678 -> 1.
// - true and true: then 123.45 -> 123.0
// 0.678 -> 1.0
//
// Returns true if the conversion succeeds. The conversion always succeeds
// except for the following cases:
// - the input value is special and no infinity_symbol or nan_symbol has
// been provided to the constructor,
// - 'value' > 10^kMaxFixedDigitsBeforePoint, or
// - 'requested_digits' > kMaxFixedDigitsAfterPoint.
// The last two conditions imply that the result will never contain more than
// 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
// (one additional character for the sign, and one for the decimal point).
MFBT_API bool ToFixed(double value,
int requested_digits,
StringBuilder* result_builder) const;
// Computes a representation in exponential format with requested_digits
// after the decimal point. The last emitted digit is rounded.
// If requested_digits equals -1, then the shortest exponential representation
// is computed.
//
// Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and
// exponent_character set to 'e'.
// ToExponential(3.12, 1) -> "3.1e0"
// ToExponential(5.0, 3) -> "5.000e0"
// ToExponential(0.001, 2) -> "1.00e-3"
// ToExponential(3.1415, -1) -> "3.1415e0"
// ToExponential(3.1415, 4) -> "3.1415e0"
// ToExponential(3.1415, 3) -> "3.142e0"
// ToExponential(123456789000000, 3) -> "1.235e14"
// ToExponential(1000000000000000019884624838656.0, -1) -> "1e30"
// ToExponential(1000000000000000019884624838656.0, 32) ->
// "1.00000000000000001988462483865600e30"
// ToExponential(1234, 0) -> "1e3"
//
// Returns true if the conversion succeeds. The conversion always succeeds
// except for the following cases:
// - the input value is special and no infinity_symbol or nan_symbol has
// been provided to the constructor,
// - 'requested_digits' > kMaxExponentialDigits.
// The last condition implies that the result will never contain more than
// kMaxExponentialDigits + 8 characters (the sign, the digit before the
// decimal point, the decimal point, the exponent character, the
// exponent's sign, and at most 3 exponent digits).
MFBT_API bool ToExponential(double value,
int requested_digits,
StringBuilder* result_builder) const;
// Computes 'precision' leading digits of the given 'value' and returns them
// either in exponential or decimal format, depending on
// max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the
// constructor).
// The last computed digit is rounded.
//
// Example with max_leading_padding_zeroes_in_precision_mode = 6.
// ToPrecision(0.0000012345, 2) -> "0.0000012"
// ToPrecision(0.00000012345, 2) -> "1.2e-7"
// Similarily the converter may add up to
// max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
// returning an exponential representation. A zero added by the
// EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
// Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
// ToPrecision(230.0, 2) -> "230"
// ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
// ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
// Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no
// EMIT_TRAILING_ZERO_AFTER_POINT:
// ToPrecision(123450.0, 6) -> "123450"
// ToPrecision(123450.0, 5) -> "123450"
// ToPrecision(123450.0, 4) -> "123500"
// ToPrecision(123450.0, 3) -> "123000"
// ToPrecision(123450.0, 2) -> "1.2e5"
//
// Returns true if the conversion succeeds. The conversion always succeeds
// except for the following cases:
// - the input value is special and no infinity_symbol or nan_symbol has
// been provided to the constructor,
// - precision < kMinPericisionDigits
// - precision > kMaxPrecisionDigits
// The last condition implies that the result will never contain more than
// kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the
// exponent character, the exponent's sign, and at most 3 exponent digits).
MFBT_API bool ToPrecision(double value,
int precision,
bool* used_exponential_notation,
StringBuilder* result_builder) const;
enum DtoaMode {
// Produce the shortest correct representation.
// For example the output of 0.299999999999999988897 is (the less accurate
// but correct) 0.3.
SHORTEST,
// Same as SHORTEST, but for single-precision floats.
SHORTEST_SINGLE,
// Produce a fixed number of digits after the decimal point.
// For instance fixed(0.1, 4) becomes 0.1000
// If the input number is big, the output will be big.
FIXED,
// Fixed number of digits (independent of the decimal point).
PRECISION
};
// The maximal number of digits that are needed to emit a double in base 10.
// A higher precision can be achieved by using more digits, but the shortest
// accurate representation of any double will never use more digits than
// kBase10MaximalLength.
// Note that DoubleToAscii null-terminates its input. So the given buffer
// should be at least kBase10MaximalLength + 1 characters long.
static const MFBT_DATA int kBase10MaximalLength = 17;
// Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or
// -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v'
// after it has been casted to a single-precision float. That is, in this
// mode static_cast<float>(v) must not be NaN, +Infinity or -Infinity.
//
// The result should be interpreted as buffer * 10^(point-length).
//
// The output depends on the given mode:
// - SHORTEST: produce the least amount of digits for which the internal
// identity requirement is still satisfied. If the digits are printed
// (together with the correct exponent) then reading this number will give
// 'v' again. The buffer will choose the representation that is closest to
// 'v'. If there are two at the same distance, than the one farther away
// from 0 is chosen (halfway cases - ending with 5 - are rounded up).
// In this mode the 'requested_digits' parameter is ignored.
// - SHORTEST_SINGLE: same as SHORTEST but with single-precision.
// - FIXED: produces digits necessary to print a given number with
// 'requested_digits' digits after the decimal point. The produced digits
// might be too short in which case the caller has to fill the remainder
// with '0's.
// Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
// Halfway cases are rounded towards +/-Infinity (away from 0). The call
// toFixed(0.15, 2) thus returns buffer="2", point=0.
// The returned buffer may contain digits that would be truncated from the
// shortest representation of the input.
// - PRECISION: produces 'requested_digits' where the first digit is not '0'.
// Even though the length of produced digits usually equals
// 'requested_digits', the function is allowed to return fewer digits, in
// which case the caller has to fill the missing digits with '0's.
// Halfway cases are again rounded away from 0.
// DoubleToAscii expects the given buffer to be big enough to hold all
// digits and a terminating null-character. In SHORTEST-mode it expects a
// buffer of at least kBase10MaximalLength + 1. In all other modes the
// requested_digits parameter and the padding-zeroes limit the size of the
// output. Don't forget the decimal point, the exponent character and the
// terminating null-character when computing the maximal output size.
// The given length is only used in debug mode to ensure the buffer is big
// enough.
static MFBT_API void DoubleToAscii(double v,
DtoaMode mode,
int requested_digits,
char* buffer,
int buffer_length,
bool* sign,
int* length,
int* point);
private:
// Implementation for ToShortest and ToShortestSingle.
MFBT_API bool ToShortestIeeeNumber(double value,
StringBuilder* result_builder,
DtoaMode mode) const;
// If the value is a special value (NaN or Infinity) constructs the
// corresponding string using the configured infinity/nan-symbol.
// If either of them is NULL or the value is not special then the
// function returns false.
MFBT_API bool HandleSpecialValues(double value, StringBuilder* result_builder) const;
// Constructs an exponential representation (i.e. 1.234e56).
// The given exponent assumes a decimal point after the first decimal digit.
MFBT_API void CreateExponentialRepresentation(const char* decimal_digits,
int length,
int exponent,
StringBuilder* result_builder) const;
// Creates a decimal representation (i.e 1234.5678).
MFBT_API void CreateDecimalRepresentation(const char* decimal_digits,
int length,
int decimal_point,
int digits_after_point,
StringBuilder* result_builder) const;
const int flags_;
const char* const infinity_symbol_;
const char* const nan_symbol_;
const char exponent_character_;
const int decimal_in_shortest_low_;
const int decimal_in_shortest_high_;
const int max_leading_padding_zeroes_in_precision_mode_;
const int max_trailing_padding_zeroes_in_precision_mode_;
DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
};
class StringToDoubleConverter {
public:
// Enumeration for allowing octals and ignoring junk when converting
// strings to numbers.
enum Flags {
NO_FLAGS = 0,
ALLOW_HEX = 1,
ALLOW_OCTALS = 2,
ALLOW_TRAILING_JUNK = 4,
ALLOW_LEADING_SPACES = 8,
ALLOW_TRAILING_SPACES = 16,
ALLOW_SPACES_AFTER_SIGN = 32
};
// Flags should be a bit-or combination of the possible Flags-enum.
// - NO_FLAGS: no special flags.
// - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers.
// Ex: StringToDouble("0x1234") -> 4660.0
// In StringToDouble("0x1234.56") the characters ".56" are trailing
// junk. The result of the call is hence dependent on
// the ALLOW_TRAILING_JUNK flag and/or the junk value.
// With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK,
// the string will not be parsed as "0" followed by junk.
//
// - ALLOW_OCTALS: recognizes the prefix "0" for octals:
// If a sequence of octal digits starts with '0', then the number is
// read as octal integer. Octal numbers may only be integers.
// Ex: StringToDouble("01234") -> 668.0
// StringToDouble("012349") -> 12349.0 // Not a sequence of octal
// // digits.
// In StringToDouble("01234.56") the characters ".56" are trailing
// junk. The result of the call is hence dependent on
// the ALLOW_TRAILING_JUNK flag and/or the junk value.
// In StringToDouble("01234e56") the characters "e56" are trailing
// junk, too.
// - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of
// a double literal.
// - ALLOW_LEADING_SPACES: skip over leading spaces.
// - ALLOW_TRAILING_SPACES: ignore trailing spaces.
// - ALLOW_SPACES_AFTER_SIGN: ignore spaces after the sign.
// Ex: StringToDouble("- 123.2") -> -123.2.
// StringToDouble("+ 123.2") -> 123.2
//
// empty_string_value is returned when an empty string is given as input.
// If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string
// containing only spaces is converted to the 'empty_string_value', too.
//
// junk_string_value is returned when
// a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not
// part of a double-literal) is found.
// b) ALLOW_TRAILING_JUNK is set, but the string does not start with a
// double literal.
//
// infinity_symbol and nan_symbol are strings that are used to detect
// inputs that represent infinity and NaN. They can be null, in which case
// they are ignored.
// The conversion routine first reads any possible signs. Then it compares the
// following character of the input-string with the first character of
// the infinity, and nan-symbol. If either matches, the function assumes, that
// a match has been found, and expects the following input characters to match
// the remaining characters of the special-value symbol.
// This means that the following restrictions apply to special-value symbols:
// - they must not start with signs ('+', or '-'),
// - they must not have the same first character.
// - they must not start with digits.
//
// Examples:
// flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,
// empty_string_value = 0.0,
// junk_string_value = NaN,
// infinity_symbol = "infinity",
// nan_symbol = "nan":
// StringToDouble("0x1234") -> 4660.0.
// StringToDouble("0x1234K") -> 4660.0.
// StringToDouble("") -> 0.0 // empty_string_value.
// StringToDouble(" ") -> NaN // junk_string_value.
// StringToDouble(" 1") -> NaN // junk_string_value.
// StringToDouble("0x") -> NaN // junk_string_value.
// StringToDouble("-123.45") -> -123.45.
// StringToDouble("--123.45") -> NaN // junk_string_value.
// StringToDouble("123e45") -> 123e45.
// StringToDouble("123E45") -> 123e45.
// StringToDouble("123e+45") -> 123e45.
// StringToDouble("123E-45") -> 123e-45.
// StringToDouble("123e") -> 123.0 // trailing junk ignored.
// StringToDouble("123e-") -> 123.0 // trailing junk ignored.
// StringToDouble("+NaN") -> NaN // NaN string literal.
// StringToDouble("-infinity") -> -inf. // infinity literal.
// StringToDouble("Infinity") -> NaN // junk_string_value.
//
// flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES,
// empty_string_value = 0.0,
// junk_string_value = NaN,
// infinity_symbol = NULL,
// nan_symbol = NULL:
// StringToDouble("0x1234") -> NaN // junk_string_value.
// StringToDouble("01234") -> 668.0.
// StringToDouble("") -> 0.0 // empty_string_value.
// StringToDouble(" ") -> 0.0 // empty_string_value.
// StringToDouble(" 1") -> 1.0
// StringToDouble("0x") -> NaN // junk_string_value.
// StringToDouble("0123e45") -> NaN // junk_string_value.
// StringToDouble("01239E45") -> 1239e45.
// StringToDouble("-infinity") -> NaN // junk_string_value.
// StringToDouble("NaN") -> NaN // junk_string_value.
StringToDoubleConverter(int flags,
double empty_string_value,
double junk_string_value,
const char* infinity_symbol,
const char* nan_symbol)
: flags_(flags),
empty_string_value_(empty_string_value),
junk_string_value_(junk_string_value),
infinity_symbol_(infinity_symbol),
nan_symbol_(nan_symbol) {
}
// Performs the conversion.
// The output parameter 'processed_characters_count' is set to the number
// of characters that have been processed to read the number.
// Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included
// in the 'processed_characters_count'. Trailing junk is never included.
double StringToDouble(const char* buffer,
int length,
int* processed_characters_count) const {
return StringToIeee(buffer, length, processed_characters_count, true);
}
// Same as StringToDouble but reads a float.
// Note that this is not equivalent to static_cast<float>(StringToDouble(...))
// due to potential double-rounding.
float StringToFloat(const char* buffer,
int length,
int* processed_characters_count) const {
return static_cast<float>(StringToIeee(buffer, length,
processed_characters_count, false));
}
private:
const int flags_;
const double empty_string_value_;
const double junk_string_value_;
const char* const infinity_symbol_;
const char* const nan_symbol_;
double StringToIeee(const char* buffer,
int length,
int* processed_characters_count,
bool read_as_double) const;
DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
};
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_

View File

@@ -0,0 +1,68 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_fallible_h
#define mozilla_fallible_h
#if defined(__cplusplus)
/* Explicit fallible allocation
*
* Memory allocation (normally) defaults to abort in case of failed
* allocation. That is, it never returns NULL, and crashes instead.
*
* Code can explicitely request for fallible memory allocation thanks
* to the declarations below.
*
* The typical use of the mozilla::fallible const is with placement new,
* like the following:
*
* foo = new (mozilla::fallible) Foo();
*
* The following forms, or derivatives, are also possible but deprecated:
*
* foo = new ((mozilla::fallible_t())) Foo();
*
* const mozilla::fallible_t fallible = mozilla::fallible_t();
* bar = new (f) Bar();
*
* It is also possible to declare method overloads with fallible allocation
* alternatives, like so:
*
* class Foo {
* public:
* void Method(void *);
* void Method(void *, const mozilla::fallible_t&);
* };
*
* Foo foo;
* foo.Method(nullptr, mozilla::fallible);
*
* If that last method call is in a method that itself takes a const
* fallible_t& argument, it is recommended to propagate that argument
* instead of using mozilla::fallible:
*
* void Func(Foo &foo, const mozilla::fallible_t& aFallible) {
* foo.Method(nullptr, aFallible);
* }
*
*/
namespace mozilla {
struct fallible_t { };
/* This symbol is kept unexported, such that in corner cases where the
* compiler can't remove its use (essentially, cross compilation-unit
* calls), the smallest machine code is used.
* Depending how the linker packs symbols, it will consume between 1 and
* 8 bytes of read-only data in each executable or shared library, but
* only in those where it's actually not optimized out by the compiler.
*/
extern const fallible_t fallible;
} // namespace mozilla
#endif
#endif // mozilla_fallible_h

View File

@@ -0,0 +1,361 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_mozalloc_h
#define mozilla_mozalloc_h
/*
* https://bugzilla.mozilla.org/show_bug.cgi?id=427099
*/
#if defined(__cplusplus)
# include <new>
// Since libstdc++ 6, including the C headers (e.g. stdlib.h) instead of the
// corresponding C++ header (e.g. cstdlib) can cause confusion in C++ code
// using things defined there. Specifically, with stdlib.h, the use of abs()
// in gfx/graphite2/src/inc/UtfCodec.h somehow ends up picking the wrong abs()
# include <cstdlib>
# include <cstring>
#else
# include <stdlib.h>
# include <string.h>
#endif
#if defined(__cplusplus)
#include "mozilla/fallible.h"
#include "mozilla/mozalloc_abort.h"
#include "mozilla/TemplateLib.h"
#endif
#include "mozilla/Attributes.h"
#include "mozilla/Types.h"
#define MOZALLOC_HAVE_XMALLOC
#if defined(MOZ_ALWAYS_INLINE_EVEN_DEBUG)
# define MOZALLOC_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG
#elif defined(HAVE_FORCEINLINE)
# define MOZALLOC_INLINE __forceinline
#else
# define MOZALLOC_INLINE inline
#endif
/* Workaround build problem with Sun Studio 12 */
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
# undef MOZ_MUST_USE
# define MOZ_MUST_USE
# undef MOZ_ALLOCATOR
# define MOZ_ALLOCATOR
#endif
#if defined(__cplusplus)
extern "C" {
#endif /* ifdef __cplusplus */
/*
* We need to use malloc_impl and free_impl in this file when they are
* defined, because of how mozglue.dll is linked on Windows, where using
* malloc/free would end up using the symbols from the MSVCRT instead of
* ours.
*/
#ifndef free_impl
#define free_impl free
#define free_impl_
#endif
#ifndef malloc_impl
#define malloc_impl malloc
#define malloc_impl_
#endif
/*
* Each declaration below is analogous to a "standard" allocation
* function, except that the out-of-memory handling is made explicit.
* The |moz_x| versions will never return a NULL pointer; if memory
* is exhausted, they abort. The |moz_| versions may return NULL
* pointers if memory is exhausted: their return value must be checked.
*
* All these allocation functions are *guaranteed* to return a pointer
* to memory allocated in such a way that that memory can be freed by
* passing that pointer to |free()|.
*/
MFBT_API void* moz_xmalloc(size_t size)
MOZ_ALLOCATOR;
MFBT_API void* moz_xcalloc(size_t nmemb, size_t size)
MOZ_ALLOCATOR;
MFBT_API void* moz_xrealloc(void* ptr, size_t size)
MOZ_ALLOCATOR;
MFBT_API char* moz_xstrdup(const char* str)
MOZ_ALLOCATOR;
MFBT_API size_t moz_malloc_usable_size(void *ptr);
MFBT_API size_t moz_malloc_size_of(const void *ptr);
#if defined(HAVE_STRNDUP)
MFBT_API char* moz_xstrndup(const char* str, size_t strsize)
MOZ_ALLOCATOR;
#endif /* if defined(HAVE_STRNDUP) */
#if defined(HAVE_POSIX_MEMALIGN)
MFBT_API MOZ_MUST_USE
int moz_xposix_memalign(void **ptr, size_t alignment, size_t size);
MFBT_API MOZ_MUST_USE
int moz_posix_memalign(void **ptr, size_t alignment, size_t size);
#endif /* if defined(HAVE_POSIX_MEMALIGN) */
#if defined(HAVE_MEMALIGN)
MFBT_API void* moz_xmemalign(size_t boundary, size_t size)
MOZ_ALLOCATOR;
#endif /* if defined(HAVE_MEMALIGN) */
#if defined(HAVE_VALLOC)
MFBT_API void* moz_xvalloc(size_t size)
MOZ_ALLOCATOR;
#endif /* if defined(HAVE_VALLOC) */
#ifdef __cplusplus
} /* extern "C" */
#endif /* ifdef __cplusplus */
#ifdef __cplusplus
/*
* We implement the default operators new/delete as part of
* libmozalloc, replacing their definitions in libstdc++. The
* operator new* definitions in libmozalloc will never return a NULL
* pointer.
*
* Each operator new immediately below returns a pointer to memory
* that can be delete'd by any of
*
* (1) the matching infallible operator delete immediately below
* (2) the matching "fallible" operator delete further below
* (3) the matching system |operator delete(void*, std::nothrow)|
* (4) the matching system |operator delete(void*) throw(std::bad_alloc)|
*
* NB: these are declared |throw(std::bad_alloc)|, though they will never
* throw that exception. This declaration is consistent with the rule
* that |::operator new() throw(std::bad_alloc)| will never return NULL.
*/
/* NB: This is defined just to silence vacuous warnings about symbol
* visibility on OS X/gcc. These symbols are force-inline and not
* exported. */
#if defined(XP_MACOSX)
# define MOZALLOC_EXPORT_NEW MFBT_API
#else
# define MOZALLOC_EXPORT_NEW
#endif
#if defined(ANDROID)
/*
* It's important to always specify 'throw()' in GCC because it's used to tell
* GCC that 'new' may return null. That makes GCC null-check the result before
* potentially initializing the memory to zero.
* Also, the Android minimalistic headers don't include std::bad_alloc.
*/
#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw()
#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
#elif defined(_MSC_VER)
/*
* Suppress build warning spam (bug 578546).
*/
#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS
#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
#else
#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw()
#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS throw(std::bad_alloc)
#endif
#define MOZALLOC_THROW_BAD_ALLOC MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
MOZALLOC_EXPORT_NEW
#if defined(__GNUC__) && !defined(__clang__) && defined(__SANITIZE_ADDRESS__)
/* gcc's asan somehow doesn't like always_inline on this function. */
__attribute__((gnu_inline)) inline
#else
MOZALLOC_INLINE
#endif
void* operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC
{
return moz_xmalloc(size);
}
MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
void* operator new(size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
return malloc_impl(size);
}
MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
void* operator new[](size_t size) MOZALLOC_THROW_BAD_ALLOC
{
return moz_xmalloc(size);
}
MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
void* operator new[](size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
return malloc_impl(size);
}
MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
void operator delete(void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
return free_impl(ptr);
}
MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
void operator delete(void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
return free_impl(ptr);
}
MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
void operator delete[](void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
return free_impl(ptr);
}
MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
void operator delete[](void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
return free_impl(ptr);
}
/*
* We also add a new allocator variant: "fallible operator new."
* Unlike libmozalloc's implementations of the standard nofail
* allocators, this allocator is allowed to return NULL. It can be used
* as follows
*
* Foo* f = new (mozilla::fallible) Foo(...);
*
* operator delete(fallible) is defined for completeness only.
*
* Each operator new below returns a pointer to memory that can be
* delete'd by any of
*
* (1) the matching "fallible" operator delete below
* (2) the matching infallible operator delete above
* (3) the matching system |operator delete(void*, std::nothrow)|
* (4) the matching system |operator delete(void*) throw(std::bad_alloc)|
*/
MOZALLOC_INLINE
void* operator new(size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
return malloc_impl(size);
}
MOZALLOC_INLINE
void* operator new[](size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
return malloc_impl(size);
}
MOZALLOC_INLINE
void operator delete(void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
free_impl(ptr);
}
MOZALLOC_INLINE
void operator delete[](void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
{
free_impl(ptr);
}
/*
* This policy is identical to MallocAllocPolicy, except it uses
* moz_xmalloc/moz_xcalloc/moz_xrealloc instead of
* malloc/calloc/realloc.
*/
class InfallibleAllocPolicy
{
public:
template <typename T>
T* maybe_pod_malloc(size_t aNumElems)
{
return pod_malloc<T>(aNumElems);
}
template <typename T>
T* maybe_pod_calloc(size_t aNumElems)
{
return pod_calloc<T>(aNumElems);
}
template <typename T>
T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
{
return pod_realloc<T>(aPtr, aOldSize, aNewSize);
}
template <typename T>
T* pod_malloc(size_t aNumElems)
{
if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
reportAllocOverflow();
}
return static_cast<T*>(moz_xmalloc(aNumElems * sizeof(T)));
}
template <typename T>
T* pod_calloc(size_t aNumElems)
{
return static_cast<T*>(moz_xcalloc(aNumElems, sizeof(T)));
}
template <typename T>
T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
{
if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
reportAllocOverflow();
}
return static_cast<T*>(moz_xrealloc(aPtr, aNewSize * sizeof(T)));
}
void free_(void* aPtr)
{
free_impl(aPtr);
}
void reportAllocOverflow() const
{
mozalloc_abort("alloc overflow");
}
bool checkSimulatedOOM() const
{
return true;
}
};
#endif /* ifdef __cplusplus */
#ifdef malloc_impl_
#undef malloc_impl_
#undef malloc_impl
#endif
#ifdef free_impl_
#undef free_impl_
#undef free_impl
#endif
#endif /* ifndef mozilla_mozalloc_h */

View File

@@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_mozalloc_abort_h
#define mozilla_mozalloc_abort_h
#include "mozilla/Attributes.h"
#include "mozilla/Types.h"
/**
* Terminate this process in such a way that breakpad is triggered, if
* at all possible.
*
* Note: MOZ_NORETURN seems to break crash stacks on ARM, so we don't
* use that annotation there.
*/
MFBT_API
#if !defined(__arm__)
MOZ_NORETURN
#endif
void mozalloc_abort(const char* const msg);
#endif /* ifndef mozilla_mozalloc_abort_h */

View File

@@ -0,0 +1,31 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_mozalloc_oom_h
#define mozilla_mozalloc_oom_h
#include "mozalloc.h"
/**
* Called when memory is critically low. Returns iff it was able to
* remedy the critical memory situation; if not, it will abort().
*/
MFBT_API void mozalloc_handle_oom(size_t requestedSize);
/**
* Called by embedders (specifically Mozilla breakpad) which wants to be
* notified of an intentional abort, to annotate any crash report with
* the size of the allocation on which we aborted.
*/
typedef void (*mozalloc_oom_abort_handler)(size_t size);
MFBT_API void mozalloc_set_oom_abort_handler(mozalloc_oom_abort_handler handler);
/* TODO: functions to query system memory usage and register
* critical-memory handlers. */
#endif /* ifndef mozilla_mozalloc_oom_h */

View File

@@ -0,0 +1,298 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef DOUBLE_CONVERSION_UTILS_H_
#define DOUBLE_CONVERSION_UTILS_H_
#include <stdlib.h>
#include <string.h>
#include "mozilla/Assertions.h"
#ifndef ASSERT
#define ASSERT(condition) MOZ_ASSERT(condition)
#endif
#ifndef UNIMPLEMENTED
#define UNIMPLEMENTED() MOZ_CRASH()
#endif
#ifndef UNREACHABLE
#define UNREACHABLE() MOZ_CRASH()
#endif
// Double operations detection based on target architecture.
// Linux uses a 80bit wide floating point stack on x86. This induces double
// rounding, which in turn leads to wrong results.
// An easy way to test if the floating-point operations are correct is to
// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then
// the result is equal to 89255e-22.
// The best way to test this, is to create a division-function and to compare
// the output of the division with the expected result. (Inlining must be
// disabled.)
// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
#if defined(_M_X64) || defined(__x86_64__) || \
defined(__ARMEL__) || defined(__avr32__) || \
defined(__hppa__) || defined(__ia64__) || \
defined(__mips__) || \
defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
defined(__SH4__) || defined(__alpha__) || \
defined(_MIPS_ARCH_MIPS32R2) || \
defined(__AARCH64EL__) || defined(__aarch64__)
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
#if defined(_WIN32)
// Windows uses a 64bit wide floating point stack.
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
#else
#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
#endif // _WIN32
#else
#error Target architecture was not detected as supported by Double-Conversion.
#endif
#include <stdint.h>
// The following macro works on both 32 and 64-bit platforms.
// Usage: instead of writing 0x1234567890123456
// write UINT64_2PART_C(0x12345678,90123456);
#define UINT64_2PART_C(a, b) (((static_cast<uint64_t>(a) << 32) + 0x##b##u))
// The expression ARRAY_SIZE(a) is a compile-time constant of type
// size_t which represents the number of elements of the given
// array. You should only use ARRAY_SIZE on statically allocated
// arrays.
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
#endif
// A macro to disallow the evil copy constructor and operator= functions
// This should be used in the private: declarations for a class
#ifndef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
#endif
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName(); \
DISALLOW_COPY_AND_ASSIGN(TypeName)
#endif
namespace double_conversion {
static const int kCharSize = sizeof(char);
// Returns the maximum of the two parameters.
template <typename T>
static T Max(T a, T b) {
return a < b ? b : a;
}
// Returns the minimum of the two parameters.
template <typename T>
static T Min(T a, T b) {
return a < b ? a : b;
}
inline int StrLength(const char* string) {
size_t length = strlen(string);
ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
return static_cast<int>(length);
}
// This is a simplified version of V8's Vector class.
template <typename T>
class Vector {
public:
Vector() : start_(NULL), length_(0) {}
Vector(T* data, int len) : start_(data), length_(len) {
ASSERT(len == 0 || (len > 0 && data != NULL));
}
// Returns a vector using the same backing storage as this one,
// spanning from and including 'from', to but not including 'to'.
Vector<T> SubVector(int from, int to) {
ASSERT(to <= length_);
ASSERT(from < to);
ASSERT(0 <= from);
return Vector<T>(start() + from, to - from);
}
// Returns the length of the vector.
int length() const { return length_; }
// Returns whether or not the vector is empty.
bool is_empty() const { return length_ == 0; }
// Returns the pointer to the start of the data in the vector.
T* start() const { return start_; }
// Access individual vector elements - checks bounds in debug mode.
T& operator[](int index) const {
ASSERT(0 <= index && index < length_);
return start_[index];
}
T& first() { return start_[0]; }
T& last() { return start_[length_ - 1]; }
private:
T* start_;
int length_;
};
// Helper class for building result strings in a character buffer. The
// purpose of the class is to use safe operations that checks the
// buffer bounds on all operations in debug mode.
class StringBuilder {
public:
StringBuilder(char* buffer, int buffer_size)
: buffer_(buffer, buffer_size), position_(0) { }
~StringBuilder() { if (!is_finalized()) Finalize(); }
int size() const { return buffer_.length(); }
// Get the current position in the builder.
int position() const {
ASSERT(!is_finalized());
return position_;
}
// Reset the position.
void Reset() { position_ = 0; }
// Add a single character to the builder. It is not allowed to add
// 0-characters; use the Finalize() method to terminate the string
// instead.
void AddCharacter(char c) {
ASSERT(c != '\0');
ASSERT(!is_finalized() && position_ < buffer_.length());
buffer_[position_++] = c;
}
// Add an entire string to the builder. Uses strlen() internally to
// compute the length of the input string.
void AddString(const char* s) {
AddSubstring(s, StrLength(s));
}
// Add the first 'n' characters of the given string 's' to the
// builder. The input string must have enough characters.
void AddSubstring(const char* s, int n) {
ASSERT(!is_finalized() && position_ + n < buffer_.length());
ASSERT(static_cast<size_t>(n) <= strlen(s));
memmove(&buffer_[position_], s, n * kCharSize);
position_ += n;
}
// Add character padding to the builder. If count is non-positive,
// nothing is added to the builder.
void AddPadding(char c, int count) {
for (int i = 0; i < count; i++) {
AddCharacter(c);
}
}
// Finalize the string by 0-terminating it and returning the buffer.
char* Finalize() {
ASSERT(!is_finalized() && position_ < buffer_.length());
buffer_[position_] = '\0';
// Make sure nobody managed to add a 0-character to the
// buffer while building the string.
ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_));
position_ = -1;
ASSERT(is_finalized());
return buffer_.start();
}
private:
Vector<char> buffer_;
int position_;
bool is_finalized() const { return position_ < 0; }
DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
};
// The type-based aliasing rule allows the compiler to assume that pointers of
// different types (for some definition of different) never alias each other.
// Thus the following code does not work:
//
// float f = foo();
// int fbits = *(int*)(&f);
//
// The compiler 'knows' that the int pointer can't refer to f since the types
// don't match, so the compiler may cache f in a register, leaving random data
// in fbits. Using C++ style casts makes no difference, however a pointer to
// char data is assumed to alias any other pointer. This is the 'memcpy
// exception'.
//
// Bit_cast uses the memcpy exception to move the bits from a variable of one
// type of a variable of another type. Of course the end result is likely to
// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005)
// will completely optimize BitCast away.
//
// There is an additional use for BitCast.
// Recent gccs will warn when they see casts that may result in breakage due to
// the type-based aliasing rule. If you have checked that there is no breakage
// you can use BitCast to cast one pointer type to another. This confuses gcc
// enough that it can no longer see that you have cast one pointer type to
// another thus avoiding the warning.
template <class Dest, class Source>
inline Dest BitCast(const Source& source) {
static_assert(sizeof(Dest) == sizeof(Source),
"BitCast's source and destination types must be the same size");
Dest dest;
memmove(&dest, &source, sizeof(dest));
return dest;
}
template <class Dest, class Source>
inline Dest BitCast(Source* source) {
return BitCast<Dest>(reinterpret_cast<uintptr_t>(source));
}
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_UTILS_H_