Modernized GAlib  3.0.0 current
GAList.hpp
1 /* ----------------------------------------------------------------------------
2  mbwall 25feb95
3  Copyright 1995 Massachusetts Institute of Technology
4 ---------------------------------------------------------------------------- */
5 
6 #pragma once
7 
8 #include <GAListBASE.h>
9 #include <gaerror.h>
10 
11 /* ----------------------------------------------------------------------------
12  GAList
13 ---------------------------------------------------------------------------- */
14 template <class T> class GAListIter;
15 
16 extern GANodeBASE *_GAListTraverse(unsigned int index, unsigned int &cur,
17  GANodeBASE *node);
18 
29 template <class T> GANode<T> *_GAListCopy(GANode<T> *node, GANode<T> *head)
30 {
31  if (!node)
32  return nullptr;
33  auto *newnode = new GANode<T>(node->contents);
34  GANode<T> *lasttmp = newnode, *newtmp = nullptr;
35  GANode<T> *tmp = DYN_CAST(GANode<T> *, node->next);
36  while (tmp && tmp != head)
37  {
38  newtmp = new GANode<T>(tmp->contents);
39  newtmp->prev = lasttmp;
40  lasttmp->next = newtmp;
41 
42  lasttmp = newtmp;
43  tmp = DYN_CAST(GANode<T> *, tmp->next);
44  }
45  if (newtmp)
46  {
47  newtmp->next = newnode;
48  newnode->prev = newtmp;
49  }
50  else
51  {
52  newnode->next = newnode;
53  newnode->prev = newnode;
54  }
55  return newnode;
56 }
57 
87 template <class T> class GAList : public GAListBASE
88 {
89  public:
90  GAList() : GAListBASE() { iter(*this); }
91  explicit GAList(const T &t) : GAListBASE(new GANode<T>(t)), iter(*this) {}
92  GAList(const GAList<T> &orig)
93  {
94  iter(*this);
95  copy(orig);
96  }
97  GAList<T> &operator=(const GAList<T> &orig)
98  {
99  if (&orig != this)
100  copy(orig);
101  return *this;
102  }
103 
104  // The destructor just goes through the list and deletes every node.
105  virtual ~GAList()
106  {
107  while (hd)
108  delete GAListBASE::remove(DYN_CAST(GANode<T> *, hd));
109  iter.node = nullptr;
110  }
111 
120  GAList<T> *clone(unsigned int i = 0) const
121  {
122  auto *t = new GAList<T>;
123  GANode<T> *node;
124  unsigned int w = 0;
125  if (i == 0)
126  node = DYN_CAST(GANode<T> *, hd);
127  else
128  node = DYN_CAST(GANode<T> *, _GAListTraverse(i, w, hd));
129  if (!node)
130  return t;
131 
132  GANode<T> *newnode = _GAListCopy(node, DYN_CAST(GANode<T> *, hd));
133 
134  t->insert(newnode, nullptr, GAListBASE::HEAD);
135 
136  // need to set iterator to right spot in the clone!! for now its at the
137  // head
138 
139  return t;
140  }
141 
142  // methods that modify the state of the list
143 
144  // Yes, this is really ugly. We do a complete destruction of the existing
145  // list
146  // then we copy the new one. No caching, no nothing. Oh well. We set the
147  // iterator to the head node - it should be set to the corresponding node,
148  // but I won't do that right now. THIS IS A BUG!
153  void copy(const GAList<T> &orig)
154  {
155  while (hd)
156  delete GAListBASE::remove(DYN_CAST(GANode<T> *, hd));
157  hd = _GAListCopy(DYN_CAST(GANode<T> *, orig.hd),
158  DYN_CAST(GANode<T> *, orig.hd));
159  iter.node = hd;
160  sz = orig.sz;
161  csz = orig.csz;
162  }
163 
164  // Destroy the specified node. This uses the current node as the one to
165  // destroy, so be sure to use the iteration methods to move to the node you
166  // want to destroy. Once the node is gone, we set the current node to the
167  // prev node of the one that was destroyed. If the node that was nuked was
168  // the head node then we set the current node to the new head.
174  int destroy()
175  {
176  GANodeBASE *node = iter.node;
177  if (!node)
178  return GAListBASE::NO_ERR;
179  if (node->prev && node->prev != node)
180  if (hd == node)
181  iter.node = node->next;
182  else
183  iter.node = node->prev;
184  else
185  iter.node = nullptr;
186  delete GAListBASE::remove(node);
187  return GAListBASE::NO_ERR;
188  }
189 
199  int swap(unsigned int a, unsigned int b)
200  {
201  if (a == b || a > (unsigned int)size() || b > (unsigned int)size())
202  return GAListBASE::NO_ERR;
203  GANodeBASE *tmp = hd, *anode = nullptr, *bnode = nullptr;
204  unsigned int cur = 0;
205  while (tmp && tmp->next != hd)
206  {
207  if (a == cur)
208  anode = tmp;
209  if (b == cur)
210  bnode = tmp;
211  tmp = tmp->next;
212  cur++;
213  }
214  if (a == cur)
215  anode = tmp;
216  if (b == cur)
217  bnode = tmp;
218  return GAListBASE::swapnode(anode, bnode);
219  }
220 
232  T *remove()
233  {
234  GANode<T> *node = DYN_CAST(GANode<T> *, iter.node);
235  if (!node)
236  return nullptr;
237 
238  if (node->prev != node)
239  iter.node = node->prev;
240  else
241  iter.node = nullptr;
242  node = DYN_CAST(GANode<T> *, GAListBASE::remove(node));
243  T *contents = new T(node->contents);
244  delete node;
245  return contents;
246  }
247 
259  int insert(GAList<T> *t, GAListBASE::Location where = GAListBASE::AFTER)
260  {
261  if (this == t)
262  {
263  GAErr(GA_LOC, "GAList", "insert", GAError::CannotInsertIntoSelf);
264  return GAListBASE::ERR;
265  }
266  if (GAListBASE::insert(t->hd, iter.node, where) == GAListBASE::ERR)
267  {
268  return GAListBASE::ERR;
269  }
270  iter.node = (t->hd ? t->hd : iter.node);
271  t->hd = nullptr;
272  t->iter.node = nullptr;
273  return GAListBASE::NO_ERR;
274  }
275 
284  int insert(const T &t, GAListBASE::Location where = GAListBASE::AFTER)
285  {
286  auto *c = new GANode<T>(t);
287  if (GAListBASE::insert(c, iter.node, where) == GAListBASE::ERR)
288  {
289  delete c;
290  return GAListBASE::ERR;
291  }
292  iter.node = c;
293  return GAListBASE::NO_ERR;
294  }
295 
296  // typesafes on iteration methods. These call the built-in iterator then
297  // return the contents of the now-current node. They do not affect the
298  // state of the list.
299  T *head() { return iter.head(); }
300  T *tail() { return iter.tail(); }
301  T *current() { return iter.current(); }
302  T *next() { return iter.next(); }
303  T *prev() { return iter.prev(); }
304  T *warp(unsigned int i) { return iter.warp(i); }
305  T *warp(const GAListIter<T> &i)
306  {
307  return ((i.list == this) ? iter.warp(i) : nullptr);
308  }
309  T *operator[](unsigned int i) { return iter.warp(i); }
310 
311  protected:
312  int insert(GANode<T> *n, GANode<T> *idx,
313  GAListBASE::Location where = GAListBASE::AFTER)
314  {
315  if (GAListBASE::insert(n, idx, where) == GAListBASE::ERR)
316  return GAListBASE::ERR;
317  iter.node = n;
318  return GAListBASE::NO_ERR;
319  }
320  GAListIter<T> iter; // the embedded iterator
321  friend class GAListIter<T>;
322 };
323 
324 /* ----------------------------------------------------------------------------
325  GAListIter
326 -------------------------------------------------------------------------------
327  This is a type-safe derivation of the base ListIter object. I copied the
328 methods from the base class (I know, a no-no) rather than doing calls to the
329 base class methods.
330  We depend on the template-ized GAList, thus the declaration.
331  Behaviour for the iterator methods is defined as follows. If the current
332 node is null, attempts to access a derived position from the current position
333 will return NULL. The only way to reset the current node is to call the head()
334 locater (you always have to start at the list head to navigate the list). If
335 the current node is non-null and the derived node is null, the current node is
336 NOT changed, but NULL is returned. You can also warp to a new position if you
337 have another iterator or a list with an embedded iterator.
338  When we create a new list iterator, it defaults to the same node as the one
339 used to create it. If it is created with a list as its argument, it defaults
340 to the list's iterator's current position.
341 ---------------------------------------------------------------------------- */
342 template <class T> class GAList;
343 
344 template <class T> class GAListIter : public GAListIterBASE
345 {
346  public:
347  GAListIter() : GAListIterBASE() {}
348  explicit GAListIter(const GAList<T> &t) : GAListIterBASE(t)
349  {
350  node = t.iter.node;
351  }
352  GAListIter(const GAListIter<T> &i) : GAListIterBASE(i) {}
353  T *current() { return (node ? &((GANode<T> *)node)->contents : nullptr); }
354  T *head()
355  {
356  return (((node = GAListIterBASE::head()) != nullptr) ? &((GANode<T> *)GAListIterBASE::head())->contents : nullptr);
357  }
358  T *tail()
359  {
360  return (((node = GAListIterBASE::tail()) != nullptr) ? &((GANode<T> *)GAListIterBASE::tail())->contents : nullptr);
361  }
362  T *next()
363  {
364  return ((node && node->next) ? &((GANode<T> *)(node = node->next))->contents : nullptr);
365  }
366  T *prev()
367  {
368  return ((node && node->prev) ? &((GANode<T> *)(node = node->prev))->contents : nullptr);
369  }
370  T *warp(const GAList<T> &t)
371  {
372  list = &t;
373  node = t.iter.node;
374  return (t.iter.node ? &((GANode<T> *)(node = t.iter.node))->contents : nullptr);
375  }
376  T *warp(const GAListIter<T> &i)
377  {
378  list = i.list;
379  node = i.node;
380  return (i.node ? &((GANode<T> *)(node = i.node))->contents : nullptr);
381  }
382  T *warp(unsigned int i)
383  {
384  GANodeBASE *n = GAListIterBASE::warp(i);
385  return (n != nullptr ? &((GANode<T> *)(node = n))->contents : nullptr);
386  }
387 
388  private:
389  friend class GAList<T>; // do I need to do this?
390 };
Definition: GAListBASE.h:78
int insert(GANodeBASE *n, GANodeBASE *idx, Location where=AFTER)
Definition: GAListBASE.h:161
Definition: GAList.hpp:345
Container for nodes that have a list structure.
Definition: GAList.hpp:88
int destroy()
Remove the current node from the list and free the memory it was using.
Definition: GAList.hpp:174
int insert(GAList< T > *t, GAListBASE::Location where=GAListBASE::AFTER)
Inserts the contents of list in to the current list and removes it from the original list.
Definition: GAList.hpp:259
T * remove()
Remove the current node from the list.
Definition: GAList.hpp:232
int insert(const T &t, GAListBASE::Location where=GAListBASE::AFTER)
Insert the object into the list at the specified place relative to the current location of the embedd...
Definition: GAList.hpp:284
GAList< T > * clone(unsigned int i=0) const
Make a copy of a list and return the pointer to the new list.
Definition: GAList.hpp:120
int swap(unsigned int a, unsigned int b)
Swap two nodes in the list.
Definition: GAList.hpp:199
void copy(const GAList< T > &orig)
Make a complete copy of the list and return a pointer to the new list.
Definition: GAList.hpp:153
This is the basic node object.
Definition: GANode.h:18
Definition: GANode.h:79