moving trigger description classes to HLTbase to make them commonly available
[u/mrichter/AliRoot.git] / HLT / BASE / AliHLTTriggerDomain.cxx
1 /**************************************************************************
2  * This file is property of and copyright by the ALICE HLT Project        *
3  * ALICE Experiment at CERN, All rights reserved.                         *
4  *                                                                        *
5  * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
6  *                  for The ALICE HLT Project.                            *
7  *                                                                        *
8  * Permission to use, copy, modify and distribute this software and its   *
9  * documentation strictly for non-commercial purposes is hereby granted   *
10  * without fee, provided that the above copyright notice appears in all   *
11  * copies and that both the copyright notice and this permission notice   *
12  * appear in the supporting documentation. The authors make no claims     *
13  * about the suitability of this software for any purpose. It is          *
14  * provided "as is" without express or implied warranty.                  *
15  **************************************************************************/
16
17 /// @file   AliHLTTriggerDomain.cxx
18 /// @author Artur Szostak <artursz@iafrica.com>
19 /// @date   19 Nov 2008
20 /// @brief  Implementation of the AliHLTTriggerDomain class.
21 ///
22 /// The trigger domain class is the set of HLT raw data block types that should
23 /// be readout and sent to HLTOUT.
24
25 #include <stdlib.h>
26
27 #include "AliHLTTriggerDomain.h"
28 #include "AliHLTDomainEntry.h"
29 #include "AliHLTReadoutList.h"
30 #include "Riostream.h"
31 #include "TObjArray.h"
32 #include "TObjString.h"
33 #include "AliHLTDAQ.h"
34
35 ClassImp(AliHLTTriggerDomain)
36
37
38 AliHLTTriggerDomain::AliHLTTriggerDomain() :
39   TObject(), fEntries(AliHLTDomainEntry::Class(), 10)
40 {
41   // Default constructor.
42 }
43
44
45 AliHLTTriggerDomain::AliHLTTriggerDomain(const char* list) :
46   TObject(), fEntries(AliHLTDomainEntry::Class(), 10)
47 {
48   // Constructs the domain from a list of entries.
49   
50   TString lst = list;
51   TObjArray* entries = lst.Tokenize(",");
52   for (Int_t i = 0; i < entries->GetEntriesFast(); i++)
53   {
54     TString entry = static_cast<TObjString*>(entries->UncheckedAt(i))->GetString();
55     TObjArray* domainStrings = entry.Tokenize(":");
56     if (domainStrings->GetEntriesFast() <= 0 or domainStrings->GetEntriesFast() > 3)
57     {
58       Error("AliHLTTriggerDomain",
59             "The domain string must contain 1, 2 or 3 fields separated by a ':'."
60            );
61       delete domainStrings;
62       continue;
63     }
64     
65     bool inclusiveEntry = true;
66     TString typeString = "*******";
67     if (domainStrings->GetEntriesFast() >= 1)
68     {
69       typeString = static_cast<TObjString*>(domainStrings->UncheckedAt(0))->GetString();
70       if (typeString.Length() > 0)
71       {
72         if (typeString[0] == '+')
73         {
74           inclusiveEntry = true;
75           typeString.Remove(0, 1);
76         }
77         if (typeString[0] == '-')
78         {
79           inclusiveEntry = false;
80           typeString.Remove(0, 1);
81         }
82       }
83     }
84     TString originString = "***";
85     if (domainStrings->GetEntriesFast() >= 2)
86     {
87       originString = static_cast<TObjString*>(domainStrings->UncheckedAt(1))->GetString();
88     }
89     bool usespec = false;
90     UInt_t spec = 0;
91     if (domainStrings->GetEntriesFast() == 3)
92     {
93       TString specString = static_cast<TObjString*>(domainStrings->UncheckedAt(2))->GetString();
94       char* error = NULL;
95       spec = UInt_t( strtoul(specString.Data(), &error, 0) );
96       if (error == NULL or *error != '\0')
97       {
98         Error("AliHLTTriggerDomain",
99               "The last field of the domain string must be a number, but we received '%s'.",
100               specString.Data()
101              );
102       }
103       else
104       {
105         usespec = true;
106       }
107     }
108     
109     if (usespec)
110     {
111       if (inclusiveEntry)
112         Add(typeString.Data(), originString.Data(), spec);
113       else
114         Remove(typeString.Data(), originString.Data(), spec);
115     }
116     else
117     {
118       if (inclusiveEntry)
119         Add(typeString.Data(), originString.Data());
120       else
121         Remove(typeString.Data(), originString.Data());
122     }
123     
124     delete domainStrings;
125   }
126   delete entries;
127 }
128
129
130 AliHLTTriggerDomain::AliHLTTriggerDomain(const AliHLTReadoutList& list) :
131   TObject(), fEntries(AliHLTDomainEntry::Class(), 10)
132 {
133   // Constructor creates a trigger domain from a readout list.
134   // See header file for more details.
135   
136   Add(list);
137 }
138
139
140 AliHLTTriggerDomain::AliHLTTriggerDomain(const AliHLTTriggerDomain& domain) :
141   TObject(domain),
142   fEntries(AliHLTDomainEntry::Class(), domain.fEntries.GetEntriesFast())
143 {
144   // Copy constructor performs a deep copy.
145   // See header file for more details.
146   
147   for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++)
148   {
149     const AliHLTDomainEntry* entry = static_cast<const AliHLTDomainEntry*>( domain.fEntries[i] );
150     new (fEntries[fEntries.GetEntriesFast()]) AliHLTDomainEntry(*entry);
151   }
152 }
153
154
155 AliHLTTriggerDomain::~AliHLTTriggerDomain()
156 {
157   // Default destructor.
158 }
159
160
161 void AliHLTTriggerDomain::Add(const AliHLTReadoutList& list)
162 {
163   // Adds the readout list to the trigger domain.
164   // See header file for more details.
165   
166   Int_t detId[] = {
167       AliHLTReadoutList::kITSSPD, AliHLTReadoutList::kITSSDD, AliHLTReadoutList::kITSSSD,
168       AliHLTReadoutList::kTPC, AliHLTReadoutList::kTRD, AliHLTReadoutList::kTOF,
169       AliHLTReadoutList::kHMPID, AliHLTReadoutList::kPHOS, AliHLTReadoutList::kCPV,
170       AliHLTReadoutList::kPMD, AliHLTReadoutList::kMUONTRK, AliHLTReadoutList::kMUONTRG,
171       AliHLTReadoutList::kFMD, AliHLTReadoutList::kT0, AliHLTReadoutList::kV0,
172       AliHLTReadoutList::kZDC, AliHLTReadoutList::kACORDE, AliHLTReadoutList::kTRG,
173       AliHLTReadoutList::kEMCAL, AliHLTReadoutList::kDAQTEST, AliHLTReadoutList::kHLT
174     };
175   
176   for (Int_t deti = 0; deti < AliHLTDAQ::NumberOfDetectors() && deti<(sizeof(detId)/sizeof(Int_t)); deti++)
177   {
178     if (list.DetectorEnabled(detId[deti]))
179     {
180       Add("DAQRDOUT", AliHLTDAQ::OnlineName(deti));
181     }
182     else
183     {
184       for (Int_t i = 0; i < AliHLTDAQ::NumberOfDdls(deti); i++)
185       {
186         Int_t ddlId = AliHLTDAQ::DdlID(deti, i);
187         if (list.IsDDLEnabled(ddlId)) Add("DAQRDOUT", AliHLTDAQ::OnlineName(deti), ddlId);
188       }
189     }
190   }
191 }
192
193 void AliHLTTriggerDomain::Add(const AliHLTDomainEntry& entry)
194 {
195   // Adds a new domain entry to the trigger domain.
196   // See header file for more details.
197   
198   AliHLTDomainEntry intersect;
199   bool alreadyInSet = false;
200   
201   // Get the initial size of the fEntries array since we might add things to the
202   // end during the calculation.
203   Int_t count = fEntries.GetEntriesFast();
204   
205   // Go through each entry that is already in fEntries and see if we can remove
206   // it because it will become redundant, or if we need to patch exclusion entries
207   // by adding inclusive intersects, or if we do not even need to add the new entry
208   // because it is already part of the trigger domain.
209   for (Int_t i = 0; i < count; i++)
210   {
211     AliHLTDomainEntry* ientry = static_cast<AliHLTDomainEntry*>(fEntries[i]);
212     if (ientry->Inclusive())
213     {
214       if (entry.SubsetOf(*ientry))
215       {
216         alreadyInSet = true;
217       }
218       else if (ientry->SubsetOf(entry))
219       {
220         ientry->SetBit(14, true);  // mark for removal.
221       }
222     }
223     else
224     {
225       if (ientry->SubsetOf(entry))
226       {
227         ientry->SetBit(14, true);  // mark for removal.
228       }
229       else if (entry.SubsetOf(*ientry))
230       {
231         alreadyInSet = false;
232       }
233       else if (ientry->IntersectWith(entry, intersect))
234       {
235         MarkForDeletionSubsetsOf(intersect, count);
236         new (fEntries[fEntries.GetEntriesFast()]) AliHLTDomainEntry(kFALSE, intersect);
237       }
238     }
239   }
240   
241   // Check if we need to add the new entry.
242   if (not alreadyInSet)
243   {
244     MarkForDeletionSubsetsOf(entry, count);
245     new (fEntries[fEntries.GetEntriesFast()]) AliHLTDomainEntry(kFALSE, entry);
246   }
247   RemoveMarkedEntries();
248 }
249
250
251 void AliHLTTriggerDomain::Add(const AliHLTComponentDataType& datatype)
252 {
253   // Adds a new domain entry with the given data type to the trigger domain.
254   // But the data block specification is set to the any matching wild card.
255   // See header file for more details.
256   
257   Add(AliHLTDomainEntry(datatype));
258 }
259
260
261 void AliHLTTriggerDomain::Add(const char* blocktype, const char* origin)
262 {
263   // Adds a new domain entry with the given data type and origin to the trigger domain.
264   // But the data block specification is set to the any matching wild card.
265   // See header file for more details.
266   
267   Add(AliHLTDomainEntry(blocktype, origin));
268 }
269
270
271 void AliHLTTriggerDomain::Add(const AliHLTComponentDataType& datatype, UInt_t spec)
272 {
273   // Adds a new domain entry to the trigger domain with the data type and data block
274   // specification bits.
275   // See header file for more details.
276   
277   Add(AliHLTDomainEntry(datatype, spec));
278 }
279
280
281 void AliHLTTriggerDomain::Add(const char* blocktype, const char* origin, UInt_t spec)
282 {
283   // Adds a new domain entry to the trigger domain with the given data type, origin
284   // and data block specification bits.
285   // See header file for more details.
286   
287   Add(AliHLTDomainEntry(blocktype, origin, spec));
288 }
289
290
291 void AliHLTTriggerDomain::Remove(const AliHLTReadoutList& list)
292 {
293   // Removes the entries in the readout list from the trigger domain that are enabled.
294   // See header file for more details.
295   
296   Int_t detId[] = {
297       AliHLTReadoutList::kITSSPD, AliHLTReadoutList::kITSSDD, AliHLTReadoutList::kITSSSD,
298       AliHLTReadoutList::kTPC, AliHLTReadoutList::kTRD, AliHLTReadoutList::kTOF,
299       AliHLTReadoutList::kHMPID, AliHLTReadoutList::kPHOS, AliHLTReadoutList::kCPV,
300       AliHLTReadoutList::kPMD, AliHLTReadoutList::kMUONTRK, AliHLTReadoutList::kMUONTRG,
301       AliHLTReadoutList::kFMD, AliHLTReadoutList::kT0, AliHLTReadoutList::kV0,
302       AliHLTReadoutList::kZDC, AliHLTReadoutList::kACORDE, AliHLTReadoutList::kTRG,
303       AliHLTReadoutList::kEMCAL, AliHLTReadoutList::kDAQTEST, AliHLTReadoutList::kHLT
304     };
305   
306   for (Int_t deti = 0; deti < AliHLTDAQ::NumberOfDetectors() && deti<(sizeof(detId)/sizeof(Int_t)); deti++)
307   {
308     if (list.DetectorEnabled(detId[deti]))
309     {
310       Remove("DAQRDOUT", AliHLTDAQ::OnlineName(deti));
311     }
312     else
313     {
314       for (Int_t i = 0; i < AliHLTDAQ::NumberOfDdls(deti); i++)
315       {
316         Int_t ddlId = AliHLTDAQ::DdlID(deti, i);
317         if (list.IsDDLEnabled(ddlId)) Remove("DAQRDOUT", AliHLTDAQ::OnlineName(deti), ddlId);
318       }
319     }
320   }
321 }
322
323
324 void AliHLTTriggerDomain::Remove(const AliHLTDomainEntry& entry)
325 {
326   // Removes the given domain entry from the trigger domain.
327   // See header file for more details.
328
329   AliHLTDomainEntry intersect;
330   bool addToExcludeSet = false;
331   
332   // Get the initial size of the fEntries array since we might add things to the
333   // end during the calculation.
334   Int_t count = fEntries.GetEntriesFast();
335   
336   // We need to go through all existing entries and see if they need to be removed
337   // because they would become redundant when we add the new 'entry' to the end of
338   // the fEntries list. We also need to check if the new entry needs to be added
339   // at all because the trigger domain might already not contain those entries.
340   // Lastly, some intersection entries might need to be added to patch up existing
341   // inclusive trigger domain entries (rules / patterns).
342   for (Int_t i = 0; i < count; i++)
343   {
344     AliHLTDomainEntry* ientry = static_cast<AliHLTDomainEntry*>(fEntries[i]);
345     if (ientry->Inclusive())
346     {
347       if (ientry->SubsetOf(entry))
348       {
349         ientry->SetBit(14, true);  // mark for removal.
350       }
351       else if (entry.SubsetOf(*ientry))
352       {
353         addToExcludeSet = true;
354       }
355       else if (ientry->IntersectWith(entry, intersect))
356       {
357         new (fEntries[fEntries.GetEntriesFast()]) AliHLTDomainEntry(kTRUE, intersect);
358       }
359     }
360     else
361     {
362       if (entry.SubsetOf(*ientry))
363       {
364         addToExcludeSet = false;
365       }
366       else if (ientry->SubsetOf(entry))
367       {
368         ientry->SetBit(14, true);  // mark for removal.
369       }
370     }
371   }
372   
373   // Check if we need to add the new entry.
374   if (addToExcludeSet)
375   {
376     MarkForDeletionSubsetsOf(entry, count);
377     new (fEntries[fEntries.GetEntriesFast()]) AliHLTDomainEntry(kTRUE, entry);
378   }
379   RemoveMarkedEntries();
380 }
381
382
383 void AliHLTTriggerDomain::Remove(const AliHLTComponentDataType& datatype)
384 {
385   // Removes the domain entries that have the given data type from the trigger domain.
386   // See header file for more details.
387   
388   Remove(AliHLTDomainEntry(datatype));
389 }
390
391
392 void AliHLTTriggerDomain::Remove(const char* blocktype, const char* origin)
393 {
394   // Removes the domain entries that have the given data type and origin from the
395   // trigger domain.
396   // See header file for more details.
397   
398   Remove(AliHLTDomainEntry(blocktype, origin));
399 }
400
401
402 void AliHLTTriggerDomain::Remove(const AliHLTComponentDataType& datatype, UInt_t spec)
403 {
404   // Removes the domain entries that have the given data type and data block
405   // specification bits from the trigger domain.
406   // See header file for more details.
407   
408   Remove(AliHLTDomainEntry(datatype, spec));
409 }
410
411
412 void AliHLTTriggerDomain::Remove(const char* blocktype, const char* origin, UInt_t spec)
413 {
414   // Removes the domain entries that have the given data type, origin and data
415   // block specification bits from the trigger domain.
416   // See header file for more details.
417   
418   Remove(AliHLTDomainEntry(blocktype, origin, spec));
419 }
420
421
422 bool AliHLTTriggerDomain::Contains(const AliHLTDomainEntry& entry) const
423 {
424   // Checks to see if the given domain entry is part of the trigger domain set.
425   // See header file for more details.
426
427   // Simply go through the whole list of fEntries and for each entry see if the
428   // given domain entry 'entry' being checked matches. If there is a match then
429   // update the result depending on the entry type. i.e. set to false if the entry
430   // in fEntries is an exclusion and set to true if it is an inclusion.
431   bool result = false;
432   for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++)
433   {
434     const AliHLTDomainEntry* ientry = static_cast<const AliHLTDomainEntry*>(fEntries[i]);
435     if (ientry->Inclusive())
436     {
437       if (*ientry == entry) result = true;
438     }
439     else
440     {
441       if (entry.SubsetOf(*ientry)) result = false;
442     }
443   }
444   return result;
445 }
446
447
448 bool AliHLTTriggerDomain::IncludeInReadout(const AliHLTComponentBlockData* block) const
449 {
450   // Checks to see if the given data block is part of the trigger domain set and
451   // should be readout.
452   // See header file for more details.
453
454   // Same algorithm as for Contains() but applied directly to the data block
455   // descriptor structure.
456   AliHLTDomainEntry blockEntry(block->fDataType, block->fSpecification);
457   bool result = false;
458   for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++)
459   {
460     const AliHLTDomainEntry* entry = static_cast<const AliHLTDomainEntry*>(fEntries[i]);
461     if (entry->Inclusive())
462     {
463       if (*entry == block) result = true;
464     }
465     else
466     {
467       if (blockEntry.SubsetOf(*entry)) result = false;
468     }
469   }
470   return result;
471 }
472
473
474 void AliHLTTriggerDomain::Clear(Option_t* option)
475 {
476   // Clears the trigger domain (Removes all entries).
477   
478   fEntries.Clear(option);
479 }
480
481
482 void AliHLTTriggerDomain::Print(Option_t* /*option*/) const
483 {
484   // Prints the trigger domain entries in the order that they are applied.
485   // See header file for more details.
486
487   cout << "Trigger domain rules (applied in order of first to last):" << endl;
488   for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++)
489   {
490     const AliHLTDomainEntry* entry = static_cast<const AliHLTDomainEntry*>( fEntries[i] );
491     if (entry->Inclusive())
492     {
493       cout << "Include ";
494     }
495     else
496     {
497       cout << "Exclude ";
498     }
499     entry->Print();
500   }
501   if (fEntries.GetEntriesFast() == 0)
502   {
503     cout << "(empty)" << endl;
504   }
505 }
506
507
508 AliHLTTriggerDomain& AliHLTTriggerDomain::operator = (const AliHLTTriggerDomain& domain)
509 {
510   // Assignment operator performs a deep copy.
511   // See header file for more details.
512   
513   if (this == &domain) return *this;
514   TObject::operator = (domain);
515   fEntries.Clear();
516   for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++)
517   {
518     const AliHLTDomainEntry* entry = static_cast<const AliHLTDomainEntry*>( domain.fEntries[i] );
519     new (fEntries[fEntries.GetEntriesFast()]) AliHLTDomainEntry(*entry);
520   }
521   return *this;
522 }
523
524
525 AliHLTTriggerDomain& AliHLTTriggerDomain::operator |= (const AliHLTTriggerDomain& domain)
526 {
527   // This operator performs the set union.
528   // See header file for more details.
529   
530   // Note that we partition the fEntries array into 3 regions for this calculation.
531   //   - 0..entriesCount-1 : contains the initial entries of this trigger domain.
532   //   - entriesCount..startOfIntersects-1 : is space reserved for the new entries
533   //       from 'domain'.
534   //   - startOfIntersects..fEntries.GetEntriesFast()-1 : This will grow as we add
535   //       all the new domain intersections created during the calculation.
536   //
537   // Get the number of entries now before we start adding more entries from 'domain'.
538   Int_t count = fEntries.GetEntriesFast();
539   // Mark the start location for new intersection entries.
540   Int_t startOfIntersects = count + domain.fEntries.GetEntriesFast();
541   Int_t newIndex = startOfIntersects;
542
543   // Allocate and initialise a single block of memory so that we do not call new twice.
544   bool* buffer = new bool[startOfIntersects];
545   for (Int_t i = 0; i < startOfIntersects; i++) buffer[i] = false;
546   bool* removeThisEntry = buffer;
547   bool* removeDomainEntry = buffer + count;
548
549   AliHLTDomainEntry intersect;
550   
551   // The idea behind this algorithm is that we need to add all inclusion domain
552   // entries from 'domain' to this object that will not be redundant, but for
553   // the exclusion entries we patch the fEntries rule set by adding the appropriate
554   // intersections to the end of fEntries.
555   for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++)
556   {
557     const AliHLTDomainEntry* newEntry = static_cast<const AliHLTDomainEntry*>( domain.fEntries[i] );
558     for (Int_t j = 0; j < count; j++)
559     {
560       const AliHLTDomainEntry* currentEntry = static_cast<const AliHLTDomainEntry*>( fEntries[j] );
561       if (currentEntry->Inclusive() and newEntry->Inclusive())
562       {
563         // If either entry is a subset of the other then we do not need to add
564         // both, so make sure to remove the one that is redundant.
565         if (newEntry->SubsetOf(*currentEntry))
566         {
567           removeDomainEntry[i] = true;
568         }
569         else if (currentEntry->SubsetOf(*newEntry))
570         {
571           removeThisEntry[j] = true;
572         }
573       }
574       else
575       {
576         if (newEntry->IntersectWith(*currentEntry, intersect))
577         {
578           // We can remove all intersections that were already added that will
579           // become redundant when this intersection is added to fEntries.
580           MarkForDeletionSubsetsOf(intersect, startOfIntersects);
581           
582           // Make the new intersection entry an exclusion if the newEntry and
583           // currentEntry flags are the same.
584           bool exclude = newEntry->Exclusive() == currentEntry->Exclusive();
585           new (fEntries[newIndex++]) AliHLTDomainEntry(exclude, intersect);
586           
587           // We can also remove entries that are subsets of another entry in the
588           // opposite list, since they will be redundant when everything is merged
589           // together. For example, remove entry x from fEntries if it is a subset
590           // of entry y in domain.fEntries.
591           if (currentEntry->IdenticalTo(intersect)) removeThisEntry[j] = true;
592           if (newEntry->IdenticalTo(intersect)) removeDomainEntry[i] = true;
593         }
594       }
595     }
596   }
597
598   MergeEntries(removeThisEntry, count, removeDomainEntry, startOfIntersects, domain);
599   delete [] buffer;
600   Optimise();
601   return *this;
602 }
603
604
605 AliHLTTriggerDomain& AliHLTTriggerDomain::operator ^= (const AliHLTTriggerDomain& domain)
606 {
607   // This operator performs the set union, less the set intersect (something like and xor).
608   // See header file for more details.
609   
610   // Note that we partition the fEntries array into 3 regions for this calculation.
611   //   - 0..entriesCount-1 : contains the initial entries of this trigger domain.
612   //   - entriesCount..startOfIntersects-1 : is space reserved for the new entries
613   //       from 'domain'.
614   //   - startOfIntersects..fEntries.GetEntriesFast()-1 : This will grow as we add
615   //       all the new domain intersections created during the calculation.
616   //
617   // Get the number of entries now before we start adding more entries from 'domain'.
618   Int_t count = fEntries.GetEntriesFast();
619   // Mark the start location for new intersection entries.
620   Int_t startOfIntersects = count + domain.fEntries.GetEntriesFast();
621   Int_t newIndex = startOfIntersects;
622
623   // Allocate and initialise a single block of memory so that we do not call new twice.
624   bool* buffer = new bool[startOfIntersects];
625   for (Int_t i = 0; i < startOfIntersects; i++) buffer[i] = false;
626   bool* removeThisEntry = buffer;
627   bool* removeDomainEntry = buffer + count;
628
629   AliHLTDomainEntry intersect;
630   
631   // This algorithm is similar to the case for the set union (operator |=), except
632   // that we make sure to remove from the trigger domain all parts where the entries
633   // from fEntries and domain.fEntries intersect.
634   // This is done by adding the intersections to the end of fEntries such that they
635   // effectively remove those overlapping trigger domain entries when calculating
636   // IncludeInReadout() or Contains().
637   for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++)
638   {
639     const AliHLTDomainEntry* newEntry = static_cast<const AliHLTDomainEntry*>( domain.fEntries[i] );
640     for (Int_t j = 0; j < count; j++)
641     {
642       const AliHLTDomainEntry* currentEntry = static_cast<const AliHLTDomainEntry*>( fEntries[j] );
643       if (newEntry->IntersectWith(*currentEntry, intersect))
644       {
645         // We can remove all intersections that were already added that will
646         // become redundant when this intersection is added to fEntries.
647         MarkForDeletionSubsetsOf(intersect, startOfIntersects);
648         
649         // Make the new intersection entry an exclusion if the newEntry and
650         // currentEntry flags are the same.
651         bool exclude = newEntry->Exclusive() == currentEntry->Exclusive();
652         new (fEntries[newIndex++]) AliHLTDomainEntry(exclude, intersect);
653         
654         // We can also remove entries that are subsets of another entry in the
655         // opposite list, since they will be redundant when everything is merged
656         // together. For example, remove entry x from fEntries if it is a subset
657         // of entry y in domain.fEntries.
658         if (currentEntry->IdenticalTo(intersect)) removeThisEntry[j] = true;
659         if (newEntry->IdenticalTo(intersect)) removeDomainEntry[i] = true;
660       }
661     }
662   }
663
664   MergeEntries(removeThisEntry, count, removeDomainEntry, startOfIntersects, domain);
665   delete [] buffer;
666   Optimise();
667   return *this;
668 }
669
670
671 AliHLTTriggerDomain& AliHLTTriggerDomain::operator -= (const AliHLTTriggerDomain& domain)
672 {
673   // This operator performs the set difference.
674   // See header file for more details.
675   
676   // Mark the number of entries in fEntries now before we start adding more
677   // entries from 'domain' or intersections.
678   Int_t startOfIntersects = fEntries.GetEntriesFast();
679   Int_t newIndex = startOfIntersects;
680   
681   AliHLTDomainEntry intersect;
682   
683   // To compute the set difference we need to remove all all parts that overlap
684   // with 'domain'. i.e. we need to find all the intersects between the domain
685   // entries in fEntries and those in domain.fEntries, and add the intersects
686   // to the fEntries list, such that they will cancel or remove the overlapping
687   // parts of the two trigger domains.
688   for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++)
689   {
690     const AliHLTDomainEntry* checkEntry = static_cast<const AliHLTDomainEntry*>( domain.fEntries[i] );
691     if (checkEntry->Inclusive())
692     {
693       // For inclusive entries we need to find the overlaps with the inclusive
694       // entries in fEntries and add exclusive entries that will remove that
695       // part of the trigger domain set.
696       for (Int_t j = 0; j < startOfIntersects; j++)
697       {
698         AliHLTDomainEntry* currentEntry = static_cast<AliHLTDomainEntry*>( fEntries[j] );
699         
700         // We only need to consider the case where both entries are inclusive,
701         // since an exclusion in fEntries already eliminates those data blocks
702         // from the trigger domain set.
703         if (currentEntry->Exclusive()) continue;
704         
705         if (checkEntry->IntersectWith(*currentEntry, intersect))
706         {
707           // We can remove all intersections that were already added that will
708           // become redundant when this intersection is added to fEntries.
709           MarkForDeletionSubsetsOf(intersect, startOfIntersects);
710           
711           new (fEntries[newIndex++]) AliHLTDomainEntry(kTRUE, intersect);
712           if (currentEntry->IdenticalTo(intersect))
713           {
714             currentEntry->SetBit(14, true);
715           }
716         }
717       }
718     }
719     else
720     {
721       // For an exclusive entry in 'domain' we need to find the intersections with
722       // all of fEntries and re-apply these with the same exclude flags.
723       for (Int_t j = 0; j < startOfIntersects; j++)
724       {
725         AliHLTDomainEntry* currentEntry = static_cast<AliHLTDomainEntry*>( fEntries[j] );
726         if (checkEntry->IntersectWith(*currentEntry, intersect))
727         {
728           // We can remove all intersections that were already added that will
729           // become redundant when this intersection is added to fEntries.
730           MarkForDeletionSubsetsOf(intersect, startOfIntersects);
731           
732           new (fEntries[newIndex++]) AliHLTDomainEntry(currentEntry->Exclusive(), intersect);
733         }
734       }
735     }
736   }
737
738   RemoveMarkedEntries();
739   Optimise();
740   return *this;
741 }
742
743
744 AliHLTTriggerDomain AliHLTTriggerDomain::operator ~ () const
745 {
746   // Performs a set complement of the trigger domain.
747   
748   // The set complement is calculated by creating a new trigger domain which
749   // accepts all possible data blocks, and then apply all the trigger domain
750   // entries (rules / patterns) from top to bottom, but apply them with the
751   // opposite meaning. For example, this->fEntries contains an inclusive domain
752   // entry then remove it from the new trigger domain 'result', but if it is
753   // an exclusion then add it.
754   AliHLTTriggerDomain result;
755   result.Add(kAliHLTAnyDataType);
756   for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++)
757   {
758     const AliHLTDomainEntry* entry = static_cast<const AliHLTDomainEntry*>( fEntries[i] );
759     if (entry->Inclusive())
760     {
761       result.Remove(*entry);
762     }
763     else
764     {
765       result.Add(*entry);
766     }
767   }
768   return result;
769 }
770
771
772 AliHLTTriggerDomain AliHLTTriggerDomain::operator & (const AliHLTTriggerDomain& domain) const
773 {
774   // This operator finds the set intersect.
775   // See header file for more details.
776   
777   AliHLTTriggerDomain result;
778   Int_t newIndex = 0;
779   AliHLTDomainEntry intersect;
780   
781   // To find the set intersect we need to compare each entry in 'domain' to those
782   // of fEntries. For each inclusive entry in 'domain' we need to add to the result
783   // the intersect between it and each entry of fEntries, with the same exclude flag
784   // value as the domain entry from fEntries.
785   // However, in principle, for the exclusion entries in 'domain' we just add them
786   // to the result, since those entries do not form part of the 'domain' trigger
787   // domain set, so they should not form part of the result (remember any data block
788   // must be contained in both trigger domains for a set intersect).
789   // In actual fact we just add the intersect of the exclusion entries in 'domain'
790   // with those of fEntries to the result. This has the same overall effect, but
791   // makes sure that all exclusion entries are always subsets of inclusion entries.
792   for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++)
793   {
794     const AliHLTDomainEntry* checkEntry = static_cast<const AliHLTDomainEntry*>( domain.fEntries[i] );
795     if (checkEntry->Inclusive())
796     {
797       for (Int_t j = 0; j < fEntries.GetEntriesFast(); j++)
798       {
799         AliHLTDomainEntry* currentEntry = static_cast<AliHLTDomainEntry*>( fEntries[j] );
800         if (checkEntry->IntersectWith(*currentEntry, intersect))
801         {
802           // We can remove all entries that were already added to the result that
803           // will become redundent because they are subsets of the new entry.
804           result.MarkForDeletionSubsetsOf(intersect, 0);
805           
806           new (result.fEntries[newIndex++]) AliHLTDomainEntry(currentEntry->Exclusive(), intersect);
807         }
808       }
809     }
810     else
811     {
812       for (Int_t j = 0; j < fEntries.GetEntriesFast(); j++)
813       {
814         AliHLTDomainEntry* currentEntry = static_cast<AliHLTDomainEntry*>( fEntries[j] );
815         if (checkEntry->IntersectWith(*currentEntry, intersect))
816         {
817           // We can remove all entries that were already added to the result that
818           // will become redundant because they are subsets of the new entry.
819           result.MarkForDeletionSubsetsOf(intersect, 0);
820           
821           new (result.fEntries[newIndex++]) AliHLTDomainEntry(kTRUE, intersect);
822         }
823       }
824     }
825   }
826
827   result.RemoveMarkedEntries();
828   result.Optimise();
829   return result;
830 }
831
832
833 AliHLTTriggerDomain::operator AliHLTReadoutList () const
834 {
835   // Typecast operator which constructs a readout list from the trigger domain.
836   
837   AliHLTReadoutList result;
838   for (Int_t deti = 0; deti < AliHLTDAQ::NumberOfDetectors(); deti++)
839   {
840     for (Int_t i = 0; i < AliHLTDAQ::NumberOfDdls(deti); i++)
841     {
842       Int_t ddlId = AliHLTDAQ::DdlID(deti, i);
843       if (Contains(AliHLTDomainEntry("DAQRDOUT", AliHLTDAQ::OnlineName(deti), ddlId)))
844       {
845         result.EnableDDLBit(ddlId);
846       }
847     }
848   }
849   return result;
850 }
851
852
853 void AliHLTTriggerDomain::MergeEntries(
854     const bool* removeThisEntry, Int_t entriesCount,
855     const bool* removeDomainEntry, Int_t startOfIntersects,
856     const AliHLTTriggerDomain& domain
857   )
858 {
859   // Merges the entries in this trigger domain with the ones in 'domain', while
860   // removing all entries that were marked for removal.
861   // See header file for more information.
862   
863   bool anythingRemoved = false;
864   
865   // Remember this method is used at the end of the calculation of the binary operators
866   // and that fEntries is expected to be partitioned into 3 regions.
867   //   - 0..entriesCount-1 : contains the original (initial) entries of this trigger domain.
868   //   - entriesCount..startOfIntersects-1 : is space reserved for the new entries
869   //       from the given trigger domain 'domain' being processed.
870   //   - startOfIntersects..fEntries.GetEntriesFast()-1 : contains all new domain entry
871   //       intersection created and added to fEntries.
872   //
873   // First we need to remove all entries marked for removal from the original entries.
874   for (Int_t i = 0; i < entriesCount; i++)
875   {
876     if (removeThisEntry[i])
877     {
878       fEntries.RemoveAt(i);
879       anythingRemoved = true;
880     }
881   }
882   
883   // Now we copy over all the new entries from 'domain' which were not marked for removal
884   // and indicate anythingRemoved = true since there will now be gaps in the clones array
885   // that need to be compressed away later.
886   for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++)
887   {
888     if (removeDomainEntry[i])
889     {
890       anythingRemoved = true;
891     }
892     else
893     {
894       const AliHLTDomainEntry* newEntry = static_cast<const AliHLTDomainEntry*>( domain.fEntries[i] );
895       new (fEntries[entriesCount+i]) AliHLTDomainEntry(*newEntry);
896     }
897   }
898   
899   // Finally remove all new intersection entries that were marked for removal by
900   // the MarkForDeletionSubsetsOf method.
901   for (Int_t i = startOfIntersects; i < fEntries.GetEntriesFast(); i++)
902   {
903     const AliHLTDomainEntry* ientry = static_cast<const AliHLTDomainEntry*>( fEntries[i] );
904     if (ientry->TestBit(14))
905     {
906       fEntries.RemoveAt(i);
907       anythingRemoved = true;
908     }
909   }
910   if (anythingRemoved) fEntries.Compress();
911 }
912
913
914 void AliHLTTriggerDomain::MarkForDeletionSubsetsOf(const AliHLTDomainEntry& entry, Int_t min)
915 {
916   // Marks for deletion all the entries in this trigger domain that are subsets
917   // of the given entry.
918   // See header file for more information.
919
920   AliHLTDomainEntry intersect;
921   for (Int_t i = min; i < fEntries.GetEntriesFast(); i++)
922   {
923     AliHLTDomainEntry* ientry = static_cast<AliHLTDomainEntry*>( fEntries[i] );
924     if (ientry->TestBit(14)) continue;
925     if (ientry->SubsetOf(entry))
926     {
927       ientry->SetBit(14, true);
928     }
929   }
930 }
931
932
933 void AliHLTTriggerDomain::RemoveMarkedEntries()
934 {
935   // Removes all entries in this trigger domain which were marked for removal.
936   // See header file for more information.
937   
938   bool anythingRemoved = false;
939   for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++)
940   {
941     const AliHLTDomainEntry* ientry = static_cast<const AliHLTDomainEntry*>( fEntries[i] );
942     if (ientry->TestBit(14))
943     {
944       fEntries.RemoveAt(i);
945       anythingRemoved = true;
946     }
947   }
948   if (anythingRemoved) fEntries.Compress();
949 }
950
951
952 void AliHLTTriggerDomain::Optimise()
953 {
954   // Removes redundant trigger domain entries from the trigger domain.
955   // See header file for more information.
956
957   AliHLTDomainEntry intersect;
958   
959   // Check that the first entry is not and exclusion which would be redundent.
960   if (fEntries.GetEntriesFast() == 0) return;
961   AliHLTDomainEntry* firstEntry = static_cast<AliHLTDomainEntry*>( fEntries[0] );
962   if (firstEntry->Exclusive()) firstEntry->SetBit(14, true);
963   
964   for (Int_t i = 1; i < fEntries.GetEntriesFast(); i++)
965   {
966     AliHLTDomainEntry* ientry = static_cast<AliHLTDomainEntry*>( fEntries[i] );
967     
968     // For the i'th entry in fEntries, compare it in reverse order with all other
969     // entries that are before it and look for redundant ones, i.e. that are subsets
970     // of the i'th entry.
971     for (Int_t j = i-1; j >= 0; j--)
972     {
973       AliHLTDomainEntry* jentry = static_cast<AliHLTDomainEntry*>( fEntries[j] );
974       if (jentry->TestBit(14)) continue;
975       // Find entries that intersect
976       if (jentry->SubsetOf(*ientry))
977       {
978         // jentry is a subset of ientry so it is redundant because for all values
979         // ientry will override jentry when calling IncludeInReadout.
980         jentry->SetBit(14, true);
981       }
982       else if (*ientry == *jentry)
983       {
984         // If intersecting entries have opposite exclude flags then search no further,
985         // we know that we will need this entry for correct behaviour of IncludeInReadout.
986         if (ientry->Inclusive() == jentry->Exclusive()) goto processNextEntry;
987         
988         if (ientry->SubsetOf(*jentry))
989         {
990           ientry->SetBit(14, true);
991           goto processNextEntry;
992         }
993       }
994     }
995     
996     // If we got to this point then we hit the top of the trigger domain rules
997     // (pattern matching) list without hitting any and overlapping entries.
998     // So now we need to check if ientry is an exclusion. If it is, then it is
999     // redundant and we can mark it for removal.
1000     if (ientry->Exclusive()) ientry->SetBit(14, true);
1001     
1002     processNextEntry: ;
1003   }
1004   
1005   RemoveMarkedEntries();
1006 }
1007