static void *find_fit(size_t asize) { /* First fit search */ void* bp; // print_list(); int offset = get_offset(asize); //printf("in first fit search \n"); for (int i = offset; i < 9; i++) { //printf ("In bucket %d \n",i); for (bp =((void*) (*(long*)GET_BUCKET(root, i))); bp != NULL ; bp = get_succ(bp) ) { // printf("bp %p \n",bp); REQUIRES ((void*)bp != NULL); REQUIRES (((size_t)(bp))%8 == 0); size_t size = GET_SIZE(HDRP((bp))); if (!GET_ALLOC( HDRP(((bp) ) )) && (asize <= size)) { ENSURES ( (size_t)(bp)%8 == 0); size_t diff = size - asize; return first_best_fit((void*)bp,asize, diff) ; } } } return NULL; /* No fit */ }
void hash_destroy (HTAB *hashp) { /* cannot destroy a shared memory hash table */ Assert(! hashp->segbase); if (hashp != NULL) { register SEG_OFFSET segNum; SEGMENT segp; int nsegs = hashp->hctl->nsegs; int j; BUCKET_INDEX *elp,p,q; ELEMENT *curr; for (segNum = 0; nsegs > 0; nsegs--, segNum++) { segp = GET_SEG(hashp,segNum); for (j = 0, elp = segp; j < hashp->hctl->ssize; j++, elp++) { for ( p = *elp; p != INVALID_INDEX; p = q ){ curr = GET_BUCKET(hashp,p); q = curr->next; MEM_FREE((char *) curr); } } free((char *)segp); } (void) MEM_FREE( (char *) hashp->dir); (void) MEM_FREE( (char *) hashp->hctl); hash_stats("destroy",hashp); (void) MEM_FREE( (char *) hashp); } }
static void remove_block(void *bp, size_t size) { //printf ("remove block\n"); REQUIRES ( bp != NULL ); REQUIRES ( (size_t)(bp) % 8 == 0); int offset = get_offset(size); void *pred = get_pred(bp); void *succ = get_succ(bp); if ( pred == NULL && succ != NULL) //block to be removed is the first block in the list { SET_SUCC(bp) = 0; SET_PRED(succ) = 0; SET_ROOT(GET_BUCKET(root, offset)) = (long)succ; } else if (pred != NULL && succ == NULL) //block to be removed is the last block in the list { SET_SUCC(pred) = 0; SET_PRED(bp) = 0; } else if (pred != NULL && succ != NULL) //block to be removed is located somewhere within the list. { SET_SUCC(pred) = (int)( (long)succ - BASE); SET_PRED(succ) = (int)((long)pred - BASE); SET_PRED(bp) = 0; SET_SUCC(bp) = 0; } else if ( pred == NULL && succ == NULL) { //printf("resetting root\n"); SET_ROOT(GET_BUCKET(root, offset)) = 0; } print_list(); return; }
// Returns 0 if no errors were found, otherwise returns the error int mm_checkheap(int verbose) { // char *bp = heap_listp; if (verbose) printf("Heap (%p):\n", heap_listp); if ((GET_SIZE(HDRP(heap_listp)) != DSIZE) || !GET_ALLOC(HDRP(heap_listp))) printf("Bad prologue header\n"); checkblock(heap_listp); void* list; int count_free_in_list = 0; int count_free_in_heap = 0; for (int i =0; i < 9; i++) { for (list = (void*)(*(long*)GET_BUCKET(root,i)); list != NULL; list = get_succ(list) ) { if (verbose) printblock(list); checkblock(list); if ( get_succ(list) != NULL && get_pred(list) !=NULL) check_succ_pred(list); check_address(list); count_free_in_list++; check_in_correct_bucket(list, i); } } char *bp; for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) { if (verbose) { if (GET_ALLOC(HDRP(bp)) == 0) count_free_in_heap ++; printblock(bp); checkblock(bp); check_coalescing( (void*)bp); } } if (count_free_in_heap != count_free_in_list) printf ("Number of free block not consistent in heap and list list \n"); if (verbose) printblock(bp); if ((GET_SIZE(HDRP(bp)) != 0) || !(GET_ALLOC(HDRP(bp)))) { printf("Bad epilogue header\n"); if (GET_SIZE(HDRP(bp)) != 0) printf ("size is not 0\n"); if (!(GET_ALLOC(HDRP(bp))) ) printf ("not allocated properly\n"); } return 0; }
bool hashmap_has_key(hashmap_t* map, hash_t key) { /*lint --e{613} */ size_t ibucket = GET_BUCKET(map, key); hashmap_node_t* bucket = map->bucket[ibucket]; size_t inode, nsize; for (inode = 0, nsize = array_size(bucket); inode < nsize; ++inode) { if (bucket[inode].key == key) return true; } return false; }
void* hashmap_lookup(hashmap_t* map, hash_t key) { /*lint --e{613} */ size_t ibucket = GET_BUCKET(map, key); hashmap_node_t* bucket = map->bucket[ibucket]; size_t inode, nsize; for (inode = 0, nsize = array_size(bucket); inode < nsize; ++inode) { if (bucket[inode].key == key) return bucket[inode].value; } return 0; }
static void add_block(void *bp, size_t size) { // printf ("in add block\n"); REQUIRES ( bp != NULL ) ; REQUIRES ((size_t)(bp) % 8 == 0); int offset = get_offset(size); if ( (*(long*)GET_BUCKET(root, offset) != 0)) { //printf ("replacing root\n"); SET_PRED((void*)(*(long*)GET_BUCKET(root, offset))) = (int)( (long)bp -BASE ); } int val = (int)(*(long*)GET_BUCKET(root,offset) - BASE); //printf ("val = 0x%x \n",val); SET_SUCC(bp) = val; SET_PRED(bp) = 0; SET_ROOT(GET_BUCKET(root, offset)) = (long)bp; //print_list(); //printf("returned from adding block\n"); return; }
void* hashmap_erase(hashmap_t* map, hash_t key) { /*lint --e{613} */ size_t ibucket = GET_BUCKET(map, key); hashmap_node_t* bucket = map->bucket[ibucket]; size_t inode, nsize; for (inode = 0, nsize = array_size(bucket); inode < nsize; ++inode) { if (bucket[inode].key == key) { void* prev = bucket[inode].value; array_erase(map->bucket[ibucket], inode); --map->num_nodes; return prev; } } return 0; }
/* * allocate some new buckets and link them into the free list */ static int bucket_alloc(HTAB *hashp) { int i; ELEMENT *tmpBucket; long bucketSize; BUCKET_INDEX tmpIndex,lastIndex; bucketSize = sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize; /* make sure its aligned correctly */ bucketSize += sizeof(long *) - (bucketSize % sizeof(long *)); /* tmpIndex is the shmem offset into the first bucket of * the array. */ tmpBucket = (ELEMENT *) hashp->alloc((unsigned long) BUCKET_ALLOC_INCR*bucketSize); if (! tmpBucket) { return(0); } tmpIndex = MAKE_HASHOFFSET(hashp,tmpBucket); /* set the freebucket list to point to the first bucket */ lastIndex = hashp->hctl->freeBucketIndex; hashp->hctl->freeBucketIndex = tmpIndex; /* initialize each bucket to point to the one behind it */ for (i=0;i<(BUCKET_ALLOC_INCR-1);i++) { tmpBucket = GET_BUCKET(hashp,tmpIndex); tmpIndex += bucketSize; tmpBucket->next = tmpIndex; } /* the last bucket points to the old freelist head (which is * probably invalid or we wouldnt be here) */ tmpBucket->next = lastIndex; return(1); }
void* hashmap_insert(hashmap_t* map, hash_t key, void* value) { /*lint --e{613} */ size_t ibucket = GET_BUCKET(map, key); hashmap_node_t* bucket = map->bucket[ibucket]; size_t inode, nsize; for (inode = 0, nsize = array_size(bucket); inode < nsize; ++inode) { if (bucket[inode].key == key) { void* prev = bucket[inode].value; bucket[inode].value = value; return prev; } } { hashmap_node_t node = { key, value }; array_push(map->bucket[ibucket], node); ++map->num_nodes; } return 0; }
/********************************* UTILITIES ************************/ static int expand_table(HTAB *hashp) { HHDR *hctl; SEGMENT old_seg,new_seg; long old_bucket, new_bucket; long new_segnum, new_segndx; long old_segnum, old_segndx; ELEMENT *chain; BUCKET_INDEX *old,*newbi; register BUCKET_INDEX chainIndex,nextIndex; #ifdef HASH_STATISTICS hash_expansions++; #endif hctl = hashp->hctl; new_bucket = ++hctl->max_bucket; old_bucket = (hctl->max_bucket & hctl->low_mask); new_segnum = new_bucket >> hctl->sshift; new_segndx = MOD ( new_bucket, hctl->ssize ); if ( new_segnum >= hctl->nsegs ) { /* Allocate new segment if necessary */ if (new_segnum >= hctl->dsize) { dir_realloc(hashp); } if (! (hashp->dir[new_segnum] = seg_alloc(hashp))) { return (0); } hctl->nsegs++; } if ( new_bucket > hctl->high_mask ) { /* Starting a new doubling */ hctl->low_mask = hctl->high_mask; hctl->high_mask = new_bucket | hctl->low_mask; } /* * Relocate records to the new bucket */ old_segnum = old_bucket >> hctl->sshift; old_segndx = MOD(old_bucket, hctl->ssize); old_seg = GET_SEG(hashp,old_segnum); new_seg = GET_SEG(hashp,new_segnum); old = &old_seg[old_segndx]; newbi = &new_seg[new_segndx]; for (chainIndex = *old; chainIndex != INVALID_INDEX; chainIndex = nextIndex){ chain = GET_BUCKET(hashp,chainIndex); nextIndex = chain->next; if ( call_hash(hashp, (char *)&(chain->key), hctl->keysize) == old_bucket ) { *old = chainIndex; old = &chain->next; } else { *newbi = chainIndex; newbi = &chain->next; } chain->next = INVALID_INDEX; } return (1); }
/* * hash_seq -- sequentially search through hash table and return * all the elements one by one, return NULL on error and * return TRUE in the end. * */ long * hash_seq(HTAB *hashp) { static uint32 curBucket = 0; static BUCKET_INDEX curIndex; ELEMENT *curElem; long segment_num; long segment_ndx; SEGMENT segp; HHDR *hctl; if (hashp == NULL) { /* * reset static state */ curBucket = 0; curIndex = INVALID_INDEX; return((long *) NULL); } hctl = hashp->hctl; while (curBucket <= hctl->max_bucket) { if (curIndex != INVALID_INDEX) { curElem = GET_BUCKET(hashp, curIndex); curIndex = curElem->next; if (curIndex == INVALID_INDEX) /* end of this bucket */ ++curBucket; return(&(curElem->key)); } /* * initialize the search within this bucket. */ segment_num = curBucket >> hctl->sshift; segment_ndx = curBucket & ( hctl->ssize - 1 ); /* * first find the right segment in the table directory. */ segp = GET_SEG(hashp, segment_num); if (segp == NULL) /* this is probably an error */ return((long *) NULL); /* * now find the right index into the segment for the first * item in this bucket's chain. if the bucket is not empty * (its entry in the dir is valid), we know this must * correspond to a valid element and not a freed element * because it came out of the directory of valid stuff. if * there are elements in the bucket chains that point to the * freelist we're in big trouble. */ curIndex = segp[segment_ndx]; if (curIndex == INVALID_INDEX) /* empty bucket */ ++curBucket; } return((long *) TRUE); /* out of buckets */ }
/* * hash_search -- look up key in table and perform action * * action is one of HASH_FIND/HASH_ENTER/HASH_REMOVE * * RETURNS: NULL if table is corrupted, a pointer to the element * found/removed/entered if applicable, TRUE otherwise. * foundPtr is TRUE if we found an element in the table * (FALSE if we entered one). */ long * hash_search(HTAB *hashp, char *keyPtr, HASHACTION action, /* * HASH_FIND / HASH_ENTER / HASH_REMOVE * HASH_FIND_SAVE / HASH_REMOVE_SAVED */ bool *foundPtr) { uint32 bucket; long segment_num; long segment_ndx; SEGMENT segp; register ELEMENT *curr; HHDR *hctl; BUCKET_INDEX currIndex; BUCKET_INDEX *prevIndexPtr; char * destAddr; static struct State { ELEMENT *currElem; BUCKET_INDEX currIndex; BUCKET_INDEX *prevIndex; } saveState; Assert((hashp && keyPtr)); Assert((action == HASH_FIND) || (action == HASH_REMOVE) || (action == HASH_ENTER) || (action == HASH_FIND_SAVE) || (action == HASH_REMOVE_SAVED)); hctl = hashp->hctl; # if HASH_STATISTICS hash_accesses++; hashp->hctl->accesses++; # endif if (action == HASH_REMOVE_SAVED) { curr = saveState.currElem; currIndex = saveState.currIndex; prevIndexPtr = saveState.prevIndex; /* * Try to catch subsequent errors */ Assert(saveState.currElem && !(saveState.currElem = 0)); } else { bucket = call_hash(hashp, keyPtr, hctl->keysize); segment_num = bucket >> hctl->sshift; segment_ndx = bucket & ( hctl->ssize - 1 ); segp = GET_SEG(hashp,segment_num); Assert(segp); prevIndexPtr = &segp[segment_ndx]; currIndex = *prevIndexPtr; /* * Follow collision chain */ for (curr = NULL;currIndex != INVALID_INDEX;) { /* coerce bucket index into a pointer */ curr = GET_BUCKET(hashp,currIndex); if (! memcmp((char *)&(curr->key), keyPtr, hctl->keysize)) { break; } prevIndexPtr = &(curr->next); currIndex = *prevIndexPtr; # if HASH_STATISTICS hash_collisions++; hashp->hctl->collisions++; # endif } } /* * if we found an entry or if we weren't trying * to insert, we're done now. */ *foundPtr = (bool) (currIndex != INVALID_INDEX); switch (action) { case HASH_ENTER: if (currIndex != INVALID_INDEX) return(&(curr->key)); break; case HASH_REMOVE: case HASH_REMOVE_SAVED: if (currIndex != INVALID_INDEX) { Assert(hctl->nkeys > 0); hctl->nkeys--; /* add the bucket to the freelist for this table. */ *prevIndexPtr = curr->next; curr->next = hctl->freeBucketIndex; hctl->freeBucketIndex = currIndex; /* better hope the caller is synchronizing access to * this element, because someone else is going to reuse * it the next time something is added to the table */ return (&(curr->key)); } return((long *) TRUE); case HASH_FIND: if (currIndex != INVALID_INDEX) return(&(curr->key)); return((long *)TRUE); case HASH_FIND_SAVE: if (currIndex != INVALID_INDEX) { saveState.currElem = curr; saveState.prevIndex = prevIndexPtr; saveState.currIndex = currIndex; return(&(curr->key)); } return((long *)TRUE); default: /* can't get here */ return (NULL); } /* If we got here, then we didn't find the element and we have to insert it into the hash table */ Assert(currIndex == INVALID_INDEX); /* get the next free bucket */ currIndex = hctl->freeBucketIndex; if (currIndex == INVALID_INDEX) { /* no free elements. allocate another chunk of buckets */ if (! bucket_alloc(hashp)) { return(NULL); } currIndex = hctl->freeBucketIndex; } Assert(currIndex != INVALID_INDEX); curr = GET_BUCKET(hashp,currIndex); hctl->freeBucketIndex = curr->next; /* link into chain */ *prevIndexPtr = currIndex; /* copy key and data */ destAddr = (char *) &(curr->key); memmove(destAddr,keyPtr,hctl->keysize); curr->next = INVALID_INDEX; /* let the caller initialize the data field after * hash_search returns. */ /* memmove(destAddr,keyPtr,hctl->keysize+hctl->datasize);*/ /* * Check if it is time to split the segment */ if (++hctl->nkeys / (hctl->max_bucket+1) > hctl->ffactor) { /* fprintf(stderr,"expanding on '%s'\n",keyPtr); hash_stats("expanded table",hashp); */ if (! expand_table(hashp)) return(NULL); } return (&(curr->key)); }