ListClass.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.oorexx.org/license.html */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX Kernel */
40 /* */
41 /* Primitive List Class */
42 /* */
43 /******************************************************************************/
44 #include "RexxCore.h"
45 #include "IntegerClass.hpp"
46 #include "ListClass.hpp"
47 #include "ArrayClass.hpp"
48 #include "SupplierClass.hpp"
49 #include "ActivityManager.hpp"
50 #include "ProtectedObject.hpp"
51 #include "WeakReferenceClass.hpp"
52 
53 // singleton class instance
55 
56 
57 /**
58  * Create initial class object at bootstrap time.
59  */
61 {
62  CLASS_CREATE(List, "List", RexxClass);
63 }
64 
65 
66 void RexxList::init(void)
67 /******************************************************************************/
68 /* Function: Initial set up of a list object instance */
69 /******************************************************************************/
70 {
71  this->first = LIST_END; /* no first element */
72  this->last = LIST_END; /* no last element */
73  this->size = INITIAL_LIST_SIZE; /* set the buffer upper bound */
74  /* chain up the free elements */
76 }
77 
79 /******************************************************************************/
80 /* Function: create a copy of a list and the associated table */
81 /******************************************************************************/
82 {
83  /* make a copy of ourself (also */
84  /* copies the object variables) */
85  RexxList *newlist = (RexxList *)this->RexxObject::copy();
86  ProtectedObject p(newlist);
87  /* make a copy of the table */
88  OrefSet(newlist, newlist->table, (RexxListTable *)this->table->copy());
89  return(RexxObject *)newlist; /* return the new list */
90 }
91 
93  size_t first_entry, /* first entry location */
94  size_t entry_count ) /* entries to partition */
95 /******************************************************************************/
96 /* Function: Partition a buffer up into a chain of free elements and set */
97 /* this up as the free element chain */
98 /******************************************************************************/
99 {
100  this->free = first_entry; /* set the new free chain head */
101  size_t i = first_entry; /* get a loop counter */
102  LISTENTRY *element = ENTRY_POINTER(i); /* point to the first element */
103  while (entry_count-- > 0)
104  {
105  /* zero the element value */
106  OrefSet(this->table, element->value, OREF_NULL);
107  element->next = ++i; /* set the next element pointer */
108  element->previous = NOT_ACTIVE; /* mark as a free element */
109  element++; /* step to the next element */
110  }
111  element--; /* step back to last element */
112  element->next = LIST_END; /* set the terminator */
113 }
114 
115 size_t RexxList::getFree(void)
116 /******************************************************************************/
117 /* Function: Check that we have at least one element on the free chain, and */
118 /* if not, expand our buffer size to add some space. */
119 /******************************************************************************/
120 {
121  if (this->free == LIST_END)
122  { /* no free elements? */
123  /* allocate a larger table */
124  RexxListTable *newLTable = new (this->size * 2) RexxListTable;
125  /* copy over to the new buffer */
126  memcpy(newLTable->getData(), this->table->getData(), TABLE_SIZE(this->size));
127  /* make this the new buffer */
128  OrefSet(this, this->table, newLTable);
129  /* If either of the objects are in */
130  /* OldSpace, we need to OrefSet */
131  /* each copied element */
132  if (this->isOldSpace() || newLTable->isOldSpace())
133  {
134  LISTENTRY *element = ENTRY_POINTER(0); /* point at the first element */
135  /* copy each element into new buffer */
136  for (size_t i = 0; i < this->size; i++)
137  {
138  /* do an explicit set operator */
139  OrefSet(this->table, element->value, element->value);
140  element++; /* step to the next element */
141  }
142  }
143  /* chain up the free elements */
144  this->partitionBuffer(this->size, this->size);
145  this->size += this->size; /* increase the size */
146  }
147  size_t new_index = this->free; /* get the free element index */
148  /* close up the free chain */
149  this->free = ENTRY_POINTER(new_index)->next;
150  return new_index; /* return the first free element */
151 }
152 
153 void RexxList::live(size_t liveMark)
154 /******************************************************************************/
155 /* Function: Normal garbage collection live marking */
156 /******************************************************************************/
157 {
158  memory_mark(this->table);
159  memory_mark(this->objectVariables);
160 }
161 
162 void RexxList::liveGeneral(int reason)
163 /******************************************************************************/
164 /* Function: Generalized object marking */
165 /******************************************************************************/
166 {
167  memory_mark_general(this->table);
168  memory_mark_general(this->objectVariables);
169 }
170 
172 /******************************************************************************/
173 /* Function: Flatten an object */
174 /******************************************************************************/
175 {
177 
178  flatten_reference(newThis->table, envelope);
179  flatten_reference(newThis->objectVariables, envelope);
180 
182 }
183 
185  RexxObject *_index, /* list index item */
186  RexxObject *position) /* index argument error position */
187 /******************************************************************************/
188 /* Function: Resolve a list index argument to a list element position */
189 /******************************************************************************/
190 {
191  if (_index == OREF_NULL) /* must have one here */
192  {
193  /* else an error */
194  reportException(Error_Incorrect_method_noarg, OREF_positional, position);
195  }
196  /* force to integer form */
197  RexxInteger *integer_index = (RexxInteger *)REQUEST_INTEGER(_index);
198  if (integer_index == TheNilObject) /* doesn't exist? */
199  {
200  /* raise an exception */
202  }
203  if (integer_index->getValue() < 0) /* not a valid index? */
204  {
205  /* raise an exception */
207  }
208  /* get the binary value */
209  size_t item_index = integer_index->getValue();
210  if (item_index >= this->size) /* out of possible range? */
211  {
212  return NULL; /* not found */
213  }
214  LISTENTRY *element = ENTRY_POINTER(item_index); /* point to the item */
215  if (element->previous == NOT_ACTIVE) /* not a real item? */
216  {
217  element = NULL; /* no element found */
218  }
219  return element; /* return this */
220 }
221 
222 
223 /**
224  * Resolve a low-level index into a list entry value.
225  *
226  * @param item_index The target index.
227  *
228  * @return A LISTENTRY value, or NULL if not found.
229  */
230 LISTENTRY * RexxList::getEntry(size_t item_index)
231 {
232  if (item_index >= this->size) /* out of possible range? */
233  {
234  return NULL; /* not found */
235  }
236  LISTENTRY *element = ENTRY_POINTER(item_index); /* point to the item */
237  if (element->previous != NOT_ACTIVE) /* got a real item? */
238  {
239  return element; // go for it
240  }
241  return NULL; // not found
242 }
243 
244 
245 
247  RexxObject *_index) /* list index item */
248 /******************************************************************************/
249 /* Function: Retrieve the value for a given list index */
250 /******************************************************************************/
251 {
252  /* locate this entry */
253  LISTENTRY *element = this->getEntry(_index, (RexxObject *)IntegerOne);
254  if (element == NULL) /* not there? */
255  {
256  return TheNilObject; /* doesn't exist, return .NIL */
257  }
258  RexxObject *result = element->value; /* get the value */
259  if (result == OREF_NULL) /* not there? */
260  {
261  result = TheNilObject; /* just return NIL */
262  }
263  return result; /* return this item */
264 }
265 
266 
267 
268 /**
269  * Primitive level getValue() for a list item.
270  *
271  * @param _index The decoded index item.
272  *
273  * @return The value associated with the index. Returns OREF_NULL if not
274  * there.
275  */
277 {
278  /* locate this entry */
279  LISTENTRY *element = this->getEntry(_index);
280  // return a real NULL if this isn't there
281  if (element == NULL)
282  {
283  return OREF_NULL;
284  }
285  return element->value; // return whatever is in this position
286 }
287 
288 
290  RexxObject *_value, /* new value for the item */
291  RexxObject *_index ) /* index of item to replace */
292 /******************************************************************************/
293 /* Function: Replace the value of an item already in the list. */
294 /******************************************************************************/
295 {
296  /* locate this entry */
297  LISTENTRY *element = this->getEntry(_index, (RexxObject *)IntegerTwo);
298  requiredArgument(_value, OREF_positional, ARG_ONE); /* must have a value also */
299  if (element == NULL) /* not a valid index? */
300  {
301  /* raise an error */
303  }
304  /* replace the value */
305  OrefSet(this->table, element->value, _value);
306  return OREF_NULL; /* return nothing at all */
307 }
308 
310  RexxObject *_index, /* index of starting item */
311  RexxObject *_count ) /* count of items to return */
312 /******************************************************************************/
313 /* Function: Create a sublist of this list */
314 /******************************************************************************/
315 {
316  size_t counter; /* object counter */
317  /* locate this entry */
318  LISTENTRY *element = this->getEntry(_index, (RexxObject *)IntegerOne);
319  if (_count != OREF_NULL)
320  { /* have a count? */
321  /* Make sure it's a good integer */
322  counter = _count->requiredNonNegative(OREF_positional, ARG_TWO);
323  }
324  else
325  {
326  counter = 999999999; /* just use largest possible count */
327  }
328  if (element == NULL) /* index doesn't exist? */
329  /* raise an error */
331  if (!isOfClass(List, this)) /* actually a list subclass? */
332  {
333  /* need to do this the slow way */
334  return this->sectionSubclass(element, counter);
335  }
336  RexxList *result = new RexxList; /* create a new list */
337  ProtectedObject p(result);
338  /* while still more to go and not at */
339  /* the end of the list */
340  while (counter--> 0)
341  { /* while still more items */
342  /* add the this item to new list */
343  result->addLast(element->value);
344  if (element->next == LIST_END) /* this the last one? */
345  {
346  break; /* done sectioning */
347  }
348  /* step to the next item */
349  element = ENTRY_POINTER(element->next);
350  }
351  return result; /* return the sectioned list */
352 }
353 
355  LISTENTRY *element, /* starting element */
356  size_t counter) /* count of elements */
357 /******************************************************************************/
358 /* Function: Rexx level section method */
359 /******************************************************************************/
360 {
361  ProtectedObject r;
362  /* create a new list */
363  this->behaviour->getOwningClass()->sendMessage(OREF_NEW, r);
364  RexxList *newList = (RexxList *)(RexxObject *)r;
365  /* while still more to go and not at */
366  /* the end of the list */
367  while (counter-- > 0) /* while still more items */
368  {
369  /* add the this item to new list */
370  newList->sendMessage(OREF_INSERT, element->value);
371  if (element->next == LIST_END) /* this the last one? */
372  {
373  break; /* done sectioning */
374  }
375  /* step to the next item */
376  element = ENTRY_POINTER(element->next);
377  }
378  return newList; /* return the sectioned list */
379 }
380 
382  RexxObject *_value, /* new value to add */
383  RexxObject *_index) /* addition insertion index */
384 /******************************************************************************/
385 /* Function: Add a new element to the list at the given insertion point. */
386 /* TheNilObject indicates it should be added to the list end */
387 /******************************************************************************/
388 {
389  LISTENTRY *element; /* list element */
390 
391  /* make sure we have room to insert */
392  size_t new_index = this->getFree();
393  /* point to the actual element */
394  LISTENTRY *new_element = ENTRY_POINTER(new_index);
395  if (_index == TheNilObject) /* inserting at the end? */
396  {
397  element = NULL; /* flag this as new */
398  }
399  else
400  {
401  /* locate this entry */
402  element = this->getEntry(_index, (RexxObject *)IntegerOne);
403  if (element == NULL) /* index doesn't exist? */
404  {
405  /* raise an error */
407  }
408  }
409  this->count++; /* increase our count */
410  /* set the value */
411  OrefSet(this->table, new_element->value, _value);
412  if (element == NULL)
413  { /* adding at the end */
414  if (this->last == LIST_END)
415  { /* first element added? */
416  this->first = new_index; /* set this as the first */
417  this->last = new_index; /* and the last */
418  new_element->next = LIST_END; /* this is the last element */
419  new_element->previous = LIST_END;/* in both directions */
420  }
421  else
422  { /* adding at the end */
423  /* previous is current last */
424  new_element->previous = this->last;
425  new_element->next = LIST_END; /* nothing after this */
426  /* point to the end element */
427  element = ENTRY_POINTER(this->last);
428  element->next = new_index; /* point it at the new entry */
429  this->last = new_index; /* this is the new last element */
430  }
431  }
432  else
433  { /* have a real insertion point */
434  /* set the next pointer */
435  new_element->next = ENTRY_INDEX(element);
436 
437  if (element->previous == LIST_END) /* inserting at the front? */
438  {
439  this->first = new_index; /* new first element */
440  }
441  else /* fudge the previous element */
442  {
443  ENTRY_POINTER(element->previous)->next = new_index;
444  }
445  /* insert before this element */
446  new_element->previous = element->previous;
447  element->previous = new_index; /* new previous one */
448  /* point at the insertion point */
449  new_element->next = ENTRY_INDEX(element);
450  }
451  /* return this index item */
452  return new_integer(new_index);
453 }
454 
456  RexxObject *_value ) /* new value to add */
457 /******************************************************************************/
458 /* Function: Add a new element to the tail of a list */
459 /******************************************************************************/
460 {
461  /* make sure we have room to insert */
462  size_t new_index = this->getFree();
463  /* point to the actual element */
464  LISTENTRY *new_element = ENTRY_POINTER(new_index);
465  this->count++; /* increase our count */
466  /* set the value */
467  OrefSet(this->table, new_element->value, _value);
468  if (this->last == LIST_END)
469  { /* first element added? */
470  this->first = new_index; /* set this as the first */
471  this->last = new_index; /* and the last */
472  new_element->next = LIST_END; /* this is the last element */
473  new_element->previous = LIST_END; /* in both directions */
474  }
475  else
476  { /* adding at the end */
477  new_element->previous = this->last;/* previous is current last */
478  new_element->next = LIST_END; /* nothing after this */
479  /* point to the end element */
480  new_element = ENTRY_POINTER(this->last);
481  new_element->next = new_index; /* point it at the new entry */
482  this->last = new_index; /* this is the new last element */
483  }
484 }
485 
487  RexxObject *_value) /* new value to add */
488 /******************************************************************************/
489 /* Function: Insert an element at the front of the list */
490 /******************************************************************************/
491 {
492  size_t new_index = this->getFree(); /* make sure we have room to insert */
493  /* point to the actual element */
494  LISTENTRY *new_element = ENTRY_POINTER(new_index);
495  this->count++; /* increase our count */
496  /* set the value */
497  OrefSet(this->table, new_element->value, _value);
498  if (this->last == LIST_END)
499  { /* first element added? */
500  this->first = new_index; /* set this as the first */
501  this->last = new_index; /* and the last */
502  new_element->next = LIST_END; /* this is the last element */
503  new_element->previous = LIST_END; /* in both directions */
504  }
505  else
506  { /* adding at the front */
507 
508  new_element->next = this->first; /* previous is current first */
509  new_element->previous = LIST_END; /* nothing before this */
510  /* point to the first element */
511  LISTENTRY *element = ENTRY_POINTER(this->first);
512  element->previous = new_index; /* point it at the new entry */
513  this->first = new_index; /* this is the new first element */
514  }
515 }
516 
517 
519  RexxObject *_value, /* new value to add */
520  RexxObject *_index) /* addition insertion index */
521 /******************************************************************************/
522 /* Function: Publicly accessible version of the list insert function. */
523 /******************************************************************************/
524 {
525  requiredArgument(_value, OREF_positional, ARG_ONE); /* must have a value to insert */
526  /* go do the real insert */
527  return this->insert(_value, _index);
528 }
529 
530 
531 /**
532  * Append an item after the last item in the list.
533  *
534  * @param value The value to append.
535  *
536  * @return The index of the appended item.
537  */
539 {
540  requiredArgument(_value, OREF_positional, ARG_ONE);
541  // this is just an insertion operation with an ommitted index.
542  return insert(_value, OREF_NULL);
543 }
544 
545 
547  RexxObject *_value, /* new value to add */
548  RexxObject *_index) /* addition insertion index */
549 /******************************************************************************/
550 /* Function: Add a new element to the list at the given insertion point. */
551 /* TheNilObject indicates it should be added to the list fron */
552 /******************************************************************************/
553 {
554  LISTENTRY *element; /* list element */
555 
556  /* make sure we have room to insert */
557  size_t new_index = this->getFree();
558  /* point to the actual element */
559  LISTENTRY *new_element = ENTRY_POINTER(new_index);
560  if (_index == TheNilObject) /* inserting at the front? */
561  {
562  element = NULL; /* flag this as new */
563  }
564  else if (_index == OREF_NULL)
565  { /* inserting at the end? */
566  if (this->last == LIST_END) /* currently empty? */
567  {
568  element = NULL; /* just use the front insert code */
569  }
570  else /* insert after the last element */
571  {
572  element = ENTRY_POINTER(this->last);
573  }
574  }
575  else
576  {
577  /* locate this entry */
578  element = this->getEntry(_index, (RexxObject *)IntegerOne);
579  if (element == NULL) /* index doesn't exist? */
580  {
581  /* raise an error */
583  }
584  }
585  this->count++; /* increase our count */
586  /* set the value */
587  OrefSet(this->table, new_element->value, _value);
588  if (element == NULL)
589  { /* adding at the front */
590  if (this->last == LIST_END)
591  { /* first element added? */
592  this->first = new_index; /* set this as the first */
593  this->last = new_index; /* and the last */
594  new_element->next = LIST_END; /* this is the last element */
595  new_element->previous = LIST_END;/* in both directions */
596  }
597  else
598  { /* adding at the front */
599 
600  new_element->next = this->first; /* previous is current first */
601  new_element->previous = LIST_END;/* nothing before this */
602  /* point to the first element */
603  element = ENTRY_POINTER(this->first);
604  element->previous = new_index; /* point it at the new entry */
605  this->first = new_index; /* this is the new first element */
606  }
607  }
608  else
609  { /* have a real insertion point */
610  /* set the next pointer */
611  new_element->previous = ENTRY_INDEX(element);
612 
613  if (element->next == LIST_END) /* inserting at the end? */
614  {
615  this->last = new_index; /* new first element */
616  }
617  else /* fudge the next element */
618  {
619  ENTRY_POINTER(element->next)->previous = new_index;
620  }
621  new_element->next = element->next; /* insert after this element */
622  element->next = new_index; /* new following one */
623  /* point at the insertion point */
624  new_element->previous = ENTRY_INDEX(element);
625  }
626  /* return this index item */
627  return new_integer(new_index);
628 }
629 
631  RexxObject *_index) /* index of item to remove */
632 /******************************************************************************/
633 /* Function: Remove a list item from the list */
634 /******************************************************************************/
635 {
636  /* just remove the given index */
637  return this->primitiveRemove(this->getEntry(_index, (RexxObject *)IntegerOne));
638 }
639 
641  LISTENTRY *element) /* element to remove */
642 /******************************************************************************/
643 /* Function: Remove a list item from the list */
644 /******************************************************************************/
645 {
646  LISTENTRY *_previous; /* previous entry */
647  LISTENTRY *_next; /* next entry */
648 
649  if (element == NULL) /* not a valid index? */
650  return TheNilObject; /* just return .nil */
651 
652  RexxObject *_value = element->value; /* copy the value */
653  if (element->next != LIST_END)
654  { /* not end of the list? */
655  /* point to the next entry */
656  _next = ENTRY_POINTER(element->next);
657  _next->previous = element->previous;/* update the previous pointer */
658  }
659  else
660  {
661  this->last = element->previous; /* need to update the last pointer */
662  }
663  if (element->previous != LIST_END)
664  { /* not end of the list? */
665  /* point to the next entry */
666  _previous = ENTRY_POINTER(element->previous);
667  _previous->next = element->next; /* remove this from the chain */
668  }
669  else
670  {
671  this->first = element->next; /* need to update the last pointer */
672  }
673 
674  this->count--; /* "forget" we had this */
675  element->previous = NOT_ACTIVE; /* no longer a good element */
676  element->next = this->free; /* new head of the free chain */
677  this->free = ENTRY_INDEX(element); /* this is the first free element */
678 
679  return _value; /* return the old value */
680 }
681 
683 /******************************************************************************/
684 /* Function: Return first item (value part) in the list */
685 /******************************************************************************/
686 {
687  if (this->first == LIST_END) /* empty list? */
688  {
689  return TheNilObject; /* give the empty indicator */
690  }
691  else /* return the first value */
692  {
693  return ENTRY_POINTER(this->first)->value;
694  }
695 }
696 
698 /******************************************************************************/
699 /* Function: Return last item (value part) in the list */
700 /******************************************************************************/
701 {
702  if (this->last == LIST_END) /* empty list? */
703  {
704  return TheNilObject; /* give the empty indicator */
705  }
706  else /* return the first value */
707  {
708  return ENTRY_POINTER(this->last)->value;
709  }
710 }
711 
713 /******************************************************************************/
714 /* Function: Return index of the first list item */
715 /******************************************************************************/
716 {
717  if (this->first == LIST_END) /* no first item? */
718  {
719  return TheNilObject; /* just return a .nil index */
720  }
721  else
722  {
723  /* return the index as an integer */
724  return new_integer(this->first);
725  }
726 }
727 
729 /******************************************************************************/
730 /* Function: Return index of the last list item */
731 /******************************************************************************/
732 {
733  if (this->last == LIST_END) /* no first item? */
734  {
735  return TheNilObject; /* just return a .nil index */
736  }
737  else
738  {
739  /* return the index as an integer */
740  return new_integer(this->last);
741  }
742 }
743 
745  RexxObject *_index) /* index of the target item */
746 /******************************************************************************/
747 /* Function: Return the next item after the given indexed item */
748 /******************************************************************************/
749 {
750  /* locate this entry */
751  LISTENTRY *element = this->getEntry(_index, (RexxObject *)IntegerOne);
752  if (element == NULL) /* not a valid index? */
753  {
754  /* raise an error */
756  }
757 
758  if (element->next == LIST_END) /* no next item? */
759  {
760  return TheNilObject; /* just return .nil */
761  }
762  else
763  {
764  /* return the next item */
765  return new_integer(element->next);
766  }
767 }
768 
770  RexxObject *_index) /* index of the target item */
771 /******************************************************************************/
772 /* Function: Return the item previous to the indexed item */
773 /******************************************************************************/
774 {
775  /* locate this entry */
776  LISTENTRY *element = this->getEntry(_index, (RexxObject *)IntegerOne);
777  if (element == NULL) /* not a valid index? */
778  {
779  /* raise an error */
781  }
782 
783  if (element->previous == LIST_END) /* no previous item? */
784  {
785  return TheNilObject; /* just return .nil */
786  }
787  else
788  { /* return the previous item index */
789  return new_integer(element->previous);
790  }
791 }
792 
793 
794 /**
795  * A low-level next() method for internal usage. This works
796  * directly off the index values without needing to create
797  * object instances. This is critical for some of the internal
798  * data structures implemented as lists.
799  *
800  * @param _index The target item index.
801  *
802  * @return The index of the next item, or LIST_END if there is no next item.
803  */
804 size_t RexxList::nextIndex(size_t _index)
805 {
806  LISTENTRY *element = this->getEntry(_index);
807  // we're a little less strict when dealing with internal lists. Just return
808  // the end of list marker here
809  if (element == NULL)
810  {
811  return LIST_END;
812  }
813  // we can just return this value directly...if there is no previous element,
814  // the next field contains LIST_END;
815  return element->next;
816 }
817 
818 
819 /**
820  * A low-level previous() method for internal usage. This works
821  * directly off the index values without needing to create
822  * object instances. This is critical for some of the internal
823  * data structures implemented as lists.
824  *
825  * @param _index The target item index.
826  *
827  * @return The index of the previous item, or LIST_END if there
828  * is no previous item.
829  */
830 size_t RexxList::previousIndex(size_t _index)
831 {
832  LISTENTRY *element = this->getEntry(_index);
833  // we're a little less strict when dealing with internal lists. Just return
834  // the end of list marker here
835  if (element == NULL)
836  {
837  return LIST_END;
838  }
839  // we can just return this value directly...if there is no previous element,
840  // the previous field contains LIST_END;
841  return element->previous;
842 }
843 
844 
846  RexxObject *_index) /* index of the target item */
847 /******************************************************************************/
848 /* Function: Return an index existence flag */
849 /******************************************************************************/
850 {
851  /* locate this entry */
852  LISTENTRY *element = this->getEntry(_index, (RexxObject *)IntegerOne);
853  /* return an existence flag */
854  return(element!= NULL) ? (RexxObject *)TheTrueObject : (RexxObject *)TheFalseObject;
855 }
856 
858 /******************************************************************************/
859 /* Function: Primitive level request('ARRAY') fast path */
860 /******************************************************************************/
861 {
862  if (isOfClass(List, this)) /* primitive level object? */
863  {
864  return this->makeArray(); /* just do the makearray */
865  }
866  else /* need to so full request mechanism */
867  {
868  return(RexxArray *)this->sendMessage( OREF_REQUEST, OREF_ARRAYSYM);
869  }
870 }
871 
872 
874 /******************************************************************************/
875 /* Function: Return all of the list values in an array */
876 /******************************************************************************/
877 {
878  return this->allItems(); // this is just all of the array items.
879 }
880 
881 
882 /**
883  * Return an array containing all elements contained in the list,
884  * in sorted order.
885  *
886  * @return An array with the list elements.
887  */
889 {
890  // just iterate through the list, copying the elements.
891  RexxArray *array = (RexxArray *)new_array(this->count);
892  size_t nextEntry = this->first;
893  for (size_t i = 1; i <= this->count; i++)
894  {
895  LISTENTRY *element = ENTRY_POINTER(nextEntry);
896  array->put(element->value, i);
897  nextEntry = element->next;
898  }
899  return array;
900 }
901 
902 
903 /**
904  * Empty all of the items from a list.
905  *
906  * @return No return value.
907  */
909 {
910  while (this->first != LIST_END)
911  {
912  // get the list entry and remove the value
913  LISTENTRY *element = ENTRY_POINTER(this->first);
914  primitiveRemove(element);
915  }
916  return OREF_NULL;
917 }
918 
919 
920 
921 /**
922  * Test if a list is empty.
923  *
924  * @return True if the list is empty, false otherwise
925  */
927 {
928  return (count == 0) ? TheTrueObject : TheFalseObject;
929 }
930 
931 
932 /**
933  * Return an array containing all elements contained in the list,
934  * in sorted order.
935  *
936  * @return An array with the list elements.
937  */
939 {
940  // just iterate through the list, copying the elements.
941  RexxArray *array = (RexxArray *)new_array(this->count);
942  // this requires protecting, since we're going to be creating new
943  // integer objects.
944  ProtectedObject p(array);
945  size_t nextEntry = this->first;
946  for (size_t i = 1; i <= this->count; i++)
947  {
948  LISTENTRY *element = ENTRY_POINTER(nextEntry);
949  array->put((RexxObject *)new_integer(nextEntry), i);
950  nextEntry = element->next;
951  }
952  return array;
953 }
954 
955 
956 /**
957  * Return the index of the first item with a matching value
958  * in the list. Returns .nil if the object is not found.
959  *
960  * @param target The target object.
961  *
962  * @return The index of the item, or .nil.
963  */
965 {
966  // we require the index to be there.
967  requiredArgument(target, OREF_positional, ARG_ONE);
968 
969  // ok, now run the list looking for the target item
970  size_t nextEntry = this->first;
971  for (size_t i = 1; i <= this->count; i++)
972  {
973  LISTENTRY *element = ENTRY_POINTER(nextEntry);
974  // if we got a match, return the item
975  if (target->equalValue(element->value))
976  {
977  return new_integer(nextEntry);
978  }
979  nextEntry = element->next;
980  }
981  // no match
982  return TheNilObject;
983 }
984 
985 
986 /**
987  * Tests whether there is an object with the given value in the
988  * list.
989  *
990  * @param target The target value.
991  *
992  * @return .true if there is a match, .false otherwise.
993  */
995 {
996  // we require the index to be there.
997  requiredArgument(target, OREF_positional, ARG_ONE);
998 
999  // ok, now run the list looking for the target item
1000  size_t nextEntry = this->first;
1001  for (size_t i = 1; i <= this->count; i++)
1002  {
1003  LISTENTRY *element = ENTRY_POINTER(nextEntry);
1004  // if we got a match, return the item
1005  if (target->equalValue(element->value))
1006  {
1007  return TheTrueObject;
1008  }
1009  nextEntry = element->next;
1010  }
1011  // no match
1012  return TheFalseObject;
1013 }
1014 
1015 
1016 /**
1017  * Removes an item from the collection.
1018  *
1019  * @param target The target value.
1020  *
1021  * @return The target item.
1022  */
1024 {
1025  // we require the index to be there.
1026  requiredArgument(target, OREF_positional, ARG_ONE);
1027 
1028  // ok, now run the list looking for the target item
1029  size_t nextEntry = this->first;
1030 
1031  for (size_t i = 1; i <= this->count; i++)
1032  {
1033  LISTENTRY *element = ENTRY_POINTER(nextEntry);
1034  // if we got a match, return the item
1035  if (target->equalValue(element->value))
1036  {
1037  // remove this item
1038  return primitiveRemove(element);
1039  }
1040  nextEntry = element->next;
1041  }
1042  // no match
1043  return TheNilObject;
1044 }
1045 
1046 
1047 /**
1048  * Removes an item from the collection using Object identity
1049  * comparisons. This is used in some special circumstances when
1050  * we don't want to have the equals method called, which can
1051  * cause some exceptions or false positives. This is used
1052  * primarily for managing the local reference save lists.
1053  *
1054  * @param target The target value.
1055  *
1056  * @return The target item.
1057  */
1059 {
1060  // we require the index to be there.
1061  requiredArgument(target, OREF_positional, ARG_ONE);
1062 
1063  // ok, now run the list looking for the target item
1064  size_t nextEntry = this->first;
1065 
1066  for (size_t i = 1; i <= this->count; i++)
1067  {
1068  LISTENTRY *element = ENTRY_POINTER(nextEntry);
1069  // if we got a match, return the item
1070  if (target == element->value)
1071  {
1072  // remove this item
1073  return primitiveRemove(element);
1074  }
1075  nextEntry = element->next;
1076  }
1077  // no match
1078  return TheNilObject;
1079 }
1080 
1081 
1083  RexxObject *_value)
1084 /*****************************************************************************/
1085 /* Function: Return the index for the value that was passed in */
1086 /* or OREF_NULL */
1087 /*****************************************************************************/
1088 {
1089  RexxObject *_index = OREF_NULL;
1090  RexxObject *this_value = OREF_NULL;
1091  /* get the last index in the list */
1092  RexxObject *last_index = this->lastRexx();
1093  /* if there was any items in list */
1094  if (last_index != TheNilObject)
1095  {
1096  /* loop thru the list looking for the */
1097  /* specified value */
1098  for (_index = this->firstRexx();
1099  ((this_value = this->value(_index)) != _value) && _index != last_index;
1100  _index = this->next(_index));
1101  }
1102  /* return the index if the value was */
1103  /* in the list */
1104  if (this_value == _value)
1105  {
1106  return _index;
1107  }
1108  /* otherwise return nothing */
1109  return OREF_NULL;
1110 }
1111 
1113 /******************************************************************************/
1114 /* Function: Return an array containing all of the list indices */
1115 /******************************************************************************/
1116 {
1117  /* allocate proper sized array */
1118  RexxArray *array = (RexxArray *)new_array(this->count);
1119  ProtectedObject p(array);
1120  size_t nextEntry = this->first; /* point to the first element */
1121  for (size_t i = 1; i <= this->count; i++)
1122  { /* step through the array elements */
1123  LISTENTRY *element = ENTRY_POINTER(nextEntry);/* get the next item */
1124  /* create an index item */
1125  array->put((RexxObject *)new_integer(nextEntry), i);
1126  nextEntry = element->next; /* get the next pointer */
1127  }
1128  return array; /* return the array element */
1129 }
1130 
1132 /******************************************************************************/
1133 /* Function: Create a supplier object for this list */
1134 /******************************************************************************/
1135 {
1136  RexxArray *values; /* array of value items */
1137  RexxArray *indices; /* array of index items */
1138 
1139  /* and all of the indices */
1140  indices = this->makeArrayIndices();
1141  ProtectedObject p_indices(indices);
1142  values = this->makeArray(); /* get the list values */
1143  ProtectedObject p_values(values);
1144  /* return the supplier values */
1145  return(RexxSupplier *)new_supplier(values, indices);
1146 }
1147 
1149 /******************************************************************************/
1150 /* Function: Return the size of the list as an integer */
1151 /******************************************************************************/
1152 {
1153  /* return the item count */
1154  return (RexxObject *)new_integer(this->count);
1155 }
1156 
1157 
1158 /**
1159  * Not really part of normal list operation, but classes
1160  * maintain their subclasses as a list of weak references
1161  * so that subclasses can get garbage collected when no
1162  * longer needed. When the class needs to iterate over
1163  * the subclasses, it needs to resolve which weak references
1164  * are still valid. This method will check the weak
1165  * references and remove any stale entries. Then it
1166  * will return an array of the dereferenced objects.
1167  *
1168  * @return An array of the dereferenced objects.
1169  */
1171 {
1172  // this is a little tricky. We allocate the result array
1173  // before we process the weak references. If we prune
1174  // the stale references first and then allocate an array,
1175  // we might hit a GC window that could create more stale
1176  // references.
1177 
1178  // make this large enough to hold what is currently there.
1179  // this could be more than we need, but that's fine. The initial size is zero.
1180  RexxArray *result = (RexxArray *)new_array(this->count);
1181  ProtectedObject p(result);
1182 
1183  LISTENTRY *element; /* current working entry */
1184  size_t i = this->firstIndex(); /* point to the first element */
1185  size_t itemCount = this->count;
1186  while (itemCount--) /* step through the array elements */
1187  {
1188  element = ENTRY_POINTER(i); /* get the next item */
1189  // step to the next element now, so we can remove this one
1190  i = element->next;
1191 
1192  // get the reference value and see if it is still valid
1193  // if not, just delink this position and allow the weak reference
1194  // to be garbage collected.
1195  WeakReference *ref = (WeakReference *)element->value;
1196  if (ref->get() == OREF_NULL)
1197  {
1198  // remove this element from the list...note that this also
1199  // decrements the count, which will effect the number of
1200  // loop iterations.
1201  primitiveRemove(element);
1202  }
1203  // we have a good value, so add this to the result array.
1204  else
1205  {
1206  result->append(ref->get());
1207  }
1208  }
1209  return result;
1210 }
1211 
1212 
1213 void *RexxList::operator new(size_t size)
1214 /******************************************************************************/
1215 /* Function: Construct and initialized a new list item */
1216 /******************************************************************************/
1217 {
1218  /* Get new object */
1219  RexxList *newList = (RexxList *)new (INITIAL_LIST_SIZE, size) RexxListTable;
1220  /* Give new object its behaviour */
1221  newList->setBehaviour(TheListBehaviour);
1222  newList->init(); /* finish initializing */
1223  return newList; /* return the new list item */
1224 }
1225 
1227  RexxObject **init_args,
1228  size_t argCount,
1229  size_t named_argCount)
1230 /******************************************************************************/
1231 /* Function: Construct and initialized a new list item */
1232 /******************************************************************************/
1233 {
1234  /* get a new directory */
1235  /* NOTE: this does not use the */
1236  /* macro version because the class */
1237  /* object might actually be for a */
1238  /* subclass */
1239 
1240  // this method is defined on the object class, but this is actually attached
1241  // to a class object instance. Therefore, any use of the this pointer
1242  // will be touching the wrong data. Use the classThis pointer for calling
1243  // any methods on this object from this method.
1244  RexxClass *classThis = (RexxClass *)this;
1245  classThis->checkAbstract(); // ooRexx5
1246 
1247  RexxList *newList = new RexxList;
1248  ProtectedObject p(newList);
1249  /* Give new object its behaviour */
1250  newList->setBehaviour(classThis->getInstanceBehaviour());
1251  if (classThis->hasUninitDefined())
1252  {
1253  newList->hasUninit();
1254  }
1255 
1256  /* Initialize the new list instance */
1257  newList->sendMessage(OREF_INIT, init_args, argCount, named_argCount);
1258  return newList; /* return the new list item */
1259 }
1260 
1262  RexxObject **args, /* array of list items */
1263  size_t argCount, /* size of the argument array */
1264  size_t named_argCount)
1265 /******************************************************************************/
1266 /* Function: Create a new list containing the given list items */
1267 /******************************************************************************/
1268 {
1269  RexxList *newList; /* newly created list */
1270 
1271  if (TheListClass == (RexxClass *)this )
1272  { /* creating an internel list item? */
1273  size_t _size = argCount; /* get the array size */
1274  newList = new RexxList; /* get a new list */
1275  ProtectedObject p(newList);
1276  for (size_t i = 0; i < _size; i++)
1277  { /* step through the array */
1278  RexxObject *item = args[i]; /* get the next item */
1279  if (item == OREF_NULL)
1280  { /* omitted item? */
1281  /* raise an error on this */
1282  reportException(Error_Incorrect_method_noarg, OREF_positional, i + 1);
1283  }
1284  /* add this to the list end */
1285  newList->addLast(item);
1286  }
1287  }
1288  else
1289  {
1290  size_t _size = argCount; /* get the array size */
1291  ProtectedObject p;
1292  /* get a new list */
1293  this->sendMessage(OREF_NEW, p);
1294  newList = (RexxList *)(RexxObject *)p;
1295  for (size_t i = 0; i < _size; i++)
1296  { /* step through the array */
1297  RexxObject *item = args[i]; /* get the next item */
1298  if (item == OREF_NULL)
1299  { /* omitted item? */
1300  /* raise an error on this */
1301  reportException(Error_Incorrect_method_noarg, OREF_positional, i + 1);
1302  }
1303  /* add this to the list end */
1304  newList->sendMessage(OREF_INSERT, item);
1305  }
1306  }
1307  return newList; /* give back the list */
1308 }
1309 
void reportException(wholenumber_t error)
RexxArray * new_array(size_t s)
Definition: ArrayClass.hpp:259
RexxInteger * new_integer(wholenumber_t v)
#define INITIAL_LIST_SIZE
Definition: ListClass.hpp:49
#define TABLE_SIZE(n)
Definition: ListClass.hpp:53
#define NOT_ACTIVE
Definition: ListClass.hpp:61
#define ENTRY_POINTER(n)
Definition: ListClass.hpp:58
#define LIST_END
Definition: ListClass.hpp:60
#define ENTRY_INDEX(p)
Definition: ListClass.hpp:59
#define TheListBehaviour
#define OREF_NULL
Definition: RexxCore.h:61
#define IntegerOne
Definition: RexxCore.h:200
#define OrefSet(o, r, v)
Definition: RexxCore.h:101
#define TheTrueObject
Definition: RexxCore.h:196
const int ARG_TWO
Definition: RexxCore.h:84
#define TheListClass
Definition: RexxCore.h:159
#define IntegerTwo
Definition: RexxCore.h:201
#define isOfClass(t, r)
Definition: RexxCore.h:224
#define TheNilObject
Definition: RexxCore.h:191
#define TheFalseObject
Definition: RexxCore.h:195
const int ARG_ONE
Definition: RexxCore.h:83
void requiredArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:303
RexxInteger * REQUEST_INTEGER(RexxObject *obj)
Definition: RexxCore.h:460
#define Error_Incorrect_method_noarg
#define Error_Incorrect_method_index
#define memory_mark(oref)
Definition: RexxMemory.hpp:450
#define flatten_reference(oref, envel)
Definition: RexxMemory.hpp:498
#define CLASS_CREATE(name, id, className)
Definition: RexxMemory.hpp:503
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:451
#define cleanUpFlatten
Definition: RexxMemory.hpp:484
#define setUpFlatten(type)
Definition: RexxMemory.hpp:478
RexxSupplier * new_supplier(RexxArray *c, RexxArray *f)
void put(RexxObject *eref, size_t pos)
Definition: ArrayClass.cpp:208
size_t append(RexxObject *)
Definition: ArrayClass.cpp:485
RexxClass * getOwningClass()
void checkAbstract()
RexxBehaviour * getInstanceBehaviour()
Definition: ClassClass.hpp:135
bool hasUninitDefined()
Definition: ClassClass.hpp:125
RexxObject * getValue(RexxActivation *)
void setBehaviour(RexxBehaviour *b)
virtual RexxObject * copy()
RexxBehaviour * behaviour
size_t previousIndex(size_t i)
Definition: ListClass.cpp:830
RexxObject * lastRexx()
Definition: ListClass.cpp:728
RexxObject * append(RexxObject *)
Definition: ListClass.cpp:538
RexxObject * value(RexxObject *)
Definition: ListClass.cpp:246
RexxArray * allIndexes()
Definition: ListClass.cpp:938
void partitionBuffer(size_t, size_t)
Definition: ListClass.cpp:92
RexxArray * makeArrayIndices()
Definition: ListClass.cpp:1112
RexxArray * allItems()
Definition: ListClass.cpp:888
size_t firstIndex()
Definition: ListClass.hpp:84
size_t getFree()
Definition: ListClass.cpp:115
RexxObject * next(RexxObject *)
Definition: ListClass.cpp:744
void live(size_t)
Definition: ListClass.cpp:153
RexxObject * removeObject(RexxObject *)
Definition: ListClass.cpp:1058
RexxObject * sectionSubclass(LISTENTRY *, size_t)
Definition: ListClass.cpp:354
size_t free
Definition: ListClass.hpp:143
RexxArray * makeArray()
Definition: ListClass.cpp:873
size_t nextIndex(size_t i)
Definition: ListClass.cpp:804
RexxObject * hasIndex(RexxObject *)
Definition: ListClass.cpp:845
void flatten(RexxEnvelope *)
Definition: ListClass.cpp:171
RexxObject * lastItem()
Definition: ListClass.cpp:697
RexxObject * insert(RexxObject *, RexxObject *)
Definition: ListClass.cpp:546
size_t size
Definition: ListClass.hpp:142
RexxObject * previous(RexxObject *)
Definition: ListClass.cpp:769
RexxObject * removeItem(RexxObject *)
Definition: ListClass.cpp:1023
size_t last
Definition: ListClass.hpp:140
size_t count
Definition: ListClass.hpp:141
RexxObject * primitiveRemove(LISTENTRY *)
Definition: ListClass.cpp:640
LISTENTRY * getEntry(RexxObject *, RexxObject *)
Definition: ListClass.cpp:184
RexxList * classOf(RexxObject **, size_t, size_t)
Definition: ListClass.cpp:1261
RexxArray * weakReferenceArray()
Definition: ListClass.cpp:1170
RexxObject * add(RexxObject *, RexxObject *)
Definition: ListClass.cpp:381
RexxObject * hasItem(RexxObject *)
Definition: ListClass.cpp:994
void liveGeneral(int reason)
Definition: ListClass.cpp:162
RexxObject * put(RexxObject *, RexxObject *)
Definition: ListClass.cpp:289
RexxObject * itemsRexx()
Definition: ListClass.cpp:1148
RexxObject * index(RexxObject *)
Definition: ListClass.cpp:964
RexxObject * firstRexx()
Definition: ListClass.cpp:712
RexxObject * remove(RexxObject *)
Definition: ListClass.cpp:630
RexxList * newRexx(RexxObject **, size_t, size_t)
Definition: ListClass.cpp:1226
RexxObject * isEmpty()
Definition: ListClass.cpp:926
RexxArray * requestArray()
Definition: ListClass.cpp:857
RexxObject * section(RexxObject *, RexxObject *)
Definition: ListClass.cpp:309
static RexxClass * classInstance
Definition: ListClass.hpp:134
RexxObject * empty()
Definition: ListClass.cpp:908
RexxObject * indexOfValue(RexxObject *)
Definition: ListClass.cpp:1082
RexxListTable * table
Definition: ListClass.hpp:138
static void createInstance()
Definition: ListClass.cpp:60
RexxObject * insertRexx(RexxObject *, RexxObject *)
Definition: ListClass.cpp:518
RexxObject * firstItem()
Definition: ListClass.cpp:682
RexxObject * getValue(size_t i)
Definition: ListClass.cpp:276
void addLast(RexxObject *value)
Definition: ListClass.cpp:455
RexxObject * copy()
Definition: ListClass.cpp:78
RexxSupplier * supplier()
Definition: ListClass.cpp:1131
void addFirst(RexxObject *value)
Definition: ListClass.cpp:486
size_t first
Definition: ListClass.hpp:139
void init()
Definition: ListClass.cpp:66
LISTENTRY * getData()
stringsize_t requiredNonNegative(RexxString *kind, size_t position, size_t precision=Numerics::ARGUMENT_DIGITS)
bool equalValue(RexxObject *other)
RexxObject * copy()
void sendMessage(RexxString *, RexxArray *, RexxDirectory *, ProtectedObject &)
RexxObject * get()
if(!yymsg) yymsg
size_t previous
RexxObject * value