home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************
- These C++ classes are copyright 1989, 1990 by William Herrera.
- All those who put this code or its derivatives in a commercial product MUST
- mention this copyright in their documentation for users of the products in
- which this code or its derivative classes are used. Otherwise, this code
- may be freely distributed and used for any purpose.
- William Herrera
- contacts:
- GENIE
- FidoNet c_plusplus
- **************************************************************************/
- // file gcobject.cpp class definition for functions in gcobject class.
-
- #include "gcobject.hpp"
-
- char heap_alloc_err[] = "Error: Out of heap space";
- char gcobject_alloc_err[] = "Error: Out of gcobject space";
- char cr[] = "\n";
-
- void gcobject::Initialize(unsigned int buf_size, int gci)
- {
- buffer_size = buf_size;
- buffer_start = ::new char[buffer_size];
- if(buffer_start == NULL)
- FatalError(heap_alloc_err);
- allocated_size = 0;
- delete_count = 0;
- garbage_collection_interval = gci;
- }
-
- int gcobject::CollectGarbage()
- {
- #ifdef DEBUG
- cerr << "\nCollecting Garbage ...\n";
- #endif
- int num_collected = 0; // number of data_records collected out.
- unsigned int garbage_bottom = 0;
- data_record * dptr;
- while(garbage_bottom < allocated_size)
- {
- dptr = (data_record *) &buffer_start[garbage_bottom];
- if(dptr->ref_count == 0) // dptr points to garbage
- break; // so exit
- garbage_bottom += dptr->alloc_length; // skip past area in use
- } // now we have found an area of garbage (ref_count == 0).
- unsigned int garbage_top = garbage_bottom;
- while(garbage_top < allocated_size)
- {
- dptr = (data_record *) &buffer_start[garbage_top];
- if(dptr->ref_count != 0) // dptr points to non-garbage
- break; // so exit
- garbage_top += dptr->alloc_length; // skip past garbage record
- ++num_collected; // we've got one to collect.
- }
- if(garbage_bottom < allocated_size && num_collected > 0)
- // there is stuff to collect!
- {
- unsigned int bytes_above_garbage = allocated_size - garbage_top;
- if(bytes_above_garbage > 0)
- memmove(&buffer_start[garbage_bottom],
- &buffer_start[garbage_top], bytes_above_garbage);
- // move stuff to cover garbage.
- allocated_size -= garbage_top - garbage_bottom;
- // reset amount of buffer currently used.
- // Now update the allocated pointers to the buffer records.
- // Each record in the buffer keeps track of what pointer is pointing
- // to it and can change its value when we reshuffle the buffer.
- unsigned int i = 0;
- while(i < allocated_size)
- {
- dptr = (data_record *) &buffer_start[i];
- data_record ** owner = dptr->owner_record;
- *owner = dptr;
- i += dptr->alloc_length;
- }
- }
- delete_count = 0; // reset the counter, since we've done garbage.
- return num_collected; // this is zero if there was none to collect.
- }
-
- data_record * gcobject::Allocate(size_t sz, data_record ** owner)
- {
- // this function allocates memory to pointer "owner" but keeps
- // track of owner's address so it can update owner if the
- // allocation changes position.
- size_t len = sizeof(data_record) - 1 + sz;
- // this is the size of the variable length records in the buffer.
- if(len & 1) // odd # of bytes
- ++len; // so make even for alignment.
- while(allocated_size + len > buffer_size) // oops, out of room
- {
- if(CollectGarbage() == 0) // try to get some space!
- return NULL; // if can't, return NULL as failure flag.
- }
- data_record * dptr = (data_record *) &buffer_start[allocated_size];
- allocated_size += len;
- dptr->alloc_length = len;
- dptr->ref_count = 1; // base reference count is always 1.
- dptr->owner_record = owner;
- return dptr;
- }
-
- void gcobject::IncDeleteCount()
- {
- ++delete_count;
- if(delete_count > garbage_collection_interval)
- CollectGarbage();
- }
-
- #ifdef DEBUG
- void gcobject::DumpBuffer()
- {
- for(unsigned int i = 0; i < buffer_size; ++i)
- cerr.put(buffer_start[i]);
- cerr.put('\n');
- }
- #endif
-
- // end of file gcobject.cpp
-