00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
#include "IDMap_AMOS.hh"
00011
#include <string>
00012
#include <sstream>
00013
#include <cstring>
00014
using namespace AMOS;
00015
using namespace std;
00016
00017
00018
00019
00020
00021
00022
00023
IDMap_t::HashTriple_t & IDMap_t::HashTriple_t::operator=
00024 (
const HashTriple_t & s)
00025 {
00026
if (
this != &s )
00027 {
00028 c = s.c;
00029 iid = s.iid;
00030 bid = s.bid;
00031 eid = s.eid;
00032 }
00033
return *
this;
00034 }
00035
00036
00037
00038
00039
00040
00041
void IDMap_t::HashNode_t::clear ( )
00042 {
00043
if ( triple != NULL )
00044
if ( -- (triple -> c) == 0 )
00045
delete triple;
00046
delete next;
00047
00048 triple = NULL;
00049 next = NULL;
00050 }
00051
00052
00053
00054
00055
00056 const NCode_t IDMap_t::NCODE =
M_IDMAP;
00057
const Size_t IDMap_t::DEFAULT_NUM_BUCKETS = 1000;
00058
00059
00060
00061 void IDMap_t::clear ( )
00062 {
00063
if ( size_m > 0 )
00064 {
00065 vector<HashNode_t>::iterator hni;
00066
for ( hni = iid_bucs_m .
begin( ); hni != iid_bucs_m .
end( ); hni ++ )
00067 hni -> clearchain( );
00068
for ( hni = eid_bucs_m .
begin( ); hni != eid_bucs_m .
end( ); hni ++ )
00069 hni -> clearchain( );
00070 size_m = 0;
00071 }
00072 type_m =
NULL_NCODE;
00073 }
00074
00075
00076
00077
Size_t IDMap_t::minbuckets (
Size_t min)
00078 {
00079
00080
const uint8_t NUM_BUCKET_SIZES = 27;
00081
const Size_t BUCKET_SIZES [NUM_BUCKET_SIZES] =
00082 {
00083 53l, 97l, 193l, 389l, 769l,
00084 1543l, 3079l, 6151l, 12289l, 24593l,
00085 49157l, 98317l, 196613l, 393241l, 786433l,
00086 1572869l, 3145739l, 6291469l, 12582917l, 25165843l,
00087 50331653l, 100663319l, 201326611l, 402653189l, 805306457l,
00088 1610612741l, 2147354947l
00089 };
00090
00091 uint8_t first = 0;
00092 uint8_t len = NUM_BUCKET_SIZES;
00093 uint8_t half, middle;
00094
00095
00096
while ( len > 0 )
00097 {
00098 half = len >> 1;
00099 middle = first + half;
00100
if ( BUCKET_SIZES [middle] < min )
00101 {
00102 first = middle + 1;
00103 len = len - half - 1;
00104 }
00105
else
00106 len = half;
00107 }
00108
if ( first == NUM_BUCKET_SIZES )
00109 first --;
00110
00111
return BUCKET_SIZES [first];
00112 }
00113
00114
00115
00116
bool IDMap_t::lookupnode (
ID_t key, HashNode_t * & node)
const
00117
{
00118
if ( key ==
NULL_ID )
00119 {
00120 node = NULL;
00121
return false;
00122 }
00123
for ( node = hashfunc (key); node -> next != NULL; node = node -> next )
00124
if ( node -> triple -> iid == key )
00125
return true;
00126
if ( node -> triple == NULL || node -> triple -> iid != key )
00127
return false;
00128
else
00129
return true;
00130 }
00131
00132
00133
00134
bool IDMap_t::lookupnode (
const string & key, HashNode_t * & node)
const
00135
{
00136
if ( key .
empty( ) )
00137 {
00138 node = NULL;
00139
return false;
00140 }
00141
for ( node = hashfunc (key); node -> next != NULL; node = node -> next )
00142
if ( node -> triple -> eid == key )
00143
return true;
00144
if ( node -> triple == NULL || node -> triple -> eid != key )
00145
return false;
00146
else
00147
return true;
00148 }
00149
00150
00151
00152
void IDMap_t::removenode (HashNode_t * curr, HashNode_t * prev)
00153 {
00154
if ( prev == NULL )
00155
00156 {
00157
if ( curr -> next == NULL )
00158 curr ->
clear( );
00159
else
00160 {
00161 prev = curr -> next;
00162 curr -> next = NULL;
00163 curr ->
clear( );
00164 *curr = *prev;
00165
delete prev;
00166 }
00167 }
00168
else
00169
00170 {
00171 prev -> next = curr -> next;
00172 curr -> next = NULL;
00173 curr ->
clear( );
00174
delete curr;
00175 }
00176 }
00177
00178
00179
00180 void IDMap_t::concat (
const IDMap_t & s)
00181 {
00182
if (
this != &s )
00183 {
00184
resize (
getSize( ) + s .
getSize( ));
00185
00186
00187
for (
const_iterator itr = s .
begin( ); itr != s .
end( ); ++ itr )
00188
insert (itr -> iid, itr -> eid, itr -> bid);
00189 }
00190 }
00191
00192
00193
00194 const IDMap_t::HashTriple_t *
IDMap_t::insert (
ID_t iid,
00195
const string & eid,
00196
ID_t bid)
00197 {
00198
if ( iid ==
NULL_ID && eid .
empty( ) )
return NULL;
00199
00200 HashNode_t * curri, * curre;
00201
00202
if ( lookupnode (iid, curri) )
00203 {
00204 ostringstream ss;
00205 ss <<
"Cannot insert int key '" << iid <<
"' multiple times";
00206
AMOS_THROW_ARGUMENT (ss . str( ));
00207 }
00208
if ( lookupnode (eid, curre) )
00209 {
00210 ostringstream ss;
00211 ss <<
"Cannot insert string key '" << eid <<
"' multiple times";
00212
AMOS_THROW_ARGUMENT (ss . str( ));
00213 }
00214
00215
HashTriple_t * currt =
new HashTriple_t (iid, eid, bid);
00216
00217
if ( curri != NULL )
00218 {
00219
if ( curri -> triple != NULL )
00220 curri = curri -> next =
new HashNode_t( );
00221 curri -> triple = currt;
00222 currt -> c ++;
00223 }
00224
if ( curre != NULL )
00225 {
00226
if ( curre -> triple != NULL )
00227 curre = curre -> next =
new HashNode_t( );
00228 curre -> triple = currt;
00229 currt -> c ++;
00230 }
00231
00232
if ( ++ size_m >=
getBuckets( ) )
00233
resize (size_m + 1);
00234
00235
return currt;
00236 }
00237
00238
00239
00240 void IDMap_t::readMessage (
const Message_t & msg)
00241 {
00242
clear( );
00243
00244
try {
00245
Size_t size = -1;
00246 istringstream ss;
00247
00248
if ( msg .
exists (
F_OBJECT) )
00249 {
00250 string str = msg . getField (
F_OBJECT);
00251
00252
if ( str . length( ) !=
NCODE_SIZE )
00253
AMOS_THROW_ARGUMENT (
"Invalid object type format");
00254 type_m =
Encode (str);
00255 }
00256
00257
if ( msg .
exists (
F_SIZE) )
00258 {
00259 ss . str (msg . getField (
F_SIZE));
00260 ss >> size;
00261
if ( !ss )
00262
AMOS_THROW_ARGUMENT (
"Invalid size format");
00263 ss .
clear( );
00264
00265
resize (size);
00266 }
00267
00268
if ( msg .
exists (
F_MAP) )
00269 {
00270 string eid;
00271
ID_t bid, iid;
00272 ss . str (msg . getField (
F_MAP));
00273
00274
while ( ss )
00275 {
00276 ss >> bid >> iid;
00277 ss . ignore( );
00278 getline (ss, eid);
00279
if ( ! ss . fail( ) )
00280
insert (iid, eid, bid);
00281 }
00282
00283
if ( ! ss . eof( ) )
00284
AMOS_THROW_ARGUMENT (
"Invalid map format");
00285 ss .
clear( );
00286
00287
if ( size >= 0 && size != size_m )
00288
AMOS_THROW_ARGUMENT (
"map and size fields do not agree");
00289 }
00290 }
00291
catch (
ArgumentException_t) {
00292
00293
clear( );
00294
throw;
00295 }
00296 }
00297
00298
00299
00300 void IDMap_t::remove (
ID_t key)
00301 {
00302
if ( key ==
NULL_ID )
return;
00303 string eid;
00304
00305 HashNode_t * prev = NULL;
00306 HashNode_t * curr = hashfunc (key);
00307
if ( curr -> triple != NULL )
00308
for ( ; curr != NULL; curr = curr -> next )
00309 {
00310
if ( curr -> triple -> iid == key )
00311 {
00312 size_m --;
00313
if ( curr -> triple -> c > 1 )
00314 eid = curr -> triple -> eid;
00315 removenode (curr, prev);
00316
break;
00317 }
00318 prev = curr;
00319 }
00320
00321
if ( eid .
empty( ) )
00322
return;
00323
00324 prev = NULL;
00325 curr = hashfunc (eid);
00326
if ( curr -> triple != NULL )
00327
for ( ; curr != NULL; curr = curr -> next )
00328 {
00329
if ( curr -> triple -> eid == eid )
00330 {
00331 removenode (curr, prev);
00332
break;
00333 }
00334 prev = curr;
00335 }
00336 }
00337
00338
00339
00340 void IDMap_t::remove (
const string & key)
00341 {
00342
if ( key .
empty( ) )
return;
00343
ID_t iid =
NULL_ID;
00344
00345 HashNode_t * prev = NULL;
00346 HashNode_t * curr = hashfunc (key);
00347
if ( curr -> triple != NULL )
00348
for ( ; curr != NULL; curr = curr -> next )
00349 {
00350
if ( curr -> triple -> eid == key )
00351 {
00352 size_m --;
00353
if ( curr -> triple -> c > 1 )
00354 iid = curr -> triple -> iid;
00355 removenode (curr, prev);
00356
break;
00357 }
00358 prev = curr;
00359 }
00360
00361
if ( iid ==
NULL_ID )
00362
return;
00363
00364 prev = NULL;
00365 curr = hashfunc (iid);
00366
if ( curr -> triple != NULL )
00367
for ( ; curr != NULL; curr = curr -> next )
00368 {
00369
if ( curr -> triple -> iid == iid )
00370 {
00371 removenode (curr, prev);
00372
break;
00373 }
00374 prev = curr;
00375 }
00376 }
00377
00378
00379
00380 void IDMap_t::resize (
Size_t min)
00381 {
00382
if ( (min = minbuckets (min)) ==
getBuckets( ) )
00383
return;
00384
00385 vector<HashTriple_t *> triples (size_m);
00386
long int pos = 0;
00387
00388
if ( size_m > 0 )
00389 {
00390
00391
for ( iterator itr =
begin( ); itr !=
end ( ); ++ itr )
00392 {
00393 itr -> c ++;
00394 triples [pos ++] = itr;
00395 }
00396
00397
Size_t size = size_m;
00398
NCode_t type = type_m;
00399
clear( );
00400 size_m = size;
00401 type_m = type;
00402 }
00403
00404
00405
if ( size_m != pos )
00406
AMOS_THROW (
"Unknown fatal error during hash resize");
00407 iid_bucs_m .
resize (min);
00408 eid_bucs_m .
resize (min);
00409
00410
00411 HashNode_t * curri, * curre;
00412 vector<HashTriple_t *>::iterator tpi;
00413
for ( tpi = triples .
begin( ); tpi != triples .
end( ); tpi ++ )
00414 {
00415 lookupnode ((*tpi) -> iid, curri);
00416 lookupnode ((*tpi) -> eid, curre);
00417
00418
if ( curri != NULL )
00419 {
00420
if ( curri -> triple != NULL )
00421 curri = curri -> next =
new HashNode_t( );
00422 curri -> triple = (*tpi);
00423 curri -> triple -> c ++;
00424 }
00425
if ( curre != NULL )
00426 {
00427
if ( curre -> triple != NULL )
00428 curre = curre -> next =
new HashNode_t( );
00429 curre -> triple = (*tpi);
00430 curre -> triple -> c ++;
00431 }
00432
00433 (*tpi) -> c --;
00434 }
00435 }
00436
00437
00438
00439 void IDMap_t::writeMessage (
Message_t & msg)
const
00440
{
00441 msg .
clear( );
00442
00443
try {
00444 ostringstream ss;
00445
00446 msg . setMessageCode (IDMap_t::NCODE);
00447
00448
if ( type_m !=
NULL_NCODE )
00449 msg . setField (
F_OBJECT,
Decode (type_m));
00450
00451 ss << size_m;
00452 msg . setField (
F_SIZE, ss . str( ));
00453 ss . str (
NULL_STRING);
00454
00455
if (size_m != 0 )
00456 {
00457
00458 string str;
00459
for (
const_iterator itr =
begin( ); itr !=
end( ); ++ itr )
00460 {
00461 ss << itr -> bid <<
'\t' << itr -> iid <<
'\t';
00462 str . append (ss . str( ));
00463 ss . str (
NULL_STRING);
00464 str . append (itr -> eid);
00465 str . push_back (
NL_CHAR);
00466 }
00467
00468 msg . setField (
F_MAP, str);
00469 }
00470 }
00471
catch (
ArgumentException_t) {
00472
00473 msg .
clear( );
00474
throw;
00475 }
00476 }
00477
00478
00479
00480 IDMap_t &
IDMap_t::operator= (
const IDMap_t & s)
00481 {
00482
if (
this != &s )
00483 {
00484
clear( );
00485 type_m = s . type_m;
00486
concat (s);
00487 }
00488
00489
return *
this;
00490 }
00491
00492
00493
00494 void IDMap_t::read (istream & in)
00495 {
00496
Size_t size;
00497 string ncode;
00498 string eid;
00499
ID_t bid, iid;
00500
00501
clear( );
00502
00503 in >> ncode >> size;
00504 type_m =
Encode (ncode);
00505
resize (size);
00506
00507
while ( in )
00508 {
00509 in >> bid >> iid;
00510 in . ignore( );
00511 getline (in, eid);
00512
if ( ! in . fail( ) )
00513
insert (iid, eid, bid);
00514 }
00515
00516
if ( size == size_m && in . eof( ) )
00517 in .
clear( );
00518 }
00519
00520
00521
00522 void IDMap_t::write (ostream & out)
const
00523
{
00524 out <<
Decode(type_m) <<
' ' << size_m <<
NL_CHAR;
00525
00526
for (
const_iterator itr =
begin( ); itr !=
end( ); ++ itr )
00527 out << itr -> bid <<
'\t' << itr -> iid <<
'\t' << itr -> eid <<
NL_CHAR;
00528 }
00529
00530
00531
00532
00533
00534
00535
00536 IDMap_t::iterator::iterator (vector<HashNode_t> * iid_bucs_p,
00537 vector<HashNode_t> * eid_bucs_p)
00538 : iid_bucs (iid_bucs_p), eid_bucs (eid_bucs_p)
00539 {
00540
if ( iid_bucs ->
empty( ) )
00541 curr = NULL;
00542
else
00543 {
00544 iids =
true;
00545 buc = iid_bucs ->
begin( );
00546 curr = &(*buc);
00547
if ( curr -> triple == NULL )
00548 this->operator++();
00549 }
00550 }
00551
00552
00553
00554 IDMap_t::iterator & IDMap_t::iterator::operator++ ( )
00555 {
00556
while ( curr != NULL )
00557 {
00558 curr = curr -> next;
00559
while ( curr == NULL )
00560 {
00561 ++ buc;
00562
00563
if ( iids && buc >= iid_bucs ->
end( ) )
00564 {
00565 iids =
false;
00566 buc = eid_bucs ->
begin( );
00567 }
00568
00569
if ( !iids && buc >= eid_bucs ->
end( ) )
00570
return *
this;
00571
00572
if ( buc -> triple != NULL )
00573 curr = &(*buc);
00574 }
00575
00576
if ( iids || curr -> triple -> c == 1 )
00577
break;
00578 }
00579
return *
this;
00580 }
00581
00582
00583
00584 IDMap_t::const_iterator::const_iterator (
const vector<HashNode_t> * iid_bucs_p,
00585
const vector<HashNode_t> * eid_bucs_p)
00586 : iid_bucs (iid_bucs_p), eid_bucs (eid_bucs_p)
00587 {
00588
if ( iid_bucs ->
empty( ) )
00589 curr = NULL;
00590
else
00591 {
00592 iids =
true;
00593 buc = iid_bucs ->
begin( );
00594 curr = &(*buc);
00595
if ( curr -> triple == NULL )
00596 this->
operator++();
00597 }
00598 }
00599
00600
00601
00602 IDMap_t::const_iterator &
IDMap_t::const_iterator::operator++ ( )
00603 {
00604
while ( curr != NULL )
00605 {
00606 curr = curr -> next;
00607
while ( curr == NULL )
00608 {
00609 ++ buc;
00610
00611
if ( iids && buc >= iid_bucs ->
end( ) )
00612 {
00613 iids =
false;
00614 buc = eid_bucs ->
begin( );
00615 }
00616
00617
if ( !iids && buc >= eid_bucs ->
end( ) )
00618
return *
this;
00619
00620
if ( buc -> triple != NULL )
00621 curr = &(*buc);
00622 }
00623
00624
if ( iids || curr -> triple -> c == 1 )
00625
break;
00626 }
00627
return *
this;
00628 }