BITARRAY.CPP
//-------------------------------------------------------------------- 
// Microsoft OLE DB Sample Provider 
// (C) Copyright 1994 - 1996 Microsoft Corporation.  All Rights Reserved. 
// 
// @doc 
// 
// @module BITARRAY.CPP | This contains an implementation of a bit array 
// class currently used by the Internal Buffer to mark released or 
// unreleased rows. 
// 
// 
#include "headers.h" 
#include "bitarray.h" 
 
 
//-------------------------------------------------------------------- 
// @mfunc Constructor for this class 
// 
// @rdesc NONE 
// 
CBitArray::CBitArray 
    ( 
    void 
    ) 
{ 
    m_rgbBit       = NULL; 
    m_cPageMax     = 0; 
    m_cPageCurrent = 0; 
    m_cslotCurrent = 0; 
} 
 
 
//-------------------------------------------------------------------- 
// @mfunc Destructor for this class 
// 
// @rdesc NONE 
// 
CBitArray:: ~CBitArray 
    ( 
    void 
    ) 
{ 
    if (m_rgbBit) 
        { 
        if (m_cPageCurrent) 
            VirtualFree((VOID *) m_rgbBit, m_cPageCurrent *m_cbPage, MEM_DECOMMIT ); 
        VirtualFree((VOID *) m_rgbBit, 0, MEM_RELEASE ); 
        } 
} 
 
 
//-------------------------------------------------------------------- 
// @mfunc Allocate and Initialize the array of bits 
// 
// @rdesc HRESULT indicating routines status 
//      @flag  S_OK          | Initialization succeeded 
//      @flag  E_OUTOFMEMORY | Not enough memory to allocate bit array 
// 
STDMETHODIMP CBitArray::FInit 
    ( 
    ULONG cslotMax,     //@parm IN  | Maximum number of slot 
    ULONG cbPage        //@parm IN  | Count of bytes per page 
    ) 
{ 
    ULONG cPage; 
    ULONG ib; 
 
    cPage = (cslotMax / 8 + 1) / cbPage + 1; 
    m_rgbBit = (BYTE *) VirtualAlloc( NULL, cbPage *cPage, MEM_RESERVE, PAGE_READWRITE ); 
 
    if (m_rgbBit == NULL) 
        return ResultFromScode( E_OUTOFMEMORY ); 
 
    m_cPageMax = cPage; 
 
    m_cbPage = cbPage; 
 
    for (ib =0; ib < 8; ib++) 
        m_rgbBitMask[ib] = (1 << ib); 
    return ResultFromScode( S_OK ); 
} 
 
 
//-------------------------------------------------------------------- 
// @mfunc Set a range of bit slots 
// 
// @rdesc HRESULT indicating routines status 
//      @flag  S_OK          | Initialization succeeded 
//      @flag  E_OUTOFMEMORY | Not enough memory to allocate bit array 
// 
STDMETHODIMP CBitArray::SetSlots 
    ( 
    ULONG islotFirst,   //@parm IN | First slot in range to set 
    ULONG islotLast             //@parm IN | Last slot in range to set 
    ) 
{ 
    ULONG islot; 
 
    if (islotLast >=    m_cslotCurrent) 
        { 
        ULONG cPageAdd; 
 
        cPageAdd = ((islotLast - m_cslotCurrent + 1) / 8 + 1) / m_cbPage + 1; 
 
        if ((cPageAdd + m_cPageCurrent) > m_cPageMax 
            || VirtualAlloc( m_rgbBit + m_cPageCurrent*m_cbPage, cPageAdd *m_cbPage, MEM_COMMIT, PAGE_READWRITE ) == NULL) 
            return ResultFromScode( E_OUTOFMEMORY ); 
 
        memset( m_rgbBit + m_cPageCurrent*m_cbPage, 0x00, cPageAdd *m_cbPage ); 
        m_cPageCurrent += cPageAdd; 
        m_cslotCurrent += cPageAdd *m_cbPage *8; 
        } 
 
    // Only do this top section 
    // if we have at least 2 byte's worth of bits to set. 
    // Although no real speedup until we have 3 byte's worth. 
    // Note really ought to be ((ilast-ifirst+1) >= 2*8). 
    // (Note could use CHAR_BIT, num bits in a char.) 
    // Also optimized end cases, so nothing is done 
    // if the start or end is byte aligned. 
    // Need this copied into ResetSlots. 
 
    //if((islotLast -islotFirst) > 2*sizeof(BYTE)) 
    if (islotLast - islotFirst > 2 * 8) 
        { 
        ULONG ibFirst, ibLast; 
        int iFixFirst, iFixLast; 
 
        ibFirst = islotFirst / 8; 
        ibLast  = islotLast / 8; 
        iFixFirst = (islotFirst % 8 != 0);  // set to 1 if first byte not totally set 
        iFixLast  = (islotLast % 8 != 7);   // set to 1 if last  byte not totally set 
 
        if (iFixFirst) 
            for (islot = islotFirst; (islot / 8) == ibFirst; islot++) 
                m_rgbBit[islot / 8] |= m_rgbBitMask[islot % 8]; 
 
        memset( &m_rgbBit[ibFirst + iFixFirst], 0xff, ibLast - ibFirst + 1 - iFixFirst - iFixLast ); 
 
        if (iFixLast) 
            for (islot = islotLast; (islot / 8) == ibLast; islot--) 
                m_rgbBit[islot / 8] |= m_rgbBitMask[islot % 8]; 
        } 
    else 
        { 
        for (islot = islotFirst; islot <= islotLast; islot++) 
            m_rgbBit[islot / 8] |= m_rgbBitMask[islot % 8]; 
        } 
 
    return ResultFromScode( S_OK ); 
} 
 
 
//-------------------------------------------------------------------- 
// @mfunc Clear all bit slots 
// 
// @rdesc NONE 
// 
VOID CBitArray::ResetAllSlots 
    ( 
    void 
    ) 
{ 
    memset( m_rgbBit, 0x00, m_cPageCurrent*m_cbPage ); 
} 
 
 
//-------------------------------------------------------------------- 
// @mfunc Reset a range of slots 
// 
// @rdesc HRESULT indicating routines status 
//      @flag  S_OK | Reset Succeeded 
// 
STDMETHODIMP CBitArray::ResetSlots 
    ( 
    ULONG islotFirst,   //@parm IN | First slot in range to reset 
    ULONG islotLast     //@parm IN | Last slot in range to reset 
    ) 
{ 
    ULONG ibFirst, ibLast, islot; 
 
    if (islotFirst < m_cslotCurrent) 
        { 
        if (islotLast >=    m_cslotCurrent) 
            islotLast = m_cslotCurrent - 1; 
 
        if ((islotLast - islotFirst) > 2*8) 
            { 
            ibFirst = islotFirst / 8; 
            ibLast  = islotLast / 8; 
            for (islot = islotFirst; (islot / 8) == ibFirst; islot++) 
                m_rgbBit[islot / 8] &= ~m_rgbBitMask[islot % 8]; 
            memset( &m_rgbBit[ibFirst + 1], 0x00, ibLast - ibFirst - 1 ); 
            for (islot = islotLast; (islot / 8) == ibLast; islot--) 
                m_rgbBit[islot / 8] &= ~m_rgbBitMask[islot % 8]; 
            } 
        else 
            { 
            for (islot = islotFirst; islot <= islotLast; islot++) 
                m_rgbBit[islot / 8] &= ~m_rgbBitMask[islot % 8]; 
            } 
        } 
 
    return ResultFromScode( S_OK ); 
} 
 
 
//-------------------------------------------------------------------- 
// @mfunc Determines if any bits are set 
// 
// @rdesc HRESULT indicating routines status 
//      @flag  S_OK     | Array is Empty 
//      @flag  S_FALSE  | Array contains set bits 
// 
STDMETHODIMP CBitArray::ArrayEmpty 
    ( 
    void 
    ) 
{ 
    if (m_cPageCurrent) 
        { 
        ULONG idw, cdw, *rgdw; 
 
        cdw = m_cPageCurrent * (m_cbPage / sizeof( ULONG )); 
        rgdw = (ULONG *) m_rgbBit; 
        for (idw =0; idw < cdw; idw++) 
            if (rgdw[idw]) 
                return ResultFromScode( S_FALSE ); 
        } 
    return ResultFromScode( S_OK ); 
} 
 
 
 
