/*****************************************************************************
 * Project: RooFit                                                           *
 * Package: RooFitCore                                                       *
 * @(#)root/roofitcore:$Id$
 * Authors:                                                                  *
 *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
 *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
 *                                                                           *
 * Copyright (c) 2000-2005, Regents of the University of California          *
 *                          and Stanford University. All rights reserved.    *
 *                                                                           *
 * Redistribution and use in source and binary forms,                        *
 * with or without modification, are permitted according to the terms        *
 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
 *****************************************************************************/

#include "RooFit.h"

#include "TMath.h"
#include "TMath.h"
#include "TCollection.h"
#include "RooHashTable.h"
#include "RooLinkedList.h"
#include "RooAbsArg.h"
#include "RooSetPair.h"

using namespace std;

ClassImp(RooHashTable)
;

//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// RooHashTable implements a hash table for TObjects. The hashing can be
// done on the object addresses, object names, or using the objects
// internal hash method. This is a utility class for RooLinkedList
// that uses RooHashTable to speed up direct access to large collections.
// END_HTML
//

//_____________________________________________________________________________
RooHashTable::RooHashTable(Int_t capacity, HashMethod hashMethod) :
  _hashMethod(hashMethod)
{
  // Construct a hash table with given capacity and hash method

  if (capacity <= 0) {
    capacity = TCollection::kInitHashTableCapacity;
  }  
  _size = (Int_t)TMath::NextPrime(TMath::Max(capacity,(int)TCollection::kInitHashTableCapacity));
  _arr  = new RooLinkedList* [_size] ;
  memset(_arr, 0, _size*sizeof(RooLinkedList*));

  _usedSlots = 0 ;
  _entries   = 0 ;
}



//_____________________________________________________________________________
RooHashTable::RooHashTable(const RooHashTable& other) :
  TObject(other),
  _hashMethod(other._hashMethod),
  _usedSlots(other._usedSlots), 
  _entries(other._entries), 
  _size(other._size)
{
  // Copy constructor

  _arr  = new RooLinkedList* [_size] ;
  memset(_arr, 0, _size*sizeof(RooLinkedList*));  
  Int_t i ;
  for (i=0 ; i<_size ; i++) {
    if (other._arr[i]) {
      _arr[i] = new RooLinkedList(*other._arr[i]) ;
    }
  }
}



//_____________________________________________________________________________
void RooHashTable::add(TObject* arg, TObject* hashArg) 
{
  // Add given object to table. If hashArg is given, hash will be calculation
  // on that rather than on 'arg'

  Int_t slot = hash(hashArg?hashArg:arg) % _size ;
  if (!_arr[slot]) {
    _arr[slot] = new RooLinkedList(0) ;
    _arr[slot]->useNptr(kFALSE) ;
    _usedSlots++ ;
   }
   _arr[slot]->Add(arg);
   _entries++;
}



//_____________________________________________________________________________
Bool_t RooHashTable::remove(TObject* arg, TObject* hashArg)
{
  // Remove given object from table. If hashArg is given, hash will be calculation
  // on that rather than on 'arg'

  Int_t slot = hash(hashArg?hashArg:arg) % _size ;
  if (_arr[slot]) {
    if (_arr[slot]->Remove(arg)) {
      _entries-- ;
      if (_arr[slot]->GetSize()==0) {
	delete _arr[slot] ;
	_arr[slot] = 0 ;
	_usedSlots-- ;
      }
      return kTRUE ;
    }
  }

  if (_hashMethod != Name) return kFALSE;

  // If we didn't find it by name, see if it might have been renamed
  RooAbsArg* p = dynamic_cast<RooAbsArg*>(arg);
  //cout << "RooHashTable::remove possibly renamed '" << arg->GetName() << "', kRenamedArg=" << (p&&p->namePtr()->TestBit(RooNameReg::kRenamedArg)) << endl;
  if (p && !p->namePtr()->TestBit(RooNameReg::kRenamedArg)) return kFALSE;

  // If so, check the whole list
  Int_t i;
  for (i=0 ; i<_size ; i++) {
    if (i != slot && _arr[i] && _arr[i]->Remove(arg)) {
      _entries-- ;
      if (_arr[i]->GetSize()==0) {
        delete _arr[i] ;
        _arr[i] = 0 ;
        _usedSlots-- ;
      }
      return kTRUE ;
    }
  }

  return kFALSE ;
}



