1976 lines
46 KiB
C++
1976 lines
46 KiB
C++
// Indicate.cpp
|
|
|
|
// Implementation for CIndicatorSet class.
|
|
|
|
// Created 8 September 1992 by Ron Murray
|
|
|
|
#include "stdafx.h"
|
|
#include "memex.h"
|
|
#include "indicate.h"
|
|
#include "Util.h"
|
|
#include "BitUtils.h"
|
|
#include "Compress.h"
|
|
#include "CallBkQ.h"
|
|
#include "AbrtSrch.h"
|
|
|
|
// The ShiftLeft and ShiftRight functions are necessary because the C definitions
|
|
// for << and >> are broken when the shift amount equals the width of the object
|
|
// being shifted. Another case where broken hardware is enshrined in a language
|
|
// standard!
|
|
|
|
inline UINT ShiftLeft(UINT ulValue, UINT cBits)
|
|
{
|
|
return((cBits < 32)? ulValue << cBits : 0);
|
|
}
|
|
|
|
inline UINT ShiftRight(UINT ulValue, UINT cBits)
|
|
{
|
|
return((cBits < 32)? ulValue >> cBits : 0);
|
|
}
|
|
|
|
CIndicatorSet::CIndicatorSet() : CRCObject WithType("IndicatorSet")
|
|
{
|
|
m_fFromFileImage = FALSE;
|
|
m_cEntries = 0;
|
|
m_how_constructed = Unbuilt;
|
|
m_paCumulativeSums = NULL;
|
|
m_paulBits = NULL;
|
|
m_fCountsValid = FALSE;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::NewIndicatorSet(UINT cItems, BOOL fFillWithOnes)
|
|
{
|
|
CIndicatorSet *pis= NULL;
|
|
|
|
__try
|
|
{
|
|
pis= New CIndicatorSet();
|
|
|
|
pis->InitialIndicatorSet(cItems, fFillWithOnes);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pis)
|
|
{
|
|
delete pis; pis= NULL;
|
|
}
|
|
}
|
|
|
|
return pis;
|
|
}
|
|
|
|
void CIndicatorSet::InitialIndicatorSet(UINT cItems, BOOL fFillWithOnes)
|
|
{
|
|
// Creates an indicator set containing cItems entry slots.
|
|
|
|
m_how_constructed = From_Count;
|
|
|
|
m_cEntries= cItems;
|
|
|
|
int cSums= 1 + (cItems + BITS_PER_SUM - 1) / BITS_PER_SUM;
|
|
|
|
int cbBits= sizeof(UINT ) * ((cItems + 31) / 32);
|
|
|
|
PBYTE pb= (PBYTE) VAlloc(FALSE, cbBits + cSums * sizeof(UINT ));
|
|
|
|
m_paCumulativeSums= (PUINT ) pb;
|
|
|
|
m_paulBits= (PUINT ) (pb + cSums * sizeof(UINT ));
|
|
|
|
m_fCountsValid= TRUE; // We make this true in the code below.
|
|
|
|
if (!fFillWithOnes)
|
|
{
|
|
memset(pb, 0, cbBits + cSums * sizeof(UINT ));
|
|
return;
|
|
}
|
|
|
|
memset(m_paulBits, 0xFF, cbBits);
|
|
|
|
UINT *pSums= m_paCumulativeSums, cBitsLeft= cItems, sum;
|
|
|
|
for (*pSums++ = sum = 0; --cSums; )
|
|
{
|
|
int increment= (cBitsLeft > BITS_PER_SUM)? BITS_PER_SUM : cBitsLeft;
|
|
|
|
*pSums++= sum+= increment;
|
|
|
|
cBitsLeft-= increment;
|
|
}
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::NewIndicatorSet(UINT cItems, UINT iFirstOne, UINT cOnes)
|
|
{
|
|
CIndicatorSet *pis= NULL;
|
|
|
|
__try
|
|
{
|
|
pis= New CIndicatorSet();
|
|
|
|
pis->InitialIndicatorSet(cItems, iFirstOne, cOnes);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pis)
|
|
{
|
|
delete pis; pis= NULL;
|
|
}
|
|
}
|
|
|
|
return pis;
|
|
}
|
|
|
|
void CIndicatorSet::InitialIndicatorSet(UINT cItems, UINT iFirstOne, UINT cOnes)
|
|
{
|
|
m_how_constructed = From_Bits;
|
|
|
|
m_paulBits= (PUINT ) VAlloc(TRUE, sizeof(UINT) * ((cItems+31)/32));
|
|
|
|
int iDWordFirst = iFirstOne / 32;
|
|
int iBitFirst = iFirstOne % 32;
|
|
|
|
int iLastOne = iFirstOne + cOnes - 1;
|
|
|
|
int iDWordLast = iLastOne / 32;
|
|
int iBitLast = iLastOne % 32;
|
|
|
|
if (iDWordFirst == iDWordLast) m_paulBits[iDWordFirst] |= ShiftLeft(~ShiftLeft(~UINT(0), cOnes), iBitFirst);
|
|
else
|
|
{
|
|
if (iBitFirst)
|
|
{
|
|
m_paulBits[iDWordFirst] |= ShiftLeft(~UINT(0), iBitFirst);
|
|
|
|
iDWordFirst++;
|
|
}
|
|
|
|
if (iBitLast != 31)
|
|
{
|
|
m_paulBits[iDWordLast] |= ShiftRight(~UINT(0), 31 - iBitLast);
|
|
iDWordLast--;
|
|
}
|
|
|
|
int cFullDWords;
|
|
|
|
PUINT pui;
|
|
|
|
cFullDWords= 1 + iDWordLast - iDWordFirst;
|
|
|
|
ASSERT(cFullDWords >= 0);
|
|
|
|
for (pui= &m_paulBits[iDWordFirst]; cFullDWords--; ) *pui++ = ~UINT(0);
|
|
}
|
|
|
|
SetupFromBitVector(cItems);
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::NewIndicatorSet(UINT cItems, PUINT paulBitVector, BOOL fFromFile)
|
|
{
|
|
CIndicatorSet *pis= NULL;
|
|
|
|
__try
|
|
{
|
|
pis= New CIndicatorSet();
|
|
|
|
pis->InitialIndicatorSet(cItems, paulBitVector, fFromFile);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pis)
|
|
{
|
|
delete pis; pis= NULL;
|
|
}
|
|
}
|
|
|
|
return pis;
|
|
}
|
|
|
|
extern BYTE acBits[];
|
|
extern BYTE acLeadingZeroes[];
|
|
|
|
void CIndicatorSet::InitialIndicatorSet(UINT cItems, PUINT paulBitVector, BOOL fFromFile)
|
|
{
|
|
m_how_constructed = From_Bits;
|
|
|
|
m_paulBits= paulBitVector;
|
|
|
|
SetupFromBitVector(cItems, fFromFile);
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::NewIndicatorSet(CCompressedSet *pcs, UINT cbits)
|
|
{
|
|
CIndicatorSet *pis= NULL;
|
|
|
|
__try
|
|
{
|
|
pis= New CIndicatorSet();
|
|
|
|
pis->InitialIndicatorSet(pcs, cbits);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pis)
|
|
{
|
|
delete pis; pis= NULL;
|
|
}
|
|
}
|
|
|
|
return pis;
|
|
}
|
|
|
|
void CIndicatorSet::InitialIndicatorSet(CCompressedSet *pcs, UINT cbits)
|
|
{
|
|
m_how_constructed = From_Bits;
|
|
|
|
ASSERT(!cbits || cbits >= pcs->ItemCount());
|
|
|
|
if (!cbits) cbits = pcs->ItemCount() ;
|
|
|
|
UINT cdw= (cbits + 31) >> 5;
|
|
|
|
m_paulBits= PUINT(VAlloc(TRUE, cdw * sizeof(UINT)));
|
|
|
|
SetupFromBitVector(cbits, FALSE);
|
|
|
|
pcs->IndicateMembers(this);
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::NewIndicatorSet(UINT cItems, PUINT pafMasks, UINT fMask, UINT value)
|
|
{
|
|
CIndicatorSet *pis= NULL;
|
|
|
|
__try
|
|
{
|
|
pis= New CIndicatorSet();
|
|
|
|
pis->InitialIndicatorSet(cItems, pafMasks, fMask, value);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pis)
|
|
{
|
|
delete pis; pis= NULL;
|
|
}
|
|
}
|
|
|
|
return pis;
|
|
}
|
|
|
|
void CIndicatorSet::InitialIndicatorSet(UINT cItems, PUINT pafMasks, UINT fMask, UINT value)
|
|
{
|
|
m_how_constructed = From_Bits;
|
|
|
|
register PUINT pui, paf;
|
|
register UINT ui, cBits;
|
|
|
|
register UINT cChunks= (cItems+31) / 32;
|
|
|
|
m_paulBits= (PUINT ) VAlloc(FALSE, sizeof(UINT) * cChunks);
|
|
|
|
cBits= cItems % 32;
|
|
|
|
if (!cBits) cBits=32;
|
|
|
|
for (paf= pafMasks + cItems, pui= m_paulBits + cChunks; cChunks--; cBits=32)
|
|
{
|
|
for (ui= 0; cBits--; ) ui= (ui << 1) | (value == (fMask & *--paf));
|
|
|
|
*--pui= ui;
|
|
}
|
|
|
|
SetupFromBitVector(cItems);
|
|
}
|
|
|
|
void CIndicatorSet::SetupFromBitVector(UINT cItems, BOOL fFromFile)
|
|
{
|
|
// Creates an indicator set around a bit vector, paulBitVector.
|
|
// The number of entries in that bit vector is given by cItems.
|
|
|
|
// NOTE: paulBitVector is assumed to point to a VAlloc object.
|
|
|
|
m_fFromFileImage = fFromFile;
|
|
|
|
m_how_constructed = From_Bits;
|
|
ASSERT(m_how_constructed);
|
|
|
|
m_cEntries = cItems;
|
|
|
|
if (fFromFile) m_paCumulativeSums= NULL;
|
|
else
|
|
{
|
|
UINT cSums= 1 + (cItems + BITS_PER_SUM - 1) / BITS_PER_SUM;
|
|
|
|
m_paCumulativeSums= (PUINT ) VAlloc(FALSE, cSums * sizeof(UINT ));
|
|
}
|
|
|
|
m_fCountsValid= FALSE;
|
|
}
|
|
|
|
void CIndicatorSet::ConstructBitCounts()
|
|
{
|
|
UINT cSums= 1 + (m_cEntries + BITS_PER_SUM - 1) / BITS_PER_SUM;
|
|
|
|
UINT cBits= m_cEntries % 32;
|
|
|
|
if (m_cEntries && cBits && !m_fFromFileImage) m_paulBits[(m_cEntries-1)/32] &= ~ShiftLeft(~UINT(0), cBits);
|
|
|
|
PUINT pulSum;
|
|
|
|
UINT ulSum;
|
|
|
|
UINT cbChunk, cb, cbBits= (m_cEntries+7)/8;
|
|
|
|
PBYTE pb;
|
|
|
|
for (pb= (PBYTE) m_paulBits, pulSum= m_paCumulativeSums+1; cbBits; cbBits-= cbChunk)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
for (ulSum= 0, cb= cbChunk= (cbBits <= BITS_PER_SUM/8)? cbBits : BITS_PER_SUM/8;
|
|
cb--;
|
|
) ulSum += acBits[*pb++];
|
|
|
|
*pulSum++ = ulSum;
|
|
}
|
|
|
|
UINT c;
|
|
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
for (pulSum= m_paCumulativeSums+1, c= cSums-1; c--; pulSum++) *pulSum+= *(pulSum-1);
|
|
|
|
m_fCountsValid= TRUE;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::NewIndicatorSet(CIndicatorSet *pis)
|
|
{
|
|
CIndicatorSet *pisResult= NULL;
|
|
|
|
__try
|
|
{
|
|
pisResult= New CIndicatorSet();
|
|
|
|
pisResult->InitialIndicatorSet(pis);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pisResult)
|
|
{
|
|
delete pisResult; pisResult= NULL;
|
|
}
|
|
}
|
|
|
|
return pisResult;
|
|
}
|
|
|
|
void CIndicatorSet::InitialIndicatorSet(CIndicatorSet *pis)
|
|
{
|
|
m_how_constructed= From_Bits;
|
|
|
|
UINT cdw= (pis->m_cEntries + 31) >> 5;
|
|
|
|
m_paulBits= (PUINT) VAlloc(FALSE, cdw * sizeof(UINT));
|
|
|
|
CopyMemory(m_paulBits, pis->m_paulBits, cdw * sizeof(UINT));
|
|
|
|
SetupFromBitVector(pis->m_cEntries);
|
|
}
|
|
|
|
CIndicatorSet::~CIndicatorSet()
|
|
{
|
|
// Releases the local allocations used to construct the indicator set.
|
|
|
|
switch(m_how_constructed)
|
|
{
|
|
case Unbuilt:
|
|
|
|
break;
|
|
|
|
case From_Count:
|
|
|
|
if (m_paCumulativeSums) VFree(m_paCumulativeSums);
|
|
|
|
break;
|
|
|
|
case From_Bits:
|
|
|
|
if (!m_fFromFileImage)
|
|
{
|
|
if (m_paCumulativeSums) VFree(m_paCumulativeSums);
|
|
if (m_paulBits ) VFree(m_paulBits );
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CIndicatorSet::StoreImage(CPersist *pDiskImage)
|
|
{
|
|
CCompressedSet *pcs = NULL;
|
|
|
|
__try
|
|
{
|
|
pcs= CCompressedSet::NewCompressedSet(this);
|
|
|
|
pcs->StoreImage(pDiskImage);
|
|
}
|
|
__finally
|
|
{
|
|
if (pcs) { delete pcs; pcs= NULL; }
|
|
}
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::CreateImage(CPersist *pDiskImage)
|
|
{
|
|
CIndicatorSet *pis = NULL;
|
|
CCompressedSet *pcs = NULL;
|
|
|
|
__try
|
|
{
|
|
pcs= CCompressedSet::CreateImage(pDiskImage);
|
|
|
|
pis= CIndicatorSet::NewIndicatorSet(pcs);
|
|
}
|
|
__finally
|
|
{
|
|
if (pcs) { delete pcs; pcs= NULL; }
|
|
|
|
if (_abnormal_termination())
|
|
{
|
|
delete pis; pis= NULL;
|
|
}
|
|
}
|
|
|
|
return pis;
|
|
}
|
|
|
|
void CIndicatorSet::SkipImage(CPersist *pDiskImage)
|
|
{
|
|
CCompressedSet::SkipImage(pDiskImage);
|
|
}
|
|
|
|
void CIndicatorSet::ConnectImage(CPersist *pDiskImage)
|
|
{
|
|
}
|
|
|
|
void CIndicatorSet::ClearAll()
|
|
{
|
|
// Turns off all the bits in the indicator set. Also resets the cumulative
|
|
// bit counts.
|
|
|
|
UINT cBytes= (m_cEntries + 7)/ 8;
|
|
|
|
memset(m_paulBits, 0, cBytes);
|
|
|
|
UINT cSums= 1 + (m_cEntries + BITS_PER_SUM - 1)/BITS_PER_SUM;
|
|
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
memset(m_paCumulativeSums, 0, cSums * sizeof(UINT ));
|
|
|
|
m_fCountsValid= TRUE;
|
|
}
|
|
|
|
int CIndicatorSet::ChangeBit(long iBit, UINT usMethod)
|
|
{
|
|
// Changes the value of bit slot iBit. The parameter usMethod indicates
|
|
// how the bit slot is to be changed.
|
|
//
|
|
// The result value will be:
|
|
//
|
|
// 0 -- for no change made
|
|
// 1 -- for a 0 bit going to 1
|
|
// -1 -- for a 1 bit going to 0
|
|
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(iBit >= 0 && iBit < long(m_cEntries));
|
|
|
|
UINT iDWord= IDWORD_OF_IBIT(iBit);
|
|
|
|
UINT dwMask= 1 << IBIT_RESIDUE(iBit);
|
|
|
|
UINT dwOld= m_paulBits[iDWord];
|
|
UINT dwNew;
|
|
|
|
switch (usMethod)
|
|
{
|
|
case CLEAR_BIT: dwNew= dwOld &~ dwMask; break;
|
|
case SET_BIT: dwNew= dwOld | dwMask; break;
|
|
case TOGGLE_BIT: dwNew= dwOld ^ dwMask; break;
|
|
}
|
|
|
|
m_paulBits[iDWord]= dwNew;
|
|
|
|
if (dwNew == dwOld) return 0;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
int increment= (dwOld < dwNew)? 1 : -1;
|
|
|
|
#if 0
|
|
|
|
int cSums= 1 + (m_cEntries+BITS_PER_SUM-1)/BITS_PER_SUM;
|
|
|
|
int * pulLimit= m_paCumulativeSums+cSums;
|
|
|
|
int * pul;
|
|
|
|
for (pul= m_paCumulativeSums+1+(iBit/BITS_PER_SUM); pul != pulLimit ; )
|
|
*pul++ += increment;
|
|
|
|
#endif
|
|
|
|
return increment;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::CopyFrom(CIndicatorSet *pis)
|
|
{
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
CopyMemory(m_paulBits, pis->m_paulBits, sizeof(UINT) * ((m_cEntries+31) >> 5));
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::ANDWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ) *puiDest++ &= *puiSrc++;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::NANDWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ++puiDest) *puiDest= ~(*puiDest & *puiSrc++);
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::ORWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ) *puiDest++ |= *puiSrc++;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::NORWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ++puiDest) *puiDest= ~(*puiDest | *puiSrc++);
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::LESSWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ++puiDest) *puiDest= (~*puiDest) & *puiSrc++;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::LEQWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ++puiDest) *puiDest= (~*puiDest) | *puiSrc++;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::EQVWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ++puiDest) *puiDest= ~(*puiDest ^ *puiSrc++);
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::NEQWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ) *puiDest++ ^= *puiSrc++;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::GTRWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ) *puiDest++ &= ~*puiSrc++;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::GEQWith(CIndicatorSet *pis)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
ASSERT(m_cEntries == pis->m_cEntries);
|
|
|
|
register PUINT puiDest= m_paulBits, puiSrc= pis->m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; ) *puiDest++ |= ~*puiSrc++;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::Catenate(CIndicatorSet *pis)
|
|
{
|
|
PUINT paulBits = NULL;
|
|
PUINT paCumulativeSums = NULL;
|
|
|
|
__try
|
|
{
|
|
UINT cBitsResult= m_cEntries + pis->m_cEntries;
|
|
|
|
UINT cDWordBits= (cBitsResult+31)/32;
|
|
|
|
UINT cSums= 1 + (cBitsResult + BITS_PER_SUM - 1) / BITS_PER_SUM;
|
|
|
|
paulBits = (PUINT ) VAlloc(FALSE, cDWordBits * sizeof(UINT));
|
|
paCumulativeSums = (PUINT ) VAlloc(TRUE , cSums * sizeof(UINT));
|
|
|
|
MoveBits( m_paulBits, 0, paulBits, 0, m_cEntries);
|
|
MoveBits(pis->m_paulBits, 0, paulBits, m_cEntries, pis->m_cEntries);
|
|
|
|
// Optimization: If m_fCountsValid, we don't have to recompute all the
|
|
// counts. Instead we just need to do the trailing counts.
|
|
|
|
switch (m_how_constructed)
|
|
{
|
|
case From_Count:
|
|
|
|
VFree(m_paulBits); m_paulBits= m_paCumulativeSums= NULL;
|
|
break;
|
|
|
|
case From_Bits:
|
|
|
|
VFree(m_paulBits); m_paulBits = NULL;
|
|
VFree(m_paCumulativeSums); m_paCumulativeSums = NULL;
|
|
break;
|
|
}
|
|
|
|
m_how_constructed = From_Bits;
|
|
|
|
m_paulBits = paulBits; paulBits = NULL;
|
|
m_paCumulativeSums = paCumulativeSums; paCumulativeSums = NULL;
|
|
m_cEntries = cBitsResult;
|
|
m_fCountsValid = FALSE;
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination())
|
|
{
|
|
if (paulBits ) VFree(paulBits );
|
|
if (paCumulativeSums) VFree(paCumulativeSums);
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::Invert()
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
register PUINT puiDest= m_paulBits;
|
|
|
|
register UINT c= (m_cEntries+31)/32;
|
|
|
|
for (; c--; puiDest++) *puiDest= ~*puiDest;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
extern BYTE nescan[256];
|
|
|
|
CIndicatorSet *CIndicatorSet::NEScan()
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
PBYTE pb= (PBYTE) m_paulBits;
|
|
UINT cb= (m_cEntries+7) >> 3;
|
|
BYTE b;
|
|
BYTE bMask;
|
|
|
|
for (bMask= 0; cb--; )
|
|
{
|
|
b=nescan[*pb];
|
|
|
|
bMask= -((*pb++ = b ^ bMask) >> 7);
|
|
}
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
return this;
|
|
}
|
|
|
|
void ClearBits(PUINT pulBase, UINT iBit, UINT cBits)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
pulBase += IDWORD_OF_IBIT(iBit);
|
|
|
|
iBit= IBIT_RESIDUE(iBit);
|
|
|
|
if (iBit)
|
|
{
|
|
UINT cBitsFirst= (iBit+cBits < 32)? cBits : 32 - iBit;
|
|
|
|
*pulBase++ &= ~RawShiftLeft(~RawShiftLeft(~UINT(0), cBitsFirst), iBit);
|
|
|
|
if (!(cBits -= cBitsFirst)) return;
|
|
}
|
|
|
|
UINT cDWords= IDWORD_OF_IBIT(cBits);
|
|
|
|
if (cDWords)
|
|
{
|
|
ZeroMemory(pulBase, cDWords*sizeof(UINT ));
|
|
pulBase += cDWords;
|
|
}
|
|
|
|
if (!(cBits= IBIT_RESIDUE(cBits))) return;
|
|
|
|
*pulBase &= RawShiftLeft(~UINT(0), cBits);
|
|
}
|
|
|
|
void SetBits(PUINT pulBase, UINT iBit, UINT cBits)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
pulBase += IDWORD_OF_IBIT(iBit);
|
|
|
|
iBit= IBIT_RESIDUE(iBit);
|
|
|
|
if (iBit)
|
|
{
|
|
UINT cBitsFirst= (iBit+cBits < 32)? cBits : 32 - iBit;
|
|
|
|
*pulBase++ |= RawShiftLeft(~RawShiftLeft(~UINT(0), cBitsFirst), iBit);
|
|
|
|
if (!(cBits -= cBitsFirst)) return;
|
|
}
|
|
|
|
UINT cDWords= IDWORD_OF_IBIT(cBits);
|
|
|
|
if (cDWords)
|
|
{
|
|
FillMemory(pulBase, cDWords*sizeof(UINT ), 0xFF);
|
|
pulBase += cDWords;
|
|
}
|
|
|
|
if (!(cBits= IBIT_RESIDUE(cBits))) return;
|
|
|
|
*pulBase |= ~RawShiftLeft(~UINT(0), cBits);
|
|
}
|
|
|
|
void MoveBits(PUINT pulSrc, UINT iSrcFirst, PUINT pulDest, UINT iDestFirst, UINT cBits)
|
|
{
|
|
// This routine copys a stream of bits.
|
|
|
|
// The source stream begins iSrcFirst bits from pulSrc.
|
|
// The destination stream begins iDestFirst bits from pulDest.
|
|
// cBits defines the number of bits to copy.
|
|
|
|
// This routine is sensitive to overlaps and will move bits in an order which avoids
|
|
// destructive source/destination collisions.
|
|
|
|
if (!cBits) return;
|
|
|
|
// The pulXXX and iXXXFirst define the location of the first bit source/destination
|
|
// areas. Here we adjust those variables to move pulXXX to the word containing that
|
|
// first bit. iXXXFirst will then lie in the interval [0..31].
|
|
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
pulSrc += IDWORD_OF_IBIT(iSrcFirst );
|
|
pulDest += IDWORD_OF_IBIT(iDestFirst);
|
|
iSrcFirst = IBIT_RESIDUE(iSrcFirst );
|
|
iDestFirst = IBIT_RESIDUE(iDestFirst);
|
|
|
|
if (pulSrc == pulDest && iSrcFirst == iDestFirst) return;
|
|
|
|
if (UINT (pulSrc) >= UINT (pulDest))
|
|
{
|
|
// Copying bits to lower memory addresses
|
|
// Using ++ for DWord pointer increment
|
|
|
|
if (iSrcFirst == iDestFirst)
|
|
{
|
|
// a DWord aligned copy...
|
|
|
|
// First we calculate how many bits we'll copy into the first
|
|
// destination dword.
|
|
|
|
UINT cBitsFirst= (cBits+iDestFirst < 32)? cBits : 32-iDestFirst;
|
|
|
|
// Since the bit stream may fit within the destination dword,
|
|
// we must construct a mask to preserve the other bits in the
|
|
// destination dword.
|
|
|
|
UINT fMask= RawShiftLeft(~ShiftLeft(~UINT(0), cBitsFirst), iDestFirst);
|
|
|
|
*pulDest= (*pulDest & ~fMask) | (*pulSrc++ & fMask);
|
|
|
|
if (!(cBits -= cBitsFirst)) return;
|
|
|
|
// Now we calculate the number of whole dword transfers necessary.
|
|
|
|
UINT cDWords= IDWORD_OF_IBIT(cBits);
|
|
|
|
for (++pulDest; cDWords--; ) *pulDest++ = *pulSrc++;
|
|
|
|
// Finally we must take care of any trailing bits.
|
|
|
|
if (!(cBits= IBIT_RESIDUE(cBits))) return;
|
|
|
|
fMask= RawShiftLeft(~UINT(0), cBits);
|
|
|
|
*pulDest= (fMask & *pulDest) | ((*pulSrc) & ~fMask);
|
|
|
|
return;
|
|
}
|
|
|
|
if (iSrcFirst > iDestFirst)
|
|
{
|
|
// Shift direction is >>
|
|
// AntiShift direction is <<
|
|
|
|
UINT cbitShift = iSrcFirst - iDestFirst;
|
|
UINT cbitAntiShift = 32 - cbitShift;
|
|
|
|
// Calculate bits going into the first destination dword
|
|
// and construct a mask to preserve the other bits.
|
|
|
|
UINT cBitsFirst= (iDestFirst+cBits <32)? cBits : 32 - iDestFirst;
|
|
|
|
UINT fMask= RawShiftLeft(~ShiftLeft(~UINT(0), cBitsFirst), iDestFirst);
|
|
|
|
UINT ulBuff= RawShiftRight(*pulSrc++, cbitShift);
|
|
|
|
UINT ulBuff2= *pulSrc++;
|
|
|
|
*pulDest= (*pulDest & ~fMask) | (fMask & (ulBuff | RawShiftLeft(ulBuff2, cbitAntiShift)));
|
|
|
|
if (!(cBits -= cBitsFirst)) return;
|
|
|
|
ulBuff= RawShiftRight(ulBuff2, cbitShift);
|
|
|
|
UINT cDWords= IDWORD_OF_IBIT(cBits);
|
|
|
|
for (++pulDest; cDWords--; )
|
|
{
|
|
ulBuff2= *pulSrc++;
|
|
|
|
*pulDest++ = ulBuff | RawShiftLeft(ulBuff2, cbitAntiShift);
|
|
ulBuff = RawShiftRight(ulBuff2, cbitShift);
|
|
}
|
|
|
|
if (!(cBits= IBIT_RESIDUE(cBits))) return;
|
|
|
|
fMask= RawShiftLeft(~UINT(0), cBits);
|
|
|
|
*pulDest= (fMask & *pulDest) | ((~fMask) & (ulBuff | RawShiftLeft(*pulSrc, cbitAntiShift)));
|
|
|
|
return;
|
|
}
|
|
|
|
// iSrcFirst < iDestFirst
|
|
// Shift direction is <<
|
|
// AntiShift direction is >>
|
|
|
|
UINT cbitShift = iDestFirst - iSrcFirst;
|
|
UINT cbitAntiShift = 32 - cbitShift;
|
|
|
|
// Calculate bits going into the first destination dword
|
|
// and construct a mask to preserve the other bits.
|
|
|
|
UINT cBitsFirst= (iDestFirst+cBits <32)? cBits : 32 - iDestFirst;
|
|
|
|
UINT fMask= RawShiftLeft(~ShiftLeft(~UINT(0), cBitsFirst), iDestFirst);
|
|
|
|
UINT ulBuff2= *pulSrc++;
|
|
|
|
*pulDest= (*pulDest & ~fMask) | (fMask & RawShiftLeft(ulBuff2, cbitShift));
|
|
|
|
if (!(cBits -= cBitsFirst)) return;
|
|
|
|
UINT ulBuff= RawShiftRight(ulBuff2, cbitAntiShift);
|
|
|
|
UINT cDWords= IDWORD_OF_IBIT(cBits);
|
|
|
|
for (++pulDest; cDWords--; )
|
|
{
|
|
UINT ulBuff2= *pulSrc++;
|
|
|
|
*pulDest++ = ulBuff | RawShiftLeft(ulBuff2, cbitShift);
|
|
ulBuff = RawShiftRight(ulBuff2, cbitAntiShift);
|
|
}
|
|
|
|
if (!(cBits= IBIT_RESIDUE(cBits))) return;
|
|
|
|
fMask= RawShiftLeft(~UINT(0), cBits);
|
|
|
|
*pulDest= (fMask & *pulDest) | ((~fMask) & (ulBuff | RawShiftLeft(*pulSrc, cbitShift)));
|
|
|
|
return;
|
|
}
|
|
|
|
ASSERT(UINT (pulSrc) < UINT (pulDest));
|
|
|
|
// Copying bits to higher memory...
|
|
// Using -- for DWord pointer increment.
|
|
|
|
// iXXXLimit will point just beyond the last bit to be moved.
|
|
|
|
UINT iSrcLimit = iSrcFirst + cBits;
|
|
UINT iDestLimit = iDestFirst + cBits;
|
|
|
|
// Now we'll adjust pulXXX to point to the words containing the highest bit offset.
|
|
|
|
pulSrc += IDWORD_OF_IBIT(iSrcLimit - 1); // The highest source and
|
|
pulDest += IDWORD_OF_IBIT(iDestLimit - 1); // destination dwords we'll touch.
|
|
|
|
// Here we adjust iXXXLimit to mark the limiting boundary in the high word.
|
|
// They will now lie in the interval [1..32].
|
|
|
|
iSrcLimit = 1 + IBIT_RESIDUE(iSrcLimit - 1); // Upper bound on source bits
|
|
iDestLimit = 1 + IBIT_RESIDUE(iDestLimit - 1); // Upper bound on destination bits
|
|
|
|
if (iSrcLimit == iDestLimit)
|
|
{
|
|
// a DWord aligned copy...
|
|
|
|
// First we calculate how many bits we'll copy into the first
|
|
// destination dword.
|
|
|
|
UINT cBitsFirst= (cBits < iDestLimit)? cBits : iDestLimit;
|
|
|
|
// Since the bit stream may fit within the destination dword,
|
|
// we must construct a mask to perserve the other bits in the
|
|
// destination dword.
|
|
|
|
UINT fMask= RawShiftLeft(~ShiftLeft(~UINT(0), cBitsFirst), iDestLimit - cBitsFirst);
|
|
|
|
*pulDest= (*pulDest & ~fMask) | (*pulSrc-- & fMask);
|
|
|
|
if (!(cBits -= cBitsFirst)) return;
|
|
|
|
// Now we calculate the number of whole dword transfers necessary.
|
|
|
|
UINT cDWords= IDWORD_OF_IBIT(cBits);
|
|
|
|
for (--pulDest; cDWords--; ) *pulDest-- = *pulSrc--;
|
|
|
|
// Finally we must take care of any trailing bits.
|
|
|
|
if (!(cBits= IBIT_RESIDUE(cBits))) return;
|
|
|
|
fMask= ~RawShiftLeft(~UINT(0), 32-cBits);
|
|
|
|
*pulDest= (fMask & *pulDest) | ((*pulSrc) & ~fMask);
|
|
|
|
return;
|
|
}
|
|
|
|
if (iSrcLimit < iDestLimit)
|
|
{
|
|
// Shift direction is <<
|
|
// AntiShift direction is >>
|
|
|
|
UINT cbitShift = iDestLimit - iSrcLimit;
|
|
UINT cbitAntiShift = 32 - cbitShift;
|
|
|
|
// Calculate bits going into the first destination dword
|
|
// and construct a mask to preserve the other bits.
|
|
|
|
UINT cBitsFirst= (cBits < iDestLimit)? cBits : iDestLimit;
|
|
|
|
UINT fMask= RawShiftLeft(~ShiftLeft(~UINT(0), cBitsFirst), iDestLimit - cBitsFirst);
|
|
|
|
UINT ulBuff= RawShiftLeft(*pulSrc--, cbitShift);
|
|
|
|
UINT ulBuff2= *pulSrc--;
|
|
|
|
*pulDest= (*pulDest & ~fMask) | (fMask & (ulBuff | RawShiftRight(ulBuff2, cbitAntiShift)));
|
|
|
|
if (!(cBits -= cBitsFirst)) return;
|
|
|
|
ulBuff= RawShiftLeft(ulBuff2, cbitShift);
|
|
|
|
UINT cDWords= IDWORD_OF_IBIT(cBits);
|
|
|
|
for (--pulDest; cDWords--; )
|
|
{
|
|
ulBuff2= *pulSrc--;
|
|
|
|
*pulDest-- = ulBuff | RawShiftRight(ulBuff2, cbitAntiShift);
|
|
ulBuff = RawShiftLeft(ulBuff2, cbitShift);
|
|
}
|
|
|
|
if (!(cBits= IBIT_RESIDUE(cBits))) return;
|
|
|
|
fMask= RawShiftRight(~UINT(0), cBits);
|
|
|
|
*pulDest= (fMask & *pulDest) | ((~fMask) & (ulBuff | RawShiftRight(*pulSrc, cbitAntiShift)));
|
|
|
|
return;
|
|
}
|
|
|
|
// iSrcLimit > iDestLimit
|
|
// Shift direction is >>
|
|
// AntiShift direction is <<
|
|
|
|
UINT cbitShift = iSrcLimit - iDestLimit;
|
|
UINT cbitAntiShift = 32 - cbitShift;
|
|
|
|
// Calculate bits going into the first destination dword
|
|
// and construct a mask to preserve the other bits.
|
|
|
|
UINT cBitsFirst= (cBits < iDestLimit)? cBits : iDestLimit;
|
|
|
|
UINT fMask= RawShiftLeft(~ShiftLeft(~UINT(0), cBitsFirst), iDestLimit - cBitsFirst);
|
|
|
|
UINT ulBuff2= *pulSrc--;
|
|
|
|
*pulDest= (*pulDest & ~fMask) | (fMask & RawShiftRight(ulBuff2, cbitShift));
|
|
|
|
if (!(cBits -= cBitsFirst)) return;
|
|
|
|
UINT ulBuff= RawShiftLeft(ulBuff2, cbitAntiShift);
|
|
|
|
UINT cDWords= IDWORD_OF_IBIT(cBits);
|
|
|
|
for (--pulDest; cDWords--; )
|
|
{
|
|
UINT ulBuff2= *pulSrc--;
|
|
|
|
*pulDest-- = ulBuff | RawShiftRight(ulBuff2, cbitShift);
|
|
ulBuff = RawShiftLeft(ulBuff2, cbitAntiShift);
|
|
}
|
|
|
|
if (!(cBits= IBIT_RESIDUE(cBits))) return;
|
|
|
|
fMask= RawShiftRight(~UINT(0), cBits);
|
|
|
|
*pulDest= (fMask & *pulDest) | ((~fMask) & (ulBuff | RawShiftRight(*pulSrc, cbitShift)));
|
|
|
|
return;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::ShiftIndicators(int cBitsDistance)
|
|
{
|
|
// Positive cBitsDistance values shift the indicator bits to
|
|
// higher index positions. Negative values shift them to lower
|
|
// positions.
|
|
|
|
if (!cBitsDistance) return this;
|
|
|
|
m_fCountsValid= FALSE;
|
|
|
|
BOOL fMovingHigher= cBitsDistance > 0;
|
|
|
|
if ((fMovingHigher? cBitsDistance : - cBitsDistance) >= (int) m_cEntries)
|
|
{
|
|
ClearAll(); return this;
|
|
}
|
|
|
|
if (cBitsDistance > 0)
|
|
{
|
|
MoveBits(m_paulBits, 0, m_paulBits, cBitsDistance, m_cEntries - cBitsDistance);
|
|
ClearBits(m_paulBits, 0, cBitsDistance);
|
|
}
|
|
else
|
|
{
|
|
MoveBits(m_paulBits, -cBitsDistance, m_paulBits, 0, m_cEntries + cBitsDistance);
|
|
ClearBits(m_paulBits, m_cEntries + cBitsDistance, -cBitsDistance);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::TakeIndicators(long cBits)
|
|
{
|
|
PUINT pulBitsNew= NULL;
|
|
|
|
BOOL fNegativeTake= cBits < 0;
|
|
|
|
__try
|
|
{
|
|
if (fNegativeTake) cBits= - cBits;
|
|
|
|
UINT cDWordsNew= IDWORD_OF_IBIT(cBits+31);
|
|
|
|
pulBitsNew= (PUINT) VAlloc(TRUE, cDWordsNew * sizeof(UINT));
|
|
|
|
MoveBits(m_paulBits, 0, pulBitsNew, fNegativeTake? cBits - m_cEntries : 0, m_cEntries);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pulBitsNew)
|
|
{
|
|
VFree(pulBitsNew); pulBitsNew= NULL;
|
|
}
|
|
}
|
|
|
|
return CIndicatorSet::NewIndicatorSet(cBits, pulBitsNew);
|
|
}
|
|
|
|
int CIndicatorSet::ActiveIndices(int iLowBound, int iHighBound,
|
|
int *piOneBits)
|
|
{
|
|
// Returns the number of 1 bits in the interval [iLowBound, iHighBound).
|
|
// If plIndices is non-null, the bit positions will be returned in the
|
|
// area referenced by piOneBits.
|
|
|
|
if (!m_fCountsValid) ConstructBitCounts();
|
|
|
|
int cIndices = 0;
|
|
|
|
int iLowBracket = iLowBound / BITS_PER_SUM;
|
|
int iLimitBracket = (iHighBound + BITS_PER_SUM - 1)/BITS_PER_SUM;
|
|
|
|
int cBitsToSkip = iLowBound % BITS_PER_SUM;
|
|
int cTrailingBits = iHighBound % BITS_PER_SUM;
|
|
|
|
BOOL fCountOnly= !piOneBits;
|
|
|
|
int iSum;
|
|
|
|
PBYTE pb, pbLimit;
|
|
BYTE b, fFinal;
|
|
|
|
for (iSum= iLowBracket; iSum < iLimitBracket ; ++iSum)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
pb= ((PBYTE) m_paulBits) + iSum * (BITS_PER_SUM/8);
|
|
|
|
pbLimit= pb + (BITS_PER_SUM/8);
|
|
|
|
if (cBitsToSkip)
|
|
{
|
|
pb+= cBitsToSkip >> 3;
|
|
|
|
b= (*pb++) & ((~0) << (cBitsToSkip & 7));
|
|
|
|
cBitsToSkip= 0;
|
|
}
|
|
else b= *pb++;
|
|
|
|
if (m_paCumulativeSums[iSum] == m_paCumulativeSums[iSum+1])
|
|
continue;
|
|
|
|
if (iSum < iLimitBracket-1)
|
|
{
|
|
fFinal= 0xFF;
|
|
}
|
|
else
|
|
{
|
|
fFinal= ~((~0) << (cTrailingBits & 7));
|
|
pbLimit+= (cTrailingBits/8) - (BITS_PER_SUM/8);
|
|
}
|
|
|
|
int cb= pbLimit - pb;
|
|
|
|
while (cb)
|
|
{
|
|
if (! --cb) b &= fFinal;
|
|
|
|
while (b)
|
|
{
|
|
int iFirstOne= acLeadingZeroes[b];
|
|
|
|
b &= ~(1 << iFirstOne);
|
|
|
|
++cIndices;
|
|
|
|
if (fCountOnly) continue;
|
|
|
|
*piOneBits++ = iFirstOne + 8 * (pb-1- (PBYTE) m_paulBits);
|
|
}
|
|
|
|
b= *pb++;
|
|
}
|
|
}
|
|
|
|
return(cIndices);
|
|
}
|
|
|
|
UINT CIndicatorSet::ItemCount()
|
|
{
|
|
return m_cEntries;
|
|
}
|
|
|
|
int CIndicatorSet::SelectionCount()
|
|
{
|
|
if (!m_fCountsValid) ConstructBitCounts();
|
|
|
|
return m_paCumulativeSums[(m_cEntries+BITS_PER_SUM-1)/BITS_PER_SUM];
|
|
}
|
|
|
|
int CIndicatorSet::MarkedItems(int iMarked, int *piUnmarked,
|
|
int cMarkedItems)
|
|
{
|
|
// Returns cMarkedItems <take> iMarked <drop> m_paulBits <compress> <iota> ItemCount()
|
|
|
|
if (!m_fCountsValid) ConstructBitCounts();
|
|
|
|
if (!cMarkedItems) return 0;
|
|
|
|
int iCluster= InxBinarySearch(iMarked, m_paCumulativeSums, CBrackets());
|
|
|
|
if (iCluster == -1) return 0;
|
|
|
|
int cItemsLeft= SelectionCount() - iMarked;
|
|
|
|
if (cItemsLeft < cMarkedItems) cMarkedItems= cItemsLeft;
|
|
|
|
if (!piUnmarked) return cMarkedItems;
|
|
|
|
int cItemsToSkip= iMarked - m_paCumulativeSums[iCluster];
|
|
|
|
int c;
|
|
|
|
if (UINT(SelectionCount()) > (ItemCount() >> 6))
|
|
{
|
|
PBYTE pbBase= PBYTE(m_paulBits) + 1;
|
|
PBYTE pb;
|
|
BYTE b;
|
|
|
|
pb = PBCluster(iCluster);
|
|
b = *pb++;
|
|
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
if (cItemsToSkip)
|
|
for (; ; b= *pb++)
|
|
{
|
|
while (b)
|
|
{
|
|
b&= ~ (b ^ (b-1));
|
|
|
|
if (!--cItemsToSkip) break;
|
|
}
|
|
|
|
if (!cItemsToSkip) break;
|
|
}
|
|
|
|
ASSERT(cMarkedItems);
|
|
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
for (c= cMarkedItems; ; b= *pb++)
|
|
{
|
|
while (b)
|
|
{
|
|
UINT iFirstOne= acLeadingZeroes[b];
|
|
|
|
b &= ~(1 << iFirstOne);
|
|
|
|
*piUnmarked++ = iFirstOne + ((pb - pbBase) << 3);
|
|
|
|
if (!--c) break;
|
|
}
|
|
|
|
if (!c) break;
|
|
}
|
|
|
|
return cMarkedItems;
|
|
}
|
|
|
|
for (c= cMarkedItems; ; ++iCluster)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
for (;
|
|
m_paCumulativeSums[iCluster] == m_paCumulativeSums[iCluster+1];
|
|
++iCluster
|
|
);
|
|
|
|
PBYTE pb, pbLimit;
|
|
BYTE b;
|
|
|
|
for (pb= PBCluster(iCluster), pbLimit= pb+BytesPerSum();
|
|
pb != pbLimit;
|
|
++pb
|
|
)
|
|
{
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
for (b= *pb; b ; )
|
|
{
|
|
int iFirstOne= acLeadingZeroes[b];
|
|
|
|
b &= ~(1 << iFirstOne);
|
|
|
|
if (cItemsToSkip)
|
|
{
|
|
--cItemsToSkip;
|
|
continue;
|
|
}
|
|
|
|
*piUnmarked++ = iFirstOne + 8 * (pb - (PBYTE) m_paulBits);
|
|
|
|
if (!--c) return cMarkedItems;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int CIndicatorSet::PredecessorMarkCount(int iItem)
|
|
{
|
|
// Returns +/iItem <take> m_paulBits
|
|
|
|
if (!m_fCountsValid) ConstructBitCounts();
|
|
|
|
ASSERT(UINT (iItem) < m_cEntries);
|
|
|
|
int iSum= iItem/BITS_PER_SUM;
|
|
|
|
int cBitsToCount= iItem % BITS_PER_SUM;
|
|
|
|
int cBytesToCount= cBitsToCount >> 3;
|
|
|
|
int cTrailingBits= cBitsToCount & 7;
|
|
|
|
int cMarks= m_paCumulativeSums[iSum];
|
|
|
|
PBYTE pb= PBCluster(iSum);
|
|
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
while (cBytesToCount--) cMarks += acBits[*pb++];
|
|
|
|
if (cTrailingBits) cMarks += acBits[(*pb) & ~((~0) << cTrailingBits)];
|
|
|
|
return cMarks;
|
|
}
|
|
|
|
CIndicatorSet *CIndicatorSet::MarkedPartitions(CIndicatorSet *pisMarks, BOOL fPartitionedAtEnd)
|
|
{
|
|
// This routine constructs an indicator set which records the partitions of
|
|
// this which are "marked" by pisMarks.
|
|
|
|
|
|
ASSERT(ItemCount() == pisMarks->ItemCount());
|
|
|
|
UINT cPartitions = SelectionCount();
|
|
UINT cBits = ItemCount();
|
|
PUINT pdwBreaks = m_paulBits;
|
|
PUINT pdwMarks = pisMarks->m_paulBits;
|
|
UINT iBreak;
|
|
|
|
if (fPartitionedAtEnd)
|
|
{
|
|
if (!IsBitSet(cBits-1)) ++cPartitions;
|
|
|
|
iBreak= 0;
|
|
}
|
|
else
|
|
{
|
|
if (!IsBitSet(0)) ++cPartitions;
|
|
|
|
iBreak= 1;
|
|
}
|
|
|
|
CIndicatorSet *pisPartitions= NULL;
|
|
|
|
__try
|
|
{
|
|
AttachRef(pisPartitions, CIndicatorSet::NewIndicatorSet(cPartitions));
|
|
|
|
UINT iMark, cBreaks;
|
|
|
|
for (iMark= 0, cBreaks= 0; ; )
|
|
{
|
|
UINT ibitsDelta= Leading0sInRange(pdwMarks, iMark, cBits);
|
|
|
|
iMark += ibitsDelta;
|
|
|
|
if (iMark == cBits) break;
|
|
|
|
cBreaks += SumOfBitsInRange(pdwBreaks, iBreak, iBreak+ibitsDelta);
|
|
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
pisPartitions->RawSetBit(cBreaks);
|
|
|
|
iBreak += ibitsDelta;
|
|
|
|
iBreak += ibitsDelta= 1 + Leading0sInRange(pdwBreaks, iBreak, cBits);
|
|
|
|
if (iBreak >= cBits) break;
|
|
else cBreaks++;
|
|
|
|
iMark+= ibitsDelta;
|
|
|
|
if (iMark >= cBits) break;
|
|
}
|
|
|
|
pisPartitions->InvalidateCache();
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pisPartitions)
|
|
DetachRef(pisPartitions);
|
|
}
|
|
|
|
ForgetRef(pisPartitions);
|
|
|
|
return pisPartitions;
|
|
}
|
|
|
|
BOOL CIndicatorSet::AnyOnes()
|
|
{
|
|
// A fast test for OR/Bits...
|
|
|
|
CAbortSearch::CheckContinueState();
|
|
|
|
if (m_fCountsValid) return SelectionCount();
|
|
|
|
UINT cdw = m_cEntries >> 5;
|
|
UINT cbitsTrailing = m_cEntries & 31;
|
|
|
|
PUINT pdw= m_paulBits + cdw;
|
|
|
|
if (cbitsTrailing)
|
|
if (*pdw & ~((~0) << cbitsTrailing)) return TRUE;
|
|
|
|
for (; cdw--; )
|
|
if (*--pdw) return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Implementation for class CCompressedSet ------------------------------------
|
|
|
|
void CCompressedSet::StoreDWords(PVOID pv, PUINT pdw, UINT cdw)
|
|
{
|
|
PUINT pdwDest= *(PUINT *) pv;
|
|
|
|
for (; cdw--; ) *pdwDest++ = *pdw++;
|
|
|
|
*((PUINT *) pv) = pdwDest;
|
|
}
|
|
|
|
CCompressedSet *CCompressedSet::NewCompressedSet(CDataRing *pdrIn, UINT cIndices, UINT iBase, UINT iLimit)
|
|
{
|
|
CCompressedSet *pcs = NULL;
|
|
CDWOutputQueue *poq = NULL;
|
|
CCompressor *pcmp = NULL;
|
|
|
|
__try
|
|
{
|
|
pcs= New CCompressedSet();
|
|
|
|
pcs->m_cPositions = iLimit;
|
|
pcs->m_rb.cReferences = cIndices;
|
|
|
|
if (cIndices < 4)
|
|
{
|
|
if (cIndices)
|
|
{
|
|
pcs->m_iRefFirst= pdrIn->GetDWordIn();
|
|
|
|
if (cIndices > 1)
|
|
{
|
|
pcs->m_iRefSecond= pdrIn->GetDWordIn();
|
|
|
|
if (cIndices > 2) pcs->m_iRefThird = ~pdrIn->GetDWordIn();
|
|
}
|
|
}
|
|
|
|
__leave;
|
|
}
|
|
|
|
UINT cbitsBasis;
|
|
|
|
pcs->m_cdwCompressed = CmpDWordCountFor(cIndices, 0, iLimit, &cbitsBasis);
|
|
pcs->m_pdwCompressed = PUINT(VAlloc(FALSE, pcs->m_cdwCompressed * sizeof(UINT)));
|
|
pcs->m_rb.cbitsBasis = cbitsBasis;
|
|
|
|
PUINT pdw= pcs->m_pdwCompressed;
|
|
|
|
poq = CDWOutputQueue::NewOutputCallQueue(StoreDWords, &pdw);
|
|
pcmp = CCompressor ::NewCompressor(poq);
|
|
|
|
#ifdef _DEBUG
|
|
UINT cbits=
|
|
#endif // _DEBUG
|
|
|
|
pcmp->Compress(pdrIn, cIndices, 0, iLimit, &cbitsBasis);
|
|
|
|
pcmp->FlushOutput();
|
|
|
|
ASSERT(cbitsBasis == pcs->m_rb.cbitsBasis);
|
|
|
|
ASSERT(((cbits + 31) >> 5) <= pcs->m_cdwCompressed);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pcs)
|
|
{ delete pcs; pcs= NULL;}
|
|
|
|
if (pcmp) delete pcmp;
|
|
if (poq ) delete poq;
|
|
}
|
|
|
|
return pcs;
|
|
}
|
|
|
|
typedef struct _DWordVectorPosition
|
|
{
|
|
PUINT pi;
|
|
PUINT piLimit;
|
|
|
|
} DWordVectorPosition;
|
|
|
|
BOOL CCompressedSet::ScanDWords(PVOID pv, PUINT pdw, PUINT pcdw)
|
|
{
|
|
DWordVectorPosition *pvp= (DWordVectorPosition *) pv;
|
|
|
|
PUINT pi= pvp->pi;
|
|
UINT cdwLeft= pvp->piLimit - pi;
|
|
|
|
// ASSERT(cdwLeft >= *pcdw);
|
|
|
|
if (cdwLeft > *pcdw) cdwLeft= *pcdw;
|
|
|
|
*pcdw= cdwLeft;
|
|
|
|
for (; cdwLeft--; ) *pdw++ = *pi++;
|
|
|
|
pvp->pi= pi;
|
|
|
|
return (pi == pvp->piLimit);
|
|
}
|
|
|
|
CCompressedSet *CCompressedSet::NewCompressedSet(PUINT paiSequence, UINT ciSequence, UINT iLimit)
|
|
{
|
|
CDWInputQueue *piq = NULL;
|
|
CCompressedSet *pcs = NULL;
|
|
|
|
DWordVectorPosition dwvp;
|
|
|
|
__try
|
|
{
|
|
dwvp.pi = paiSequence;
|
|
dwvp.piLimit = paiSequence + ciSequence;
|
|
|
|
piq = CDWInputQueue ::NewInputCallQueue(ScanDWords, &dwvp);
|
|
pcs = CCompressedSet::NewCompressedSet(piq, ciSequence, 0, iLimit);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pcs)
|
|
{
|
|
delete pcs; pcs= NULL;
|
|
}
|
|
|
|
if (piq) { delete piq; piq= NULL; }
|
|
}
|
|
|
|
return pcs;
|
|
}
|
|
|
|
typedef struct _IndicatorPosition
|
|
{
|
|
CIndicatorSet *pis;
|
|
UINT iNext;
|
|
UINT iLimit;
|
|
|
|
} IndicatorPosition;
|
|
|
|
BOOL CCompressedSet::DumpIndicatorBits(PVOID pv, PUINT pdw, PUINT pcdw)
|
|
{
|
|
IndicatorPosition *pip= (IndicatorPosition *) pv;
|
|
|
|
UINT cdwLeft= pip->iLimit - pip->iNext;
|
|
|
|
if (cdwLeft > *pcdw) cdwLeft= *pcdw;
|
|
|
|
*pcdw= cdwLeft;
|
|
|
|
#ifdef _DEBUG
|
|
UINT cIndices=
|
|
#endif // _DEBUG
|
|
|
|
pip->pis->MarkedItems(pip->iNext, PINT(pdw), cdwLeft);
|
|
|
|
ASSERT(cIndices == cdwLeft);
|
|
|
|
return (pip->iLimit == (pip->iNext += cdwLeft));
|
|
}
|
|
|
|
CCompressedSet *CCompressedSet::NewCompressedSet(CIndicatorSet *pis)
|
|
{
|
|
CDWInputQueue *piq = NULL;
|
|
CCompressedSet *pcs = NULL;
|
|
|
|
UINT cMembers= pis->SelectionCount();
|
|
|
|
IndicatorPosition ip;
|
|
|
|
__try
|
|
{
|
|
ip.pis = pis;
|
|
ip.iNext = 0;
|
|
ip.iLimit = cMembers;
|
|
|
|
piq = CDWInputQueue ::NewInputCallQueue(DumpIndicatorBits, &ip);
|
|
pcs = CCompressedSet::NewCompressedSet(piq, cMembers, 0, pis->ItemCount());
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pcs)
|
|
{
|
|
delete pcs; pcs= NULL;
|
|
}
|
|
|
|
if (piq) { delete piq; piq= NULL; }
|
|
}
|
|
|
|
return pcs;
|
|
}
|
|
|
|
CCompressedSet *CCompressedSet::NewCompressedSet(CCompressedSet *pcs)
|
|
{
|
|
CCompressedSet *pcsResult= NULL;
|
|
|
|
__try
|
|
{
|
|
CCompressedSet *pcsResult= New CCompressedSet();
|
|
|
|
pcsResult->m_cPositions = pcs->m_cPositions;
|
|
pcsResult->m_iRefFirst = pcs->m_iRefFirst ;
|
|
pcsResult->m_iRefSecond = pcs->m_iRefSecond;
|
|
pcsResult->m_iRefThird = pcs->m_iRefThird ;
|
|
|
|
if (pcsResult->SelectionCount() > 3)
|
|
{
|
|
pcsResult->m_pdwCompressed= PUINT(VAlloc(FALSE, pcs->m_cdwCompressed * sizeof(UINT)));
|
|
|
|
CopyMemory(pcsResult->m_pdwCompressed, pcs->m_pdwCompressed, pcs->m_cdwCompressed);
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pcsResult)
|
|
{
|
|
delete pcsResult; pcsResult= NULL;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
return pcsResult;
|
|
}
|
|
|
|
CCompressedSet::~CCompressedSet()
|
|
{
|
|
// ASSERT(SelectionCount() < 3 || m_pdwCompressed);
|
|
|
|
if (!m_fFromFile && SelectionCount() > 3 && m_pdwCompressed) VFree(m_pdwCompressed);
|
|
}
|
|
|
|
typedef struct _CompressedSetHeader
|
|
{
|
|
UINT cPositions;
|
|
UINT iRefFirst;
|
|
UINT iRefSecond;
|
|
UINT iRefThird;
|
|
UINT offadw;
|
|
|
|
} CompressedSetHeader;
|
|
|
|
void CCompressedSet::StoreImage(CPersist *pDiskImage)
|
|
{
|
|
CompressedSetHeader *pcsh= (CompressedSetHeader *) (pDiskImage->ReserveTableSpace(sizeof(CompressedSetHeader)));
|
|
|
|
pcsh->cPositions = m_cPositions;
|
|
pcsh->iRefFirst = m_iRefFirst;
|
|
pcsh->iRefSecond = m_iRefSecond;
|
|
pcsh->iRefThird = m_iRefThird;
|
|
pcsh->offadw = 0;
|
|
|
|
if (SelectionCount() > 3)
|
|
{
|
|
pcsh->offadw = pDiskImage->NextOffset();
|
|
|
|
pDiskImage->WriteDWords(m_pdwCompressed, m_cdwCompressed);
|
|
}
|
|
}
|
|
|
|
CCompressedSet * CCompressedSet::CreateImage(CPersist *pDiskImage)
|
|
{
|
|
CCompressedSet *pcs= NULL;
|
|
|
|
__try
|
|
{
|
|
pcs= New CCompressedSet();
|
|
|
|
pcs->ConnectImage(pDiskImage);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pcs)
|
|
{
|
|
delete pcs; pcs= NULL;
|
|
}
|
|
}
|
|
|
|
return pcs;
|
|
}
|
|
|
|
void CCompressedSet::SkipImage(CPersist *pDiskImage)
|
|
{
|
|
CompressedSetHeader *pcsh= (CompressedSetHeader *) (pDiskImage->ReserveTableSpace(sizeof(CompressedSetHeader)));
|
|
}
|
|
|
|
void CCompressedSet::ConnectImage(CPersist *pDiskImage)
|
|
{
|
|
CompressedSetHeader *pcsh= (CompressedSetHeader *) (pDiskImage->ReserveTableSpace(sizeof(CompressedSetHeader)));
|
|
|
|
m_cPositions = pcsh->cPositions;
|
|
m_iRefFirst = pcsh->iRefFirst ;
|
|
m_iRefSecond = pcsh->iRefSecond;
|
|
m_iRefThird = pcsh->iRefThird ;
|
|
|
|
if (SelectionCount() > 3) m_pdwCompressed= PUINT(pDiskImage->LocationOf(pcsh->offadw));
|
|
|
|
m_fFromFile= TRUE;
|
|
}
|
|
|
|
void CCompressedSet::SetBits(PVOID pv, PUINT pdw, UINT cdw)
|
|
{
|
|
CIndicatorSet *pis= (CIndicatorSet *)pv;
|
|
|
|
for (; cdw--; ) pis->RawSetBit(*pdw++);
|
|
}
|
|
|
|
void CCompressedSet::IndicateMembers(CIndicatorSet *pis)
|
|
{
|
|
ASSERT(m_cPositions <= pis->ItemCount());
|
|
|
|
UINT c= SelectionCount();
|
|
|
|
if (!c) return;
|
|
|
|
if (c < 4)
|
|
{
|
|
switch(c)
|
|
{
|
|
case 3:
|
|
|
|
pis->RawSetBit(~m_iRefThird);
|
|
|
|
case 2:
|
|
|
|
pis->RawSetBit(m_iRefSecond);
|
|
|
|
case 1:
|
|
|
|
pis->RawSetBit(m_iRefFirst);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CExpandor *pex= NULL;
|
|
CDWOutputQueue *poq= NULL;
|
|
|
|
__try
|
|
{
|
|
pex= CExpandor ::NewExpandor(m_pdwCompressed);
|
|
poq= CDWOutputQueue::NewOutputCallQueue(CCompressedSet::SetBits, pis);
|
|
|
|
pex->Expand(poq, 0, m_rb.cReferences, m_rb.cbitsBasis);
|
|
}
|
|
__finally
|
|
{
|
|
if (pex) { delete pex; pex= NULL; }
|
|
if (poq) { delete poq; poq= NULL; }
|
|
}
|
|
}
|
|
|
|
pis->InvalidateCache();
|
|
}
|
|
|
|
CCompressedSet::CCompressedSet() : CRCObject WithType("CompressedIndicatorSet")
|
|
{
|
|
m_cPositions= m_iRefFirst= m_iRefSecond= m_iRefThird= 0;
|
|
|
|
m_fFromFile= FALSE;
|
|
}
|
|
|
|
CCmpEnumerator::CCmpEnumerator()
|
|
{
|
|
m_pcs = NULL;
|
|
m_iNext = 0;
|
|
m_pex = NULL;
|
|
}
|
|
|
|
CCmpEnumerator::~CCmpEnumerator()
|
|
{
|
|
if (m_pcs) DetachRef(m_pcs);
|
|
if (m_pex) delete m_pex;
|
|
}
|
|
|
|
CCmpEnumerator* CCmpEnumerator::NewEnumerator(CCompressedSet *pcs)
|
|
{
|
|
CCmpEnumerator *pce= NULL;
|
|
|
|
__try
|
|
{
|
|
pce= New CCmpEnumerator();
|
|
|
|
pce->Initial(pcs);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && pce) { delete pce; pce= NULL; }
|
|
}
|
|
|
|
return pce;
|
|
}
|
|
|
|
void CCmpEnumerator::Initial(CCompressedSet *pcs)
|
|
{
|
|
AttachRef(m_pcs, pcs);
|
|
|
|
if (pcs->SelectionCount() > 3)
|
|
{
|
|
m_pex= CExpandor::NewExpandor(pcs->m_pdwCompressed);
|
|
|
|
m_pex->StartExpansion(0, pcs->m_rb.cReferences, pcs->m_rb.cbitsBasis);
|
|
|
|
CDWInputQueue::Initial(CCmpEnumerator::ReadLarge, this);
|
|
|
|
return;
|
|
}
|
|
|
|
CDWInputQueue::Initial(CCmpEnumerator::ReadSmall, this);
|
|
}
|
|
|
|
BOOL CCmpEnumerator::ReadSmall(PVOID pv, PUINT pdw, PUINT pcdw)
|
|
{
|
|
CCmpEnumerator *pce= (CCmpEnumerator *) pv;
|
|
|
|
UINT ai[3];
|
|
|
|
ai[0]= pce->m_pcs->m_iRefFirst;
|
|
ai[1]= pce->m_pcs->m_iRefSecond;
|
|
ai[1]= pce->m_pcs->m_iRefSecond;
|
|
|
|
UINT cTotal = pce->m_pcs->SelectionCount();
|
|
UINT cdwLeft = cTotal - pce->m_iNext;
|
|
|
|
if (cdwLeft > *pcdw) cdwLeft= *pcdw;
|
|
|
|
*pcdw= cdwLeft;
|
|
|
|
if (cdwLeft) CopyMemory(pdw, ai + pce->m_iNext, cdwLeft);
|
|
|
|
return cTotal == (pce->m_iNext += cdwLeft);
|
|
}
|
|
|
|
BOOL CCmpEnumerator::ReadLarge(PVOID pv, PUINT pdw, PUINT pcdw)
|
|
{
|
|
return ((CCmpEnumerator *) pv)->m_pex->ExpandNextSpan(pdw, pcdw);
|
|
}
|