/*********************************************************************** NAME alloc_node, free_node, flush_node, free_list_of_nodes alloc_cube_list, free_cube_list, flush_cube_list, free_list_of_cubes alloc_binary, free_binary, flush_binary alloc_parent, free_parent, flush_parent, free_list_of_parents PURPOSE because the system allocation routines are not efficient when they are called very often for small blocks, special routines will be provided for each structure type to be allocated for cube manipulation. SYNOPSIS struct node *alloc_node() free_node(node) struct node *node; flush_node() free_list_of_nodes(list) struct node **list; struct cube_list *alloc_cube_list() free_cube_list(cube) struct cube_list *cube; flush_cube_list() free_list_of_cubes(list) struct cube_list **list; struct binary *alloc_binary() free_binary(binary) struct binary *binary; flush_binary() struct parent *alloc_parent() free_parent(parent) struct parent *parent; flush_parent() free_list_of_parents(list) struct parent **list; DESCRIPTION Big blocks of memory are allocated from which several nodes can be made. Each time alloc node is called a piece of this block is passed; when the whole block is used a new one is allocated. When some node freed, they are kept in a list to be reallocated next time alloc node is called. The blocks are not freed by the free node function since they can be freed in any order and we never know when a block contains only blocks that were released and are presently in the free list. However when all the nodes are not useful anymore the function flush nodes can be called to release all the blocks. All the comments that apply for the structure node will apply most of the time as well for the structures parent,binary and cube_list. DIAGNOSTIC Each time we allocate space the code returned by the system is verified and an error is signaled when no more memory is available. COORDINATES McGill University Electrical Engineering MONTREAL CANADA 2 july 1984 AUTHOR Michel DAGENAIS ************************************************************************/ #include "cubes.h" #include /* The size of the big blocks is defined here in terms of how many elements of the specified structure they contain. Those values can be changed to best values depending on your system and the average size of the exaamples you expect to run; in any case it must be much bigger then 1. */ #define MANY_NODE 100 #define MANY_CUBE 100 #define MANY_BINARY 200 #define MANY_PARENT 400 int nb_alloc_cube_list = 0, nb_alloc_parent = 0, nb_alloc_binary = 0, nb_alloc_nodes = 0; struct block { struct block *next_block; /* pointer to next block allocated */ char space[1]; /* the real size > 1 will be computed later */ }; static struct block *temp_block, /* temp block pointer */ *node_block_list = NULL, /* list of blocks allocated */ *cube_block_list = NULL, /* list of blocks allocated for cube_list */ *binary_block_list = NULL,/* list of blocks allocated for binary nodes*/ *parent_block_list = NULL; /* list of blocks allocated for parent */ static struct node *node_free_list = NULL, /* list of nodes released */ *next_node, /* temp pointer to next node in a list */ *temp_node; /* temp node pointer */ static struct cube_list *cube_free_list = NULL, /* list of cube_list released */ *next_cube, /* temp pointer to next cube in a list */ *temp_cube; /* temp cube_list pointer */ static struct binary *binary_free_list = NULL, /* list of binary nodes released */ *temp_binary; /* temp binary node pointer */ static struct parent *parent_free_list = NULL, /* list of parents released */ *next_parent, /* temp pointer to next parent in a list */ *temp_parent; /* temp parent pointer */ static char *start_node_free = NULL, /* address of free space in block */ *end_node_free = NULL, /* address of block end */ *start_cube_free = NULL, /* address of free space in block for cubes */ *end_cube_free = NULL, /* address of block end */ *start_binary_free = NULL,/* address of free space in block for binary */ *end_binary_free = NULL, /* address of block end */ *start_parent_free = NULL, /* address of free space in block for parents */ *end_parent_free = NULL; /* address of block end */ struct node *alloc_node() { /* check if some released nodes are present in the list node free list, We first try to reallocate those by simply removing them from the list and sending their address to the calling program. */ nb_alloc_nodes++; if(node_free_list != NULL) { temp_node = node_free_list; node_free_list = node_free_list->next_node; temp_node->next_node = NULL; temp_node->ancestors = NULL; temp_node->descendants = NULL; temp_node->status = NULL; return(temp_node); } /* Allocate fresh new space from a huge block allocated earlier using the calloc routine. We keep track of the space left in the block after we allocate each node */ if(start_node_free < end_node_free) { temp_node = (struct node *)start_node_free; start_node_free = start_node_free + node_size; return(temp_node); } /* No more space left in the block we will have to allocate a new one initialize the pointers in it and send one node out of it for now. */ temp_block = node_block_list; node_block_list = (struct block *) calloc(1,sizeof(struct block) + MANY_NODE * node_size); if(node_block_list == NULL)fatal_system_error("unable to alloc nodes"); node_block_list->next_block = temp_block; temp_node = (struct node *)node_block_list->space; start_node_free = node_block_list->space + node_size; end_node_free = node_block_list->space + MANY_NODE * node_size; return(temp_node); } /************************************************************************/ free_node(node) struct node *node; { /* All the nodes freed by the user are kept in a list until he wants to allocate other nodes in which case the old nodes are sent back. we do not send back this space to the system to avoid inefficient repetion of alloc and free operations on nodes */ nb_alloc_nodes--; node->next_node = node_free_list; node_free_list = node; } /************************************************************************/ #ifdef DEBUG flush_node() { /* All the blocks allocated to contain nodes are freed one by one */ nb_alloc_nodes = 0; for(; node_block_list != NULL ; node_block_list = temp_block) { temp_block = node_block_list->next_block; free((char *)node_block_list); } node_free_list = NULL; start_node_free = NULL; end_node_free = NULL; } #endif /*************************************************************************/ free_list_of_nodes(list) struct node **list; { /* We go to the end of the list to free, append the free list and put this new list back as the free list. The pointer to the list freed is reset to 0. */ temp_node = *list; if(temp_node == NULL) return; for( ; ; temp_node = next_node) { next_node = temp_node->next_node; nb_alloc_nodes--; if(next_node == NULL) break; } temp_node->next_node = node_free_list; node_free_list = *list; *list = NULL; } /************************************************************************/ struct cube_list *alloc_cube_list() { /* The allocation routines for the other kind of structures are similar to the ones for the nodes so for explanations refer to the previous section. */ nb_alloc_cube_list++; if(cube_free_list != NULL) { temp_cube = cube_free_list; cube_free_list = cube_free_list->next_cube; temp_cube->next_cube = NULL; return(temp_cube); } if(start_cube_free < end_cube_free) { temp_cube = (struct cube_list *)start_cube_free; start_cube_free = start_cube_free + cube_list_size; return(temp_cube); } temp_block = cube_block_list; cube_block_list = (struct block *) calloc(1,sizeof(struct block) + MANY_CUBE * cube_list_size); if(cube_block_list == NULL)fatal_system_error("unable to alloc cubes"); cube_block_list->next_block = temp_block; temp_cube = (struct cube_list *)cube_block_list->space; start_cube_free = cube_block_list->space + cube_list_size; end_cube_free = cube_block_list->space + MANY_CUBE * cube_list_size; return(temp_cube); } /************************************************************************/ free_cube_list(cube) struct cube_list *cube; { nb_alloc_cube_list--; cube->next_cube = cube_free_list; cube_free_list = cube; } /************************************************************************/ #ifdef DEBUG flush_cube_list() { nb_alloc_cube_list = NULL; for(; cube_block_list != NULL ; cube_block_list = temp_block) { temp_block = cube_block_list->next_block; free((char *)cube_block_list); } cube_free_list = NULL; start_cube_free = NULL; end_cube_free = NULL; } #endif /*************************************************************************/ free_list_of_cubes(list) struct cube_list **list; { temp_cube = *list; if(temp_cube == NULL) return; for( ; ; temp_cube = next_cube) { next_cube = temp_cube->next_cube; nb_alloc_cube_list--; if(next_cube == NULL) break; } temp_cube->next_cube = cube_free_list; cube_free_list = *list; *list = NULL; } /*************************************************************************/ struct binary *alloc_binary() { /* The allocation routines for the other kind of structures are similar to the ones for the nodes so for explanations refer to the previous section. */ nb_alloc_binary++; if(binary_free_list != NULL) { temp_binary = binary_free_list; binary_free_list = binary_free_list->is0._.subtree; temp_binary->is0.status = NULL; temp_binary->is1.status = NULL; temp_binary->isx = NULL; return(temp_binary); } if(start_binary_free < end_binary_free) { temp_binary = (struct binary *)start_binary_free; start_binary_free = start_binary_free + sizeof(struct binary); return(temp_binary); } temp_block = binary_block_list; binary_block_list = (struct block *) calloc(1,sizeof(struct block) + MANY_BINARY * sizeof(struct binary)); if(binary_block_list == NULL)fatal_user_error("unable to alloc binarys"); binary_block_list->next_block = temp_block; temp_binary = (struct binary *)binary_block_list->space; start_binary_free = binary_block_list->space + sizeof(struct binary); end_binary_free = binary_block_list->space + MANY_BINARY * sizeof(struct binary); return(temp_binary); } /****************************************************************************/ free_binary(binary) struct binary *binary; { nb_alloc_binary--; binary->is0._.subtree = binary_free_list; binary_free_list = binary; } /************************************************************************/ flush_binary() { nb_alloc_binary = 0; for(; binary_block_list != NULL ; binary_block_list = temp_block) { temp_block = binary_block_list->next_block; free((char *)binary_block_list); } binary_free_list = NULL; start_binary_free = NULL; end_binary_free = NULL; } /*************************************************************************/ struct parent *alloc_parent() { /* The allocation routines for the other kind of structures are similar to the ones for the nodes so for explanations refer to the previous section. */ nb_alloc_parent++; if(parent_free_list != NULL) { temp_parent = parent_free_list; parent_free_list = parent_free_list->next_parent; temp_parent->next_parent = NULL; return(temp_parent); } if(start_parent_free < end_parent_free) { temp_parent = (struct parent *)start_parent_free; start_parent_free = start_parent_free + sizeof(struct parent); return(temp_parent); } temp_block = parent_block_list; parent_block_list = (struct block *)calloc(1,sizeof(struct block) + MANY_PARENT * sizeof(struct parent)); if(parent_block_list == NULL)fatal_system_error("unable to alloc parents"); parent_block_list->next_block = temp_block; temp_parent = (struct parent *)parent_block_list->space; start_parent_free = parent_block_list->space + sizeof(struct parent); end_parent_free = parent_block_list->space + MANY_PARENT * sizeof(struct parent); return(temp_parent); } /******************************************************************************/ free_parent(parent) struct parent *parent; { nb_alloc_parent--; parent->next_parent = parent_free_list; parent_free_list = parent; } /************************************************************************/ #ifdef DEBUG flush_parent() { nb_alloc_parent = 0; for(; parent_block_list != NULL ; parent_block_list = temp_block) { temp_block = parent_block_list->next_block; free((char *)parent_block_list); } parent_free_list = NULL; start_parent_free = NULL; end_parent_free = NULL; } #endif /*************************************************************************/ free_list_of_parents(list) struct parent **list; { temp_parent = *list; if(temp_parent == NULL) return; for( ; ; temp_parent = next_parent) { next_parent = temp_parent->next_parent; nb_alloc_parent--; if(next_parent == NULL) break; } temp_parent->next_parent = parent_free_list; parent_free_list = *list; *list = NULL; }