/* lil-gp Genetic Programming System, version 1.0, 11 July 1995 * Copyright (C) 1995 Michigan State University * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Douglas Zongker (zongker@isl.cps.msu.edu) * Dr. Bill Punch (punch@isl.cps.msu.edu) * * Computer Science Department * A-714 Wells Hall * Michigan State University * East Lansing, Michigan 48824 * USA * */ #include /* total counts of ERCs used and freed */ int ercused = 0; int ercfree = 0; int ercalloc = 0; /* the active list. */ ephem_const *active_head; int active_count; /* the free list. */ ephem_const *free_head; int free_count; /* pointers for the allocated blocks for ERCs. */ ephem_const **block_list; int block_list_size; int block_count; /* initialize_ephem_const() * * allocate and set up the first block of ERCs, the free list, * etc. */ void initialize_ephem_const ( void ) { int i; int size; oputs ( OUT_SYS, 30, " ephemeral random constants.\n" ); active_head = (ephem_const *)MALLOC ( sizeof ( ephem_const ) ); active_head->refcount = 1; active_head->next = NULL; free_head = (ephem_const *)MALLOC ( sizeof ( ephem_const ) ); free_head->refcount = 1; free_head->next = NULL; /** how many block >>pointers<< to allocate (not blocks). **/ block_list_size = EPHEM_METABLOCKSIZE; block_list = (ephem_const **)MALLOC ( block_list_size * sizeof ( ephem_const * ) ); /* allocate the first block. */ size = EPHEM_STARTSIZE; block_count = 1; block_list[0] = (ephem_const *)MALLOC ( size * sizeof ( ephem_const ) ); free_count = ercalloc = size; /* chain all the ERC records in the block together. */ for ( i = 0; i < size-1; ++i ) block_list[0][i].next = block_list[0]+i+1; block_list[0][size-1].next = NULL; /* add the chain to the free list. */ free_head->next = block_list[0]; } /* free_ephem_const() * * free all the memory allocated to hold ERCs. */ void free_ephem_const ( void ) { int i; ephem_const_gc(); for ( i = 0; i < block_count; ++i ) FREE ( block_list[i] ); FREE ( block_list ); FREE ( active_head ); FREE ( free_head ); } /* enlarge_ephem_space() * * allocate a new block of ERCs, and add all the records in it * to the free list. */ void enlarge_ephem_space ( void ) { int i; int size = EPHEM_GROWSIZE; /** if we've allocated too many blocks, we need to lengthen the list that holds block pointers. **/ if ( block_count == block_list_size ) { block_list_size += EPHEM_METABLOCKSIZE; block_list = (ephem_const **)REALLOC ( block_list, block_list_size * sizeof ( ephem_const *)); } /* allocate the new block. */ block_list[block_count] = (ephem_const *)MALLOC ( size * sizeof ( ephem_const ) ); free_count += size; ercalloc += size; /* chain together all the records in it. */ for ( i = 0; i < size-1; ++i ) block_list[block_count][i].next = block_list[block_count]+i+1; block_list[block_count][size-1].next = free_head->next; free_head->next = block_list[block_count]; ++block_count; } /* new_ephemeral_const() * * create a new ERC, corresponding to the given function. */ ephem_const *new_ephemeral_const ( function *f ) { ephem_const *p; /* make sure we have enough space. */ while ( free_count <= 0 ) enlarge_ephem_space(); /* take the next record off the free list. */ p = free_head->next; free_head->next = free_head->next->next; --free_count; /* call user code to generate the constant, placing the value in the new record. */ f->ephem_gen ( &(p->d) ); p->f = f; /* no references yet. */ p->refcount = 0; /* add this record to the linked list of active ERCs. */ p->next = active_head->next; active_head->next = p; ++active_count; ++ercused; return p; } /* ephem_const_gc() * * traverse the linked list of active ERCs, removing those with * a reference count of 0. */ void ephem_const_gc ( void ) { ephem_const *p = active_head->next; ephem_const *m = active_head; while ( p != NULL ) { if ( p->refcount == 0 ) { /* patch the linked list to skip this record. */ m->next = p->next; /* add this record to the free list. */ p->next = free_head->next; free_head->next = p; ++free_count; ++ercfree; --active_count; p = m->next; } else { /* move past this record. */ m = p; p = p->next; } } } /* read_ephem_list() * * read list of ERCs from a checkpoint file. */ ephem_const **read_ephem_list ( FILE *f ) { ephem_const **ind; ephem_const *p; int count; int i, j; char *buffer; /* read the count. */ fscanf ( f, "%*s %d\n", &count ); /** if no ERCs, do nothing and return a NULL pointer for the index. **/ if ( count == 0 ) return NULL; /* somewhere to place (and ignore) the human-readable forms of the ERCs after the hex blocks. */ buffer = (char *)MALLOC ( MAXCHECKLINELENGTH ); /* allocate the index translating integers --> addresses. */ ind = (ephem_const **)MALLOC ( count * sizeof ( ephem_const * ) ); /** allocate a new block to hold all the ERCs we read. **/ /* we shouldn't EVER need to lengthen the block list while reading a checkpoint, but check anyway... */ if ( block_count == block_list_size ) { block_list_size += EPHEM_METABLOCKSIZE; block_list = (ephem_const **)REALLOC ( block_list, block_list_size * sizeof ( ephem_const *)); } /* allocate the new block. */ block_list[block_count] = (ephem_const *)MALLOC ( count * sizeof ( ephem_const ) ); ercalloc += count; /* read the checkpointed ERCs into the new block. */ for ( i = 0; i < count; ++i ) { p = block_list[block_count]+i; fscanf ( f, "%d %d ", &j, &(p->refcount) ); ind[j] = p; read_hex_block ( &(p->d), sizeof ( DATATYPE ), f ); fgets ( buffer, MAXCHECKLINELENGTH, f ); /* chain together all the records. */ block_list[block_count][i].next = block_list[block_count]+i+1; } /* add the chained block to the active list. */ block_list[block_count][count-1].next = active_head->next; active_head->next = block_list[block_count]; active_count += count; ercused += count; ++block_count; FREE ( buffer ); return ind; } /* write_ephem_list() * * write the active list of ERCs to a checkpoint file. returns an * index listing for translating an ERC address to a unique integer. * (we can't store the address directly in the checkpoint, since * the ERCs won't be loaded in the same spot in memory on restart.) */ ephem_index *write_ephem_list ( FILE *f ) { ephem_index *ind; ephem_const *p = active_head->next; int j; ind = (ephem_index *)MALLOC ( active_count * sizeof ( ephem_index ) ); fprintf ( f, "erc-count: %d\n", active_count ); j = 0; while ( p ) { /* store the index entry. */ ind[j].e = p; ind[j].i = j; /* write the reference count and the value. */ fprintf ( f, "%d %d ", j, p->refcount ); write_hex_block ( &(p->d), sizeof(DATATYPE), f ); fprintf ( f, " %s %s\n", p->f->string, p->f->ephem_str ( p->d ) ); /* move down the list. */ p = p->next; ++j; } /* sort the index by address, so we can use binary searching on it. */ qsort ( ind, active_count, sizeof(ephem_index), ephem_index_comp ); return ind; } /* lookup_ephem() * * look up an ERC (by address) in an index returned by write_ephem_list() * and return its integer index. */ int lookup_ephem ( ephem_index *ind, ephem_const *e ) { int low = 0; int high = (ercused-ercfree); int mid; while ( low < high-1 ) { mid = (low+high)/2; if ( e >= ind[mid].e ) low = mid; else high = mid; } return ind[low].i; } /* ephem_index_comp() * * comparison function for using qsort() to order the ERC index by * address. */ int ephem_index_comp ( const void *a, const void *b ) { if ( ((ephem_index *)a)->e < ((ephem_index *)b)->e ) return -1; else return 1; } /* get_ephem_stats() * * return ERC statistics. */ void get_ephem_stats ( int *used, int *free, int *blocks, int *alloc ) { *used = ercused; *free = ercfree; *blocks = block_count; *alloc = ercalloc; }