]> git.uio.no Git - u/mrichter/AliRoot.git/blame - HLT/MUON/AliHLTMUONList.h
--- Access to bad channel map implemented in reconstruction chain.
[u/mrichter/AliRoot.git] / HLT / MUON / AliHLTMUONList.h
CommitLineData
feb10c40 1#ifndef ALIHLTMUONLIST_H
2#define ALIHLTMUONLIST_H
3/**************************************************************************
4 * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
5 * *
6 * Author: The ALICE Off-line Project. *
7 * Contributors are mentioned in the code where appropriate. *
8 * *
9 * Permission to use, copy, modify and distribute this software and its *
10 * documentation strictly for non-commercial purposes is hereby granted *
11 * without fee, provided that the above copyright notice appears in all *
12 * copies and that both the copyright notice and this permission notice *
13 * appear in the supporting documentation. The authors make no claims *
14 * about the suitability of this software for any purpose. It is *
15 * provided "as is" without express or implied warranty. *
16 **************************************************************************/
17
18/* $Id$ */
19
20/**
21 * @file AliHLTMUONList.h
22 * @author Artur Szostak <artursz@iafrica.com>
23 * @date
24 * @brief Declaration of a singly linked-list class which preallocates memory
25 * to give faster online performance.
26 */
27
28#include "AliHLTDataTypes.h"
29#include <ostream>
30#include <cassert>
31#include <cstdlib>
32#include <new>
33
34/**
35 * The AliHLTMUONList class is a unidirectional linked-list which preallocates
36 * a large memory buffer where it stores its elements. This strategy gives higher
37 * online performance.
38 */
39template <typename DataType>
40class AliHLTMUONList
41{
42protected:
43
44 struct Node; // forward declaration for ConstIterator and Iterator
45
46public:
47
48 /**
49 * This is an iterator class which allows one to iterate through the list
50 * using the prefix or postfix operators ++.
51 */
52 class ConstIterator
53 {
54 public:
55
56 ConstIterator() : fCurrent(NULL) {}
57
58 ConstIterator(const ConstIterator& iter) : fCurrent(iter.fCurrent) {}
59
60 ConstIterator(Node* node) : fCurrent(node) {}
61
62 ConstIterator& operator = (const ConstIterator& iter)
63 {
64 fCurrent = iter.fCurrent;
65 return *this;
66 }
67
68 virtual ~ConstIterator() {} // Just to make gcc -Weffc++ option shutup.
69
70 // Dereference operator returns the elements data.
71 const DataType& operator * () const { return fCurrent->fData; }
72
73 // Pointer dereferencing returns the elements data.
74 const DataType* operator -> () const { return &fCurrent->fData; }
75
76 // Move to the next element in the list.
77 ConstIterator& operator ++ ()
78 {
79 assert( fCurrent != NULL );
80 fCurrent = fCurrent->fNext;
81 return *this;
82 }
83
84 // Move to the next element in the list.
85 ConstIterator operator ++ (int)
86 {
87 assert( fCurrent != NULL );
88 ConstIterator copy = *this;
89 fCurrent = fCurrent->fNext;
90 return copy;
91 }
92
93 // Typecast operator returns a pointer to the data.
94 operator const DataType* () const { return &fCurrent->fData; }
95
96 friend bool operator == (const ConstIterator& a, const ConstIterator& b)
97 {
98 return a.fCurrent == b.fCurrent;
99 }
100
101 friend bool operator != (const ConstIterator& a, const ConstIterator& b)
102 {
103 return a.fCurrent != b.fCurrent;
104 }
105
106 protected:
107
108 friend class AliHLTMUONList;
109 Node* fCurrent; // The pointer to the current element selected by the iterator.
110 };
111
112 /**
113 * This is an iterator class which allows one to iterate through the list
114 * just like ConstIterator, but also allows modification of the elements.
115 */
116 class Iterator : public ConstIterator
117 {
118 public:
119
120 Iterator() : ConstIterator(), fPrevious(NULL) {}
121
122 Iterator(const Iterator& iter) : ConstIterator(iter), fPrevious(iter.fPrevious) {}
123
124 Iterator(Node* current, Node* prev) : ConstIterator(current), fPrevious(prev) {}
125
126 Iterator& operator = (const Iterator& iter)
127 {
128 ConstIterator::operator = (iter);
129 fPrevious = iter.fPrevious;
130 return *this;
131 }
132
133 virtual ~Iterator() {} // Just to make gcc -Weffc++ option shutup.
134
135 // Dereference operator returns the elements data.
136 DataType& operator * () { return ConstIterator::fCurrent->fData; }
137
138 // Pointer dereferencing returns the elements data.
139 DataType* operator -> () { return &ConstIterator::fCurrent->fData; }
140
141 // Move to the next element in the list.
142 Iterator& operator ++ ()
143 {
144 assert( ConstIterator::fCurrent != NULL );
145 fPrevious = ConstIterator::fCurrent;
146 ConstIterator::fCurrent = ConstIterator::fCurrent->fNext;
147 return *this;
148 }
149
150 // Move to the next element in the list.
151 Iterator operator ++ (int)
152 {
153 assert( ConstIterator::fCurrent != NULL );
154 Iterator copy = *this;
155 fPrevious = ConstIterator::fCurrent;
156 ConstIterator::fCurrent = ConstIterator::fCurrent->fNext;
157 return copy;
158 }
159
160 // Typecast operator returns a pointer to the data.
161 operator DataType* ()
162 {
163 if (ConstIterator::fCurrent != NULL)
164 return &ConstIterator::fCurrent->fData;
165 else
166 return NULL;
167 }
168
169 protected:
170
171 friend class AliHLTMUONList;
172 Node* fPrevious; // The pointer to the previous element.
173 };
174
175 /**
176 * Constructor allocates a buffer to hold at least 'minentries' number
177 * of nodes for the list.
178 */
179 AliHLTMUONList(AliHLTUInt32_t maxentries = 1024*4) :
180 fFirst(NULL), fNextFree(0), fMaxEntries(maxentries), fEntry(NULL)
181 {
182 // Allocate buffer space.
183 fEntry = reinterpret_cast<NodeEntry*>(
184 malloc( sizeof(NodeEntry) * fMaxEntries )
185 );
186 if (fEntry == NULL) throw std::bad_alloc();
187 // Set the availability flags.
188 for (AliHLTUInt32_t i = 0; i < fMaxEntries; i++)
189 fEntry[i].fFree = true;
190 }
191
192 /**
193 * Deep copy the list.
194 */
195 AliHLTMUONList(const AliHLTMUONList& list) :
196 fFirst(NULL), fNextFree(0), fMaxEntries(list.fMaxEntries),
197 fEntry(NULL)
198 {
199 if (list.fFirst != NULL)
200 {
201 // First allocate the buffer space.
202 fEntry = reinterpret_cast<NodeEntry*>(
203 malloc( sizeof(NodeEntry) * fMaxEntries )
204 );
205 if (fEntry == NULL) throw std::bad_alloc();
206 // Set the availability flags.
207 for (AliHLTUInt32_t i = 0; i < fMaxEntries; i++)
208 fEntry[i].fFree = true;
209
210 // Now copy the list by adding new node entries.
211 Add(list.fFirst->fData);
212 Node* current = fFirst;
213 Node* listcurrent = list.fFirst->fNext;
214 while (listcurrent != NULL)
215 {
216 current->fNext = NewNode(listcurrent->fData);
217 current = current->fNext;
218 listcurrent = listcurrent->fNext;
219 }
220 }
221 }
222
223 /**
224 * Delete the list and release all allocated memory.
225 */
226 virtual ~AliHLTMUONList()
227 {
228 Node* current = fFirst;
229 while (current != NULL)
230 {
231 Node* temp = current;
232 current = current->fNext;
233 DeleteNode(temp);
234 }
235 // Delete the buffer space after all nodes are deleted,
236 // else we will cause a crash.
237 assert(fEntry != NULL);
238 free(fEntry);
239 }
240
241 /**
242 * Deep copy the list.
243 */
244 AliHLTMUONList& operator = (const AliHLTMUONList& list)
245 {
246 if (list.fFirst == NULL)
247 {
248 Clear();
249 return *this;
250 }
251 if (fFirst == NULL)
252 {
253 // The list in 'this' object is empty so we need to create
254 // new nodes for everything.
255 Add(list.fFirst->fData);
256 Node* current = fFirst;
257 Node* listcurrent = list.fFirst->fNext;
258 while (listcurrent != NULL)
259 {
260 current->fNext = NewNode(listcurrent->fData);
261 current = current->fNext;
262 listcurrent = listcurrent->fNext;
263 }
264 return *this;
265 }
266
267 // At least the first node does not need to be created.
268 fFirst->fData = list.fFirst->fData;
269
270 Node* current = fFirst;
271 Node* listcurrent = list.fFirst->fNext;
272 while (listcurrent != NULL)
273 {
274 if (current->fNext == NULL)
275 {
276 // The list of 'this' object is shorter so we need
277 // to create new nodes.
278 do
279 {
280 current->fNext = NewNode(listcurrent->fData);
281 current = current->fNext;
282 listcurrent = listcurrent->fNext;
283 }
284 while (listcurrent != NULL);
285 break;
286 }
287 current->fNext->fData = listcurrent->fData;
288 current = current->fNext;
289 listcurrent = listcurrent->fNext;
290 }
291
292 // Unlink the remaining nodes.
293 Node* temp = current->fNext;
294 current->fNext = NULL;
295 current = temp;
296 // Remove any excess nodes from 'this' list.
297 while (current != NULL)
298 {
b1179a48 299 temp = current;
feb10c40 300 current = current->fNext;
301 DeleteNode(temp);
302 }
303
304 return *this;
305 }
306
307 /**
308 * Returns true if the list is empty and false otherwise.
309 */
310 bool Empty() const { return fFirst == NULL; }
311
312 /**
313 * Adds a new element to the start of the linked list.
314 * @return The pointer to the new element to fill its fields.
315 */
316 DataType* Add()
317 {
318 Node* newnode = NewNode();
319 newnode->fNext = fFirst;
320 fFirst = newnode;
321 return &newnode->fData;
322 }
323
324 /**
325 * Adds a new element to the start of the linked list and fills it with
326 * the data specified in 'data'.
327 * @param data The value to set the new element to.
328 */
329 void Add(const DataType& data)
330 {
331 Node* newnode = NewNode(data);
332 newnode->fNext = fFirst;
333 fFirst = newnode;
334 }
335
336 /**
337 * Searches the list if the element 'data' is already in the list. If it
338 * is then a pointer to the existing element is returned, otherwise a new
339 * element is created and a pointer to it is returned.
340 * @param data The value to search for or set the new element to.
341 * @return A pointer to the existing or new element.
342 */
343 DataType* AddUniquely(const DataType& data)
344 {
345 Iterator result = Find(data);
346 if (result == ConstIterator(NULL))
347 {
348 DataType* newdata = Add();
349 *newdata = data;
350 return newdata;
351 }
352 else
353 return result;
354 }
355
356 /**
357 * Removes the index'th element from the list.
358 * No error checking is done so there better be at least 'index' number
359 * of entries in the list. You can use Count() to find out how many
360 * entries there are.
361 */
362 void Remove(const AliHLTUInt32_t index)
363 {
364 Node* previous = NULL;
365 Node* current = fFirst;
366 for (AliHLTUInt32_t i = 0; i < index; i++)
367 {
368 assert( current != NULL );
369 previous = current;
370 current = current->fNext;
371 }
372 Node* temp;
373 if (previous == NULL)
374 {
375 temp = fFirst;
376 fFirst = fFirst->fNext;
377 }
378 else
379 {
380 temp = current;
381 previous->fNext = current->fNext;
382 }
383 DeleteNode(temp);
384 }
385
386 /**
387 * Looks for the entry with the same values as 'data' and removes it
388 * from the list. If the entry could not be found then false is returned.
389 * However if it is found then it is deleted and true is returned.
390 */
391 bool Remove(const DataType& data)
392 {
393 Iterator current = Find(data);
394 if (current != ConstIterator(NULL))
395 {
396 Remove(current);
397 return true;
398 }
399 else
400 return false;
401 }
402
403 /**
404 * Removes the entry pointed to by the iterator which must have been
405 * extracted from the list with a call to First() and/or several calls
406 * to the iterators increment operators.
407 * @param iter The entry to remove from the list.
408 */
409 void Remove(Iterator& iter)
410 {
411 Node* previous = iter.fPrevious;
412 Node* current = iter.fCurrent;
413 assert( current != NULL );
414
415 Node* temp;
416 if (previous == NULL)
417 {
418 temp = fFirst;
419 fFirst = fFirst->fNext;
420 }
421 else
422 {
423 temp = current;
424 previous->fNext = current->fNext;
425 }
426 DeleteNode(temp);
427 }
428
429 /**
430 * Finds the first element with the same value as 'data' and returns an
431 * iterator to it. The iterator points to the end of the list i.e. End()
432 * if nothing was found.
433 * @param data The value to look for.
434 * @return The iterator pointing to the found element or End().
435 */
436 Iterator Find(const DataType& data)
437 {
438 Node* previous = NULL;
439 Node* current = fFirst;
440 while (current != NULL)
441 {
442 if (current->fData == data)
443 return Iterator(current, previous);
444 previous = current;
445 current = current->fNext;
446 }
447 return End();
448 }
449
450 ConstIterator Find(const DataType& data) const
451 {
452 Node* current = fFirst;
453 while (current != NULL)
454 {
455 if (current->fData == data)
456 return ConstIterator(current);
457 current = current->fNext;
458 };
459 return End();
460 }
461
462 /**
463 * Finds the first element in the list that returns true for the predicate.
464 * That is, the first element for which the data evaluates to true in the
465 * test: predicate(fData). The iterator points to the end of the list
466 * i.e. End() if nothing was found.
467 * @param predicate Predicate that the data must return true for.
468 * This can usually be some one variable function.
469 * @return The iterator pointing to the found element or End().
470 */
471 template <typename PredicateType>
472 Iterator Find(PredicateType predicate)
473 {
474 Node* previous = NULL;
475 Node* current = fFirst;
476 while (current != NULL)
477 {
478 if ( predicate(current->fData) )
479 return Iterator(current, previous);
480 previous = current;
481 current = current->fNext;
482 }
483 return End();
484 }
485
486 template <typename PredicateType>
487 ConstIterator Find(PredicateType predicate) const
488 {
489 Node* current = fFirst;
490 while (current != NULL)
491 {
492 if ( predicate(current->fData) )
493 return ConstIterator(current);
494 current = current->fNext;
495 }
496 return End();
497 }
498
499 /**
500 * Returns true if the list contains the specified element, else false.
501 * @param data The value to search for in the list.
502 */
503 bool Contains(const DataType& data) const { return Find(data) != End(); }
504
505 /**
506 * This deletes all elements from the list.
507 */
508 void Clear()
509 {
510 Node* current = fFirst;
511 while (current != NULL)
512 {
513 Node* temp = current;
514 current = current->fNext;
515 DeleteNode(temp);
516 }
517 fFirst = NULL;
518 }
519
520 /**
521 * This deletes all elements from the list and resizes the buffer which
522 * is used to store the entries for the list.
523 */
524 void Clear(AliHLTUInt32_t maxentries) throw(std::bad_alloc)
525 {
526 Clear();
527
528 NodeEntry* newp = reinterpret_cast<NodeEntry*>(
529 realloc(fEntry, sizeof(NodeEntry) * fMaxEntries)
530 );
531 if (newp == NULL) throw std::bad_alloc();
532
533 // Set the availability flags for the node entries
534 for (AliHLTUInt32_t i = fMaxEntries; i < maxentries; i++)
535 fEntry[i].fFree = true;
536
537 fEntry = newp;
538 fMaxEntries = maxentries;
539 fNextFree = 0;
540 }
541
542 /**
543 * Returns an iterator to the first element of the list.
544 */
545 Iterator First() { return Iterator(fFirst, NULL); }
546 ConstIterator First() const { return fFirst; }
547
548 /**
549 * Returns an iterator pointing to the end of the list. The returned
550 * iterator does not actually point to a real data value but rather a
551 * sentinel value, and so it should not be dereferenced directly.
552 */
553 Iterator End() { return Iterator(NULL, NULL); }
554 ConstIterator End() const { return ConstIterator(NULL); }
555
556 /**
557 * Counts and returns the number of elements in the list.
558 */
559 AliHLTUInt32_t Count() const
560 {
561 AliHLTUInt32_t n = 0;
562 Node* current = fFirst;
563 while (current != NULL)
564 {
565 n++;
566 current = current->fNext;
567 }
568 return n;
569 }
570
571protected:
572
573 /**
574 * The internal node structure for the linked list.
575 */
576 struct Node
577 {
578 Node* fNext; // Next element in the list.
579 DataType fData; // The data for the current link.
580
581 Node() : fNext(NULL), fData() {};
582 Node(const DataType& data) : fNext(NULL), fData(data) {};
583 Node(const Node& node) : fNext(node.fNext), fData(node.data) {};
584
585 // Shallow copy the node.
586 Node& operator = (const Node& node)
587 {
588 fNext = node.fNext;
589 fData = node.fData;
590 return *this;
591 }
592 };
593
594 Node* fFirst; // The first element in the linked list.
595
596 struct NodeEntry
597 {
2a35bc39 598 bool fFree; // Indicates if this block is free.
feb10c40 599 Node fNode; // The node structure.
600 };
601
2a35bc39 602 AliHLTUInt32_t fNextFree; // The next entry that is presumably free.
feb10c40 603 AliHLTUInt32_t fMaxEntries; // The number of node entries that can be stored in fEntries.
604 NodeEntry* fEntry; // Buffer of preallocated node entries.
605
606 /**
607 * Locates the next free location in the fEntry buffer, creates a new node
608 * at that location and returns the pointer.
609 */
610 Node* NewNode() throw(std::bad_alloc)
611 {
612 //return new Node();
613 assert( fNextFree < fMaxEntries );
614 AliHLTUInt32_t i = fNextFree;
615 while (not fEntry[i].fFree and i < fMaxEntries) i++;
616 if (fEntry[i].fFree)
617 {
618 fEntry[i].fFree = false;
619 fNextFree = (i+1) % fMaxEntries;
620 return new (&fEntry[i].fNode) Node();
621 }
622 i = 0;
623 while (not fEntry[i].fFree and i < fNextFree) i++;
624 if (fEntry[i].fFree)
625 {
626 fEntry[i].fFree = false;
627 fNextFree = (i+1) % fMaxEntries;
628 return new (&fEntry[i].fNode) Node();
629 }
630 throw std::bad_alloc();
631 }
632
2a35bc39 633 Node* NewNode(const DataType& data) throw(std::bad_alloc)
feb10c40 634 {
635 //return new Node(data);
636 assert( fNextFree < fMaxEntries );
637 AliHLTUInt32_t i = fNextFree;
638 while (not fEntry[i].fFree and i < fMaxEntries) i++;
639 if (fEntry[i].fFree)
640 {
641 fEntry[i].fFree = false;
642 fNextFree = (i+1) % fMaxEntries;
643 return new (&fEntry[i].fNode) Node(data);
644 }
645 i = 0;
646 while (not fEntry[i].fFree and i < fNextFree) i++;
647 if (fEntry[i].fFree)
648 {
649 fEntry[i].fFree = false;
650 fNextFree = (i+1) % fMaxEntries;
651 return new (&fEntry[i].fNode) Node(data);
652 }
653 throw std::bad_alloc();
654 }
655
656 /**
657 * Destructs the node object.
658 */
659 void DeleteNode(Node* node)
660 {
661 //delete node;
662 node->~Node();
663 // Now mark the entry as free.
664 char* p = reinterpret_cast<char*>(node);
665 p -= (sizeof(NodeEntry) - sizeof(Node));
666 NodeEntry* entry = reinterpret_cast<NodeEntry*>(p);
667 entry->fFree = true;
668 }
669};
670
671
672/**
673 * Stream operator to write the list to std::ostream. The output is printed in
674 * the following format: [element1, element2, ..., elementN]
675 */
676template <typename DataType>
677std::ostream& operator << (
678 std::ostream& stream, const AliHLTMUONList<DataType>& list
679 )
680{
681 typename AliHLTMUONList<DataType>::ConstIterator current;
682 current = list.First();
683 stream << "[";
684 if (current == list.End())
685 {
686 stream << "]";
687 return stream;
688 }
689 stream << (*current++);
690 while (current != list.End())
691 stream << ", " << (*current++);
692 stream << "]";
693 return stream;
694}
695
696#endif // ALIHLTMUONLIST_H