Free Electron
List.h
Go to the documentation of this file.
1 /* Copyright (C) 2003-2021 Free Electron Organization
2  Any use of this software requires a license. If a valid license
3  was not distributed with this file, visit freeelectron.org. */
4 
5 /** @file */
6 
7 #ifndef __core_List_h__
8 #define __core_List_h__
9 
10 
11 #define FE_LIST_REF_DEBUG FALSE
12 
13 //* verify pointer usage with lists
14 #ifndef FE_LIST_STORE_CHECKPOINTER
15 #define FE_LIST_STORE_CHECKPOINTER TRUE
16 #endif
17 
18 #if FE_CODEGEN<=FE_DEBUG && FE_LIST_STORE_CHECKPOINTER
19 #define FE_LIST_CHECKPOINTER TRUE
20 #else
21 #define FE_LIST_CHECKPOINTER FALSE
22 #endif
23 
24 namespace fe
25 {
26 
27 /******************************************************************************
28  WARNING: this class must contain all data used by List;
29  it is intended to be interchangable with a List through a void*
30 
31  TODO allocator policy
32 ******************************************************************************/
33 /**************************************************************************//**
34  @brief Type-nonspecific Base Functionality of fe::List <>
35 
36  @ingroup core
37 
38  Allows access to generic list without knowing the element type.
39 *//***************************************************************************/
40 class FE_DL_EXPORT ListCore
41 {
42  protected:
43  class NodeCore;
44  public:
45  class Context;
46 
47  ListCore(void);
48 virtual ~ListCore(void);
49 
50  /// Set the AutoDestruct flag. If TRUE, destruction of
51  /// the list will attempt to destroy all the elements.
52  void setAutoDestruct(BWORD set) { m_autodestruct=set; }
53 
54  /// Get the AutoDestruct flag.
55  BWORD autoDestruct(void) { return m_autodestruct; }
56 
57  /// Returns the number of elements on the list.
58  U32 size(void) const { return m_length; }
59 
60  /// Remove and delete nodes, but don't delete contents
61  void removeAll(void);
62 
63  /// Moves the node at the first context before the
64  /// node at the second context.
65  BWORD moveNodeBefore(Context& from,Context& to)
66  { return coreMoveNode(true,from,to); }
67  /// Moves the node at the first context after the
68  /// node at the second context.
69  BWORD moveNodeAfter(Context& from,Context& to)
70  { return coreMoveNode(false,from,to); }
71 
72  /// Returns TRUE if the context is before the first element.
73  BWORD isAtHeadNull(Context& rContext) const
74  { return !m_length ||
75  (!rContext.current() && !rContext.isAtTailNull());}
76  /// Returns TRUE if the context is after the last element.
77  BWORD isAtTailNull(Context& rContext) const
78  { return !m_length ||
79  (!rContext.current() && rContext.isAtTailNull()); }
80 
81  /**********************************************************************//**
82  @brief A view state into an fe::List <>
83 
84  @ingroup core
85 
86  Do not access Context members except indirectly through List.
87 
88  If you like iterators better, use fe::List::Iterator which
89  wraps an fe::List::Context.
90 
91  Context is similar to an iterator except that it does not contain
92  a pointer to an List<>. All access to an List<> is done directly
93  through List<> member functions with an Context argument.
94  This means that
95  * Context is generic and does not need to be templated.
96  * The context is very lightweight and has no template
97  instantiation.
98  * No special permissions are needed for context to list accesses.
99  * Your code always explicitly says which list it is accessing.
100  *//***********************************************************************/
101  class FE_DL_EXPORT Context
102  {
103  public:
104  Context(void) { init(); }
105 
106  /// Copy constructor
107  Context(const Context& operand)
108  {
109 #if FE_LIST_STORE_CHECKPOINTER
110  FE_MAYBE_UNUSED(m_pListCore);
111 #endif
112  init();
113  setCurrent(operand.m_pCurrent);
114  setAtTailNull(operand.isAtTailNull());
115  }
116 
117  virtual ~Context(void)
118  {
119 // feLog("%p Context dec %p\n",this,m_pCurrent);
120  if(m_pCurrent)
121  m_pCurrent->decRef();
122  }
123 
124  /// Copy state from another context
126  {
127  setCurrent(operand.current());
128  setAtTailNull(operand.isAtTailNull());
129  return *this;
130  }
131 
132 
133  /** @brief Reinitialize state
134 
135  @internal */
136  void init(void)
137  {
138  m_pCurrent=NULL;
139  m_at_tail=false;
140 #if FE_LIST_CHECKPOINTER
141  m_pListCore=NULL;
142 #endif
143  }
144 
145  /** @brief Get current position on list
146 
147  @internal */
148  NodeCore* current(void)
149  {
150  checkValid();
151  return m_pCurrent;
152  }
153 
154  /** @brief Set current position on list
155 
156  @internal */
157  void setCurrent(NodeCore* set)
158  {
159 // feLog("%p Context set %p -> %p\n",
160 // (U32)this,(U32)m_pCurrent,(U32)set);
161  if(m_pCurrent==set)
162  return;
163 
164  if(m_pCurrent)
165  m_pCurrent->decRef();
166  if(set)
167  {
168  FEASSERT(set->valid());
169  set->incRef();
170  }
171  m_pCurrent=set;
172  }
173 
174  /** @brief Set whether context is after the tail
175 
176  @internal */
177  void setAtTailNull(BWORD set) { m_at_tail=set; }
178 
179  /** @brief Get whether context is after the tail
180 
181  @internal */
182  BWORD isAtTailNull(void) const
183  {
184  return m_at_tail;
185  }
186 
187  private:
188  void checkValid(void)
189  {
190  // if m_pCurrent is fine
191  if(!m_pCurrent || m_pCurrent->valid())
192  return;
193 
194  // find heir
195  NodeCore* heir=m_pCurrent;
196  while(heir && !heir->valid())
197  heir=heir->heir();
198 
199  // if good heir, copy
200  if(heir && heir->valid())
201  {
202 // fe_printf("heir %p\n",heir);
203  setCurrent(heir);
204  setAtTailNull(false);
205  }
206  // reset, reset
207  else
208  {
209  setCurrent(NULL);
210  setAtTailNull(false);
211  }
212  }
213 
214  NodeCore* m_pCurrent;
215  BWORD m_at_tail;
216 
217 #if FE_LIST_CHECKPOINTER
218  public:
219  /** @brief Store pointer to current list for debug
220 
221  @internal */
222  void setCorePointer(const ListCore *pSet)
223  {
224  m_pListCore=pSet;
225  }
226 
227  /** @brief Verify that we are accessing the
228  correct list
229 
230  @internal */
231  BWORD checkCorePointer(const ListCore *pCheck) const
232  {
233  if(pCheck && m_pListCore && m_pListCore!=pCheck)
234  feLog("Context::CheckCorePointer"
235  "(%p) does not match %p\n",
236  pCheck,m_pListCore);
237  FEASSERT(!pCheck || !m_pListCore ||
238  m_pListCore==pCheck);
239  return (!pCheck || !m_pListCore ||
240  m_pListCore==pCheck);
241  }
242 #endif
243 #if FE_LIST_STORE_CHECKPOINTER
244  private:
245  const ListCore* m_pListCore;
246 #endif
247  };
248 
249  protected:
250 
251  class FE_DL_EXPORT NodeCore: public Counted
252  {
253  public:
254  NodeCore(void):
255  m_valid(TRUE),
256  m_pPrevious(NULL),
257  m_pNext(NULL),
258  m_pHeir(NULL)
259  {
260  acquire();
261  }
262 
263  virtual ~NodeCore(void) {}
264 
265  /** @brief Set pointer to node before this one
266 
267  @internal */
268  void setPrevious(NodeCore* set) { m_pPrevious=set; }
269  /** @brief Get pointer to node before this one
270 
271  @internal */
272  NodeCore* previous(void) const { return m_pPrevious;}
273 
274  /** @brief Set pointer to node after this one
275 
276  @internal */
277  void setNext(NodeCore* set) { m_pNext=set; }
278  /** @brief Get pointer to node after this one
279 
280  @internal */
281  NodeCore* next(void) const { return m_pNext; }
282 
283  /** @brief Set pointer to heir node
284 
285  @internal */
286  void setHeir(NodeCore* set) { m_pHeir=set; }
287  /** @brief Get pointer to heir node
288 
289  @internal */
290  NodeCore* heir(void) const { return m_pHeir; }
291 
292  /** @brief Set flag indicating if node is in a list
293 
294  @internal */
295  void setValid(BWORD set) { m_valid=set;}
296  /** @brief Get flag indicating if node is in a list
297 
298  @internal */
299  BWORD valid(void) const { return m_valid; }
300 
301  /** @brief Mark node as invalid and determine an heir
302 
303  This happens when the node is removed
304  from its list. It may still have references.
305 
306  @internal */
307  void abandon(void)
308  {
309  const int references=releaseInternal();
310 #if FE_LIST_REF_DEBUG
311  feLog("%p Node::Abandon() %d\n",
312  this,references+1);
313 #endif
314  // if someone is still pointing at this node,
315  // leave a trail to a potentially valid node
316  if(references)
317  {
318  if(m_pNext)
319  m_pHeir=m_pNext;
320  else
321  m_pHeir=m_pPrevious;
322 
323  if(m_pHeir)
324  m_pHeir->incRef();
325 #if FE_LIST_REF_DEBUG
326  feLog("%p Node heir=%p\n",this,m_pHeir);
327 #endif
328 
329  setValid(false);
330  }
331  else
332  {
333  delete this;
334  }
335  }
336 
337  /** @brief Increment reference count
338 
339  @internal */
340  void incRef(void)
341  {
342 #if FE_LIST_REF_DEBUG
343  const int references=releaseInternal();
344  feLog("%p Node::IncRef() %d->%d\n",
345  this,references,references+1);
346 #endif
347  acquire();
348  }
349  /** @brief Decrement reference count
350 
351  @internal */
352  void decRef(void);
353 
354  protected:
355 
356  BWORD m_valid;
357 
358  NodeCore* m_pPrevious;
359  NodeCore* m_pNext;
360  NodeCore* m_pHeir;
361  };
362 
363  NodeCore* coreGetElement(I32 index) const;
364  NodeCore* coreInsert(BWORD before,Context& rContext,
365  NodeCore* existingNode);
366  BWORD coreRemoveNode(NodeCore* node);
367  BWORD coreMoveNode(BWORD before,Context& from,Context& to);
368 
369  NodeCore* m_pHead;
370  NodeCore* m_pTail;
371  I32 m_length;
372  BWORD m_autodestruct;
373 
374  protected:
375 virtual NodeCore* newNode(void) const =0;
376  void internalToHead(Context& rContext) const;
377  void internalPostIncrement(Context& rContext) const;
378  void internalDetachNode(NodeCore* node);
379  NodeCore* internalGetCurrent(Context& rContext) const
380  {
381 #if FE_LIST_CHECKPOINTER
382  rContext.checkCorePointer(this);
383 #endif
384  return rContext.current();
385  }
386 };
387 
388 /**************************************************************************//**
389  @brief Fully Bidirectional Doubly-Linked List
390 
391  @ingroup core
392 
393  Why would you use this list?
394  - Truly bidirectional: no need for reverse lists or reverse iterators
395  - Retainable iterators: designed to endure long term access
396  - Complete iterators: you don't have to go back to the list for any
397  subset of the functionality.
398  The iterators can do everything.
399  - Delete anything you want, whenever you want:
400  you can erase nodes that other contexts are looking at or even
401  a list itself with still outstanding contexts.
402  Cascading references will adapt on next usage as though the other
403  contexts were watching along with every step (but they aren't).
404 
405  What is a Context?
406  - A Context is basically the typeless state of an Iterator.
407  But really, the Iterator is a Context permanently associated with a
408  specific instance of a typed List.
409  - You can manipulate a List through Context's, Iterator's, or directly
410  through the List itself.
411  - Context's can be reused between multiple Lists of different types,
412  but Iterator's don't require you to keep track of which List
413  you're looking into.
414 
415  Since the List is fully bidirectional, there is a NULL entry at both
416  beginning and the end. The toHead and toTail methods move to the first
417  entry next to the NULL on either end (if a non-NULL entry exists).
418 
419  If SearchForContent() is to be used and type T has non-trivial data
420  complexity, the operator == should probably be defined for type T.
421  Some examples of data complexity are:
422  - pointer data members
423  - data members that do not contribute to 'equality'
424  - data whose equality can be more efficiently determined with something
425  other than the default bytewise comparison.
426  - fuzzy or soft data
427 
428  A new Context defaults to pointing at the NULL at the start of the list.
429  A new Iterator defaults to pointing at the head of the list.
430 
431  Example using a fe::List::Iterator:
432  @code
433  List<MyClass*> list;
434  List<MyClass*>::Iterator iterator(list);
435  MyClass* one=new MyClass();
436 
437  // add element
438  list.append(one);
439 
440  // read element
441  MyClass* two= *iterator;
442 
443  // do something to all elements
444  MyClass* node;
445  iterator.toHead();
446  while((node= *iterator++)!=NULL)
447  {
448  node->doSomething();
449  }
450  @endcode
451 
452  Example using a fe::ListCore::Context:
453  @code
454  List<MyClass*> list;
455  ListCore::Context context;
456  MyClass* one=new MyClass();
457 
458  // add element
459  list.append(one);
460 
461  // read element
462  MyClass* two=list.current(context);
463 
464  // do something to all elements
465  MyClass* node;
466  list.toHead(context);
467  while( (node=list.postIncrement(context)) != NULL)
468  {
469  node->doSomething();
470  }
471  @endcode
472 
473  No Context's or Iterator's will lose place if elements are removed,
474  even if removed with a different Context or Iterator.
475  Reference counting prevents invalid pointers and heir chains
476  follow destruction chains to find valid nodes.
477 
478  Note that much of the functionality of this class is implemented in the
479  non-template class ListCore. This is done to reduce template
480  instantiation size.
481 
482  By using setAutoDestruct(true), all elements remaining
483  on the list are deleted when the list is destructed.
484 
485  WARNING: if pointer-to elements were not created with new(),
486  failures during auto-delete will probably occur. Note that
487  setAutoDestruct(true) is especially precarious when elements may be in
488  more than one list.
489  In that case, it is very possible for elements to be deleted
490  that are still members of other lists.
491 
492  NOTE: Modern mechanisms are in place that attempt to do the right delete
493  operation for a variety of types. See fe::deleteByType<> for details.
494 *//***************************************************************************/
495 template <typename T>
496 class FE_DL_EXPORT List: public ListCore
497 {
498  private:
499 
500  class FE_DL_EXPORT Node: public NodeCore
501  {
502  public:
503  Node(void)
504  {
505  m_entry=defaultByType<T>(T());
506 #if FE_COUNTED_TRACK
507  setName(FE_TYPESTRING(T));
508  trackReference(*(void**)&m_entry,this,verboseName());
509 #endif
510  }
511  virtual ~Node(void)
512  {
513 #if FE_COUNTED_TRACK
514  untrackReference(*(void**)&m_entry,this);
515 #endif
516  }
517 
518  /** @brief Set the payload
519 
520  @internal */
521  void setEntry(T& set)
522  {
523 #if FE_COUNTED_TRACK
524  untrackReference(*(void**)&m_entry,this);
525  trackReference(*(void**)&set,this,verboseName());
526 #endif
527  m_entry=set;
528  }
529  /** @brief Get the payload
530 
531  @internal */
532  T entry(void) const { return m_entry; }
533  /** @brief Get the location of the payload
534 
535  @internal */
536  T* storage(void) { return &m_entry; }
537 
538 #if FE_COUNTED_STORE_TRACKER
539 const String verboseName(void) const
540  { return "List::Node "+name(); }
541 #endif
542  private:
543 
544  T m_entry;
545  };
546 
547 virtual NodeCore* newNode(void) const
548  {
549  NodeCore* pNode=new Node();
550 #if FE_COUNTED_TRACK
551  pNode->trackReference(
552  const_cast<void*>((const void*)this),
553  "List::newNode");
554 #endif
555  return pNode;
556  }
557 
558  public:
559  List(void)
560  {
561 #if FE_COUNTED_TRACK
562  //* Generally, there is no need to register a list since it
563  //* will usually be member of an object already registered.
564 // Counted::registerRegion(this,
565 // sizeof(List),
566 // String("List<")+FE_TYPESTRING(T)+">");
567 #endif
568  }
569 virtual ~List(void)
570  {
571 #if FE_COUNTED_TRACK
572 // Counted::deregisterRegion(this);
573 #endif
574  if(m_autodestruct)
575  deleteAll();
576  else
577  removeAll();
578  }
579 
580  /*** STANDARD RULES
581  prefix
582  const MyIncrementableClass& operator++();
583  const MyIncrementableClass& operator--();
584  postfix
585  MyIncrementableClass operator++(int);
586  MyIncrementableClass operator--(int);
587 
588  a and b values of type X
589  u, m identifiers
590  r value of type X&
591  t value of type T
592 
593  X u u might have a singular value
594  X() X() might be singular
595  X(a) copy constructor, a == X(a)
596  X u(a) copy constructor, u == a
597  X u = a assignment, u == a
598  a == b,
599  a != b return value convertible to bool
600  *a = t result is not used
601  *a return value convertible to T&
602  a->m equivalent to (*a).m
603  ++r returns X&
604  r++ return value convertable to const X&
605  *r++ returns T&
606  --r returns X&
607  r-- return value convertable to const X&
608  *r-- returns T&
609  */
610  /*********************************************************************//**
611  @brief Type-specific Iterator for an fe::List <>
612 
613  @ingroup core
614 
615  This is a templated wrapper for the type-non-specific
616  fe::ListCore::Context.
617  *//**********************************************************************/
618  class FE_DL_EXPORT Iterator: protected Context
619  {
620  public:
621  Iterator(List<T>& rList): m_pList(&rList) { toHead(); }
622  Iterator(const Iterator& rOperand): Context(rOperand),
623  m_pList(rOperand.m_pList) {}
624  Iterator& operator=(Iterator& rOperand)
625  { Context::operator=(rOperand);
626  m_pList=rOperand.m_pList;
627  return *this; }
628  /// @brief Compare by content (not by pointer)
629  BWORD operator==(const Iterator& rOperand) const
630  { return operator*()==rOperand.operator*(); }
631  /// @brief Inverse compare by content (not by pointer)
632  BWORD operator!=(const Iterator& rOperand) const
633  { return operator*()!=rOperand.operator*(); }
634  /// @brief Use the entry pointed at
635  T operator->(void)
636  { return m_pList->current(*this); }
637  /// @brief Return the entry pointed at
638  T operator*(void)
639  { return m_pList->current(*this); }
640  /// @brief Pre Increment
642  { m_pList->preIncrement(*this);
643  return *this; }
644  /// @brief Pre Decrement
646  { m_pList->preDecrement(*this);
647  return *this; }
648  /// @brief Post Increment
650  { Iterator iterator=*this;
651  m_pList->postIncrement(*this);
652  return iterator; }
653  /// @brief Post Decrement
655  { Iterator iterator=*this;
656  m_pList->postDecrement(*this);
657  return iterator; }
658 
659  /// @brief Point the iterator at the first entry.
660  T toHead(void) { return m_pList->toHead(*this); }
661  /// @brief Point the iterator at the last entry.
662  T toTail(void) { return m_pList->toTail(*this); }
663  /// @brief Returns TRUE if pointing to the head NULL
664  BWORD isAtHeadNull(void)
665  { return m_pList->isAtHeadNull(*this); }
666  /// @brief Returns TRUE if pointing to the tail NULL
667  BWORD isAtTailNull(void)
668  { return m_pList->isAtTailNull(*this); }
669  /// @brief Add a new entry directly before this iterator
670  T* insertBefore(T pEntry)
671  { return m_pList->insertBefore(*this,pEntry); }
672  /// @brief Add a new entry directly after this iterator
673  T* insertAfter(T pEntry)
674  { return m_pList->insertAfter(*this,pEntry); }
675  /** @brief Move the entry at this iterator to the
676  position before the argument */
677  BWORD moveCurrentBefore(const Iterator& rOperand)
678  { return m_pList->moveNodeBefore(*this,rOperand); }
679  /** @brief Move the entry at this iterator to the
680  position after the argument */
681  BWORD moveCurrentAfter(const Iterator& rOperand)
682  { return m_pList->moveNodeAfter(*this,rOperand); }
683  /// @brief Remove this entry from the list
684  BWORD remove(void)
685  { return m_pList->removeCurrent(*this); }
686  /** @brief Replace this entry with a new object
687 
688  The previous entry is returned. */
689  T replace(T pSubstitute)
690  { return m_pList->replaceCurrent(*this,pSubstitute); }
691  /// @brief Remove this entry from the list and delete it
692  BWORD deleteEntry(void)
693  { return m_pList->deleteCurrent(*this); }
694  /** @brief Point the iterator at the first entry with
695  a given pointer */
696  T searchForElement(const T pEntry)
697  { return m_pList->searchForElement(*this,pEntry); }
698  /** @brief Point the iterator at the first entry
699  equivalent to the given pointed-to value */
700  T searchForContent(const T pValue)
701  { return m_pList->searchForContent(*this,pValue); }
702  List* list(void) { return m_pList; }
703  private:
704  List* m_pList;
705  };
706 
707  /** Insert a new element before the context.
708  Returns the location of the new element or NULL if the
709  internal node allocation failed. */
710  T* insertBefore(Context& rContext,T pEntry)
711  { Node* pNode=(Node *)coreInsert(true,rContext,NULL);
712  pNode->setEntry(pEntry); return pNode->storage(); }
713  /** Insert a new element after the context.
714  Returns the location of the new element or NULL if the
715  internal node allocation failed. */
716  T* insertAfter(Context& rContext,T pEntry)
717  { Node* pNode=(Node *)coreInsert(false,rContext,NULL);
718  pNode->setEntry(pEntry); return pNode->storage(); }
719  /** Insert a new element at the beginning of the list.
720  Returns the location of the new element or NULL if the
721  internal node allocation failed. */
722  T* prepend(T pEntry)
723  {
724  Context rContext;
725  rContext.setCurrent(m_pHead);
726 #if FE_LIST_CHECKPOINTER
727  rContext.setCorePointer(this);
728 #endif
729  Node* pNode=(Node*)coreInsert(true,rContext,NULL);
730  if(!pNode)
731  return (T*)NULL;
732  pNode->setEntry(pEntry);
733  return pNode->storage();
734  }
735  /** Insert a new element at the end of the list.
736  Returns the location of the new element or NULL if the
737  internal node allocation failed. */
738  T* append(T pEntry)
739  {
740  Context rContext;
741  rContext.setCurrent(m_pTail);
742 #if FE_LIST_CHECKPOINTER
743  rContext.setCorePointer(this);
744 #endif
745  Node* pNode=(Node*)coreInsert(false,rContext,NULL);
746  if(!pNode)
747  return (T*)NULL;
748  pNode->setEntry(pEntry);
749  return pNode->storage();
750  }
751 
752  /// Append a copy of an entire list of identical type
753  void append(List<T>& list)
754  {
755  T pT;
756  Context rContext;
757  list.toHead(rContext);
758  while((pT=list.postIncrement(rContext))!=NULL)
759  append(pT);
760  }
761 
762  /** This is the straightforward remove implementation. This
763  Remove() will look for the entry in the list by simply
764  checking each member entry in order. This can be very slow
765  in some cases. See remove(T entry, Context& hint)
766  for a faster alternative. */
767  BWORD remove(T pEntry)
768  {
769  Context context;
770  Node* pNode;
771  T pEntry2;
772 
773  internalToHead(context);
774  while((pNode=(Node*)internalGetCurrent(context)) != NULL
775  && (pEntry2=pNode->entry()) !=
776  defaultByType<T>(T()))
777  {
778  if(pEntry2==pEntry)
779  return coreRemoveNode(context.current());
780  else
781  internalPostIncrement(context);
782  }
783 
784  return false;
785  }
786 
787  /** This remove() method uses a hint Context to check
788  current, next, and prev nodes (in that order) before
789  reverting to a head to tail scan. In most cases this
790  significantly reduces execution time. */
791  BWORD remove(T pEntry, Context& hint)
792  {
793 #if FE_LIST_CHECKPOINTER
794  hint.checkCorePointer(this);
795 #endif
796 
797  NodeCore* pNodeCore;
798  if((pNodeCore=hint.current()))
799  {
800  if(((Node*)pNodeCore)->entry()==pEntry)
801  return coreRemoveNode(pNodeCore);
802  else if(pNodeCore->next() &&
803  ((Node*)pNodeCore->next())->entry()==pEntry)
804  return coreRemoveNode(pNodeCore->next());
805  else if(pNodeCore->previous() &&
806  ((Node*)pNodeCore->previous())->entry()==pEntry)
807  return coreRemoveNode(pNodeCore->previous());
808  }
809 
810  return remove(pEntry);
811  }
812 
813 
814  /// Remove the current node on the given context.
815  BWORD removeCurrent(Context& rContext)
816  {
817  Node* pNode=(Node*)rContext.current();
818 
819  if(pNode)
820  {
821  T ptr=pNode->entry();
822  BWORD success=coreRemoveNode(pNode);
823  FEASSERT(success);
824  return success;
825  }
826 
827  return false;
828  }
829 
830  /// Replace the current pointer on the given context.
831  T replaceCurrent(Context& rContext,T pSubstitute)
832  {
833  Node* pNode=(Node*)rContext.current();
834  if(pNode)
835  {
836  T pCurrent=pNode->entry();
837  pNode->setEntry(pSubstitute);
838  return pCurrent;
839  }
840  return defaultByType<T>(T());
841  }
842 /*
843  template<bool B>
844  void deleteIfTrue(List<T,B>* pList,T t) {}
845  void deleteIfTrue(List<T,true>* pList,T pT) { delete pT; }
846 */
847  /// Remove all nodes and delete their pointers.
848  void deleteAll(void)
849  {
850  while( m_pHead != NULL)
851  {
852  T pEntry=((Node*)m_pHead)->entry();
853 #if FE_CODEGEN<=FE_DEBUG
854  BWORD result=
855 #endif
856  coreRemoveNode(m_pHead);
857  FEASSERT(result);
858 // deleteIfTrue(this,pEntry);
859  deleteByType(pEntry);
860  }
861  }
862 
863  /// Remove and delete the current node on the given context.
864  BWORD deleteCurrent(Context& rContext)
865  {
866  Node* node=rContext.current();
867 
868  if(node)
869  {
870  T pEntry=node->entry();
871  BWORD success=coreRemoveNode(node);
872  FEASSERT(success);
873 // deleteIfTrue(this,pEntry);
874  deleteByType(pEntry);
875  return success;
876  }
877 
878  return false;
879  }
880 
881  /** Remove and delete the first entry that matches the argument.
882  If a match is not found, the argument is still deleted. */
883  BWORD deleteElement(T pEntry)
884  {
885  BWORD result=remove(pEntry);
886  deleteByType(pEntry);
887 
888  return result;
889  }
890 
891  /** Rewind the context to the beginning of the list and return
892  the first element. */
893  T toHead(Context& rContext) const
894  {
895  rContext.setCurrent(m_pHead);
896 #if FE_LIST_CHECKPOINTER
897  rContext.setCorePointer(this);
898 #endif
899  return current(rContext);
900  }
901 
902  /** Move the context to the end of the list and return
903  the last element. */
904  T toTail(Context& rContext) const
905  {
906  rContext.setCurrent(m_pTail);
907 #if FE_LIST_CHECKPOINTER
908  rContext.setCorePointer(this);
909 #endif
910  return current(rContext);
911  }
912 
913  /** @brief Return the location of the first element matching
914  the given pointer or smart pointer
915 
916  Only the pointers are compared.
917  Matches are not made by the content they point to. */
918  T* searchForElement(Context& rContext,const T pEntry) const
919  {
920  Node* pNode;
921  T pEntry2;
922 
923  internalToHead(rContext);
924  while((pNode=(Node*)internalGetCurrent(rContext)) != NULL
925  && (pEntry2=pNode->entry()) !=
926  defaultByType<T>(T()))
927  {
928  if(pEntry2==pEntry)
929  return ((Node*)rContext.current())->storage();
930  else
931  internalPostIncrement(rContext);
932  }
933 
934  return NULL;
935  }
936 
937  /** @brief Return the location of the first pointed-to
938  element with the same value
939 
940  The elements are compared to the contents of *value.
941  The value argument is passed by pointer instead of
942  value or reference to prevent a requirement the
943  T be an instantiable class. */
944  T* searchForContent(Context& rContext,const T pValue) const
945  {
946  if(!pValue)
947  return NULL;
948 
949  toHead(rContext);
950 
951  T pEntry2;
952  while( (pEntry2=current(rContext)) != NULL)
953  {
954  if(*pEntry2==*pValue)
955  return ((Node*)rContext.current())->storage();
956  else
957  postIncrement(rContext);
958  }
959 
960  return NULL;
961  }
962 
963  /// Return the current element before incrementing to the next
964  T postIncrement(Context& rContext) const
965  {
966  Node* pNode,*pNext;
967 
968  if((pNode=(Node*)rContext.current())!=NULL)
969  {
970  rContext.setCurrent(pNext=(Node*)pNode->next());
971  if(!pNext)
972  rContext.setAtTailNull(true);
973  return (pNode->entry());
974  }
975  else if(!isAtTailNull(rContext))
976  rContext.setCurrent(m_pHead);
977 
978  return defaultByType<T>(T());
979  }
980 
981  /** Return the current element before decrementing to the
982  previous */
983  T postDecrement(Context& rContext) const
984  {
985  Node* pNode=(Node*)rContext.current();
986 
987  if(pNode)
988  {
989  rContext.setCurrent(pNode->previous());
990  rContext.setAtTailNull(false);
991  return pNode->entry();
992  }
993  else if(isAtTailNull(rContext))
994  rContext.setCurrent(m_pTail);
995 
996  rContext.setAtTailNull(false);
997  return defaultByType<T>(T());
998  }
999 
1000  /// Return the first element of the list (no context required)
1001  T head(void) const
1002  { return m_pHead?
1003  ((Node*)m_pHead)->entry(): defaultByType<T>(T()); }
1004 
1005  /// Return the last element of the list (no context required)
1006  T tail(void) const
1007  { return m_pTail?
1008  ((Node*)m_pTail)->entry(): defaultByType<T>(T()); }
1009 
1010  /// Return the current element of the context.
1011  T current(Context& rContext) const
1012  {
1013 #if FE_LIST_CHECKPOINTER
1014  rContext.checkCorePointer(this);
1015 #endif
1016  Node* pNode=(Node*)rContext.current();
1017  return pNode? pNode->entry(): defaultByType<T>(T());
1018  }
1019 
1020  //* trivial convenience functions
1021 
1022  /// Increment the context and return the next element
1023  T preIncrement(Context& rContext) const
1024  { postIncrement(rContext);
1025  return current(rContext); }
1026 
1027  /// Decrement the context and return the previous element
1028  T preDecrement(Context& rContext) const
1029  { postDecrement(rContext);
1030  return current(rContext); }
1031 
1032  /** Get an element by index. This is not an array, so this
1033  can be an inefficient operation */
1034  T operator[](I32 index) const
1035  { Node* pNode=(Node*)coreGetElement(index);
1036  return pNode? pNode->entry(): defaultByType<T>(T()); }
1037 };
1038 
1039 } // namespace
1040 
1041 #endif // __core_List_h__
BWORD removeCurrent(Context &rContext)
Remove the current node on the given context.
Definition: List.h:815
Iterator & operator--(void)
Pre Decrement.
Definition: List.h:645
T toHead(Context &rContext) const
Rewind the context to the beginning of the list and return the first element.
Definition: List.h:893
BWORD autoDestruct(void)
Get the AutoDestruct flag.
Definition: List.h:55
Fully Bidirectional Doubly-Linked List.
Definition: List.h:496
T searchForElement(const T pEntry)
Point the iterator at the first entry with a given pointer.
Definition: List.h:696
BWORD moveNodeAfter(Context &from, Context &to)
Moves the node at the first context after the node at the second context.
Definition: List.h:69
void init(void)
Reinitialize state.
Definition: List.h:136
T * prepend(T pEntry)
Insert a new element at the beginning of the list.
Definition: List.h:722
Context(const Context &operand)
Copy constructor.
Definition: List.h:107
T * append(T pEntry)
Insert a new element at the end of the list.
Definition: List.h:738
T * insertAfter(Context &rContext, T pEntry)
Insert a new element after the context.
Definition: List.h:716
BWORD moveCurrentAfter(const Iterator &rOperand)
Move the entry at this iterator to the position after the argument.
Definition: List.h:681
Context & operator=(Context &operand)
Copy state from another context.
Definition: List.h:125
Heap-based support for classes participating in fe::ptr <>
Definition: Counted.h:35
kernel
Definition: namespace.dox:3
BWORD deleteElement(T pEntry)
Remove and delete the first entry that matches the argument.
Definition: List.h:883
T operator[](I32 index) const
Get an element by index.
Definition: List.h:1034
T operator->(void)
Use the entry pointed at.
Definition: List.h:635
BWORD checkValid(const T &a_value)
Definition: Vector.h:79
T * insertAfter(T pEntry)
Add a new entry directly after this iterator.
Definition: List.h:673
T toTail(Context &rContext) const
Move the context to the end of the list and return the last element.
Definition: List.h:904
void deleteAll(void)
Remove all nodes and delete their pointers.
Definition: List.h:848
void append(List< T > &list)
Append a copy of an entire list of identical type.
Definition: List.h:753
BWORD operator==(const Iterator &rOperand) const
Compare by content (not by pointer)
Definition: List.h:629
NodeCore * current(void)
Get current position on list.
Definition: List.h:148
BWORD moveCurrentBefore(const Iterator &rOperand)
Move the entry at this iterator to the position before the argument.
Definition: List.h:677
T head(void) const
Return the first element of the list (no context required)
Definition: List.h:1001
T searchForContent(const T pValue)
Point the iterator at the first entry equivalent to the given pointed-to value.
Definition: List.h:700
T toHead(void)
Point the iterator at the first entry.
Definition: List.h:660
void setAtTailNull(BWORD set)
Set whether context is after the tail.
Definition: List.h:177
T toTail(void)
Point the iterator at the last entry.
Definition: List.h:662
T tail(void) const
Return the last element of the list (no context required)
Definition: List.h:1006
BWORD isAtTailNull(Context &rContext) const
Returns TRUE if the context is after the last element.
Definition: List.h:77
A view state into an fe::List <>
Definition: List.h:101
T operator*(void)
Return the entry pointed at.
Definition: List.h:638
BWORD deleteCurrent(Context &rContext)
Remove and delete the current node on the given context.
Definition: List.h:864
Iterator & operator++(void)
Pre Increment.
Definition: List.h:641
T * insertBefore(Context &rContext, T pEntry)
Insert a new element before the context.
Definition: List.h:710
void setAutoDestruct(BWORD set)
Set the AutoDestruct flag.
Definition: List.h:52
Automatically reference-counted string container.
Definition: String.h:128
Iterator operator--(int)
Post Decrement.
Definition: List.h:654
T replaceCurrent(Context &rContext, T pSubstitute)
Replace the current pointer on the given context.
Definition: List.h:831
T replace(T pSubstitute)
Replace this entry with a new object.
Definition: List.h:689
Type-nonspecific Base Functionality of fe::List <>
Definition: List.h:40
Type-specific Iterator for an fe::List <>
Definition: List.h:618
T postDecrement(Context &rContext) const
Return the current element before decrementing to the previous.
Definition: List.h:983
T postIncrement(Context &rContext) const
Return the current element before incrementing to the next.
Definition: List.h:964
BWORD isAtTailNull(void) const
Get whether context is after the tail.
Definition: List.h:182
T current(Context &rContext) const
Return the current element of the context.
Definition: List.h:1011
T preIncrement(Context &rContext) const
Increment the context and return the next element.
Definition: List.h:1023
BWORD isAtTailNull(void)
Returns TRUE if pointing to the tail NULL.
Definition: List.h:667
T * searchForContent(Context &rContext, const T pValue) const
Return the location of the first pointed-to element with the same value.
Definition: List.h:944
BWORD operator!=(const Iterator &rOperand) const
Inverse compare by content (not by pointer)
Definition: List.h:632
Iterator operator++(int)
Post Increment.
Definition: List.h:649
void setCurrent(NodeCore *set)
Set current position on list.
Definition: List.h:157
BWORD moveNodeBefore(Context &from, Context &to)
Moves the node at the first context before the node at the second context.
Definition: List.h:65
T * insertBefore(T pEntry)
Add a new entry directly before this iterator.
Definition: List.h:670
U32 size(void) const
Returns the number of elements on the list.
Definition: List.h:58
BWORD deleteEntry(void)
Remove this entry from the list and delete it.
Definition: List.h:692
T preDecrement(Context &rContext) const
Decrement the context and return the previous element.
Definition: List.h:1028
BWORD isAtHeadNull(void)
Returns TRUE if pointing to the head NULL.
Definition: List.h:664
T * searchForElement(Context &rContext, const T pEntry) const
Return the location of the first element matching the given pointer or smart pointer.
Definition: List.h:918
BWORD isAtHeadNull(Context &rContext) const
Returns TRUE if the context is before the first element.
Definition: List.h:73