gerv%gerv.net 912583b021 Bug 236613: change to MPL/LGPL/GPL tri-license.
git-svn-id: svn://10.0.0.236/trunk@155485 18797224-902f-48f8-a5cc-f745e15eee43
2004-04-25 15:37:13 +00:00

268 lines
9.7 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mem_h___
#define mem_h___
#include "systemtypes.h"
#include "stlcfg.h"
#include "utilities.h"
namespace JavaScript
{
//
// Zones
//
// A zone is a region of memory from which objects can be allocated
// individually.
// The memory in a zone is deallocated when the zone is deallocated or its
// clear method called.
class Zone {
union Header {
Header *next; // Next block header in linked list
char padding[basicAlignment];// Padding to ensure following block is fully aligned
};// Block data follows header
Header *headers; // Linked list of allocated blocks
char *freeBegin; // Pointer to free bytes left in current block
char *freeEnd; // Pointer to end of free bytes left in current block
size_t blockSize; // Size of individual arena blocks
public:
explicit Zone(size_t blockSize = 1024);
private:
Zone(const Zone&); // No copy constructor
void operator=(const Zone&); // No assignment operator
public:
void clear();
~Zone() {clear();}
private:
void *newBlock(size_t size);
public:
void *allocate(size_t size);
void *allocateUnaligned(size_t size);
};
//
// Arenas
//
#ifndef _WIN32
// Pretend that obj points to a value of class T and call obj's destructor.
template<class T>
void classDestructor(void *obj)
{
static_cast<T *>(obj)->~T();
}
#else // Microsoft Visual C++ 6.0 bug workaround
template<class T>
struct DestructorHolder
{
static void destroy(void *obj) {static_cast<T *>(obj)->~T();}
};
#endif
// An arena is a region of memory from which objects either derived from
// ArenaObject or allocated using a ArenaAllocator can be allocated. Deleting
// these objects individually runs the destructors, if any, but does not
// deallocate the memory. On the other hand, the entire arena can be
// deallocated as a whole.
//
// One may also allocate other objects in an arena by using the Arena
// specialization of the global operator new. However, be careful not to
// delete any such objects explicitly!
//
// Destructors can be registered for objects (or parts of objects) allocated
// in the arena. These destructors are called, in reverse order of being
// registered, at the time the arena is deallocated or cleared. When
// registering destructors for an object O be careful not to delete O manually
// because that would run its destructor twice.
class Arena: public Zone {
struct DestructorEntry;
DestructorEntry *destructorEntries;// Linked list of destructor registrations, ordered from most to least recently registered
public:
explicit Arena(size_t blockSize = 1024): Zone(blockSize), destructorEntries(0) {}
private:
void runDestructors();
public:
void clear() {runDestructors(); Zone::clear();}
~Arena() {runDestructors();}
private:
void newDestructorEntry(void (*destructor)(void *), void *object);
public:
// Ensure that object's destructor is called at the time the arena is deallocated or cleared.
// The destructors will be called in reverse order of being registered.
// registerDestructor might itself runs out of memory, in which case it immediately
// calls object's destructor before throwing bad_alloc.
#ifndef _WIN32
template<class T> void registerDestructor(T *object) {newDestructorEntry(&classDestructor<T>, object);}
#else
template<class T> void registerDestructor(T *object) {newDestructorEntry(&DestructorHolder<T>::destroy, object);}
#endif
};
// Objects derived from this class will be contained in the Arena
// passed to the new operator.
struct ArenaObject {
void *operator new(size_t size, Arena &arena) {return arena.allocate(size);}
void *operator new[](size_t size, Arena &arena) {return arena.allocate(size);}
void operator delete(void *, Arena &) {}
void operator delete[](void *, Arena &) {}
private:
void operator delete(void *, size_t) {}
void operator delete[](void *) {}
};
// Objects allocated by passing this class to standard containers will
// be contained in the Arena passed to the ArenaAllocator's constructor.
template<class T> class ArenaAllocator {
Arena &arena;
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
static pointer address(reference r) {return &r;}
static const_pointer address(const_reference r) {return &r;}
ArenaAllocator(Arena &arena): arena(arena) {}
template<class U> ArenaAllocator(const ArenaAllocator<U> &u): arena(u.arena) {}
pointer allocate(size_type n, const void *hint = 0) {return static_cast<pointer>(arena.allocate(n*sizeof(T)));}
static void deallocate(pointer, size_type) {}
static void construct(pointer p, const T &val) {new(p) T(val);}
static void destroy(pointer p) {p->~T();}
#ifdef __GNUC__ // why doesn't g++ support numeric_limits<T>?
static size_type max_size() {return size_type(-1) / sizeof(T);}
#else
static size_type max_size() {return std::numeric_limits<size_type>::v_max() / sizeof(T);}
#endif
template<class U> struct rebind {typedef ArenaAllocator<U> other;};
};
//
// Pools
//
// A Pool holds a collection of objects of the same type. These
// objects can be allocated and deallocated inexpensively.
// To allocate a T, use new(pool) T(...), where pool has type Pool<T>.
// To deallocate a T, use pool.destroy(t), where t has type T*.
template <typename T> class Pool: public Zone {
struct FreeList {
FreeList *next; // Next item in linked list of freed objects
};
STATIC_CONST(size_t, entrySize = sizeof(T) >= sizeof(FreeList *) ? sizeof(T) : sizeof(FreeList *));
FreeList *freeList; // Head of linked list of freed objects
public:
// clumpSize is the number of T's that are allocated at a time.
explicit Pool(size_t clumpSize): Zone(clumpSize * entrySize), freeList(0) {}
// Allocate memory for a single T. Use this with a placement new operator to create a new T.
void *allocate() {
if (freeList) {
FreeList *p = freeList;
freeList = p->next;
return p;
}
return allocateUnaligned(entrySize);
}
void deallocate(void *t) {
FreeList *p = static_cast<FreeList *>(t);
p->next = freeList;
freeList = p;
}
void destroy(T *t) {ASSERT(t); t->~T(); deallocate(t);}
};
}
inline void *operator new(size_t size, JavaScript::Arena &arena) {
return arena.allocate(size);
}
#ifndef _WIN32
// Microsoft Visual C++ 6.0 bug: new and new[] aren't distinguished
inline void *operator new[](size_t size, JavaScript::Arena &arena) {
return arena.allocate(size);
}
#endif
// Global delete operators. These are only called in the rare cases that a
// constructor throws an exception and has to undo an operator new.
// An explicit delete statement will never invoke these.
inline void operator delete(void *, JavaScript::Arena &) {}
// Microsoft Visual C++ 6.0 bug: new and new[] aren't distinguished
#ifndef _WIN32
inline void operator delete[](void *, JavaScript::Arena &) {}
#endif
template <typename T>
inline void *operator new(size_t DEBUG_ONLY(size), JavaScript::Pool<T> &pool) {
ASSERT(size == sizeof(T)); return pool.allocate();
}
template <typename T>
inline void operator delete(void *t, JavaScript::Pool<T> &pool) {
pool.deallocate(t);
}
#endif /* mem_h___ */