//_____________________________________________________________________________
Double_t RooHashTable::avgCollisions() const 
{
  // Calculate the average number of collisions (table slots with >1 filled entry)
  
  Int_t i,h[20] ;
  for (i=0 ;  i<20 ; i++) h[i]=0 ; 

  for (i=0 ; i<_size ; i++) {
    if (_arr[i]) {
      Int_t count = _arr[i]->GetSize() ;
      if (count<20) {
	h[count]++ ;
      } else {
	h[19]++ ;
      }
    } else {
      h[0]++ ;
    }
  }

  return 0 ;
}



//_____________________________________________________________________________
Bool_t RooHashTable::replace(const TObject* oldArg, const TObject* newArg, const TObject* oldHashArg) 
{
  // Replace oldArg with newArg in the table. If oldHashArg is given, use that to calculate
  // the hash associated with oldArg

  Int_t slot = hash(oldHashArg?oldHashArg:oldArg) % _size ;
  if (_arr[slot]) {
    Int_t newSlot = hash(newArg) % _size ;
    if (newSlot == slot) {
      return _arr[slot]->Replace(oldArg,newArg) ;
    }
  }

  // We didn't find the oldArg or they have different slots.
  if (remove((TObject*)oldArg,(TObject*)oldHashArg)) {
    add((TObject*)newArg);
    return kTRUE;
  }
  return kFALSE ;
}



//_____________________________________________________________________________
TObject* RooHashTable::find(const char* name) const 
{
  // Return the object with given name from the table.

  if (_hashMethod != Name) assert(0) ;

  Int_t slot = TMath::Hash(name) % _size ;
  if (_arr[slot]) return _arr[slot]->find(name) ;
  return 0;  
}



//_____________________________________________________________________________
RooAbsArg* RooHashTable::findArg(const RooAbsArg* arg) const 
{
  if (_hashMethod != Name) assert(0) ;
  
  Int_t slot = TMath::Hash(arg->GetName()) % _size ;
  if (_arr[slot]) return _arr[slot]->findArg(arg) ;
  return 0;  
}



//_____________________________________________________________________________
TObject* RooHashTable::find(const TObject* hashArg) const 
{
  // Return object with the given pointer from the table

  RooLinkedListElem* elem = findLinkTo(hashArg) ;
  return elem ? elem->_arg : 0 ;
}



//_____________________________________________________________________________
RooLinkedListElem* RooHashTable::findLinkTo(const TObject* hashArg) const 
{
  // Return RooLinkedList element link to object 'hashArg'

  if (_hashMethod != Pointer) assert(0) ;

  Int_t slot = hash(hashArg) % _size ;
  RooLinkedList* lst = _arr[slot];
  if (lst) {
    RooFIter it = lst->fwdIterator() ;
    TObject* obj;
    while ((obj=it.next())) {
      RooLinkedListElem* elem = (RooLinkedListElem*)obj ;
      if (elem->_arg == hashArg) return elem ;
    }
  }
  return 0;  
}



//_____________________________________________________________________________
RooSetPair* RooHashTable::findSetPair(const RooArgSet* set1, const RooArgSet* set2) const 
{  
  // Return RooSetPair with given pointers in table

  if (_hashMethod != Intrinsic) assert(0) ;

  Int_t slot = RooSetPair(set1,set2).Hash() % _size ;
  if (_arr[slot]) {
    Int_t i ; 
    for (i=0 ; i<_arr[slot]->GetSize() ; i++) {
      RooSetPair* pair = (RooSetPair*)_arr[slot]->At(i) ;
      if (pair->_set1==set1 && pair->_set2==set2) {
	return pair ;
      }
    }
  }

  return 0 ;
}




