Files
mlpack/fastlib2/fastlib/base/ccmem.h
T
2008-04-07 23:07:18 +00:00

470 lines
14 KiB
C++

// Copyright 2007 Georgia Institute of Technology. All rights reserved.
/**
* @file ccmem.h
*
* Low-level (read: scary) memory management routines used by core
* data structures.
*
* @see namespace mem
*/
#ifndef BASE_CCMEM_H
#define BASE_CCMEM_H
#include "common.h"
#include "debug.h"
#include "cc.h"
#include <new>
#define MEM__DEBUG_MEMORY(ptr) \
DEBUG_ASSERT_MSG((ptr) != NULL, "out of memory")
namespace mem__private {
const size_t BIG_BAD_BUF_SIZE = 64;
extern const int32 BIG_BAD_BUF[];
void PoisonBytes(char *array_cp, size_t bytes);
const size_t SWAP_BUF_SIZE = 64;
void SwapBytes(char *a_cp, char *b_cp, size_t bytes);
};
/**
* Wrappers and tools for low-level memory management, including:
*
* @li debuggable memory allocation wrappers
* @li poisoning, zeroing, copying, and swapping of memory
* @li construction and destruction of allocated object arrays
* @li absolute pointer arithmetic functions
*
* You likely do not need to care about these functions: use new and
* delete (like normal) for allocation of single objects and FASTlib's
* ArrayList (or Vector or Matrix) for arrays.
*
* If you really need to manage your own memory, use these instead of
* malloc and free, because these will perform "memory poising" in
* debug mode.
*/
namespace mem {
/** Fills memory with BIG_BAD_NUMBER, measured in bytes. */
template<typename T>
T *PoisonBytes(T *array, size_t bytes) {
char *array_cp = reinterpret_cast<char *>(array);
mem__private::PoisonBytes(array_cp, bytes);
return array;
}
/** Fills memory with BIG_BAD_NUMBER, measured in elements. */
template<typename T>
inline T *Poison(T *array, size_t elems) {
return PoisonBytes(array, elems * sizeof(T));
}
/** Fills an element with BIG_BAD_NUMBER. */
template<typename T>
inline T *Poison(T *ptr) {
if (sizeof(T) <= mem__private::BIG_BAD_BUF_SIZE) {
return reinterpret_cast<T *>(
::memcpy(ptr, mem__private::BIG_BAD_BUF, sizeof(T)));
} else {
return PoisonBytes(ptr, sizeof(T));
}
}
/** Fills memory with BIG_BAD_NUMBER, measured in bytes. */
template<typename T>
inline T *DebugPoisonBytes(T *array, size_t bytes) {
DEBUG_ONLY(PoisonBytes(array, bytes));
return array;
}
/** Fills memory with BIG_BAD_NUMBER, measured in elements. */
template<typename T>
inline T *DebugPoison(T *array, size_t elems) {
DEBUG_ONLY(Poison(array, elems));
return array;
}
/** Fills an element with BIG_BAD_NUMBER. */
template<typename T>
inline T *DebugPoison(T *ptr) {
DEBUG_ONLY(Poison(ptr));
return ptr;
}
/** Allocates a (debug) poisoned array, measured in bytes. */
template<typename T>
inline T *AllocBytes(size_t bytes) {
#ifdef SCALE_NORMAL
// sanity check for small-scale problems
DEBUG_BOUNDS(bytes, BIG_BAD_NUMBER);
#endif
T *array = reinterpret_cast<T *>(::malloc(bytes));
MEM__DEBUG_MEMORY(array);
return DebugPoisonBytes(array, bytes);
}
/** Allocates a (debug) poisoned array, measured in elements. */
template<typename T>
inline T *Alloc(size_t elems) {
#ifdef SCALE_NORMAL
// sanity check for small-scale problems
DEBUG_BOUNDS(elems, BIG_BAD_NUMBER);
#endif
return AllocBytes<T>(elems * sizeof(T));
}
/** Allocates a (debug) poisoned element. */
template<typename T>
inline T *Alloc() {
T *array = reinterpret_cast<T *>(::malloc(sizeof(T)));
MEM__DEBUG_MEMORY(array);
return DebugPoisonBytes(array);
}
/** Bit-zeros memory, measured in bytes. */
template<typename T>
inline T *ZeroBytes(T *array, size_t bytes) {
return reinterpret_cast<T *>(::memset(array, 0, bytes));
}
/** Bit-zeros memory, measured in elements. */
template<typename T>
inline T *Zero(T *array, size_t elems = 1) {
return ZeroBytes(array, elems * sizeof(T));
}
/** Allocates a bit-zerod array, measured in bytes. */
template<typename T>
inline T *AllocZeroBytes(size_t bytes) {
T *array = reinterpret_cast<T *>(::calloc(bytes, 1));
MEM__DEBUG_MEMORY(array);
return array;
}
/** Allocates a bit-zerod array, measured in elements. */
template<typename T>
inline T *AllocZero(size_t elems = 1) {
T *array = reinterpret_cast<T *>(::calloc(elems, sizeof(T)));
MEM__DEBUG_MEMORY(array);
return array;
}
/** Bit-copies from src to dest, measured in bytes. */
template<typename T, typename U>
inline T *CopyBytes(T *dest, const U *src, size_t bytes) {
return reinterpret_cast<T *>(::memcpy(dest, src, bytes));
}
/** Bit-copies from src to dest, measured in elements. */
template<typename V, typename T, typename U>
inline T *Copy(T *dest, const U *src, size_t elems = 1) {
return CopyBytes(dest, src, elems * sizeof(V));
}
template<typename T>
inline T *Copy(T *dest, const T *src, size_t elems = 1) {
return Copy<T, T, T>(dest, src, elems);
}
/** Allocates an array bit-copied from src, measured in bytes. */
template<typename T, typename U>
inline T *AllocCopyBytes(const U *src, size_t bytes) {
T *array = reinterpret_cast<T *>(::malloc(bytes));
MEM__DEBUG_MEMORY(array);
return CopyBytes(array, src, bytes);
}
/** Allocates an array bit-copied from src, measured in elements. */
template<typename T, typename U>
inline T *AllocCopy(const U *src, size_t elems = 1) {
return AllocCopyBytes<T>(src, elems * sizeof(T));
}
template<typename T>
inline T *AllocCopy(const T *src, size_t elems = 1) {
return AllocCopy<T, T>(src, elems);
}
/**
* Resizes allocated memory, mesured in bytes.
*
* Added bytes (if any) are not poisoned or zeroed. The input
* pointer is invalidated and should be replaced by the return in
* all subsequent uses.
*/
template<typename T>
inline T *ReallocBytes(T *array, size_t bytes) {
array = reinterpret_cast<T *>(::realloc(array, bytes));
MEM__DEBUG_MEMORY(array);
return array;
}
/**
* Resizes allocated memory, measured in elements.
*
* Added elements (if any) are not poisoned or zeroed. The input
* pointer is invalidated and should be replaced by the return in
* all subsequent uses.
*/
template<typename T>
inline T *Realloc(T *array, size_t elems) {
return ReallocBytes<T>(array, elems * sizeof(T));
}
/** Frees memory allocated by mem::Alloc and its derivatives. */
template<typename T>
inline void Free(T* ptr) {
::free(ptr);
}
/**
* Bit-swaps two arrays, measured in bytes.
*
* This code works best for arrays starting at multiple-of-eight
* (and higher powers of two) byte locations. Freshly allocated
* memory and locations within arrays of longs, doubles, and most
* structs will have this property. Suboptimal performance arises
* when swapping between offset locations in arrays of small types,
* such as portions of strings.
*/
template<typename T, typename U>
void SwapBytes(T *a, U *b, size_t bytes) {
char *a_cp = reinterpret_cast<char *>(a);
char *b_cp = reinterpret_cast<char *>(b);
mem__private::SwapBytes(a_cp, b_cp, bytes);
}
/**
* Bit-swaps two arrays, measured in elements.
*
* This code is optimized for swapping arrays starting at
* multiple-of-eight byte locations. Freshly allocated memory and
* all locations within arrays of longs, doubles, and most structs
* will have this property. Suboptimal performance will arise only
* when swapping between offset locations in arrays of small types,
* such as portions of strings.
*/
template<typename V, typename T, typename U>
inline void Swap(T *a, U *b, size_t elems) {
SwapBytes(a, b, elems * sizeof(V));
}
template<typename T>
inline void Swap(T *a, T *b, size_t elems) {
Swap<T, T, T>(a, b, elems);
}
template<typename V, typename T, typename U>
inline void Swap(T *a, U *b) {
if (sizeof(V) <= mem__private::SWAP_BUF_SIZE * 2) {
char buf[sizeof(V)];
::memcpy(buf, a, sizeof(V));
::memcpy(a, b, sizeof(V));
::memcpy(b, buf, sizeof(V));
} else {
SwapBytes(a, b, sizeof(V));
}
}
template<typename T>
inline void Swap(T *a, T *b) {
Swap<T, T, T>(a, b);
}
/** Bit-moves bytes from src to dest, permitting overlap. */
template<typename T, typename U>
inline T *MoveBytes(T *dest, const U *src, size_t bytes) {
return reinterpret_cast<T *>(::memmove(dest, src, bytes));
}
/** Bit-moves elements from src to dest, permitting overlap. */
template<typename V, typename T, typename U>
inline T *Move(T *dest, const U *src, size_t elems = 1) {
return MoveBytes(dest, src, elems * sizeof(V));
}
template<typename T>
inline T *Move(T *dest, const T *src, size_t elems = 1) {
return Move<T, T, T>(dest, src, elems);
}
/** Default Constructs An element. */
template<typename T>
inline T *Construct(T *ptr) {
new(ptr) T;
return ptr;
}
/** Default constructs each element in an array. */
template<typename T>
inline T *Construct(T *array, size_t elems) {
new(array) T[elems];
return array;
}
/** Destructs an element. */
template<typename T>
inline T *Destruct(T *ptr) {
ptr->~T();
return DebugPoison(ptr);
}
/** Destructs each element in an array. */
template<typename T>
inline T *Destruct(T *array, size_t elems) {
for (size_t i = 0; i < elems; ++i) {
array[i].~T();
}
return DebugPoison(array, elems);
}
/** Element-wise copy constructs one element given another. */
template<typename T, typename U>
inline T *CopyConstruct(T *dest, const U *src) {
new(dest) T(*src);
return dest;
}
/** Element-wise copy constructs one array given another. */
template<typename T, typename U>
inline T *CopyConstruct(T *dest, const U *src, size_t elems) {
for (size_t i = 0; i < elems; ++i) {
new(dest + i) T(src[i]);
}
return dest;
}
/** Simple constructors and destcutors for primatives types. */
#define BASE_CCMEM__SIMPLE_CONSTRUCTORS(T, TF) \
template<> \
inline T *Construct< T >(T *ptr) { \
return DebugPoison(ptr); \
} \
template<> \
inline T *Construct< T >(T *array, size_t elems) { \
return DebugPoison(array, elems); \
} \
template<> \
inline T *Destruct< T >(T *ptr) { \
return DebugPoison(ptr); \
} \
template<> \
inline T *Destruct< T >(T *array, size_t elems) { \
return DebugPoison(array, elems); \
} \
template<> \
inline T *CopyConstruct< T >(T *dest, const T *src) { \
return Copy(dest, src, 1); \
} \
template<> \
inline T *CopyConstruct< T >(T *dest, const T *src, size_t elems) { \
return Copy(dest, src, elems); \
}
FOR_ALL_PRIMITIVES_DO(BASE_CCMEM__SIMPLE_CONSTRUCTORS)
/** No-op constructs an array of pointers. */
template<typename T>
inline T **Construct(T **array, size_t elems = 1) {
return DebugPoison(array, elems);
}
/** No-op destructs an array of pointers. */
template<typename T>
inline T **Destruct(T **array, size_t elems = 1) {
return DebugPoison(array, elems);
}
/** Bit-copy copy constructs an array of pointers. */
template<typename T>
inline T **CopyConstruct(T **dest, const T **src, size_t elems = 1) {
return Copy(dest, src, elems);
}
#undef BASE_CCMEM__SIMPLE_CONSTRUCTORS
/** Constructs each element in an array with an initial value. */
template<typename T, typename U>
inline T *RepeatConstruct(T *array, const U &init, size_t elems) {
for (size_t i = 0; i < elems; ++i) {
new(array + i) T(init);
}
return array;
}
/** Allocates and default constructs an array. */
template<typename T>
inline T *AllocConstruct(size_t elems = 1) {
return Construct(Alloc<T>(elems), elems);
}
/** Allocates and element-wise copy constructs an array. */
template<typename T, typename U>
inline T *AllocCopyConstruct(const U *src, size_t elems = 1) {
return CopyConstruct(Alloc<T>(elems), src, elems);
}
template<typename T>
inline T *AllocCopyConstruct(const T *src, size_t elems = 1) {
return AllocCopyConstruct<T, T>(src, elems);
}
/** Allocates and copy constructs an array. */
template<typename T, typename U>
inline T *AllocRepeatConstruct(const U &init, size_t elems) {
return RepeatConstruct(Alloc<T>(elems), init, elems);
}
template<typename T>
inline T *AllocRepeatConstruct(const T &init, size_t elems) {
return AllocRepeatConstruct<T, T>(init, elems);
}
/** Destructs and frees an array. */
template<typename T>
inline void FreeDestruct(T *array, size_t elems = 1) {
Free(Destruct(array, elems));
}
/** Offsets a pointer by a given number of bytes. */
template<typename T>
inline T *PtrAddBytes(T *ptr, ptrdiff_t bytes) {
return reinterpret_cast<T *>(
reinterpret_cast<char *>(ptr) + bytes);
}
/** Offsets a const pointer by a given number of bytes. */
template<typename T>
inline const T *PtrAddBytes(const T *ptr, ptrdiff_t bytes) {
return reinterpret_cast<const T *>(
reinterpret_cast<const char *>(ptr) + bytes);
}
/** Finds the byte difference of two pointers, i.e. lhs - rhs. */
template<typename T, typename U>
inline ptrdiff_t PtrDiffBytes(const T *lhs, const U *rhs) {
return reinterpret_cast<const char *>(lhs)
- reinterpret_cast<const char *>(rhs);
}
/** Converts a pointer to its integral absolute address. */
template<typename T>
inline ptrdiff_t PtrAbsAddr(const T *ptr) {
return reinterpret_cast<ptrdiff_t>(ptr);
}
/** Determines if two pointers are the same, i.e. lhs == rhs. */
template<typename T, typename U>
inline bool PtrsEqual(const T *lhs, const U *rhs) {
return reinterpret_cast<size_t>(lhs)
== reinterpret_cast<size_t>(rhs);
}
////////// Deprecated //////////////////////////////////////////////
/** Renamed ZeroBytes */
template<typename T>
T *BitZeroBytes(T *array, size_t bytes) {
return ZeroBytes(array, bytes);
}
/** Renamed Zero */
template<typename T>
T *BitZero(T *array, size_t elems = 1) {
return Zero(array, elems);
}
/** Renamed CopyBytes */
template<typename T, typename U>
T *BitCopyBytes(T *dest, const U *src, size_t bytes) {
return CopyBytes(dest, src, bytes);
}
/** Renamed Copy */
template<typename T>
T *BitCopy(T *dest, const T *src, size_t elems = 1) {
return Copy(dest, src, elems);
}
/** Renamed Swap */
template<typename T>
void BitSwap(T *a, T *b, size_t elems = 1) {
Swap(a, b, elems);
}
};
#undef MEM__DEGUG_MEMORY
#endif /* BASE_CCMEM_H */