- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
360 lines
11 KiB
Plaintext
360 lines
11 KiB
Plaintext
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* BTREELFN.CPP */
|
|
/* */
|
|
/* Copyright Borland International 1991, 1993 */
|
|
/* All Rights Reserved */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
#if !defined( __STDLIB_H )
|
|
#include <stdlib.h>
|
|
#endif // __STDLIB_H
|
|
|
|
#if !defined( __IOSTREAM_H )
|
|
#include <iostream.h>
|
|
#endif // __IOSTREAM_H
|
|
|
|
#if !defined( CHECKS_H )
|
|
#include <checks.h>
|
|
#endif // CHECKS_H
|
|
|
|
#if !defined( __BTREE_H )
|
|
#include "classlib\obsolete\btree.h"
|
|
#endif // __BTREE_H
|
|
|
|
//====== LeafNode functions =======
|
|
|
|
LeafNode::LeafNode(InnerNode* P, Sortable* O, Btree* T): Node(1, P, T)
|
|
{
|
|
item = new Sortable *[maxIndex()+1];
|
|
if( item == 0 )
|
|
ClassLib_error( __ENOMEMLN );
|
|
if( O != 0 )
|
|
item[++last] = O;
|
|
}
|
|
|
|
LeafNode::~LeafNode()
|
|
{
|
|
if( tree->ownsElements() )
|
|
{
|
|
for( int i = 0; i <= last; i++ )
|
|
delete item[i];
|
|
}
|
|
delete [] item;
|
|
}
|
|
|
|
void LeafNode::add(Sortable *obj, int index)
|
|
{
|
|
// add the object OBJ to the leaf node, inserting it at location INDEX
|
|
// in the item array
|
|
PRECONDITION( 0 <= index && index <= last+1 );
|
|
PRECONDITION( last <= maxIndex() );
|
|
for( int i = last+1; i > index ; i-- )
|
|
item[i] = item[ i - 1 ];
|
|
item[ index ] = obj;
|
|
last++;
|
|
|
|
// check for overflow
|
|
if( parent == 0 )
|
|
tree->incrNofKeys( );
|
|
else
|
|
parent->incrNofKeys( this );
|
|
|
|
if( isFull() )
|
|
{
|
|
// it's full; tell parent node
|
|
if( parent == 0 )
|
|
{
|
|
// this occurs when this leaf is the only node in the
|
|
// btree, and this->tree->root == this
|
|
CHECK( tree->root == this );
|
|
// in which case we inform the btree, which can be
|
|
// considered the parent of this node
|
|
tree->rootIsFull();
|
|
}
|
|
else
|
|
{
|
|
// the parent is responsible for splitting/balancing subnodes
|
|
parent->isFull( this );
|
|
}
|
|
}
|
|
}
|
|
|
|
void LeafNode::appendFrom( LeafNode* src, int start, int stop )
|
|
{
|
|
// A convenience function, does not worry about the element in
|
|
// the parent, simply moves elements from SRC[start] to SRC[stop]
|
|
// into the current array.
|
|
// This should never create a full node.
|
|
// That is, it is not used anywhere where THIS could possibly be
|
|
// near full.
|
|
// Does NOT handle nofKeys.
|
|
if( start > stop )
|
|
return;
|
|
PRECONDITION( 0 <= start && start <= src->last );
|
|
PRECONDITION( 0 <= stop && stop <= src->last );
|
|
PRECONDITION( last + stop - start + 1 < maxIndex() ); // full-node check
|
|
for( int i = start; i <= stop; i++ )
|
|
item[++last] = src->item[i];
|
|
CHECK( last < maxIndex() );
|
|
}
|
|
|
|
void LeafNode::append( Sortable* D )
|
|
{
|
|
// never called from anywhere where it might fill up THIS
|
|
// does NOT handle nofKeys.
|
|
item[++last] = D;
|
|
CHECK( last < maxIndex() );
|
|
}
|
|
|
|
|
|
void LeafNode::balanceWithLeft( LeafNode* leftsib, int pidx )
|
|
{
|
|
// THIS has more than LEFTSIB; move some items from THIS to LEFTSIB.
|
|
PRECONDITION( Vsize() >= leftsib->Psize() );
|
|
int newThisSize = (Vsize() + leftsib->Psize())/2;
|
|
int noFromThis = Psize() - newThisSize;
|
|
pushLeft( noFromThis, leftsib, pidx );
|
|
}
|
|
|
|
void LeafNode::balanceWithRight( LeafNode* rightsib, int pidx )
|
|
{
|
|
// THIS has more than RIGHTSIB; move some items from THIS to RIGHTSIB.
|
|
PRECONDITION( Psize() >= rightsib->Vsize() );
|
|
int newThisSize = (Psize() + rightsib->Vsize())/2;
|
|
int noFromThis = Psize() - newThisSize;
|
|
pushRight( noFromThis, rightsib, pidx );
|
|
}
|
|
|
|
void LeafNode::balanceWith( LeafNode* rightsib, int pidx )
|
|
{
|
|
// PITEM is the parent item whose key will change when keys are shifted
|
|
// from one LeafNode to the other.
|
|
if( Psize() < rightsib->Vsize() )
|
|
rightsib->balanceWithLeft( this, pidx );
|
|
else
|
|
balanceWithRight( rightsib, pidx );
|
|
}
|
|
|
|
long LeafNode::findRank( Sortable* what ) const
|
|
{
|
|
// WHAT was not in any inner node; it is either here, or it's
|
|
// not in the tree
|
|
for( int i = 0; i <= last; i++ )
|
|
{
|
|
if( *item[i] == *what )
|
|
return i;
|
|
if( *item[i] >= *what )
|
|
return -1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
LeafNode *LeafNode::firstLeafNode()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
Object& LeafNode::found(Sortable* what, Node** which, int* where )
|
|
{
|
|
// WHAT was not in any inner node; it is either here, or it's
|
|
// not in the tree
|
|
for( int i = 0; i <= last; i++ )
|
|
{
|
|
if( *item[i] == *what )
|
|
{
|
|
*which = this;
|
|
*where = i;
|
|
return *item[i];
|
|
}
|
|
if( *item[i] >= *what )
|
|
{
|
|
*which = this;
|
|
*where = i;
|
|
return NOOBJECT;
|
|
}
|
|
}
|
|
*which = this;
|
|
*where = last+1;
|
|
return NOOBJECT;
|
|
}
|
|
|
|
#pragma warn -rvl
|
|
|
|
int LeafNode::indexOf( const Sortable *that ) const
|
|
{
|
|
// returns a number in the range 0 to maxIndex()
|
|
for( int i = 0; i <= last; i++ )
|
|
{
|
|
if( item[i] == that )
|
|
return i;
|
|
}
|
|
CHECK(0);
|
|
}
|
|
|
|
#pragma warn .rvl
|
|
|
|
LeafNode *LeafNode::lastLeafNode()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
void LeafNode::mergeWithRight( LeafNode* rightsib, int pidx )
|
|
{
|
|
PRECONDITION( Psize() + rightsib->Vsize() < maxPsize() );
|
|
rightsib->pushLeft( rightsib->Psize(), this, pidx );
|
|
append( parent->getKey( pidx ) );
|
|
parent->setNofKeys( pidx-1, nofKeys() );
|
|
// cout << "in mergeWithRight:\n" << *parent << "\n";
|
|
parent->removeItem( pidx );
|
|
delete rightsib;
|
|
// cout << "in mergeWithRight:\n" << *parent << "\n";
|
|
}
|
|
|
|
long LeafNode::nofKeys( int ) const
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
long LeafNode::nofKeys() const
|
|
{
|
|
return Psize();
|
|
}
|
|
|
|
void LeafNode::printOn(ostream& out) const
|
|
{
|
|
out << " < ";
|
|
for( int i = 0; i <= last; i++ )
|
|
out << *item[i] << " " ;
|
|
out << "> ";
|
|
}
|
|
|
|
void LeafNode::pushLeft( int noFromThis, LeafNode* leftsib, int pidx )
|
|
{
|
|
// noFromThis==1 => moves the parent item into the leftsib,
|
|
// and the first item in this's array into the parent item
|
|
PRECONDITION( noFromThis > 0 && noFromThis <= Psize() );
|
|
PRECONDITION( noFromThis + leftsib->Psize() < maxPsize() );
|
|
PRECONDITION( parent->getTree(pidx) == this );
|
|
leftsib->append( parent->getKey(pidx) );
|
|
if( noFromThis > 1 )
|
|
leftsib->appendFrom( this, 0, noFromThis-2 );
|
|
parent->setKey( pidx, item[noFromThis-1] );
|
|
shiftLeft( noFromThis );
|
|
parent->setNofKeys( pidx-1, leftsib->nofKeys() );
|
|
parent->setNofKeys( pidx, nofKeys() );
|
|
}
|
|
|
|
void LeafNode::pushRight( int noFromThis, LeafNode* rightsib, int pidx )
|
|
{
|
|
// noFromThis==1 => moves the parent item into the
|
|
// rightsib, and the last item in this's array into the parent
|
|
// item
|
|
PRECONDITION(noFromThis > 0 && noFromThis <= Psize());
|
|
PRECONDITION(noFromThis + rightsib->Psize() < maxPsize());
|
|
PRECONDITION(parent->getTree(pidx) == rightsib);
|
|
// The operation is five steps:
|
|
// Step I. Make room for the incoming keys in RIGHTSIB.
|
|
// Step II. Move the key in the parent into RIGHTSIB.
|
|
// Step III.Move the items from THIS into RIGHTSIB.
|
|
// Step IV. Move the item from THIS into the parent.
|
|
// Step V. Update the length of THIS.
|
|
//
|
|
// Step I.: make space for noFromThis items
|
|
//
|
|
int start = last - noFromThis + 1;
|
|
int tgt, src;
|
|
tgt = rightsib->last + noFromThis;
|
|
src = rightsib->last;
|
|
rightsib->last = tgt;
|
|
while (src >= 0)
|
|
rightsib->item[tgt--] = rightsib->item[src--];
|
|
|
|
// Step II. Move the key from the parent into place
|
|
rightsib->item[ tgt-- ] = parent->getKey( pidx );
|
|
|
|
// Step III.Move the items from THIS into RIGHTSIB
|
|
for( int i = last; i > start; i-- )
|
|
rightsib->item[tgt--] = item[i];
|
|
CHECK( tgt == -1 );
|
|
|
|
// Step IV.
|
|
parent->setKey( pidx, item[ start ] );
|
|
|
|
// Step V.
|
|
last -= noFromThis;
|
|
|
|
// Step VI. update nofKeys
|
|
parent->setNofKeys( pidx-1, nofKeys() );
|
|
parent->setNofKeys( pidx, rightsib->nofKeys() );
|
|
}
|
|
|
|
void LeafNode::remove( int index )
|
|
{
|
|
PRECONDITION( index >= 0 && index <= last );
|
|
for( int to = index; to < last; to++ )
|
|
item[to] = item[to+1];
|
|
last--;
|
|
if( parent == 0 )
|
|
tree->decrNofKeys();
|
|
else
|
|
parent->decrNofKeys( this );
|
|
if( isLow() )
|
|
{
|
|
if( parent == 0 )
|
|
{
|
|
// then this is the root; when no keys left, inform the tree
|
|
if( Psize() == 0 )
|
|
tree->rootIsEmpty();
|
|
}
|
|
else
|
|
parent->isLow( this );
|
|
}
|
|
}
|
|
|
|
void LeafNode::shiftLeft( int cnt )
|
|
{
|
|
if( cnt <= 0 )
|
|
return;
|
|
for( int i = cnt; i <= last; i++ )
|
|
item[i-cnt] = item[i];
|
|
last -= cnt;
|
|
}
|
|
|
|
void LeafNode::split()
|
|
{
|
|
// this function is called only when THIS is the only descendent
|
|
// of the root node, and THIS needs to be split.
|
|
// assumes that idx of THIS in Parent is 0.
|
|
LeafNode* newnode = new LeafNode( parent );
|
|
CHECK( newnode != 0 );
|
|
parent->append( item[last--], newnode );
|
|
parent->setNofKeys( 0, parent->getTree(0)->nofKeys() );
|
|
parent->setNofKeys( 1, parent->getTree(1)->nofKeys() );
|
|
balanceWithRight( newnode, 1 );
|
|
}
|
|
|
|
void LeafNode::splitWith( LeafNode *rightsib, int keyidx )
|
|
{
|
|
PRECONDITION(parent == rightsib->parent);
|
|
PRECONDITION(keyidx > 0 && keyidx <= parent->last);
|
|
int nofKeys = Psize() + rightsib->Vsize();
|
|
int newSizeThis = nofKeys / 3;
|
|
int newSizeNew = (nofKeys - newSizeThis) / 2;
|
|
int newSizeSib = (nofKeys - newSizeThis - newSizeNew);
|
|
int noFromThis = Psize() - newSizeThis;
|
|
int noFromSib = rightsib->Vsize() - newSizeSib;
|
|
CHECK(noFromThis >= 0);
|
|
CHECK(noFromSib >= 1);
|
|
LeafNode* newNode = new LeafNode(parent);
|
|
CHECK( newNode != 0 );
|
|
parent->addElt( keyidx, item[last--], newNode );
|
|
parent->setNofKeys( keyidx, 0 );
|
|
parent->decNofKeys( keyidx-1 );
|
|
this->pushRight( noFromThis-1, newNode, keyidx );
|
|
rightsib->pushLeft( noFromSib, newNode, keyidx+1 );
|
|
if( parent->isFull() )
|
|
parent->informParent();
|
|
}
|