/******************************************************************************\ * This is a part of the Microsoft Source Code Samples. * Copyright (C) 1993-1997 Microsoft Corporation. * All rights reserved. * This source code is only intended as a supplement to * Microsoft Development Tools and/or WinHelp documentation. * See these sources for detailed information regarding the * Microsoft samples programs. \******************************************************************************/ /****************************** Module Header ******************************* * Module Name: GBIT.C * * Bitmap allocation routines to manage a bit-mapped free list, and find * free sections. * * Functions: * * gbit_set() * gbit_init() * gbit_alloc() * gbit_free() * gbit_findfree() * * Comments: * * Each map is an array of unsigned longs where bit 0 of the first * long represents block 1. * ****************************************************************************/ #include #include "gutils.h" BOOL gbit_set(DWORD FAR * map, long blknr, long nblks, BOOL op_set); /*************************************************************************** * Function: gbit_init * * Purpose: * * Initialise a pre-allocated map of ulongs to represent a free * area of nblks */ void APIENTRY gbit_init(DWORD FAR * map, long nblks) { long i; long leftover = nblks % 32; long blks = nblks / 32; DWORD last = 0; for (i=0; i < blks; i++) { map[i] = 0xffffffff; } for (i = 0; i < leftover; i++) { last = (last << 1) | 1; } if(leftover) map[blks] = last; } /*************************************************************************** * Function: gbit_alloc * * Purpose: * * Mark a region starting at blknr for nblks, as busy (ie 0) */ BOOL APIENTRY gbit_alloc(DWORD FAR * map, long blknr, long nblks) { return(gbit_set(map, blknr, nblks, FALSE)); } /*************************************************************************** * Function: gbit_set * * Purpose: * * Mark region - if op_set, to 1s, otherwise to 0s */ BOOL gbit_set(DWORD FAR * map, long blknr, long nblks, BOOL op_set) { long first; long last; long fullwords; long startbit, startword; long i; DWORD dword = 0; blknr--; first = min(32 - (blknr % 32), nblks); nblks -= first; last = nblks % 32; fullwords = (nblks - last) / 32; startword = blknr / 32; startbit = blknr % 32; for (i = 0; i < first; i++) { dword = (dword << 1) | 1; } dword <<= startbit; if (op_set) { map[startword] |= dword; dword = 0xffffffff; } else { map[startword] &= ~dword; dword = 0; } startword++; for (i = 0; i < fullwords; i++) { map[startword+i] = dword; } startword += fullwords; for(i = 0, dword = 0; i < last; i++) { dword = (dword << 1) | 1; } if (last) { if (op_set) { map[startword] |= dword; } else { map[startword] &= ~dword; } } return(TRUE); } /*************************************************************************** * Function: gbit_free * * Purpose: * * Mark region of nblks starting at blknr to 0s - ie not busy */ BOOL APIENTRY gbit_free(DWORD FAR * map, long blknr, long nblks) { return(gbit_set(map, blknr, nblks, TRUE)); } /*************************************************************************** * Function: gbit_findfree * * Purpose: * * Find a free segment (ie contiguous sequence of 1s) of nblks in length. * If not found, find longest sequence. Store address of segment in *blknr. * * Return value is nr of blks in sequence found. Region is *not* marked busy. */ long APIENTRY gbit_findfree(DWORD FAR* map, long nblks, long mapsize, long FAR * blknr) { long curblk, startblk, len, i; long startbit, nfull, nlast, nbitsleft; DWORD mask; long mapblks = (mapsize + 31) / 32; long aubegin = 0, aulen = 0; long curbit = 0; /* main loop looking at segments */ for (curblk = 0; curblk < mapblks; ) { loop: /* loop finding first 1 */ for (; curblk < mapblks; curblk++, curbit = 0) { if (map[curblk] > 0) { break; } } if (curblk >= mapblks) break; /* find first 1 in this long */ startblk = curblk; for (mask = 1, i = 0; i < curbit; i++) { mask <<= 1; } for(; curbit < 32; curbit++, mask <<= 1) { if (map[curblk] & mask) { break; } } if (curbit >= 32) { /* abandon this word - start again with next word */ curblk++; curbit = 0; goto loop; } /* we've now found a 1 - calc remaining * bits in this word, complete words etc required. */ startbit = curbit; nbitsleft = min( (32 - curbit), nblks); nfull = (nblks - nbitsleft) / 32; nlast = (nblks - nbitsleft) % 32; /* check for required sequence within this word */ for (i = 0; i < nbitsleft; i++, curbit++, mask <<= 1) { if ((map[curblk] & mask) == 0) { /* abandon and start again - start * next pass at curbit in same word */ /* store free region if longest yet */ if (i > aulen) { aulen = i; aubegin = curblk * 32 + startbit +1; } goto loop; } } /* check for nfull full words */ for (curblk++; curblk <= startblk + nfull; curblk++) { if (curblk >= mapblks) { /* end of map - abandon here and exit at top * of loop */ len = nbitsleft + ((curblk - (startblk + 1)) * 32); if (len > aulen) { aubegin = startblk * 32 + startbit + 1; aulen = len; } goto loop; } if (map[curblk] != 0xffffffff) { /* not a full word - start again at this bit */ len = 0; curbit = 0; for (mask = 1; mask & map[curblk]; mask <<= 1) { len++; curbit++; } len += nbitsleft + (curblk - (startblk+ 1)) * 32; if (len > aulen) { aulen = len; aubegin = startblk * 32 + startbit + 1; } /* continue with current blk, bit */ goto loop; } } /* left-over bits required in last word */ mask = 1; for (curbit = 0; curbit < nlast; curbit++, mask <<= 1) { if ((map[curblk] & mask) == 0) { len = nbitsleft + (nfull * 32); len += curbit; if (len > aulen) { aulen = len; aubegin = startblk * 32 + startbit + 1; } goto loop; } } /* ok - found a block big enough! */ aubegin = startblk * 32 + startbit + 1; *blknr = aubegin; return(nblks); } /* end of map - return longest sequence */ *blknr = aubegin; return(aulen); }