Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Static Region Allocator...

5 views
Skip to first unread message

Chris Thomasson

unread,
Jun 17, 2008, 6:33:08 PM6/17/08
to
This region allocator is not dynamic and can be fed with a buffer residing
on the stack of the calling thread. Therefore, you can use this in an
environment which does not have a heap; its basically analogous to `alloca'.
However, it does not align each buffer on a boundary sufficient for _any_
type. Instead, it dynamically calculates the types alignment requirements
and mutates the offset accordingly. This makes it more efficient wrt
conserving space. For instance, it does not need to align a char pointer on
a max-boundary. Here is the code (pre-alpha sketch) which should compile
fine:
________________________________________________________________________
#include <cstdio>
#include <cstddef>
#include <cassert>
#include <new>


#if ! defined(NDEBUG)
# include <typeinfo>
# define DBG_PRINTF(mp_exp) std::printf mp_exp
#else
# define DBG_PRINTF(mp_exp)
#endif


#define ALIGN_POW2(mp_this, mp_type) ((mp_type)( \
(((std::ptrdiff_t const)(mp_this)) + 1) & (-2) \
))


#define ALIGN(mp_this, mp_type, mp_align) ((mp_type)( \
(((std::ptrdiff_t const)(mp_this)) + \
ALIGN_POW2(mp_align, std::ptrdiff_t const) - 1) \
& (-ALIGN_POW2(mp_align, std::ptrdiff_t const)) \
))


class stack_region_allocator {
unsigned char* const m_buf;
std::size_t const m_size;
std::size_t m_offset;
unsigned m_count;


public:
stack_region_allocator(
unsigned char* const buf,
std::size_t const size
) throw(std::bad_alloc)
: m_buf(buf),
m_size(size),
m_offset(0),
m_count(0) {
if (! m_buf || ! m_size) {
assert(m_buf);
assert(m_size);
throw std::bad_alloc();
}
}

~stack_region_allocator() throw() {
assert(! m_offset);
assert(! m_count);
}


public:
template<typename T>
T* allocate(
std::size_t count = 1
) throw(std::bad_alloc) {

struct offset_calc {
char pad;
T object;
};

if (! count) {
count = 1;
}

DBG_PRINTF(("typename: %s\n", typeid(T).name()));
DBG_PRINTF(("object count: %lu\n",
(unsigned long)count));

DBG_PRINTF(("object size: %lu\n",
(unsigned long)sizeof(T)));

std::size_t const alignment = offsetof(offset_calc, object);
DBG_PRINTF(("object alignment: %lu\n",
(unsigned long)alignment));

std::size_t const osize = count * sizeof(T);
DBG_PRINTF(("allocation size: %lu\n",
(unsigned long)osize));

unsigned char* const origin = m_buf + m_offset;
DBG_PRINTF(("origin buffer: %p\n", (void*)origin));

unsigned char* const align = (alignment != 1) ?
ALIGN(origin, unsigned char*, alignment) : origin;
DBG_PRINTF(("align buffer: %p\n", (void*)align));

std::ptrdiff_t const diff = align - origin;
DBG_PRINTF(("difference size: %d\n", diff));

std::size_t const offset = m_offset + diff;
DBG_PRINTF(("offset pre-size: %lu\n",
(unsigned long)offset));

if (offset + osize > m_size) {
throw std::bad_alloc();
}

m_offset = offset + osize;
DBG_PRINTF(("offset post-size: %lu\n\
--------------------------------------\n",
(unsigned long)(offset + osize)));

++m_count;

return reinterpret_cast<T*>(align);
}

void deallocate(void*) throw() {
if (! (--m_count)) {
m_offset = 0;
}
}

void reset() throw() {
m_count = 0;
m_offset = 0;
}
};


struct foo {
char c[5];
short s[2];
int i[3];
double d[3];
long double ld[2];
};


int main() {
{
unsigned char buf[1024 * 8] = { '\0' };
stack_region_allocator region(buf, sizeof(buf));
long double* ld1 = region.allocate<long double>();
char* c = region.allocate<char>(125);
long double* ld2 = region.allocate<long double>(4);
double* d = region.allocate<double>(2);
short* s = region.allocate<short>(7);
float* f = region.allocate<float>(5);
foo* _fo = region.allocate<foo>(0);
foo* _foa = region.allocate<foo>(12);
char* c2 = region.allocate<char>(13);
char* c3 = region.allocate<char>(17);
short* s1 = region.allocate<short>(3);
foo* _foa1 = region.allocate<foo>(3);
region.reset();
}
std::puts("\n\n\n____________________________________________\
_________________\npress <ENTER> to exit...");
std::getchar();
return 0;
}

________________________________________________________________________


Here is a link to the same code just in case it gets mangled by the
newsreader:

http://pastebin.com/f7cfdef4d


Any thoughts? Is it CRAP!?

;^o

--
Chris M. Thomasson
http://appcore.home.comcast.net

Chris Thomasson

unread,
Jun 17, 2008, 8:06:18 PM6/17/08
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:DoqdnR4bDZHZpsXV...@comcast.com...

> This region allocator is not dynamic and can be fed with a buffer residing
> on the stack of the calling thread. Therefore, you can use this in an
> environment which does not have a heap; its basically analogous to
> `alloca'. However, it does not align each buffer on a boundary sufficient
> for _any_ type. Instead, it dynamically calculates the types alignment
> requirements and mutates the offset accordingly. This makes it more
> efficient wrt conserving space. For instance, it does not need to align a
> char pointer on a max-boundary. Here is the code (pre-alpha sketch) which
> should compile fine:

[...]


> Any thoughts? Is it CRAP!?

Here is how to use it with a non-POD type:
______________________________________________________________
#include <string>
#include <cstdio>
#include <new>


#define PRINTF_THIS(mp_type, mp_func) \
std::printf("(%p)->" mp_type "::" mp_func "\n", (void*)this)


struct foo_ctor {
std::string const m_name;

foo_ctor(std::string const& name) : m_name(name) {
PRINTF_THIS("foo_ctor", "foo_ctor()");
}

~foo_ctor() {
PRINTF_THIS("foo_ctor", "~foo_ctor()");
}

void display_name() {
PRINTF_THIS("foo_ctor", "display_name()");
std::printf("%s\n", m_name.c_str());
}
};


int main() {
{
unsigned char buf[1024 * 8] = { '\0' };
stack_region_allocator region(buf, sizeof(buf));

foo_ctor* fctor = new (region.allocate<foo_ctor>()) foo_ctor("Chris");
fctor->display_name();
fctor->~foo_ctor();


region.reset();
}
std::puts("\n\n\n____________________________________________\
_________________\npress <ENTER> to exit...");
std::getchar();
return 0;
}

______________________________________________________________


No need to call delete; just the dtor.


> ;^o

0 new messages