btrees.cpp
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C++ 代码 · 共 643 行 · 第 1/2 页
CPP
643 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
/*
BTREES: WinHelp-style B-tree implementation.
*/
#include "btrees.h"
#include <stdlib.h>
//
// BtreePage --A b-tree 'node'. Used only by other
// b-tree functions.
//
struct BtreePage
{
uint_16 _numEntries; // # of BtreeData in this page.
BtreePage *_prevPage; // Prev page in this level.
BtreePage *_nextPage; // Next page in this level.
uint_16 _thisPage; // Index # of this page.
uint_32 _size; // Size of the page
uint_32 _maxSize; // The page size; used for dumping
BtreeData *_entries; // Pointer to BtreeData list.
BtreePage *_parent; // Parent page.
BtreePage *_firstChild; // First child page.
// Dump this page to an output file.
int dump( OutFile *dest );
// Split a page which has gotten too large into two pages.
int split();
BtreePage( uint_32 max_size, BtreePage *ancestor, BtreePage *descendant=NULL );
~BtreePage();
};
// BtreeData::BtreeData
BtreeData::BtreeData()
: _bnext( NULL ),
_bprev( NULL ),
_child( NULL )
{
// empty
}
// BtreeData::insertSelf --Insert this object into the specified page.
void BtreeData::insertSelf( BtreePage *dest )
{
BtreeData *current = dest->_entries;
BtreeData *temp = NULL;
while( current != NULL && current->lessThan( this ) ){
temp = current;
current = current->_bnext;
}
if( temp == NULL ){
if( current != NULL ){
_bnext = current;
current->_bprev = this;
}
dest->_entries = this;
} else {
_bnext = temp->_bnext;
_bprev = temp;
temp->_bnext = this;
if( _bnext != NULL ){
_bnext->_bprev = this;
}
}
dest->_size += size();
dest->_numEntries += 1;
return;
}
// BtreeDate::seekNext --Find the child of the specified
// page where this data belongs.
BtreePage *BtreeData::seekNext( BtreePage *first )
{
BtreePage *result = first->_firstChild;
BtreeData *current = first->_entries;
while( current != NULL ){
if( lessThan( current ) ) break;
result = current->_child;
current = current->_bnext;
}
return result;
}
// BtreePage::BtreePage
#define TREEPAGE_HEADER_SIZE 4
BtreePage::BtreePage( uint_32 max_size, BtreePage *ancestor, BtreePage *descendant )
: _maxSize( max_size ),
_parent( ancestor ),
_firstChild( descendant ),
_numEntries( 0 ),
_prevPage( NULL ),
_nextPage( NULL ),
_entries( NULL )
{
if( descendant == NULL ){
// Leaf pages start with a header and indices to the previous
// and next leaf pages.
_size = TREEPAGE_HEADER_SIZE+2*sizeof( uint_16 );
} else {
// Index pages start with a header and index to the leftmost
// child.
_size = TREEPAGE_HEADER_SIZE+sizeof( uint_16 );
}
}
// BtreePage::~BtreePage --Deletes all of its contents as well.
BtreePage::~BtreePage()
{
BtreeData *current = _entries;
BtreeData *temp;
while( current != NULL ){
temp = current;
current = current->bnext();
delete temp;
}
}
// BtreePage::dump --Dump the page to an output file.
BtreePage::dump( OutFile *dest )
{
uint_32 amount_left = _maxSize;
uint_16 nil_16 = (uint_16) ~0;
// Spit out the page header.
dest->writech(0);
dest->writech(0);
dest->writebuf( &_numEntries, sizeof( uint_16 ), 1 );
amount_left -= TREEPAGE_HEADER_SIZE;
// If this a leaf node, print the indices of the previous
// and next pages.
if( _firstChild == NULL ){
if( _prevPage ){
dest->writebuf( &(_prevPage->_thisPage), sizeof( uint_16 ), 1 );
} else {
dest->writebuf( &nil_16, sizeof( uint_16 ), 1 );
}
if( _nextPage ){
dest->writebuf( &(_nextPage->_thisPage), sizeof( uint_16 ), 1 );
} else {
dest->writebuf( &nil_16, sizeof( uint_16 ), 1 );
}
amount_left -= 2 * sizeof( uint_16 );
} else {
// If this is a tree node, print the index of the first child.
dest->writebuf( &(_firstChild->_thisPage), sizeof( uint_16 ), 1 );
amount_left -= sizeof( uint_16 );
}
for( BtreeData *i = _entries; i != NULL; i = i->bnext() ){
// Dump the data.
i->dump( dest );
amount_left -= i->size();
// if this is a tree node, print the index of the child page
// corresponding to this data.
if( _firstChild != NULL ){
dest->writebuf( &(i->child()->_thisPage), sizeof( uint_16 ), 1 );
amount_left -= sizeof( uint_16 );
}
}
// Pad out the remaining space.
while( amount_left ){
dest->writech( 0 );
amount_left--;
}
return 1;
}
// BtreePage::split --Break the page in two. Assumes the parent
// page is non-empty.
int BtreePage::split()
{
int i=0;
uint_16 limit = (uint_16) ((_numEntries + 1) / 2);
uint_32 cur_size = 0;
uint_16 cur_num = 0;
BtreeData *current = _entries;
BtreePage *sibling;
// Search for the point to break the page at.
while( current != NULL ){
if( cur_num >= limit ) break;
cur_size += current->size();
cur_num++;
current = current->bnext();
}
if( current == NULL ) return 0;
// Create a new page, and modify the assorted pointers.
sibling = new BtreePage( _maxSize, _parent, current->child() );
sibling->_prevPage = this;
sibling->_nextPage = _nextPage;
if( _nextPage != NULL ){
_nextPage->_prevPage = sibling;
}
_nextPage = sibling;
// Give some of our data to the new page by modifying our data list.
if( _firstChild != NULL ){
sibling->_entries = current->bnext();
if( current->bprev() != NULL ){
current->bprev()->bnext( NULL );
} else {
_entries = NULL;
}
if( current->bnext() != NULL ){
current->bnext()->bprev( NULL );
}
sibling->_numEntries = (uint_16) (_numEntries-cur_num-1);
sibling->_size = _size-cur_size-current->size();
} else {
sibling->_entries = current;
if( current->bprev() != NULL ){
current->bprev()->bnext( NULL );
} else {
_entries = NULL;
}
current->bprev( NULL );
sibling->_numEntries = (uint_16) (_numEntries-cur_num);
sibling->_size = _size-cur_size;
}
// Record the fact that we've lost data.
_numEntries = cur_num;
_size = cur_size + TREEPAGE_HEADER_SIZE + sizeof(uint_16);
if( _firstChild == NULL ){
_size += sizeof( uint_16 );
}
if( _parent == NULL ){
// Die in flames!!!
HCError( BTREE_ERR );
} else {
// Notify the parent page of the split by passing a new data item.
BtreeData *newdata;
if( _firstChild == NULL ){
// If this is a leaf page, we generate a new item.
newdata = current->myKey();
} else {
// If this is a tree page, we pass an existing item.
newdata = current;
newdata->bnext( NULL );
newdata->bprev( NULL );
}
newdata->child( sibling );
newdata->insertSelf( _parent );
_parent->_size += sizeof( uint_16 );
}
// Update the parent field of 'sibling's children.
if( _firstChild != NULL ){
sibling->_firstChild->_parent = sibling;
current = sibling->_entries;
while( current != NULL ){
current->child()->_parent = sibling;
current = current->bnext();
}
}
// And we're done!
return 1;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?