WindowsXP/Source/XPSP1/NT/inetsrv/query/cindex/dirtree.cxx
2024-08-03 16:30:48 +02:00

150 lines
3.3 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: DIRTREE.CXX
//
// Contents: Directory Tree
//
// Classes: CDirTree
//
// History: 13-Aug-91 BartoszM Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <misc.hxx>
#include <dirtree.hxx>
void CDirTree::Init ( unsigned count )
{
//
// If we are rebuilding the directory tree, cleanup the old one
//
if (_count != 0)
{
delete _pKeys;
_pKeys = new CKeyArray(1);
}
ciAssert ( count > 0 );
_count = count;
// How many binary digits are needed
// to represent numbers from 0 to _count-1?
if ( _count > 1 )
_digits = Log2 ( _count - 1 );
else
_digits = 0;
_firstLeaf = 1 << _digits;
}
void CDirTree::Init ( CKeyArray& keys, unsigned count )
{
Init ( count );
for ( unsigned n = 1; n < count; n++)
{
ciAssert ( keys.Get(n).Pid() != pidAll );
_pKeys->Add ( Index(n), keys.Get(n) );
}
Done ( n );
}
void CDirTree::Add ( unsigned i, const CKeyBuf& key )
{
// skip the zerot'th key
if ( i == 0 )
return;
ciAssert ( &key != 0 );
ciAssert ( key.Pid() != pidAll );
_pKeys->Add ( Index(i), key);
}
unsigned CDirTree::Seek ( const CKey& key ) const
{
ciDebugOut (( DEB_PDIR, "CDirTree::Seek %.*ws pid %d\n",
key.StrLen(), key.GetStr(), key.Pid() ));
//----------------------------------------------------
// Notice: Make sure that pidAll is smaller
// than any other legal PID. If the search key
// has pidAll we want to be positioned at the beginning
// of the range.
//----------------------------------------------------
ciAssert ( pidAll == 0 );
for ( unsigned i = 1; i < _firstLeaf; )
{
ciDebugOut (( DEB_PDIR, "\tCompare with %.*ws pid %d ",
_pKeys->Get(i).StrLen(), _pKeys->Get(i).GetStr(), _pKeys->Get(i).Pid() ));
if ( key.Compare(_pKeys->Get(i)) < 0 )
{
ciDebugOut (( DEB_PDIR, "too big\n" ));
i = 2 * i;
}
else
{
ciDebugOut (( DEB_PDIR, "too small or equal\n" ));
i = 2 * i + 1;
}
}
return i - _firstLeaf;
}
// Decompose idx = (1, 2^digits - 1) in the following form
// idx = i * 2^n, where i is odd
// n counts the number of trailing zeros,
// i has (digits - n) digits
//
// level = digits - n
// is the level of the tree (root is level 1)
//
// i / 2 is the node number within this level
// it has (level-1) digits
unsigned CDirTree::Index( unsigned idx )
{
ciAssert (idx != 0);
unsigned i = idx;
unsigned n = 0;
while ( (i & 1) == 0 )
{
i >>= 1;
n++;
}
// n = number of trailing 0's
// i is odd
idx = (1 << (_digits - n - 1)) + (i >> 1);
ciAssert ( idx < _firstLeaf );
return idx;
}
void CDirTree::Done( unsigned i )
{
//
// This can be very expensive, since each key will allocate
// > 250 bytes and fill them with 0xff. But it's too late to do anything
// about it since the definition of max key is defined now that we've
// shipped.
//
for ( ; i < _firstLeaf; i++ )
_pKeys->FillMax(Index(i));
}