home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************
- These C++ classes are copyright 1989, 1990, 1991 by William Herrera.
- I hereby release this source code for free distrubution and use.
- If you modify it and distribute it, please indicate any changes you
- make as your own and the code as copyrighted above.
- **************************************************************************/
-
- // file gcobject.cpp class definition for functions in gcobject class.
-
- #include <stdlib.h>
- #include <string.h>
- #include <dos.h>
- #include <limits.h>
- #include <fstream.h>
- #include <alloc.h>
-
-
- #include "gcobject.hpp"
- #include "error.hpp"
-
- const char handle_alloc_err[] = "Error: Out of handle space";
- const char gcobject_alloc_err[] = "Error: Out of gcobject space";
-
- gcobject::gcobject(unsigned int buf_size, int gci)
- : buffer_size(buf_size), garbage_collection_interval(gci),
- allocated_size(0), delete_count(0), lockcount(0)
- {
- buffer_start = ::new char[buffer_size];
- if(buffer_start == NULL)
- Error(handle_alloc_err);
- }
-
- gcobject::~gcobject()
- {
- if(buffer_start != NULL)
- delete buffer_start;
- }
-
- void gcobject::CompactBuffer()
- {
- while(CollectGarbage() != 0) // collect until all compacted.
- ;
- }
-
- void gcobject::Lock()
- {
- ++lockcount;
- }
-
- void gcobject::Unlock()
- {
- --lockcount;
- }
-
- int gcobject::CollectGarbage()
- {
- if(lockcount != 0) // the buffer is locked.
- return 0;
- #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;
- if(dptr->ref_count > 0)
- *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.
- }
-
- void 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!
- {
- *owner = NULL; // if can't, assign NULL as failure flag.
- return;
- }
- }
- 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;
- *owner = dptr;
- return;
- }
-
- 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
-