405 lines
5.4 KiB
C++
405 lines
5.4 KiB
C++
![]() |
/*
|
||
|
** Command & Conquer Generals Zero Hour(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// Bin.cpp
|
||
|
//
|
||
|
|
||
|
#include "stdAfx.h"
|
||
|
#include "bin.h"
|
||
|
#include "assert.h"
|
||
|
#include "list.h"
|
||
|
|
||
|
Bin::Bin ( int size )
|
||
|
{
|
||
|
assert ( size > 0 );
|
||
|
num_buckets = size;
|
||
|
sh_item = NULL;
|
||
|
|
||
|
bucket = new List[size];
|
||
|
|
||
|
}
|
||
|
|
||
|
Bin::~Bin ( )
|
||
|
{
|
||
|
Clear ();
|
||
|
|
||
|
delete [] bucket;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void Bin::Clear ( void )
|
||
|
{
|
||
|
int count = num_buckets;
|
||
|
sh_item = NULL;
|
||
|
while ( count-- )
|
||
|
{
|
||
|
List *head = &bucket[count];
|
||
|
BinItem *item;
|
||
|
|
||
|
while ( ( item = (BinItem *) head->Next ()))
|
||
|
{
|
||
|
Remove ( item );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void* Bin::Get ( OLECHAR *text1, OLECHAR *text2 )
|
||
|
{
|
||
|
BinItem *item;
|
||
|
|
||
|
if ( ( item = GetBinItem ( text1, text2 )) )
|
||
|
{
|
||
|
return item->Item();
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void* Bin::GetNext ( void )
|
||
|
{
|
||
|
BinItem *item;
|
||
|
|
||
|
if ( ( item = GetNextBinItem ( )) )
|
||
|
{
|
||
|
return item->Item();
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void Bin::Add ( void *data, OLECHAR *text1, OLECHAR *text2 )
|
||
|
{
|
||
|
BinItem *item;
|
||
|
List *list;
|
||
|
int hash;
|
||
|
|
||
|
sh_item = NULL;
|
||
|
|
||
|
hash = calc_hash ( text1 );
|
||
|
item = new BinItem ( data, hash, text1, text2 );
|
||
|
|
||
|
list = &bucket[hash%num_buckets];
|
||
|
|
||
|
list->AddToTail ( (ListNode *) item );
|
||
|
|
||
|
}
|
||
|
|
||
|
BinItem* Bin::GetBinItem ( OLECHAR *text1, OLECHAR *text2)
|
||
|
{
|
||
|
|
||
|
sh_size1 = sh_size2 = 0;
|
||
|
sh_text1 = text1;
|
||
|
sh_text2 = text2;
|
||
|
|
||
|
sh_hash = calc_hash ( text1 );
|
||
|
|
||
|
if ( sh_text1 )
|
||
|
{
|
||
|
sh_size1 = wcslen ( sh_text1 );
|
||
|
}
|
||
|
|
||
|
if ( sh_text2 )
|
||
|
{
|
||
|
sh_size2 = wcslen ( sh_text2 );
|
||
|
}
|
||
|
|
||
|
sh_item = (BinItem *) &bucket[sh_hash%num_buckets];
|
||
|
|
||
|
|
||
|
return GetNextBinItem ();
|
||
|
}
|
||
|
|
||
|
BinItem* Bin::GetNextBinItem ( void )
|
||
|
{
|
||
|
if ( sh_item )
|
||
|
{
|
||
|
sh_item = (BinItem *) sh_item->Next ();
|
||
|
}
|
||
|
|
||
|
while ( sh_item )
|
||
|
{
|
||
|
if ( sh_item->Same ( sh_hash, sh_text1, sh_size1, sh_text2, sh_size2 ))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
sh_item = (BinItem *) sh_item->Next ();
|
||
|
}
|
||
|
|
||
|
return sh_item;
|
||
|
}
|
||
|
|
||
|
BinItem* Bin::GetBinItem ( void *item )
|
||
|
{
|
||
|
BinItem *bitem = NULL;
|
||
|
int i;
|
||
|
|
||
|
|
||
|
for ( i=0; i< num_buckets; i++)
|
||
|
{
|
||
|
|
||
|
if ( ( bitem = (BinItem *) bucket[i].Find ( item )))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return bitem;
|
||
|
|
||
|
}
|
||
|
|
||
|
void Bin::Remove ( void *item )
|
||
|
{
|
||
|
BinItem *bitem;
|
||
|
|
||
|
if ( ( bitem = GetBinItem ( item ) ))
|
||
|
{
|
||
|
Remove ( bitem );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void Bin::Remove ( OLECHAR *text1, OLECHAR *text2 )
|
||
|
{
|
||
|
BinItem *bitem;
|
||
|
|
||
|
if ( ( bitem = GetBinItem ( text1, text2 ) ))
|
||
|
{
|
||
|
Remove ( bitem );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void Bin::Remove ( BinItem *item )
|
||
|
{
|
||
|
sh_item = NULL;
|
||
|
item->Remove ();
|
||
|
delete item ;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
BinItem::BinItem ( void *data, int new_hash, OLECHAR *new_text1, OLECHAR *new_text2 )
|
||
|
{
|
||
|
SetItem ( data );
|
||
|
hash = new_hash;
|
||
|
|
||
|
if ( (text1 = new_text1) )
|
||
|
{
|
||
|
text1size = wcslen ( text1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
text1size = 0;
|
||
|
}
|
||
|
|
||
|
if ( (text2 = new_text2) )
|
||
|
{
|
||
|
text2size = wcslen ( text2 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
text2size = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int BinItem::Same ( int chash, OLECHAR *ctext1, int size1, OLECHAR *ctext2, int size2 )
|
||
|
{
|
||
|
if ( hash != chash || text1size != size1 || text2size != size2 )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( wcsicmp ( text1, ctext1 ))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( text2 && ctext2 && wcsicmp ( text2, ctext2 ))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
|
||
|
}
|
||
|
int Bin::calc_hash ( OLECHAR *text )
|
||
|
{
|
||
|
int hash = 0;
|
||
|
|
||
|
while ( *text )
|
||
|
{
|
||
|
hash += *text++;
|
||
|
}
|
||
|
|
||
|
return hash;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Bin ID code
|
||
|
|
||
|
BinID::BinID ( int size )
|
||
|
{
|
||
|
assert ( size > 0 );
|
||
|
num_buckets = size;
|
||
|
|
||
|
bucket = new List[size];
|
||
|
|
||
|
}
|
||
|
|
||
|
BinID::~BinID ( )
|
||
|
{
|
||
|
Clear ();
|
||
|
|
||
|
delete [] bucket;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void BinID::Clear ( void )
|
||
|
{
|
||
|
int count = num_buckets;
|
||
|
|
||
|
while ( count-- )
|
||
|
{
|
||
|
List *head = &bucket[count];
|
||
|
BinIDItem *item;
|
||
|
|
||
|
while ( ( item = (BinIDItem *) head->Next ()))
|
||
|
{
|
||
|
Remove ( item );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void* BinID::Get ( int id)
|
||
|
{
|
||
|
BinIDItem *item;
|
||
|
|
||
|
if ( ( item = GetBinIDItem ( id )) )
|
||
|
{
|
||
|
return item->Item();
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void BinID::Add ( void *data, int id )
|
||
|
{
|
||
|
BinIDItem *item;
|
||
|
List *list;
|
||
|
|
||
|
|
||
|
item = new BinIDItem ( data, id );
|
||
|
|
||
|
list = &bucket[id%num_buckets];
|
||
|
|
||
|
list->AddToTail ( (ListNode *) item );
|
||
|
|
||
|
}
|
||
|
|
||
|
BinIDItem* BinID::GetBinIDItem ( int id )
|
||
|
{
|
||
|
BinIDItem *item;
|
||
|
|
||
|
|
||
|
item = (BinIDItem *) bucket[id%num_buckets].Next();
|
||
|
|
||
|
while ( item )
|
||
|
{
|
||
|
if ( item->Same ( id ))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
item = (BinIDItem *) item->Next ();
|
||
|
}
|
||
|
|
||
|
return item ;
|
||
|
}
|
||
|
|
||
|
|
||
|
BinIDItem* BinID::GetBinIDItem ( void *item )
|
||
|
{
|
||
|
BinIDItem *bitem = NULL;
|
||
|
int i;
|
||
|
|
||
|
|
||
|
for ( i=0; i< num_buckets; i++)
|
||
|
{
|
||
|
|
||
|
if ( ( bitem = (BinIDItem *) bucket[i].Find ( item )))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return bitem;
|
||
|
|
||
|
}
|
||
|
|
||
|
void BinID::Remove ( void *item )
|
||
|
{
|
||
|
BinIDItem *bitem;
|
||
|
|
||
|
if ( ( bitem = GetBinIDItem ( item ) ))
|
||
|
{
|
||
|
Remove ( bitem );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void BinID::Remove ( int id )
|
||
|
{
|
||
|
BinIDItem *bitem;
|
||
|
|
||
|
if ( ( bitem = GetBinIDItem ( id ) ))
|
||
|
{
|
||
|
Remove ( bitem );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void BinID::Remove ( BinIDItem *item )
|
||
|
{
|
||
|
item->Remove ();
|
||
|
delete item ;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
BinIDItem::BinIDItem ( void *data, int new_id )
|
||
|
{
|
||
|
SetItem ( data );
|
||
|
id = new_id;
|
||
|
|
||
|
}
|
||
|
|
||
|
int BinIDItem::Same ( int compare_id )
|
||
|
{
|
||
|
return id == compare_id;
|
||
|
}
|
||
|
|