mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1027 lines
28 KiB
1027 lines
28 KiB
// TokenC.cpp -- Implementation for class CTokenCollection
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "TokenC.h"
|
|
#include "Memex.h"
|
|
|
|
CTokenCollection *CTokenCollection::NewTokenCollection(CTextSet **papts, UINT ctsSlots, CPersist *pPersistRelations)
|
|
{
|
|
CTokenCollection *ptc= NULL;
|
|
|
|
__try
|
|
{
|
|
ptc= New CTokenCollection();
|
|
|
|
ptc->AttachParameters(papts, ctsSlots, pPersistRelations);
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination() && ptc)
|
|
{
|
|
delete ptc; ptc= NULL;
|
|
}
|
|
}
|
|
|
|
return ptc;
|
|
}
|
|
|
|
CTokenCollection::CTokenCollection() :
|
|
#ifdef _DEBUG
|
|
CTokenList(FALSE, "TokenCollection")
|
|
#else // _DEBUG
|
|
CTokenList(FALSE)
|
|
#endif // _DEBUG
|
|
{
|
|
m_ctsSlots = 0;
|
|
m_cTokens = 0;
|
|
m_fOptions = 0;
|
|
m_patsi = NULL;
|
|
m_paiTokenStart = NULL;
|
|
m_pati = NULL;
|
|
m_pcsPrimaries = NULL;
|
|
m_pisActivePrimaries = NULL;
|
|
m_paptiSorted = NULL;
|
|
m_paptiSortedRL = NULL;
|
|
m_paptiReps = NULL;
|
|
m_paiCategoryMaps = NULL;
|
|
m_fFromFileImage = FALSE;
|
|
m_fResorted = FALSE;
|
|
}
|
|
|
|
CTokenCollection::~CTokenCollection()
|
|
{
|
|
if (m_fFromFileImage && !m_fResorted)
|
|
{
|
|
m_pRLRanking = NULL;
|
|
m_paiCategoryMaps = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (m_paiCategoryMaps) VFree(m_paiCategoryMaps);
|
|
}
|
|
|
|
if (m_pati ) VFree(m_pati );
|
|
if (m_paptiSorted ) VFree(m_paptiSorted );
|
|
if (m_paptiSortedRL ) VFree(m_paptiSortedRL );
|
|
if (m_paptiReps ) VFree(m_paptiReps );
|
|
if (m_paiTokenStart ) VFree(m_paiTokenStart );
|
|
|
|
if (m_pcsPrimaries ) DetachRef(m_pcsPrimaries );
|
|
if (m_pisActivePrimaries) DetachRef(m_pisActivePrimaries);
|
|
|
|
if (m_patsi)
|
|
{
|
|
UINT c= m_ctsSlots;
|
|
|
|
for (; c--; ) if (m_patsi[c].pts) DetachRef(m_patsi[c].pts);
|
|
|
|
VFree(m_patsi);
|
|
}
|
|
}
|
|
|
|
typedef struct _TokenHashInfo
|
|
{
|
|
PTokenInfo pti;
|
|
|
|
} TokenHashInfo, *PTokenHashInfo;
|
|
|
|
typedef struct _CategoryEnvironment
|
|
{
|
|
PTokenInfo ptiLimit;
|
|
|
|
} CategoryEnvironment, *PCategoryEnvironment;
|
|
|
|
void CTokenCollection::AttachParameters(CTextSet **papts, UINT ctsSlots, CPersist *pPersistRelations)
|
|
{
|
|
if (pPersistRelations) m_fFromFileImage= TRUE;
|
|
|
|
m_patsi= (PTextSetInfo) VAlloc(TRUE, ctsSlots * sizeof(TextSetInfo));
|
|
|
|
m_ctsSlots = ctsSlots;
|
|
|
|
UINT c;
|
|
|
|
for (c= ctsSlots, m_cTokens= 0; c--; )
|
|
{
|
|
CTextSet *pts= papts[c];
|
|
|
|
if (!pts) continue;
|
|
|
|
InstallTextSet(c, pts);
|
|
|
|
m_cTokens += m_patsi[c].cd;
|
|
}
|
|
|
|
if (pPersistRelations) ReconstructRelations(pPersistRelations);
|
|
|
|
InvalidateRepresentatives();
|
|
}
|
|
|
|
typedef struct _TokenRelationHeader
|
|
{
|
|
UINT ctsSlots;
|
|
UINT cTokens;
|
|
UINT offRLRanking;
|
|
UINT offaiCategoryMaps;
|
|
|
|
} TokenRelationHeader, *PTokenRelationHeader;
|
|
|
|
void CTokenCollection::RecordRelations(CPersist *pPersistDiskImage)
|
|
{
|
|
PUINT paiTokenReps = NULL;
|
|
PUINT pcRefs = NULL;
|
|
|
|
__try
|
|
{
|
|
CTokenList::StoreImage2(pPersistDiskImage);
|
|
|
|
PTokenRelationHeader ptrh= (PTokenRelationHeader) pPersistDiskImage->ReserveTableSpace(sizeof(TokenRelationHeader));
|
|
|
|
ptrh->ctsSlots = m_ctsSlots;
|
|
ptrh->cTokens = m_cTokens;
|
|
|
|
ptrh->offRLRanking = pPersistDiskImage->NextOffset(); pPersistDiskImage->WriteDWords(m_pRLRanking, m_cd);
|
|
ptrh->offaiCategoryMaps = pPersistDiskImage->NextOffset(); pPersistDiskImage->WriteDWords(m_paiCategoryMaps, m_cTokens);
|
|
}
|
|
__finally
|
|
{
|
|
if (paiTokenReps) { VFree(paiTokenReps); paiTokenReps= NULL; }
|
|
}
|
|
}
|
|
|
|
void CTokenCollection::ReconstructRelations(CPersist *pPersistRelations)
|
|
{
|
|
BOOL fNewSortOrder= CTokenList::ConnectImage2(pPersistRelations);
|
|
|
|
// We set the PREVIOUSLY_PRESENT flag for every text set we encounter.
|
|
// That's necessary to skip the call to ReconstructCollection in InvalidateRepresentatives.
|
|
// For similar reasons we also set the PREVIOUSLY_ACTIVE flag.
|
|
|
|
UINT c= m_ctsSlots;
|
|
|
|
UINT fOptions = TOPIC_SEARCH | PHRASE_SEARCH | PHRASE_FEEDBACK | VECTOR_SEARCH;
|
|
|
|
for (; c--; )
|
|
{
|
|
if (IsPresent(c)) m_patsi[c].fFlags |= PREVIOUSLY_PRESENT;
|
|
|
|
if (IsActive(c))
|
|
{
|
|
m_patsi[c].fFlags |= PREVIOUSLY_ACTIVE;
|
|
fOptions &= GetTextSet(c)->IndexOptions();
|
|
}
|
|
}
|
|
|
|
m_fOptions= fOptions;
|
|
|
|
ASSERT(!m_pisActivePrimaries);
|
|
|
|
AttachRef(m_pisActivePrimaries, CIndicatorSet::NewIndicatorSet(RowCount(), TRUE));
|
|
|
|
// Bugbug!! m_pcsPrimaries is not used anywhere. Probably should remove it.
|
|
|
|
ASSERT(!m_pcsPrimaries);
|
|
|
|
AttachRef(m_pcsPrimaries, CCompressedSet::NewCompressedSet(m_pisActivePrimaries));
|
|
|
|
PTokenRelationHeader ptrh= (PTokenRelationHeader) pPersistRelations->ReserveTableSpace(sizeof(TokenRelationHeader));
|
|
|
|
ASSERT(m_ctsSlots == ptrh->ctsSlots && m_cTokens == ptrh->cTokens);
|
|
|
|
ASSERT(!m_paiTokenStart);
|
|
|
|
m_paiTokenStart= PUINT(VAlloc(FALSE, (m_ctsSlots + 1) * sizeof(UINT)));
|
|
|
|
ASSERT(!m_pati);
|
|
|
|
m_pati= (PTokenInfo) VAlloc(TRUE, m_cTokens * sizeof(TokenInfo));
|
|
|
|
// The code below constructs most of m_paiTokenStart and m_pati.
|
|
// The ptiCloneLink fields are set up later in the code as a function
|
|
// of m_paptiReps and m_paiCategoryMaps.
|
|
|
|
PTextSetInfo ptsi = m_patsi + m_ctsSlots;
|
|
PUINT piLimit = m_paiTokenStart + m_ctsSlots + 1;
|
|
PTokenInfo pti = m_pati + m_cTokens;
|
|
|
|
for (c= m_ctsSlots; c--; )
|
|
{
|
|
*--piLimit = pti - m_pati;
|
|
|
|
if (!(PRESENT & (--ptsi)->fFlags)) continue;
|
|
|
|
CTextSet *pts= ptsi->pts;
|
|
|
|
UINT cd = pts->DescriptorCount();
|
|
|
|
for (; cd--; )
|
|
{
|
|
(--pti)->iDescriptor = cd;
|
|
pti ->iaTSSlot = c;
|
|
}
|
|
}
|
|
|
|
*--piLimit= 0;
|
|
|
|
ASSERT(!m_pRLRanking);
|
|
|
|
m_pRLRanking= (PUINT) (pPersistRelations->LocationOf(ptrh->offRLRanking));
|
|
|
|
ASSERT(!m_paiCategoryMaps);
|
|
|
|
m_paiCategoryMaps= (PUINT) (pPersistRelations->LocationOf(ptrh->offaiCategoryMaps));
|
|
|
|
if (fNewSortOrder)
|
|
{
|
|
PUINT paiRankMap = NULL;
|
|
|
|
__try
|
|
{
|
|
paiRankMap= PUINT(VAlloc(FALSE, m_cd * sizeof(UINT)));
|
|
|
|
UINT c = m_cd;
|
|
PDESCRIPTOR *ppd = m_ppdSorted + m_cd;
|
|
|
|
// We can build a rank map because the previous ranking is
|
|
// given by m_paiCategoryMaps and the iTokenInfo DESCRIPTOR field.
|
|
|
|
for (; c--; )
|
|
paiRankMap[m_paiCategoryMaps[(*--ppd)->iTokenInfo]]= c;
|
|
|
|
PUINT pRLRanking = m_pRLRanking; m_pRLRanking = NULL;
|
|
PUINT paiCategoryMaps = m_paiCategoryMaps; m_paiCategoryMaps = NULL;
|
|
|
|
m_fResorted= TRUE; // So the destructor will deallocate
|
|
// m_pRLRanking and m_paiCategoryMaps
|
|
|
|
m_pRLRanking = PUINT(VAlloc(FALSE, m_cd * sizeof(UINT)));
|
|
m_paiCategoryMaps = PUINT(VAlloc(FALSE, m_cTokens * sizeof(UINT)));
|
|
|
|
PUINT piSrc, piDest;
|
|
|
|
for (c= m_cd, piSrc= pRLRanking, piDest= m_pRLRanking; c--; )
|
|
*piDest++ = paiRankMap[*piSrc++];
|
|
|
|
for (c= m_cTokens, piSrc= paiCategoryMaps, piDest= m_paiCategoryMaps; c--;)
|
|
*piDest++ = paiRankMap[*piSrc++];
|
|
}
|
|
__finally
|
|
{
|
|
if (paiRankMap)
|
|
{
|
|
VFree(paiRankMap); paiRankMap= NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT(!m_paptiReps);
|
|
|
|
m_paptiReps= (PTokenInfo *) VAlloc(FALSE, m_cd * sizeof(PTokenInfo));
|
|
|
|
PTokenInfo *ppti = m_paptiReps;
|
|
PDESCRIPTOR *ppd = m_ppdSorted;
|
|
|
|
for (c= m_cd; c--; )
|
|
{
|
|
UINT iTI= (*ppd++)->iTokenInfo;
|
|
|
|
*ppti++ = m_pati + iTI;
|
|
}
|
|
|
|
// The code below constructs the Clone links from m_paptiReps and m_paiCategoryMaps.
|
|
|
|
PUINT pi;
|
|
|
|
for (pi= m_paiCategoryMaps, pti= m_pati, c= m_cTokens; c--; pti++)
|
|
{
|
|
UINT iCategory= *pi++;
|
|
|
|
PTokenInfo ptiCategory = m_pati + m_ppdSorted[iCategory]->iTokenInfo;
|
|
|
|
if (ptiCategory == pti) continue;
|
|
|
|
pti ->ptiCloneLink = ptiCategory->ptiCloneLink;
|
|
ptiCategory->ptiCloneLink = pti;
|
|
}
|
|
}
|
|
|
|
void CTokenCollection::ConstructCollection()
|
|
{
|
|
m_paiTokenStart = PUINT(VAlloc(FALSE, (m_ctsSlots + 1) * sizeof(UINT)));
|
|
m_paiCategoryMaps = PUINT(VAlloc(FALSE, m_cTokens * sizeof(UINT)));
|
|
|
|
m_pati= (PTokenInfo) VAlloc(TRUE, m_cTokens * sizeof(TokenInfo));
|
|
|
|
#ifdef _DEBUG
|
|
FillMemory(m_paiCategoryMaps, m_cTokens * sizeof(UINT), UCHAR(-1));
|
|
#endif // _DEBUG
|
|
|
|
m_paptiSorted = (PTokenInfo *) VAlloc(FALSE, m_cTokens * sizeof(PTokenInfo));
|
|
m_paptiSortedRL = (PTokenInfo *) VAlloc(FALSE, m_cTokens * sizeof(PTokenInfo));
|
|
|
|
PTextSetInfo ptsi = m_patsi + m_ctsSlots;
|
|
PUINT piLimit = m_paiTokenStart + m_ctsSlots + 1;
|
|
PTokenInfo pti = m_pati + m_cTokens;
|
|
PTokenInfo *pptiLR = m_paptiSorted + m_cTokens;
|
|
PTokenInfo *pptiRL = m_paptiSortedRL + m_cTokens;
|
|
|
|
BOOL fLCID_Initialed = FALSE;
|
|
|
|
m_lcidSorting= LCID(-1); // an invalid LCID value
|
|
|
|
for (UINT c= m_ctsSlots; c--; )
|
|
{
|
|
*--piLimit = pptiLR - m_paptiSorted;
|
|
|
|
if (!(PRESENT & (--ptsi)->fFlags)) continue;
|
|
|
|
CTextSet *pts= ptsi->pts;
|
|
|
|
if (fLCID_Initialed)
|
|
{
|
|
if (m_lcidSorting != pts->SortingLCID())
|
|
m_lcidSorting = LCID(-1);
|
|
}
|
|
else
|
|
{
|
|
m_lcidSorting= pts->SortingLCID();
|
|
fLCID_Initialed= TRUE;
|
|
}
|
|
|
|
pts->SyncIndices();
|
|
|
|
INT cbMaxToken= pts->MaxTokenWidth();
|
|
|
|
if (m_cbMaxLength < cbMaxToken) m_cbMaxLength= cbMaxToken;
|
|
|
|
UINT cd = pts->DescriptorCount();
|
|
PTokenInfo ptiBase = pti -= cd;
|
|
PDESCRIPTOR *ppd = pts->m_ppdSorted + cd;
|
|
PDESCRIPTOR pdBase = pts->DescriptorBase();
|
|
|
|
// In the loop below note the tricky code which sets up the
|
|
// token info elements to be in the same sequence as the
|
|
// descriptors in the source text set.
|
|
|
|
PDESCRIPTOR *ppdRL = pts->m_ppdTailSorted + cd;
|
|
|
|
for (; cd--; )
|
|
{
|
|
PDESCRIPTOR pd= *--ppd;
|
|
|
|
PTokenInfo ptiTarget= ptiBase + (pd - pdBase);
|
|
|
|
ptiTarget->pd = pd;
|
|
ptiTarget->iRank = cd;
|
|
|
|
*--pptiLR = ptiTarget;
|
|
|
|
ASSERT( cd + 1 == pts->DescriptorCount()
|
|
|| 0 >= CompareImagesLR(ppd, ppd + 1)
|
|
);
|
|
|
|
*--pptiRL = ptiBase + (*--ppdRL - pdBase);
|
|
|
|
ASSERT( cd + 1 == pts->DescriptorCount()
|
|
|| 0 >= CompareImagesRL(ppdRL, ppdRL + 1)
|
|
);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
|
|
PTokenInfo ptiDebug= ptiBase;
|
|
PTokenInfo *pptiLRDebug = pptiLR;
|
|
PTokenInfo *pptiRLDebug = pptiRL;
|
|
|
|
for (cd=pts->DescriptorCount();
|
|
cd--;
|
|
++ptiDebug, ++pptiLRDebug, ++pptiRLDebug
|
|
)
|
|
{
|
|
ASSERT(ptiDebug - ptiBase == ptiDebug->pd - pdBase);
|
|
ASSERT(!cd || 0 >= CompareTokenInfoRLI(pptiRLDebug, pptiRLDebug + 1));
|
|
ASSERT(!cd || 0 >= CompareTokenInfo (pptiLRDebug, pptiLRDebug + 1));
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
}
|
|
|
|
*--piLimit= 0;
|
|
|
|
PTokenInfo *pptiResult= NULL;
|
|
|
|
__try
|
|
{
|
|
CombineTokenLists(m_paptiSortedRL, m_paiTokenStart, m_ctsSlots, &pptiResult, &c, CompareTokenInfoRLI);
|
|
|
|
#ifdef _DEBUG
|
|
{
|
|
for (int c=m_ctsSlots; --c > 0 ; )
|
|
ASSERT(0 >= CompareTokenInfoRLI(m_paptiSortedRL + c - 1, m_paptiSortedRL + c));
|
|
}
|
|
#endif // _DEBUG
|
|
|
|
ASSERT(c == m_cTokens);
|
|
|
|
if (m_paptiSortedRL != pptiResult)
|
|
{
|
|
VFree(m_paptiSortedRL);
|
|
|
|
m_paptiSortedRL= pptiResult;
|
|
}
|
|
|
|
pptiResult= NULL;
|
|
|
|
CombineTokenLists(m_paptiSorted, m_paiTokenStart, m_ctsSlots, &pptiResult, &c);
|
|
|
|
#ifdef _DEBUG
|
|
{
|
|
for (int c=m_ctsSlots; --c > 0 ; )
|
|
ASSERT(0 >= CompareTokenInfo(m_paptiSorted + c - 1, m_paptiSorted + c));
|
|
}
|
|
#endif // _DEBUG
|
|
|
|
ASSERT(c == m_cTokens);
|
|
|
|
if (m_paptiSorted != pptiResult)
|
|
{
|
|
VFree(m_paptiSorted);
|
|
|
|
m_paptiSorted= pptiResult;
|
|
}
|
|
|
|
pptiResult= NULL;
|
|
}
|
|
__finally
|
|
{
|
|
if (pptiResult && pptiResult != m_paptiSorted && pptiResult != m_paptiSortedRL)
|
|
{
|
|
VFree(pptiResult); pptiResult= NULL;
|
|
}
|
|
}
|
|
|
|
if (m_pcsPrimaries) DetachRef(m_pcsPrimaries);
|
|
}
|
|
|
|
void CTokenCollection::ReconstructCollection()
|
|
{
|
|
if (!m_pati) { ConstructCollection(); return; }
|
|
|
|
ASSERT(FALSE); // Collection Change to be completed...
|
|
}
|
|
|
|
void CTokenCollection::ConstructRepresentatives()
|
|
{
|
|
ASSERT(!m_pcsPrimaries);
|
|
|
|
// This routine was written assuming we'll be adding and removing
|
|
// text sets frequently. Actually the current implementation creates
|
|
// the collection once and doesn't alter it thereafter. So we'll
|
|
// change these deallocations to assertions.
|
|
|
|
ASSERT(!m_paptiReps );
|
|
ASSERT(!m_ppdSorted );
|
|
ASSERT(!m_ppdTailSorted );
|
|
ASSERT(!m_pafClassifications);
|
|
|
|
m_clsf.Initial;
|
|
|
|
UINT c;
|
|
PTokenInfo *ppti;
|
|
|
|
for (c= m_cTokens, ppti= m_paptiSorted + c; c--; ) (*--ppti)->iRank= c;
|
|
|
|
CSegHashTable *psht = NULL;
|
|
CAValRef *pavr = NULL;
|
|
CIndicatorSet *pis = NULL;
|
|
|
|
__try
|
|
{
|
|
psht= CSegHashTable::NewSegHashTable(sizeof(TokenHashInfo), sizeof(PVOID));
|
|
|
|
pavr= CAValRef::NewValRef(C_VALREF_SLOTS);
|
|
|
|
CategoryEnvironment catenv;
|
|
|
|
PTokenInfo pti;
|
|
|
|
// The loop below processes token entries against a hash table to
|
|
// construct a set of clone chains. Entries within a single chain
|
|
// have the same display image.
|
|
|
|
for (c= m_cTokens, pti= m_pati + c; c; )
|
|
{
|
|
UINT cChunk= C_VALREF_SLOTS;
|
|
|
|
if (cChunk > c) cChunk= c;
|
|
|
|
c -= cChunk;
|
|
|
|
pavr->DiscardRefs();
|
|
|
|
catenv.ptiLimit = pti;
|
|
|
|
for (; cChunk--; )
|
|
{
|
|
PDESCRIPTOR pd= (--pti)->pd;
|
|
|
|
UINT cw= CbImage(pd);
|
|
|
|
pavr->AddWCRef(pd->pbImage, cw);
|
|
}
|
|
|
|
psht->Assimilate(pavr, &catenv, MergeTokenCategory, AddTokenCategory);
|
|
}
|
|
|
|
delete pavr; pavr= NULL;
|
|
|
|
// Now we'll construct pis so that it marks the head entry for each of
|
|
// the clone chains.
|
|
|
|
AttachRef(pis, CIndicatorSet::NewIndicatorSet(m_cTokens));
|
|
|
|
psht->ForEach(pis, IndicatePrimaryClones);
|
|
|
|
pis->InvalidateCache();
|
|
|
|
// Here we store a compressed form of the clone mask.
|
|
|
|
AttachRef(m_pcsPrimaries, CCompressedSet::NewCompressedSet(pis));
|
|
}
|
|
__finally
|
|
{
|
|
delete psht; psht= NULL;
|
|
|
|
if (_abnormal_termination())
|
|
{
|
|
if (pavr) { delete pavr; pavr= NULL; }
|
|
if (pis ) DetachRef(pis);
|
|
}
|
|
}
|
|
|
|
PWCHAR pwDispImages = NULL;
|
|
PDESCRIPTOR pdTokenReps = NULL;
|
|
PUINT paiReps = NULL;
|
|
PUINT paiRanks = NULL;
|
|
PDESCRIPTOR *ppdSortRLOrder = NULL;
|
|
UINT cwDisplayTotal = 0;
|
|
|
|
// The number of 1's in pis tells us how many unique display images
|
|
// we have.
|
|
|
|
UINT cd= pis->SelectionCount();
|
|
|
|
__try
|
|
{
|
|
// Now we can begin to construct the component information for our
|
|
// parent token set. First we'll construct the array of descriptors
|
|
// and their right-to-left sorting order. As a byproduct we'll also
|
|
// calculate the space required for the unique display images.
|
|
|
|
// Here we're converting the bit mask (pis) into a sequence of
|
|
// array indices (paiReps).
|
|
|
|
paiReps = PUINT(VAlloc(FALSE, cd * sizeof(UINT)));
|
|
|
|
pis->MarkedItems(0, PINT(paiReps), cd);
|
|
|
|
PDESCRIPTOR *ppd, pdNext;
|
|
PUINT pi;
|
|
|
|
pdTokenReps = (PDESCRIPTOR ) VAlloc(FALSE, (cd+1) * sizeof( DESCRIPTOR));
|
|
|
|
for (pi= paiReps, pdNext= pdTokenReps, c= cd; c--; )
|
|
{
|
|
PTokenInfo pti = m_paptiSorted[*pi++];
|
|
PDESCRIPTOR pd = pti->pd;
|
|
|
|
*pdNext = *pd;
|
|
|
|
UINT cw= CwDisplay(pd);
|
|
|
|
pdNext->cwDisplay = cw;
|
|
pdNext->iTokenInfo = pti - m_pati;
|
|
|
|
cwDisplayTotal += CwDisplay(pd);
|
|
|
|
// We keep the new pd address in pdAux rather than
|
|
// overwriting pd because we'll need the old pd value
|
|
// later to map to an iDescriptor value relative to the
|
|
// text set for this token entry.
|
|
|
|
pti->pdAux= pdNext++;
|
|
}
|
|
|
|
// Here we're allocating space for the unique display images and
|
|
// copying those images from the text sets.
|
|
|
|
pwDispImages = PWCHAR(VAlloc(FALSE, cwDisplayTotal * sizeof(WCHAR)));
|
|
|
|
PWCHAR pwc;
|
|
|
|
for (pwc= pwDispImages, pdNext= pdTokenReps, c= cd; c--; pdNext++)
|
|
{
|
|
CopyMemory(pwc, pdNext->pwDisplay, pdNext->cwDisplay * sizeof(WCHAR));
|
|
|
|
pdNext->pwDisplay = pwc;
|
|
pwc += pdNext->cwDisplay;
|
|
}
|
|
|
|
// The last descriptor entry must point just beyond the end of the
|
|
// display images.
|
|
|
|
pdNext->pwDisplay= pwc;
|
|
|
|
ppdSortRLOrder = (PDESCRIPTOR *) VAlloc(FALSE, cd * sizeof(PDESCRIPTOR));
|
|
|
|
for (ppd= ppdSortRLOrder, c= m_cTokens, ppti= m_paptiSortedRL;
|
|
c--;
|
|
)
|
|
{
|
|
PTokenInfo pti= *ppti++;
|
|
|
|
if (pis->IsBitSet(pti->iRank)) *ppd++ = pti->pdAux;
|
|
}
|
|
|
|
DetachRef(pis);
|
|
|
|
// We'll also construct a sort ordering (m_paptiReps) for the tokens that head
|
|
// the clone lists.
|
|
|
|
m_paptiReps= (PTokenInfo *) VAlloc(FALSE, cd * sizeof(PTokenInfo));
|
|
|
|
ASSERT(sizeof(UINT) == sizeof(PDESCRIPTOR));
|
|
|
|
// Notice that we use aliasing to treat paiReps as an array of UINTs and
|
|
// as an array of PDESCRIPTOR * values.
|
|
|
|
ppd= (PDESCRIPTOR *) paiReps;
|
|
|
|
// The paiRanks array is used to construct the RL Rankings below
|
|
|
|
paiRanks= PUINT(VAlloc(FALSE, m_cTokens * sizeof(UINT)));
|
|
|
|
FillMemory(paiRanks, m_cTokens * sizeof(UINT), UCHAR(-1));
|
|
|
|
for (pi= paiReps, c= cd, ppti= m_paptiReps; c--; )
|
|
{
|
|
PTokenInfo pti;
|
|
|
|
*ppti++ = pti = m_paptiSorted[*pi++];
|
|
*ppd ++ = pti->pdAux;
|
|
|
|
paiRanks[pti - m_pati]= cd - c - 1;
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
if (_abnormal_termination())
|
|
{
|
|
if (pwDispImages ) { VFree(pwDispImages ); pwDispImages = NULL; }
|
|
if (pdTokenReps ) { VFree(pdTokenReps ); pdTokenReps = NULL; }
|
|
if (paiReps ) { VFree(paiReps ); paiReps = NULL; }
|
|
if (ppdSortRLOrder) { VFree(ppdSortRLOrder); ppdSortRLOrder = NULL; }
|
|
if (paiRanks ) { VFree(paiRanks ); paiRanks = NULL; }
|
|
}
|
|
}
|
|
|
|
__try
|
|
{
|
|
InitialTokenList(pwDispImages, cwDisplayTotal, pdTokenReps, cd,
|
|
m_lcidSorting, NULL, 0, (PDESCRIPTOR *)paiReps,
|
|
ppdSortRLOrder
|
|
);
|
|
|
|
m_pRLRanking= (PUINT) VAlloc(FALSE, m_cd * sizeof(UINT));
|
|
|
|
UINT cd2;
|
|
|
|
for (cd2= cd, c= m_cTokens, ppti= m_paptiSortedRL + m_cTokens; c--; )
|
|
{
|
|
PTokenInfo pti= *--ppti;
|
|
|
|
INT iRank= (INT) paiRanks[pti - m_pati];
|
|
|
|
if (iRank >= 0)
|
|
m_pRLRanking[--cd2]= UINT(iRank);
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
ASSERT(paiRanks);
|
|
VFree(paiRanks); paiRanks= NULL;
|
|
}
|
|
|
|
PTextSetInfo ptsi;
|
|
PTokenInfo pti;
|
|
|
|
for (ptsi= m_patsi + m_ctsSlots, pti= m_pati + m_cTokens, c= m_ctsSlots; c--; )
|
|
{
|
|
if (!(PRESENT & (--ptsi)->fFlags)) continue;
|
|
|
|
CTextSet *pts= ptsi->pts;
|
|
|
|
PDESCRIPTOR pdBase = pts->DescriptorBase ();
|
|
UINT cd = pts->DescriptorCount();
|
|
|
|
for (; cd--; )
|
|
{
|
|
(--pti)->iaTSSlot = c;
|
|
pti ->iDescriptor = pti->pd - pdBase;
|
|
}
|
|
}
|
|
|
|
for (c= m_cd, ppti= m_paptiReps; c--; )
|
|
{
|
|
PTokenInfo pti= *ppti++;
|
|
|
|
UINT iCategory= m_cd - c - 1;
|
|
|
|
for (; pti; pti= pti->ptiCloneLink)
|
|
m_paiCategoryMaps[pti->iDescriptor + m_paiTokenStart[pti->iaTSSlot]]= iCategory;
|
|
}
|
|
}
|
|
|
|
void CTokenCollection::ReconstructRepresentatives()
|
|
{
|
|
if (!m_pcsPrimaries) ConstructRepresentatives();
|
|
|
|
ChangeRef(m_pisActivePrimaries, CIndicatorSet::NewIndicatorSet(m_cd));
|
|
|
|
PTokenInfo *ppti= m_paptiReps;
|
|
|
|
UINT c= m_cd;
|
|
|
|
for (; c--; )
|
|
{
|
|
UINT iSlot= ppti - m_paptiReps;
|
|
|
|
PTokenInfo pti= *ppti++;
|
|
|
|
for (; pti; pti= pti->ptiCloneLink)
|
|
{
|
|
if ((m_patsi[pti->iaTSSlot].fFlags & ACTIVE))
|
|
{
|
|
m_pisActivePrimaries->RawSetBit(iSlot);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_pisActivePrimaries->InvalidateCache();
|
|
}
|
|
|
|
BOOL CTokenCollection::InvalidateRepresentatives()
|
|
{
|
|
UINT fChanges = 0;
|
|
UINT fOptions = TOPIC_SEARCH | PHRASE_SEARCH | PHRASE_FEEDBACK | VECTOR_SEARCH;
|
|
UINT c;
|
|
|
|
#ifdef _DEBUG
|
|
|
|
UINT cTokens = 0;
|
|
|
|
#endif // _DEBUG
|
|
|
|
for (c= m_ctsSlots; c--; )
|
|
{
|
|
UINT fFlags= m_patsi[c].fFlags;
|
|
|
|
ASSERT((fFlags & (PRESENT | ACTIVE)) != ACTIVE);
|
|
|
|
#ifdef _DEBUG
|
|
|
|
if (fFlags & PRESENT) cTokens += m_patsi[c].cd;
|
|
|
|
#endif // _DEBUG
|
|
|
|
if (fFlags & ACTIVE) fOptions &= GetTextSet(c)->IndexOptions();
|
|
|
|
fChanges |= (fFlags & CURRENT_STATE) ^ ((fFlags & PREVIOUS_STATE) >> TIME_SHIFT);
|
|
}
|
|
|
|
if (!fChanges)
|
|
{
|
|
ASSERT(m_cTokens == cTokens );
|
|
ASSERT(m_fOptions == fOptions);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
m_fOptions= fOptions;
|
|
|
|
if (fChanges & PRESENT) ReconstructCollection();
|
|
|
|
if (fChanges & ACTIVE || !m_pcsPrimaries) ReconstructRepresentatives();
|
|
|
|
PTextSetInfo ptsi= m_patsi;
|
|
|
|
for (c= m_ctsSlots; c--; ++ptsi)
|
|
{
|
|
UINT fOptions= ptsi->fFlags & (PRESENT | ACTIVE);
|
|
|
|
ptsi->fFlags &= ~(PRESENT | ACTIVE | PREVIOUSLY_PRESENT | PREVIOUSLY_ACTIVE);
|
|
|
|
ptsi->fFlags |= fOptions | (fOptions << TIME_SHIFT);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
const UINT *CTokenCollection::LRRanking()
|
|
{
|
|
ASSERT(FALSE); // Shouldn't be called!
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const UINT *CTokenCollection::RLRanking()
|
|
{
|
|
ASSERT(m_pRLRanking);
|
|
|
|
return m_pRLRanking;
|
|
}
|
|
|
|
void CTokenCollection::CombineTokenLists(PTokenInfo *paptiSets, PUINT paiTokenStarts, UINT ctiSets,
|
|
PTokenInfo **ppptiSorted, PUINT pcti,
|
|
PCompareImages pfnCompareImages
|
|
)
|
|
{
|
|
PTokenInfo *paptiSortedLeft = NULL,
|
|
*paptiSortedRight = NULL;
|
|
PTokenInfo *paptiSortedResult= NULL;
|
|
|
|
UINT cFirst = 0;
|
|
UINT cSecond = 0;
|
|
|
|
__try
|
|
{
|
|
if (ctiSets == 1)
|
|
{
|
|
*ppptiSorted = paptiSets + *paiTokenStarts;
|
|
*pcti = *(paiTokenStarts + 1) - *paiTokenStarts;
|
|
|
|
__leave;
|
|
}
|
|
|
|
UINT ctiLeft = 0,
|
|
ctiRight = 0;
|
|
|
|
cFirst = ctiSets / 2;
|
|
cSecond = ctiSets - cFirst;
|
|
|
|
CombineTokenLists(paptiSets, paiTokenStarts, cFirst, &paptiSortedLeft, &ctiLeft, pfnCompareImages);
|
|
|
|
CombineTokenLists(paptiSets, paiTokenStarts + cFirst, cSecond, &paptiSortedRight, &ctiRight, pfnCompareImages);
|
|
|
|
UINT ctiResult= ctiLeft + ctiRight;
|
|
|
|
paptiSortedResult= (PTokenInfo *) VAlloc(FALSE, ctiResult * sizeof(PTokenInfo));
|
|
|
|
MergeImageRefSets((PVOID *) paptiSortedResult, ctiResult,
|
|
(PVOID *) paptiSortedLeft, ctiLeft,
|
|
(PVOID *) paptiSortedRight, ctiRight,
|
|
pfnCompareImages
|
|
);
|
|
|
|
#ifdef _DEBUG
|
|
{
|
|
for (int c=ctiResult; --c > 0 ; )
|
|
ASSERT(0 >= pfnCompareImages(paptiSortedResult + c - 1, paptiSortedResult + c));
|
|
}
|
|
#endif // _DEBUG
|
|
|
|
|
|
*ppptiSorted = paptiSortedResult; paptiSortedResult= NULL;
|
|
*pcti = ctiResult;
|
|
}
|
|
__finally
|
|
{
|
|
if (paptiSortedLeft && cFirst > 1) { VFree(paptiSortedLeft ); paptiSortedLeft = NULL; }
|
|
if (paptiSortedRight && cSecond > 1) { VFree(paptiSortedRight); paptiSortedRight = NULL; }
|
|
|
|
if (_abnormal_termination() && paptiSortedResult)
|
|
{
|
|
VFree(paptiSortedResult); paptiSortedResult = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
int __cdecl CTokenCollection::CompareTokenInfo(const void *pvL, const void *pvR)
|
|
{
|
|
return CompareImagesLR(&(*(const TokenInfo **) pvL)->pd, &(*(const TokenInfo **) pvR)->pd);
|
|
}
|
|
|
|
int __cdecl CTokenCollection::CompareTokenInfoRLI(const void *pvL, const void *pvR)
|
|
{
|
|
return CompareImagesRL(&(*(const TokenInfo **) pvL)->pd, &(*(const TokenInfo **) pvR)->pd);
|
|
}
|
|
|
|
void CTokenCollection::MergeTokenCategory(UINT iValue, PVOID pvTag, PVOID pvEnvironment)
|
|
{
|
|
PCategoryEnvironment pcatenv= PCategoryEnvironment(pvEnvironment);
|
|
PTokenHashInfo pthi = PTokenHashInfo (pvTag );
|
|
|
|
PTokenInfo ptiNew = pcatenv->ptiLimit - (iValue + 1);
|
|
PTokenInfo ptiOld = pthi ->pti;
|
|
|
|
ASSERT(ptiNew != ptiOld);
|
|
|
|
if (ptiNew < ptiOld)
|
|
{
|
|
ptiNew->ptiCloneLink = ptiOld;
|
|
pthi ->pti = ptiNew;
|
|
}
|
|
else
|
|
{
|
|
ptiNew->ptiCloneLink = ptiOld->ptiCloneLink;
|
|
ptiOld->ptiCloneLink = ptiNew;
|
|
}
|
|
}
|
|
|
|
void CTokenCollection::AddTokenCategory(UINT iValue, PVOID pvTag, PVOID pvEnvironment)
|
|
{
|
|
PCategoryEnvironment pcatenv= PCategoryEnvironment(pvEnvironment);
|
|
PTokenHashInfo pthi = PTokenHashInfo (pvTag );
|
|
|
|
PTokenInfo ptiNew = pcatenv->ptiLimit - (iValue + 1);
|
|
|
|
ptiNew->ptiCloneLink= NULL;
|
|
|
|
pthi->pti= ptiNew;
|
|
}
|
|
|
|
void CTokenCollection::IndicatePrimaryClones(PVOID pvTag, PVOID pvEnvironment)
|
|
{
|
|
CIndicatorSet *pis = (CIndicatorSet *) pvEnvironment;
|
|
PTokenHashInfo pthi = PTokenHashInfo(pvTag);
|
|
|
|
pis->RawSetBit(pthi->pti->iRank);
|
|
}
|
|
|
|
UINT CTokenCollection::MapToTokenLists(CIndicatorSet * pisTokenReps, PTokenInfo *paptiLists, UINT cLists)
|
|
{
|
|
ASSERT(cLists >= m_ctsSlots);
|
|
|
|
PUINT paiBuffer = NULL;
|
|
UINT cTokens = 0;
|
|
|
|
|
|
__try
|
|
{
|
|
UINT cReps= pisTokenReps? pisTokenReps->SelectionCount() : m_cd;
|
|
|
|
UINT cChunk= C_INDICES_CHUNK;
|
|
|
|
if (cChunk > cReps) cChunk= cReps;
|
|
|
|
paiBuffer= PUINT(VAlloc(FALSE, cChunk * sizeof(UINT)));
|
|
|
|
ASSERT(paiBuffer);
|
|
|
|
ZeroMemory(paptiLists, cLists * sizeof(PTokenInfo));
|
|
|
|
UINT iRepFirst;
|
|
|
|
for (iRepFirst= 0; cReps; iRepFirst += cChunk, cReps -= cChunk)
|
|
{
|
|
if (cChunk > cReps) cChunk= cReps;
|
|
|
|
UINT c, i;
|
|
PUINT pi;
|
|
|
|
if (pisTokenReps) pisTokenReps->MarkedItems(iRepFirst, PINT(paiBuffer), cChunk);
|
|
else
|
|
for (i= iRepFirst, c= cChunk, pi= paiBuffer; c--; ) *pi++ = i++;
|
|
|
|
for (c= cChunk, pi= paiBuffer + cChunk; c--; )
|
|
{
|
|
PTokenInfo pti= m_pati + m_ppdSorted[*--pi]->iTokenInfo;
|
|
|
|
for (; pti; pti= pti->ptiCloneLink)
|
|
{
|
|
UINT iSlot= pti->iaTSSlot;
|
|
|
|
ASSERT(m_patsi[iSlot].fFlags & PRESENT);
|
|
|
|
if (!(ACTIVE & m_patsi[iSlot].fFlags)) continue;
|
|
|
|
++cTokens;
|
|
|
|
pti->ptiTextSetLink= paptiLists[iSlot];
|
|
|
|
paptiLists[iSlot]= pti;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
if (paiBuffer) { VFree(paiBuffer); paiBuffer = NULL; }
|
|
}
|
|
|
|
return cTokens;
|
|
}
|