diff options
Diffstat (limited to 'libcult/cult/mm/new.cxx')
-rw-r--r-- | libcult/cult/mm/new.cxx | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/libcult/cult/mm/new.cxx b/libcult/cult/mm/new.cxx new file mode 100644 index 0000000..2443f1f --- /dev/null +++ b/libcult/cult/mm/new.cxx @@ -0,0 +1,192 @@ +// file : cult/mm/new.cxx +// author : Boris Kolpackov <boris@kolpackov.net> +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <cult/mm/new.hxx> +#include <cult/mm/counter.hxx> + +#include <cstdlib> // std::malloc, std::free + +#include <cult/trace/stream.hxx> + +namespace +{ + Cult::Trace::Stream& + tout () + { + static Cult::Trace::Stream o ("Cult::MM", 7); + return o; + } +} + +namespace Cult +{ + namespace MM + { + using Bits::Offset; + + + namespace + { + Void* + allocate (Size size, KeyList const& l) throw (StdBadAlloc) + { + Size zone_size (0); + + for (KeyList::Iterator i (l.begin ()); i != l.end (); ++i) + { + zone_size += (*i)->size (); + } + + Size map_size ((l.size () + 1) * sizeof (Offset)); + + //tout () << "allocate: size: " << size + // << " map size: " << map_size + // << " zone size: " << zone_size; + + Char* block (reinterpret_cast<Char*> ( + std::malloc (size + zone_size + map_size))); + + Char* base (block + zone_size + map_size); + + Offset* map (reinterpret_cast<Offset*> (base) - 1); // map bottom + Char* zone (block + zone_size); // zone bottom + + //tout () << 9 << "allocate:" << '\n' + // << " block : " << (Void*) block << '\n' + // << " base : " << (Void*) base << '\n' + // << " map : " << (Void*) zone << '\n' + // << " zone : " << (Void*) block; + + + // Initialize zone map and construct services. + // + for (KeyList::Iterator i (l.begin ()); i != l.end (); ++i) + { + KeyBase const& k (**i); + + zone -= k.size (); // now at the beginning of the block + + try + { + k.construct (zone); + } + catch (...) + { + std::free (block); + throw StdBadAlloc (); + } + + map->key = &k; + map->offset = base - zone; + + --map; + } + + // Last element. + // + map->key = 0; + map->offset = 0; + + return base; + } + + Void + free (Void* p) throw () + { + Char* base (reinterpret_cast<Char*> (p)); + + Offset* map (reinterpret_cast<Offset*> (base) - 1); // Map bottom. + + Char* block (reinterpret_cast<Char*> (map)); + + while (map->key != 0) + { + Char* zone (base - map->offset); + + block = zone; // Last zone is the begining of the block. + + map->key->destroy (zone); + + --map; + } + + //tout () << 9 << "free:" << '\n' + // << " block : " << (Void*) block; + + std::free (block); + } + } + } +} + +namespace Cult +{ + namespace MM + { + namespace Bits + { +#ifdef CULT_THREADS + __thread + Block* first_ __attribute__ ((tls_model ("initial-exec"))) = 0; +#else + Block* first_ = 0; +#endif + } + } +} + +using namespace Cult; + +Void* +operator new (Size s) throw (MM::StdBadAlloc) +{ + return MM::allocate (s, *MM::counted); +} + +Void* +operator new (Size size, MM::KeyList const& list, MM::Bits::Block const& b) + throw (MM::StdBadAlloc) +{ + Void* p (MM::allocate (size, list)); + + const_cast<MM::Bits::Block&> (b).set (p, size); + + return p; +} + +Void +operator delete (Void* p) throw () +{ + if (p) MM::free (p); +} + +Void +operator delete (Void* p, Size) throw () +{ + if (p) MM::free (p); +} + +namespace Cult +{ + namespace MM + { + + Void* ServiceAwareObject:: + operator new (Size size, Bits::Block const& block) + { + Void* p (allocate (size, *MM::counted)); + + const_cast<MM::Bits::Block&> (block).set (p, size); + + return p; + } + + Void ServiceAwareObject:: + operator delete (Void* p, Size) + { + if (p) MM::free (p); + } + } +} |