#ifndef _H_WALKERS
#define _H_WALKERS
#include <Security/utilities.h>
#include <Security/cssmalloc.h>
#include <Security/memutils.h>
#include <set>
#ifdef _CPP_WALKERS
# pragma export on
#endif
namespace Security
{
namespace DataWalkers
{
class SizeWalker : public LowLevelMemoryUtilities::Writer::Counter {
public:
template <class T>
void operator () (T *, size_t size = sizeof(T))
{ LowLevelMemoryUtilities::Writer::Counter::insert(size); }
void reserve(size_t space)
{ LowLevelMemoryUtilities::Writer::Counter::insert(space); }
static const bool needsRelinking = false;
static const bool needsSize = true;
};
class CopyWalker : public LowLevelMemoryUtilities::Writer {
public:
CopyWalker() { }
CopyWalker(void *base) : LowLevelMemoryUtilities::Writer(base) { }
template <class T>
void operator () (T * &addr, size_t size = sizeof(T))
{
if (addr)
addr = reinterpret_cast<T *>(LowLevelMemoryUtilities::Writer::operator () (addr, size));
}
static const bool needsRelinking = true;
static const bool needsSize = true;
};
class ReconstituteWalker {
public:
ReconstituteWalker(off_t offset) : mOffset(offset) { }
ReconstituteWalker(void *ptr, void *base)
: mOffset(LowLevelMemoryUtilities::difference(ptr, base)) { }
template <class T>
void operator () (T * &addr, size_t = 0)
{
if (addr)
addr = LowLevelMemoryUtilities::increment<T>(addr, mOffset);
}
static const bool needsRelinking = true;
static const bool needsSize = false;
private:
off_t mOffset;
};
class ChunkCopyWalker {
public:
ChunkCopyWalker(CssmAllocator &alloc = CssmAllocator::standard()) : allocator(alloc) { }
CssmAllocator &allocator;
template <class T>
void operator () (T * &addr, size_t size = sizeof(T))
{
#if BUG_GCC
T *copy = reinterpret_cast<T *>(allocator.malloc(size));
#else
T *copy = allocator.malloc<T>(size);
#endif
memcpy(copy, addr, size);
addr = copy;
}
static const bool needsRelinking = true;
static const bool needsSize = true;
};
class ChunkFreeWalker {
public:
ChunkFreeWalker(CssmAllocator &alloc = CssmAllocator::standard()) : allocator(alloc) { }
CssmAllocator &allocator;
template <class T>
void operator () (T *addr, size_t = sizeof(T))
{
freeSet.insert(addr);
}
void free();
~ChunkFreeWalker() { free(); }
static const bool needsRelinking = false;
static const bool needsSize = false;
private:
std::set<void *> freeSet;
};
class VirtualWalker {
public:
VirtualWalker(bool nrl = false) : needsRelinking(nrl) { }
virtual ~VirtualWalker();
virtual void operator () (void * &addr, size_t size) = 0;
const bool needsRelinking;
};
template <class Walker>
class VirtualWalkerFor : public VirtualWalker {
public:
VirtualWalkerFor(Walker &w, bool nrl = false) : VirtualWalker(nrl), walker(w) { }
void operator () (void * &addr, size_t size)
{ walker(addr, size); }
Walker &walker;
};
template <class T>
size_t size(T obj)
{
SizeWalker w;
walk(w, obj);
return w;
}
template <class T>
T *copy(const T *obj, void *addr)
{
if (obj == NULL)
return NULL;
CopyWalker w(addr);
walk(w, obj);
return reinterpret_cast<T *>(addr);
}
template <class T>
T *copy(const T *obj, CssmAllocator &alloc = CssmAllocator::standard())
{
return obj ? copy(obj, alloc, size(obj)) : NULL;
}
template <class T>
T *copy(const T *obj, CssmAllocator &alloc, size_t size)
{
if (obj == NULL)
return NULL;
return copy(obj, alloc.malloc(size));
}
template <class T>
void copy(const T *obj, CssmAllocator &alloc, CssmData &data)
{
if (obj == NULL) {
data.Length = 0;
return;
}
if (data.data() == NULL) {
size_t length = size(obj);
data = CssmData(alloc.malloc(length), length);
} else
assert(size(obj) <= data.length());
copy(obj, data.data());
}
template <class T>
void relocate(T *obj, T *base)
{
if (obj) {
ReconstituteWalker w(LowLevelMemoryUtilities::difference(obj, base));
walk(w, base);
}
}
template <class T>
T *chunkCopy(const T *obj, CssmAllocator &alloc = CssmAllocator::standard())
{
if (obj) {
ChunkCopyWalker w(alloc);
return walk(w, obj);
} else
return NULL;
}
template <class T>
void chunkFree(const T *obj, CssmAllocator &alloc = CssmAllocator::standard())
{
if (obj) {
ChunkFreeWalker w(alloc);
walk(w, obj);
}
}
template <class T>
class Copier {
public:
Copier(const T *obj, CssmAllocator &alloc = CssmAllocator::standard()) : allocator(alloc)
{
if (obj == NULL) {
mValue = NULL;
mLength = 0;
} else {
mLength = size(obj);
#if BUG_GCC
mValue = reinterpret_cast<T *>(alloc.malloc(mLength));
#else
mValue = alloc.malloc<T>(mLength);
#endif
mValue = copy(obj, mValue);
}
}
Copier(const T *obj, uint32 count, CssmAllocator &alloc = CssmAllocator::standard())
: allocator(alloc)
{
if (obj == NULL) {
mValue = NULL;
mLength = 0;
} else {
SizeWalker sizer;
sizer.reserve(sizeof(T) * count); for (uint32 n = 0; n < count; n++)
walk(sizer, obj[n]); mLength = sizer;
#if BUG_GCC
mValue = reinterpret_cast<T *>(alloc.malloc(mLength));
#else
mValue = alloc.malloc<T>(mLength);
#endif
CopyWalker copier(LowLevelMemoryUtilities::increment(mValue, sizeof(T) * count));
for (uint32 n = 0; n < count; n++) {
mValue[n] = obj[n];
walk(copier, mValue[n]);
}
}
}
CssmAllocator &allocator;
~Copier() { allocator.free(mValue); }
operator T *() const { return mValue; }
size_t length() const { return mLength; }
T *keep() { T *result = mValue; mValue = NULL; return result; }
private:
T *mValue;
size_t mLength;
};
template <class Action, class T>
T *walk(Action &operate, const T * &obj)
{ return walk(operate, const_cast<T * &>(obj)); }
template <class Action, class Type>
Type *walk(Action &operate, Type * &obj)
{
operate(obj);
return obj;
}
}
}
#ifdef _CPP_WALKERS
# pragma export off
#endif
#endif //_H_WALKERS