ROOT  6.07/01
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
TEntryListBlock.cxx
Go to the documentation of this file.
1 // @(#)root/tree:$Id$
2 // Author: Anna Kreshuk 27/10/2006
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TEntryListBlock
13 Used by TEntryList to store the entry numbers.
14 
15 There are 2 ways to represent entry numbers in a TEntryListBlock:
16 
17  1. as bits, where passing entry numbers are assigned 1, not passing - 0
18  2. as a simple array of entry numbers
19  - storing the numbers of entries that pass
20  - storing the numbers of entries that don't pass
21 
22 In both cases, a UShort_t* is used. The second option is better in case
23 less than 1/16 or more than 15/16 of entries pass the selection, and the representation can be
24 changed by calling OptimizeStorage() function.
25 When the block is being filled, it's always stored as bits, and the OptimizeStorage()
26 function is called by TEntryList when it starts filling the next block. If
27 Enter() or Remove() is called after OptimizeStorage(), representation is
28 again changed to 1).
29 
30 Begin_Macro(source)
31 entrylistblock_figure1.C
32 End_Macro
33 
34 ## Operations on blocks (see also function comments)
35 
36  - __Merge__() - adds all entries from one block to the other. If the first block
37  uses array representation, it's changed to bits representation only
38  if the total number of passing entries is still less than kBlockSize
39  - __GetEntry(n)__ - returns n-th non-zero entry.
40  - __Next__() - return next non-zero entry. In case of representation 1), Next()
41  is faster than GetEntry()
42 */
43 
44 #include "TEntryListBlock.h"
45 #include "TString.h"
46 
48 
49 ////////////////////////////////////////////////////////////////////////////////
50 /// Default c-tor
51 
53 {
54  fIndices = 0;
55  fN = kBlockSize;
56  fNPassed = 0;
57  fType = -1;
58  fPassing = 1;
59  fCurrent = 0;
60  fLastIndexReturned = -1;
61  fLastIndexQueried = -1;
62 }
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 /// Copy c-tor
66 
68 {
69  fN = eblock.fN;
70  if (eblock.fIndices){
71  fIndices = new UShort_t[fN];
72  for (Int_t i=0; i<fN; i++)
73  fIndices[i] = eblock.fIndices[i];
74  } else {
75  fIndices = 0;
76  }
77  fNPassed = eblock.fNPassed;
78  fType = eblock.fType;
79  fPassing = eblock.fPassing;
80  fCurrent = eblock.fCurrent;
81  fLastIndexReturned = -1;
82  fLastIndexQueried = -1;
83 }
84 
85 ////////////////////////////////////////////////////////////////////////////////
86 /// Destructor
87 
89 {
90  if (fIndices)
91  delete [] fIndices;
92  fIndices = 0;
93 }
94 
95 ////////////////////////////////////////////////////////////////////////////////
96 
98 {
99  if (this != &eblock) {
100  if (fIndices)
101  delete [] fIndices;
102 
103  fN = eblock.fN;
104  if (eblock.fIndices){
105  fIndices = new UShort_t[fN];
106  for (Int_t i=0; i<fN; i++)
107  fIndices[i] = eblock.fIndices[i];
108  } else {
109  fIndices = 0;
110  }
111  fNPassed = eblock.fNPassed;
112  fType = eblock.fType;
113  fPassing = eblock.fPassing;
114  fCurrent = eblock.fCurrent;
115  fLastIndexReturned = -1;
116  fLastIndexQueried = -1;
117  }
118  return *this;
119 }
120 
121 ////////////////////////////////////////////////////////////////////////////////
122 /// If the block has already been optimized and the entries
123 /// are stored as a list and not as bits, trying to enter a new entry
124 /// will make the block switch to bits representation
125 
127 {
128  if (entry > kBlockSize*16) {
129  Error("Enter", "illegal entry value!");
130  return 0;
131  }
132  if (!fIndices){
133  fIndices = new UShort_t[kBlockSize] ;
134  for (Int_t i=0; i<kBlockSize; i++)
135  fIndices[i] = 0;
136  fType = 0; //start in bits
137  }
138  if (fType==0){
139  //bits
140  Int_t i = entry>>4;
141  Int_t j = entry & 15;
142  if ((fIndices[i] & (1<<j))==0){
143  fIndices[i] |= 1<<j;
144  fNPassed++;
145  return 1;
146  } else {
147  return 0;
148  }
149  }
150  //list
151  //change to bits
152  UShort_t *bits = new UShort_t[kBlockSize];
153  Transform(1, bits);
154  Enter(entry);
155  return 0;
156 }
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 /// Remove entry #entry
160 /// If the block has already been optimized and the entries
161 /// are stored as a list and not as bits, trying to remove a new entry
162 /// will make the block switch to bits representation
163 
165 {
166  if (entry > kBlockSize*16) {
167  Error("Remove", "Illegal entry value!\n");
168  return 0;
169  }
170  if (fType==0){
171  Int_t i = entry>>4;
172  Int_t j = entry & 15;
173  if ((fIndices[i] & (1<<j))!=0){
174  fIndices[i] &= (0xFFFF^(1<<j));
175  fNPassed--;
176  return 1;
177  } else {
178  return 0;
179  }
180  }
181  //list
182  //change to bits
183  UShort_t *bits = new UShort_t[kBlockSize];
184  Transform(1, bits);
185  return Remove(entry);
186  //return 0;
187 }
188 
189 ////////////////////////////////////////////////////////////////////////////////
190 /// True if the block contains entry #entry
191 
193 {
194  if (entry > kBlockSize*16) {
195  Error("Contains", "Illegal entry value!\n");
196  return 0;
197  }
198  if (!fIndices && fPassing)
199  return 0;
200  if (fType==0 && fIndices){
201  //bits
202  Int_t i = entry>>4;
203  Int_t j = entry & 15;
204  Bool_t result = (fIndices[i] & (1<<j))!=0;
205  return result;
206  }
207  //list
208  if (entry < fCurrent) fCurrent = 0;
209  if (fPassing && fIndices){
210  for (Int_t i = fCurrent; i<fNPassed; i++){
211  if (fIndices[i]==entry){
212  fCurrent = i;
213  return kTRUE;
214  }
215  }
216  } else {
217  if (!fIndices || fNPassed==0){
218  //all entries pass
219  return kTRUE;
220  }
221  if (entry > fIndices[fNPassed-1])
222  return kTRUE;
223  for (Int_t i= fCurrent; i<fNPassed; i++){
224  if (fIndices[i]==entry){
225  fCurrent = i;
226  return kFALSE;
227  }
228  if (fIndices[i]>entry){
229  fCurrent = i;
230  return kTRUE;
231  }
232  }
233  }
234  return 0;
235 }
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 /// Merge with the other block
239 /// Returns the resulting number of entries in the block
240 
242 {
243  Int_t i, j;
244  if (block->GetNPassed() == 0) return GetNPassed();
245  if (GetNPassed() == 0){
246  //this block is empty
247  fN = block->fN;
248  fIndices = new UShort_t[fN];
249  for (i=0; i<fN; i++)
250  fIndices[i] = block->fIndices[i];
251  fNPassed = block->fNPassed;
252  fType = block->fType;
253  fPassing = block->fPassing;
254  fCurrent = block->fCurrent;
255  fLastIndexReturned = -1;
256  fLastIndexQueried = -1;
257  return fNPassed;
258  }
259  if (fType==0){
260  //stored as bits
261  if (block->fType == 0){
262  for (i=0; i<kBlockSize*16; i++){
263  if (block->Contains(i))
264  Enter(i);
265  }
266  } else {
267  if (block->fPassing){
268  //the other block stores entries that pass
269  for (i=0; i<block->fNPassed; i++){
270  Enter(block->fIndices[i]);
271  }
272  } else {
273  //the other block stores entries that don't pass
274  if (block->fNPassed==0){
275  for (i=0; i<kBlockSize*16; i++){
276  Enter(i);
277  }
278  }
279  for (j=0; j<block->fIndices[0]; j++)
280  Enter(j);
281  for (i=0; i<block->fNPassed-1; i++){
282  for (j=block->fIndices[i]+1; j<block->fIndices[i+1]; j++){
283  Enter(j);
284  }
285  }
286  for (j=block->fIndices[block->fNPassed-1]+1; j<kBlockSize*16; j++)
287  Enter(j);
288  }
289  }
290  } else {
291  //stored as a list
292  if (GetNPassed() + block->GetNPassed() > kBlockSize){
293  //change to bits
294  UShort_t *bits = new UShort_t[kBlockSize];
295  Transform(1, bits);
296  Merge(block);
297  } else {
298  //this is only possible if fPassing=1 in both blocks
299  if (block->fType==1){
300  //second block stored as a list
301  //make a bigger list
302  Int_t en = block->fNPassed;
303  Int_t newsize = fNPassed + en;
304  UShort_t *newlist = new UShort_t[newsize];
305  UShort_t *elst = block->fIndices;
306  Int_t newpos, elpos;
307  newpos = elpos = 0;
308  for (i=0; i<fNPassed; i++) {
309  while (elpos < en && fIndices[i] > elst[elpos]) {
310  newlist[newpos] = elst[elpos];
311  newpos++;
312  elpos++;
313  }
314  if (fIndices[i] == elst[elpos]) elpos++;
315  newlist[newpos] = fIndices[i];
316  newpos++;
317  }
318  while (elpos < en) {
319  newlist[newpos] = elst[elpos];
320  newpos++;
321  elpos++;
322  }
323  delete [] fIndices;
324  fIndices = newlist;
325  fNPassed = newpos;
326  fN = fNPassed;
327  } else {
328  //second block is stored as bits
329 
330  Int_t en = block->fNPassed;
331  Int_t newsize = fNPassed + en;
332  UShort_t *newlist = new UShort_t[newsize];
333  Int_t newpos, current;
334  newpos = current = 0;
335  for (i=0; i<kBlockSize*16; i++){
336  if (!block->Contains(i)) continue;
337  while(current < fNPassed && fIndices[current]<i){
338  newlist[newpos] = fIndices[current];
339  current++;
340  newpos++;
341  }
342  if (fIndices[current]==i) current++;
343  newlist[newpos] = i;
344  newpos++;
345  }
346  while(current<fNPassed){
347  newlist[newpos] = fIndices[current];
348  newpos++;
349  current++;
350  }
351  delete [] fIndices;
352  fIndices = newlist;
353  fNPassed = newpos;
354  fN = fNPassed;
355  }
356  }
357  }
358  fLastIndexQueried = -1;
359  fLastIndexReturned = -1;
360  OptimizeStorage();
361  return GetNPassed();
362 }
363 
364 ////////////////////////////////////////////////////////////////////////////////
365 /// Returns the number of entries, passing the selection.
366 /// In case, when the block stores entries that pass (fPassing=1) returns fNPassed
367 
369 {
370  if (fPassing)
371  return fNPassed;
372  else
373  return kBlockSize*16-fNPassed;
374 }
375 
376 ////////////////////////////////////////////////////////////////////////////////
377 /// Return entry #entry.
378 /// See also Next()
379 
381 {
382  if (entry > kBlockSize*16) return -1;
383  if (entry > GetNPassed()) return -1;
384  if (entry == fLastIndexQueried+1) return Next();
385  else {
386  Int_t i=0; Int_t j=0; Int_t entries_found=0;
387  if (fType==0){
388  if ((fIndices[i] & (1<<j))!=0)
389  entries_found++;
390  while (entries_found<entry+1){
391  if (j==15){i++; j=0;}
392  else j++;
393  if ((fIndices[i] & (1<<j))!=0)
394  entries_found++;
395  }
397  fLastIndexReturned = i*16+j;
398  return fLastIndexReturned;
399  }
400  if (fType==1){
401  if (fPassing){
404  return fIndices[entry];
405  } else {
407  if (!fIndices || fNPassed==0){
408  //all entries pass
410  return fLastIndexReturned;
411  }
412  for (i=0; i<fIndices[0]; i++){
413  entries_found++;
414  if (entries_found==entry+1){
415  fLastIndexReturned = i;
416  return fLastIndexReturned;
417  }
418  }
419  for (i=0; i<fNPassed-1; i++){
420  for (j=fIndices[i]+1; j<fIndices[i+1]; j++){
421  entries_found++;
422  if (entries_found==entry+1){
423  fLastIndexReturned = j;
424  return fLastIndexReturned;
425  }
426  }
427  }
428  for (j=fIndices[fNPassed-1]+1; j<kBlockSize*16; j++){
429  entries_found++;
430  if (entries_found==entry+1){
431  fLastIndexReturned = j;
432  return fLastIndexReturned;
433  }
434  }
435  }
436  }
437  return -1;
438  }
439 }
440 
441 ////////////////////////////////////////////////////////////////////////////////
442 /// Return the next non-zero entry
443 /// Faster than GetEntry() function
444 
446 {
447  if (fLastIndexQueried==GetNPassed()-1){
449  fLastIndexReturned = -1;
450  return -1;
451  }
452 
453  if (fType==0) {
454  //bits
455  Int_t i=0;
456  Int_t j=0;
458  i = fLastIndexReturned>>4;
459  j = fLastIndexReturned & 15;
460  Bool_t result=(fIndices[i] & (1<<j))!=0;
461  while (result==0){
462  if (j==15) {j=0; i++;}
463  else j++;
464  result = (fIndices[i] & (1<<j))!=0;
465  }
466  fLastIndexReturned = i*16+j;
468  return fLastIndexReturned;
469 
470  }
471  if (fType==1) {
473  if (fPassing){
475  return fIndices[fLastIndexQueried];
476  } else {
478  while (!Contains(fLastIndexReturned)){
480  }
481  return fLastIndexReturned;
482  }
483 
484  }
485  return -1;
486 }
487 
488 ////////////////////////////////////////////////////////////////////////////////
489 /// Print the entries in this block
490 
491 void TEntryListBlock::Print(const Option_t *option) const
492 {
493  TString opt = option;
494  opt.ToUpper();
495  if (opt.Contains("A")) PrintWithShift(0);
496 }
497 
498 ////////////////////////////////////////////////////////////////////////////////
499 /// Print the indices of this block + shift (used from TEntryList::Print()) to
500 /// print the corrent values
501 
502 void TEntryListBlock::PrintWithShift(Int_t shift) const
503 {
504  Int_t i;
505  if (fType==0){
506  Int_t ibit, ibite;
507  Bool_t result;
508  for (i=0; i<kBlockSize*16; i++){
509  ibite = i>>4;
510  ibit = i & 15;
511  result = (fIndices[ibite] & (1<<ibit))!=0;
512  if (result)
513  printf("%d\n", i+shift);
514  }
515  } else {
516  if (fPassing){
517  for (i=0; i<fNPassed; i++){
518  printf("%d\n", fIndices[i]+shift);
519  }
520  } else {
521  if (fNPassed==0){
522  for (i=0; i<kBlockSize*16; i++)
523  printf("%d\n", i+shift);
524  return;
525  }
526  for (i=0; i<fIndices[0]; i++){
527  printf("%d\n", i+shift);
528  }
529  for (i=0; i<fNPassed-1; i++){
530  for (Int_t j=fIndices[i]+1; j<fIndices[i+1]; j++){
531  printf("%d\n", j+shift);
532  }
533  }
534  for (Int_t j=fIndices[fNPassed-1]+1; j<kBlockSize*16; j++){
535  printf("%d\n", j+shift);
536  }
537  }
538  }
539 }
540 
541 ////////////////////////////////////////////////////////////////////////////////
542 /// If there are < kBlockSize or >kBlockSize*15 entries, change to an array
543 /// representation
544 
546 {
547  if (fType!=0) return;
548  if (fNPassed > kBlockSize*15)
549  fPassing = 0;
550  if (fNPassed<kBlockSize || !fPassing){
551  //less than 4000 entries passing, makes sense to change from bits to list
552  UShort_t *indexnew = new UShort_t[fNPassed];
553  Transform(0, indexnew);
554  }
555 }
556 
557 ////////////////////////////////////////////////////////////////////////////////
558 /// Transform the existing fIndices
559 /// - dir=0 - transform from bits to a list
560 /// - dir=1 - tranform from a list to bits
561 
563 {
564  Int_t i=0;
565  Int_t ilist = 0;
566  Int_t ibite, ibit;
567  if (!dir) {
568  for (i=0; i<kBlockSize*16; i++){
569  ibite = i >> 4;
570  ibit = i & 15;
571  Bool_t result = (fIndices[ibite] & (1<<ibit))!=0;
572  if (result && fPassing){
573  //fill with the entries that pass
574  indexnew[ilist] = i;
575  ilist++;
576  }
577  else if (!result && !fPassing){
578  //fill with the entries that don't pass
579  indexnew[ilist] = i;
580  ilist++;
581  }
582  }
583  if (fIndices)
584  delete [] fIndices;
585  fIndices = indexnew;
586  fType = 1;
587  if (!fPassing)
588  fNPassed = kBlockSize*16-fNPassed;
589  fN = fNPassed;
590  return;
591  }
592 
593  if (fPassing){
594  for (i=0; i<kBlockSize; i++)
595  indexnew[i] = 0;
596  for (i=0; i<fNPassed; i++){
597  ibite = fIndices[i]>>4;
598  ibit = fIndices[i] & 15;
599  indexnew[ibite] |= 1<<ibit;
600  }
601  } else {
602  for (i=0; i<kBlockSize; i++)
603  indexnew[i] = 65535;
604  for (i=0; i<fNPassed; i++){
605  ibite = fIndices[i]>>4;
606  ibit = fIndices[i] & 15;
607  indexnew[ibite] ^= 1<<ibit;
608  }
609  fNPassed = kBlockSize*16-fNPassed;
610  }
611  if (fIndices)
612  delete [] fIndices;
613  fIndices = indexnew;
614  fType = 0;
615  fN = kBlockSize;
616  fPassing = 1;
617  return;
618 }
Int_t fLastIndexQueried
to fasten Contains() in list mode
const char Option_t
Definition: RtypesCore.h:62
const char * current
Definition: demos.C:12
void OptimizeStorage()
If there are < kBlockSize or >kBlockSize*15 entries, change to an array representation.
unsigned short UShort_t
Definition: RtypesCore.h:36
void ToUpper()
Change string to upper case.
Definition: TString.cxx:1088
Int_t fLastIndexReturned
to optimize GetEntry() in a loop
Int_t Merge(TEntryListBlock *block)
Merge with the other block Returns the resulting number of entries in the block.
Basic string class.
Definition: TString.h:137
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
Bool_t Enter(Int_t entry)
If the block has already been optimized and the entries are stored as a list and not as bits...
Int_t GetEntry(Int_t entry)
Return entry entry.
UShort_t * fIndices
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:918
void PrintWithShift(Int_t shift) const
Print the indices of this block + shift (used from TEntryList::Print()) to print the corrent values...
~TEntryListBlock()
Destructor.
Int_t Contains(Int_t entry)
True if the block contains entry entry.
Int_t GetNPassed()
Returns the number of entries, passing the selection.
Long64_t entry
PyObject * fType
Int_t Next()
Return the next non-zero entry Faster than GetEntry() function.
ClassImp(TEntryListBlock) TEntryListBlock
Default c-tor.
ClassImp(TMCParticle) void TMCParticle printf(": p=(%7.3f,%7.3f,%9.3f) ;", fPx, fPy, fPz)
void dir(char *path=0)
Definition: rootalias.C:30
virtual void Print(const Option_t *option="") const
Print the entries in this block.
Mother of all ROOT objects.
Definition: TObject.h:58
Bool_t Remove(Int_t entry)
Remove entry entry If the block has already been optimized and the entries are stored as a list and n...
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
void Transform(Bool_t dir, UShort_t *indexnew)
to optimize GetEntry() in a loop
double result[121]
Used by TEntryList to store the entry numbers.
const Bool_t kTRUE
Definition: Rtypes.h:91
TEntryListBlock & operator=(const TEntryListBlock &rhs)