//_____________________________________________________________________________
RooHashTable::~RooHashTable() 
{  
  // Destructor

  Int_t i ;
  for (i=0 ; i<_size ; i++) {
    if (_arr[i]) delete _arr[i] ;  
  }
  delete[] _arr ;
}
 RooHashTable.cxx:1
 RooHashTable.cxx:2
 RooHashTable.cxx:3
 RooHashTable.cxx:4
 RooHashTable.cxx:5
 RooHashTable.cxx:6
 RooHashTable.cxx:7
 RooHashTable.cxx:8
 RooHashTable.cxx:9
 RooHashTable.cxx:10
 RooHashTable.cxx:11
 RooHashTable.cxx:12
 RooHashTable.cxx:13
 RooHashTable.cxx:14
 RooHashTable.cxx:15
 RooHashTable.cxx:16
 RooHashTable.cxx:17
 RooHashTable.cxx:18
 RooHashTable.cxx:19
 RooHashTable.cxx:20
 RooHashTable.cxx:21
 RooHashTable.cxx:22
 RooHashTable.cxx:23
 RooHashTable.cxx:24
 RooHashTable.cxx:25
 RooHashTable.cxx:26
 RooHashTable.cxx:27
 RooHashTable.cxx:28
 RooHashTable.cxx:29
 RooHashTable.cxx:30
 RooHashTable.cxx:31
 RooHashTable.cxx:32
 RooHashTable.cxx:33
 RooHashTable.cxx:34
 RooHashTable.cxx:35
 RooHashTable.cxx:36
 RooHashTable.cxx:37
 RooHashTable.cxx:38
 RooHashTable.cxx:39
 RooHashTable.cxx:40
 RooHashTable.cxx:41
 RooHashTable.cxx:42
 RooHashTable.cxx:43
 RooHashTable.cxx:44
 RooHashTable.cxx:45
 RooHashTable.cxx:46
 RooHashTable.cxx:47
 RooHashTable.cxx:48
 RooHashTable.cxx:49
 RooHashTable.cxx:50
 RooHashTable.cxx:51
 RooHashTable.cxx:52
 RooHashTable.cxx:53
 RooHashTable.cxx:54
 RooHashTable.cxx:55
 RooHashTable.cxx:56
 RooHashTable.cxx:57
 RooHashTable.cxx:58
 RooHashTable.cxx:59
 RooHashTable.cxx:60
 RooHashTable.cxx:61
 RooHashTable.cxx:62
 RooHashTable.cxx:63
 RooHashTable.cxx:64
 RooHashTable.cxx:65
 RooHashTable.cxx:66
 RooHashTable.cxx:67
 RooHashTable.cxx:68
 RooHashTable.cxx:69
 RooHashTable.cxx:70
 RooHashTable.cxx:71
 RooHashTable.cxx:72
 RooHashTable.cxx:73
 RooHashTable.cxx:74
 RooHashTable.cxx:75
 RooHashTable.cxx:76
 RooHashTable.cxx:77
 RooHashTable.cxx:78
 RooHashTable.cxx:79
 RooHashTable.cxx:80
 RooHashTable.cxx:81
 RooHashTable.cxx:82
 RooHashTable.cxx:83
 RooHashTable.cxx:84
 RooHashTable.cxx:85
 RooHashTable.cxx:86
 RooHashTable.cxx:87
 RooHashTable.cxx:88
 RooHashTable.cxx:89
 RooHashTable.cxx:90
 RooHashTable.cxx:91
 RooHashTable.cxx:92
 RooHashTable.cxx:93
 RooHashTable.cxx:94
 RooHashTable.cxx:95
 RooHashTable.cxx:96
 RooHashTable.cxx:97
 RooHashTable.cxx:98
 RooHashTable.cxx:99
 RooHashTable.cxx:100
 RooHashTable.cxx:101
 RooHashTable.cxx:102
 RooHashTable.cxx:103
 RooHashTable.cxx:104
 RooHashTable.cxx:105
 RooHashTable.cxx:106
 RooHashTable.cxx:107
 RooHashTable.cxx:108
 RooHashTable.cxx:109
 RooHashTable.cxx:110
 RooHashTable.cxx:111
 RooHashTable.cxx:112
 RooHashTable.cxx:113
 RooHashTable.cxx:114
 RooHashTable.cxx:115
 RooHashTable.cxx:116
 RooHashTable.cxx:117
 RooHashTable.cxx:118
 RooHashTable.cxx:119
 RooHashTable.cxx:120
 RooHashTable.cxx:121
 RooHashTable.cxx:122
 RooHashTable.cxx:123
 RooHashTable.cxx:124
 RooHashTable.cxx:125
 RooHashTable.cxx:126
 RooHashTable.cxx:127
 RooHashTable.cxx:128
 RooHashTable.cxx:129
 RooHashTable.cxx:130
 RooHashTable.cxx:131
 RooHashTable.cxx:132
 RooHashTable.cxx:133
 RooHashTable.cxx:134
 RooHashTable.cxx:135
 RooHashTable.cxx:136
 RooHashTable.cxx:137
 RooHashTable.cxx:138
 RooHashTable.cxx:139
 RooHashTable.cxx:140
 RooHashTable.cxx:141
 RooHashTable.cxx:142
 RooHashTable.cxx:143
 RooHashTable.cxx:144
 RooHashTable.cxx:145
 RooHashTable.cxx:146
 RooHashTable.cxx:147
 RooHashTable.cxx:148
 RooHashTable.cxx:149
 RooHashTable.cxx:150
 RooHashTable.cxx:151
 RooHashTable.cxx:152
 RooHashTable.cxx:153
 RooHashTable.cxx:154
 RooHashTable.cxx:155
 RooHashTable.cxx:156
 RooHashTable.cxx:157
 RooHashTable.cxx:158
 RooHashTable.cxx:159
 RooHashTable.cxx:160
 RooHashTable.cxx:161
 RooHashTable.cxx:162
 RooHashTable.cxx:163
 RooHashTable.cxx:164
 RooHashTable.cxx:165
 RooHashTable.cxx:166
 RooHashTable.cxx:167
 RooHashTable.cxx:168
 RooHashTable.cxx:169
 RooHashTable.cxx:170
 RooHashTable.cxx:171
 RooHashTable.cxx:172
 RooHashTable.cxx:173
 RooHashTable.cxx:174
 RooHashTable.cxx:175
 RooHashTable.cxx:176
 RooHashTable.cxx:177
 RooHashTable.cxx:178
 RooHashTable.cxx:179
 RooHashTable.cxx:180
 RooHashTable.cxx:181
 RooHashTable.cxx:182
 RooHashTable.cxx:183
 RooHashTable.cxx:184
 RooHashTable.cxx:185
 RooHashTable.cxx:186
 RooHashTable.cxx:187
 RooHashTable.cxx:188
 RooHashTable.cxx:189
 RooHashTable.cxx:190
 RooHashTable.cxx:191
 RooHashTable.cxx:192
 RooHashTable.cxx:193
 RooHashTable.cxx:194
 RooHashTable.cxx:195
 RooHashTable.cxx:196
 RooHashTable.cxx:197
 RooHashTable.cxx:198
 RooHashTable.cxx:199
 RooHashTable.cxx:200
 RooHashTable.cxx:201
 RooHashTable.cxx:202
 RooHashTable.cxx:203
 RooHashTable.cxx:204
 RooHashTable.cxx:205
 RooHashTable.cxx:206
 RooHashTable.cxx:207
 RooHashTable.cxx:208
 RooHashTable.cxx:209
 RooHashTable.cxx:210
 RooHashTable.cxx:211
 RooHashTable.cxx:212
 RooHashTable.cxx:213
 RooHashTable.cxx:214
 RooHashTable.cxx:215
 RooHashTable.cxx:216
 RooHashTable.cxx:217
 RooHashTable.cxx:218
 RooHashTable.cxx:219
 RooHashTable.cxx:220
 RooHashTable.cxx:221
 RooHashTable.cxx:222
 RooHashTable.cxx:223
 RooHashTable.cxx:224
 RooHashTable.cxx:225
 RooHashTable.cxx:226
 RooHashTable.cxx:227
 RooHashTable.cxx:228
 RooHashTable.cxx:229
 RooHashTable.cxx:230
 RooHashTable.cxx:231
 RooHashTable.cxx:232
 RooHashTable.cxx:233
 RooHashTable.cxx:234
 RooHashTable.cxx:235
 RooHashTable.cxx:236
 RooHashTable.cxx:237
 RooHashTable.cxx:238
 RooHashTable.cxx:239
 RooHashTable.cxx:240
 RooHashTable.cxx:241
 RooHashTable.cxx:242
 RooHashTable.cxx:243
 RooHashTable.cxx:244
 RooHashTable.cxx:245
 RooHashTable.cxx:246
 RooHashTable.cxx:247
 RooHashTable.cxx:248
 RooHashTable.cxx:249
 RooHashTable.cxx:250
 RooHashTable.cxx:251
 RooHashTable.cxx:252
 RooHashTable.cxx:253
 RooHashTable.cxx:254
 RooHashTable.cxx:255
 RooHashTable.cxx:256
 RooHashTable.cxx:257
 RooHashTable.cxx:258
 RooHashTable.cxx:259
 RooHashTable.cxx:260
 RooHashTable.cxx:261
 RooHashTable.cxx:262
 RooHashTable.cxx:263
 RooHashTable.cxx:264
 RooHashTable.cxx:265
 RooHashTable.cxx:266
 RooHashTable.cxx:267
 RooHashTable.cxx:268
 RooHashTable.cxx:269
 RooHashTable.cxx:270
 RooHashTable.cxx:271
 RooHashTable.cxx:272
 RooHashTable.cxx:273
 RooHashTable.cxx:274
 RooHashTable.cxx:275
 RooHashTable.cxx:276
 RooHashTable.cxx:277
 RooHashTable.cxx:278
 RooHashTable.cxx:279
 RooHashTable.cxx:280
 RooHashTable.cxx:281
 RooHashTable.cxx:282
 RooHashTable.cxx:283
 RooHashTable.cxx:284
 RooHashTable.cxx:285
 RooHashTable.cxx:286
 RooHashTable.cxx:287
 RooHashTable.cxx:288
 RooHashTable.cxx:289