/* 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 Utils_h #define Utils_h #include #include #include #include #include "mozilla/Assertions.h" /** * On architectures that are little endian and that support unaligned reads, * we can use direct type, but on others, we want to have a special class * to handle conversion and alignment issues. */ #if defined(__i386__) || defined(__x86_64__) typedef uint16_t le_uint16; typedef uint32_t le_uint32; #else /** * Template that allows to find an unsigned int type from a (computed) bit size */ template struct UInt { }; template <> struct UInt<16> { typedef uint16_t Type; }; template <> struct UInt<32> { typedef uint32_t Type; }; /** * Template to read 2 n-bit sized words as a 2*n-bit sized word, doing * conversion from little endian and avoiding alignment issues. */ template class le_to_cpu { public: operator typename UInt<16 * sizeof(T)>::Type() const { return (b << (sizeof(T) * 8)) | a; } private: T a, b; }; /** * Type definitions */ typedef le_to_cpu le_uint16; typedef le_to_cpu le_uint32; #endif /** * AutoClean is a helper to create RAII wrappers * The Traits class is expected to look like the following: * 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 None(); * // Cleans up resources corresponding to the wrapped value * const static void clean(type); * } */ template class AutoClean { typedef typename Traits::type T; public: AutoClean(): value(Traits::None()) { } AutoClean(const T& value): value(value) { } ~AutoClean() { if (value != Traits::None()) Traits::clean(value); } operator const T&() const { return value; } const T& operator->() const { return value; } const T& get() const { return value; } T forget() { T _value = value; value = Traits::None(); return _value; } bool operator ==(T other) const { return value == other; } AutoClean& operator =(T other) { if (value != Traits::None()) Traits::clean(value); value = other; return *this; } private: T value; }; /** * AUTOCLEAN_TEMPLATE defines a templated class derived from AutoClean * This allows to implement templates such as AutoFreePtr. */ #define AUTOCLEAN_TEMPLATE(name, Traits) \ template \ struct name: public AutoClean > \ { \ using AutoClean >::operator =; \ name(): AutoClean >() { } \ name(typename Traits::type ptr): AutoClean >(ptr) { } \ } /** * AutoCloseFD is a RAII wrapper for POSIX file descriptors */ struct AutoCloseFDTraits { typedef int type; static int None() { return -1; } static void clean(int fd) { close(fd); } }; typedef AutoClean AutoCloseFD; /** * AutoFreePtr is a RAII wrapper for pointers that need to be free()d. * * struct S { ... }; * AutoFreePtr foo = malloc(sizeof(S)); * AutoFreePtr bar = strdup(str); */ template struct AutoFreePtrTraits { typedef T *type; static T *None() { return NULL; } static void clean(T *ptr) { free(ptr); } }; AUTOCLEAN_TEMPLATE(AutoFreePtr, AutoFreePtrTraits); /** * AutoDeletePtr is a RAII wrapper for pointers that need to be deleted. * * struct S { ... }; * AutoDeletePtr foo = new S(); */ template struct AutoDeletePtrTraits: public AutoFreePtrTraits { static void clean(T *ptr) { delete ptr; } }; AUTOCLEAN_TEMPLATE(AutoDeletePtr, AutoDeletePtrTraits); /** * AutoDeleteArray is a RAII wrapper for pointers that need to be delete[]ed. * * struct S { ... }; * AutoDeleteArray foo = new S[42]; */ template struct AutoDeleteArrayTraits: public AutoFreePtrTraits { static void clean(T *ptr) { delete [] ptr; } }; AUTOCLEAN_TEMPLATE(AutoDeleteArray, AutoDeleteArrayTraits); /** * MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as * a simple void * or unsigned char *. * * It is defined as a derivative of a template that allows to use a * different unmapping strategy. */ template class GenericMappedPtr { public: GenericMappedPtr(void *buf, size_t length): buf(buf), length(length) { } GenericMappedPtr(): buf(MAP_FAILED), length(0) { } void Assign(void *b, size_t len) { if (buf != MAP_FAILED) static_cast(this)->munmap(buf, length); buf = b; length = len; } ~GenericMappedPtr() { if (buf != MAP_FAILED) static_cast(this)->munmap(buf, length); } operator void *() const { return buf; } operator unsigned char *() const { return reinterpret_cast(buf); } bool operator ==(void *ptr) const { return buf == ptr; } bool operator ==(unsigned char *ptr) const { return buf == ptr; } void *operator +(off_t offset) const { return reinterpret_cast(buf) + offset; } /** * Returns whether the given address is within the mapped range */ bool Contains(void *ptr) const { return (ptr >= buf) && (ptr < reinterpret_cast(buf) + length); } /** * Returns the length of the mapped range */ size_t GetLength() const { return length; } private: void *buf; size_t length; }; struct MappedPtr: public GenericMappedPtr { MappedPtr(void *buf, size_t length) : GenericMappedPtr(buf, length) { } MappedPtr(): GenericMappedPtr() { } void munmap(void *buf, size_t length) { ::munmap(buf, length); } }; /** * UnsizedArray is a way to access raw arrays of data in memory. * * struct S { ... }; * UnsizedArray a(buf); * UnsizedArray b; b.Init(buf); * * This is roughly equivalent to * const S *a = reinterpret_cast(buf); * const S *b = NULL; b = reinterpret_cast(buf); * * An UnsizedArray has no known length, and it's up to the caller to make * sure the accessed memory is mapped and makes sense. */ template class UnsizedArray { public: typedef size_t idx_t; /** * Constructors and Initializers */ UnsizedArray(): contents(NULL) { } UnsizedArray(const void *buf): contents(reinterpret_cast(buf)) { } void Init(const void *buf) { MOZ_ASSERT(contents == NULL); contents = reinterpret_cast(buf); } /** * Returns the nth element of the array */ const T &operator[](const idx_t index) const { MOZ_ASSERT(contents); return contents[index]; } /** * Returns whether the array points somewhere */ operator bool() const { return contents != NULL; } private: const T *contents; }; /** * Array, like UnsizedArray, is a way to access raw arrays of data in memory. * Unlike UnsizedArray, it has a known length, and is enumerable with an * iterator. * * struct S { ... }; * Array a(buf, len); * UnsizedArray b; b.Init(buf, len); * * In the above examples, len is the number of elements in the array. It is * also possible to initialize an Array with the buffer size: * * Array c; c.InitSize(buf, size); * * It is also possible to initialize an Array in two steps, only providing * one data at a time: * * Array d; * d.Init(buf); * d.Init(len); // or d.InitSize(size); * */ template class Array: public UnsizedArray { public: typedef typename UnsizedArray::idx_t idx_t; /** * Constructors and Initializers */ Array(): UnsizedArray(), length(0) { } Array(const void *buf, const idx_t length) : UnsizedArray(buf), length(length) { } void Init(const void *buf) { UnsizedArray::Init(buf); } void Init(const idx_t len) { MOZ_ASSERT(length == 0); length = len; } void InitSize(const idx_t size) { Init(size / sizeof(T)); } void Init(const void *buf, const idx_t len) { UnsizedArray::Init(buf); Init(len); } void InitSize(const void *buf, const idx_t size) { UnsizedArray::Init(buf); InitSize(size); } /** * Returns the nth element of the array */ const T &operator[](const idx_t index) const { MOZ_ASSERT(index < length); MOZ_ASSERT(operator bool()); return UnsizedArray::operator[](index); } /** * Returns the number of elements in the array */ idx_t numElements() const { return length; } /** * Returns whether the array points somewhere and has at least one element. */ operator bool() const { return (length > 0) && UnsizedArray::operator bool(); } /** * Iterator for an Array. Use is similar to that of STL const_iterators: * * struct S { ... }; * Array a(buf, len); * for (Array::iterator it = a.begin(); it < a.end(); ++it) { * // Do something with *it. * } */ class iterator { public: iterator(): item(NULL) { } const T &operator *() const { return *item; } const T *operator ->() const { return item; } const T &operator ++() { return *(++item); } bool operator<(const iterator &other) const { return item < other.item; } protected: friend class Array; iterator(const T &item): item(&item) { } private: const T *item; }; /** * Returns an iterator pointing at the beginning of the Array */ iterator begin() const { if (length) return iterator(UnsizedArray::operator[](0)); return iterator(); } /** * Returns an iterator pointing past the end of the Array */ iterator end() const { if (length) return iterator(UnsizedArray::operator[](length)); return iterator(); } private: idx_t length; }; /** * Transforms a pointer-to-function to a pointer-to-object pointing at the * same address. */ template void *FunctionPtr(T func) { union { void *ptr; T func; } f; f.func = func; return f.ptr; } #endif /* Utils_h */