//-------------------------------------------------------------------- 
// @mfunc Determine if a particular bit slot is set 
// 
// @rdesc HRESULT indicating routines status 
//      @flag  S_OK          | Slot is set 
//      @flag  E_OUTOFMEMORY | Slot is not set 
// 
STDMETHODIMP CBitArray::IsSlotSet 
    ( 
    ULONG islot                 //@parm IN | Bit slot to check 
    ) 
{ 
    if (islot >= m_cslotCurrent || (m_rgbBit[islot / 8] & m_rgbBitMask[islot % 8]) == 0x00) 
        return ResultFromScode( S_FALSE );  // not set 
    else 
        return ResultFromScode( S_OK ); // is set 
} 
 
 
//-------------------------------------------------------------------- 
// @mfunc Find the first set slot within the bit array given a starting 
// position 
// 
// @rdesc HRESULT indicating routines status 
//      @flag  S_OK          | Initialization succeeded 
//      @flag  E_OUTOFMEMORY | Not enough memory to allocate bit array 
// 
STDMETHODIMP CBitArray::FindSet 
    ( 
    ULONG islotStart,   //@parm IN | Starting slot to search from 
    ULONG islotLimit,   //@parm IN | Number of slots to check 
    ULONG *pislot       //@parm OUT | Index of first set slot 
    ) 
{ 
    ULONG ibStart, ibLimit, idwStart, idwLimit, ibEnd, ib, islot, islotEnd, idw, *pdw; 
 
    if (islotStart > islotLimit) 
        { 
        ibStart  = islotStart / 8; 
        ibLimit  = islotLimit / 8; 
        if ((ibStart - ibLimit) > 1) 
            { 
            islotEnd = ibStart*8; 
            for (islot = islotStart; islot >= islotEnd; islot--) 
                if (m_rgbBit[islot / 8] & m_rgbBitMask[islot % 8]) 
                    { 
                    *pislot = islot; 
                    return ResultFromScode( S_OK ); 
                    } 
            idwStart = islotStart / 32; 
            idwLimit = islotLimit / 32; 
            if (idwStart - idwLimit > 1) 
                { 
                ibEnd = idwStart*4; 
                for (ib = ibStart - 1; ib >= ibEnd; ib--) 
                    if (m_rgbBit[ib]) 
                        { 
                        islot = ib*8 + 7; 
                        goto Found1; 
                        } 
                for (pdw = (ULONG *) & m_rgbBit[ (idwStart - 1) *4], idw = idwStart - 1; idw > idwLimit; idw--, pdw--) 
                    if (*pdw) 
                        { 
                        islot = idw*32 + 31; 
                        goto Found1; 
                        } 
                ib = (idwLimit*4 + 3); 
                } 
            else 
                ib = ibStart - 1; 
            for (; ib > ibLimit; ib--) 
                if (m_rgbBit[ib]) 
                    { 
                    islot = ib*8 + 7; 
                    goto Found1; 
                    } 
            islot = (ibLimit*8 + 7); 
            } 
        else 
            islot = islotStart; 
 
        Found1: 
        for (; islot >= islotLimit; islot--) 
            if (m_rgbBit[islot / 8] & m_rgbBitMask[islot % 8]) 
                { 
                *pislot = islot; 
                return ResultFromScode( S_OK ); 
                } 
        return ResultFromScode( S_FALSE );  // not found 
        } 
    else 
        return ResultFromScode( E_FAIL ); 
}