RexxHashTable.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 Hash Table Class */
42 /* */
43 /******************************************************************************/
44 #include "RexxCore.h"
45 #include "RexxHashTable.hpp"
46 #include "ArrayClass.hpp"
47 #include "SupplierClass.hpp"
48 #include "ProtectedObject.hpp"
49 
50 /******************************************************************************/
51 /* */
52 /* NOTE: The following value for NO_MORE is based on the assumption that all */
53 /* hash table entry chaining proceeds upward from the lower section of the */
54 /* table to the upper table. That is, offset zero is never used for a next */
55 /* element location. This fact allows us to just issue a ClearObject call */
56 /* to initialize the hash table rather than having to explicitly set each */
57 /* index pointer to a value such as -1. */
58 /* */
59 /******************************************************************************/
60 
61 // link terminator
62 const HashLink NO_MORE = 0;
63 // indicates not linked
64 const HashLink NO_LINK = ~((HashLink)0);
65 
66  /* compare a value item to the value */
67  /* at the specified position */
68 bool inline EQUAL_VALUE(RexxObject *value, RexxObject *other)
69 {
70  /* true for either direct identity or*/
71  /* real equality ("==") */
72  return (value == other) || value->isEqual(other);
73 }
74 
76  size_t entries ) /* number of entries in the table */
77 /******************************************************************************/
78 /* Function: Create a new hash table */
79 /******************************************************************************/
80 {
81  RexxHashTable * newHash; /* new hash table object */
82  size_t bytes; /* size of the allocated object */
83  size_t bucketSize; /* size of the bucket */
84 
85  bucketSize = entries / 2; /* get the size of the bucket from this capacity */
86  if (bucketSize % 2 == 0)
87  { /* if this is even, increase it */
88  bucketSize++;
89  }
90 
91  entries = bucketSize * 2; /* double the bucket size for the overflow */
92 
93  bytes = sizeof(RexxHashTable) + (sizeof(TABENTRY) * (entries - 1));
94  /* Get new object */
95  newHash = (RexxHashTable *)new_object(bytes, T_HashTable);
96  newHash->size = bucketSize; /* record the size */
97  newHash->free = entries - 1; /* and the first free slot */
98  return newHash; /* and return it */
99 }
100 
102  size_t entries, /* number of entries in the table */
103  size_t companionSize, /* size of companion "table" object */
104  size_t type) // type of collection we're creating
105 /******************************************************************************/
106 /* Function: Create a hash table object and a "companion" table, vdict, */
107 /* directory, or relation object all in one shot. */
108 /* */
109 /* Note: It is necessary to make several assumptions about the */
110 /* "companion" object. 1) The size specified is already a */
111 /* multiple of 4. 2) The companion has an OREF pointing to the */
112 /* hashtab object in the same location as the table class. */
113 /******************************************************************************/
114 {
115  RexxHashTable *newHash; /* new hash table object */
116  RexxTable *newObj; /* associated table object */
117  size_t bytes; /* size of the allocated object */
118  size_t bucketSize; /* size of the bucket */
119 
120  bucketSize = entries / 2; /* get the size of the bucket from this capacity */
121  if (bucketSize % 2 == 0)
122  { /* if this is even, increase it */
123  bucketSize++;
124  }
125 
126  entries = bucketSize * 2; /* double the bucket size for the overflow */
127  /* Compute size of hash tab object */
128  bytes = roundObjectBoundary(sizeof(RexxHashTable) + (sizeof(TABENTRY) * (entries - 1)));
129  /* make sure we've got proper sizes for each of the object parts. */
130  companionSize = roundObjectBoundary(companionSize);
131  /* Get space for two objects */
132  newObj = (RexxTable *)new_object(bytes + companionSize, type);
133  /* address the hash table */
134  newHash = (RexxHashTable *)(((char *)newObj) + companionSize);
135  /* compute total size of the hash */
136  /* table (allowing for possible */
137  /* over allocation by the memory */
138  /* manager */
139  bytes = newObj->getObjectSize() - companionSize;
140 
141  // initialize the hash table object
143  /* reduce the companion size */
144  newObj->setObjectSize(companionSize);
145  newHash->size = bucketSize; /* record the size */
146  newHash->free = entries - 1; /* and the first free slot */
147  /* hook the hash into the companion */
148  /* OrefSet is not used, because the */
149  /* companion object is not fully set */
150  newObj->contents = newHash; /* up yet (no behaviour) */
151  return newObj; /* return the object */
152 }
153 
154 void RexxHashTable::live(size_t liveMark)
155 /******************************************************************************/
156 /* Function: Normal garbage collection live marking */
157 /******************************************************************************/
158 {
159  TABENTRY *ep; /* table element pointer */
160  TABENTRY *endp;
161  /* hash table size */
162  size_t count = this->totalSlotsSize();
163 
164  /* loop through all of the entries */
165  for (ep = this->entries, endp = ep + count; ep < endp; ep++)
166  {
167  if (ep->index != OREF_NULL) /* have a value here? */
168  {
169  memory_mark(ep->index); /* mark both the index and the */
170  memory_mark(ep->value); /* value */
171  }
172  }
173 }
174 
176 /******************************************************************************/
177 /* Function: Generalized object marking */
178 /******************************************************************************/
179 {
180  TABENTRY *ep; /* table element pointer */
181  /* hash table size */
182  size_t count = this->totalSlotsSize();
183 
184  /* loop through all of the entries */
185  for (ep = this->entries; ep < this->entries + count; ep++)
186  {
187  if (ep->index != OREF_NULL) /* have a value here? */
188  {
189  memory_mark_general(ep->index); /* mark both the index and the */
190  memory_mark_general(ep->value); /* value */
191  }
192  }
193 }
194 
196 /******************************************************************************/
197 /* Function: Flatten an object */
198 /******************************************************************************/
199 {
201  size_t count = this->totalSlotsSize(); /* hash table size */
202 
203  for (size_t i=0; i < count ; i++)
204  {
205  if (this->entries[i].index != OREF_NULL)
206  {
207  flatten_reference(newThis->entries[i].index, envelope);
208  flatten_reference(newThis->entries[i].value, envelope);
209  }
210  }
212 }
213 
215  RexxObject *_value, /* added element value */
216  RexxObject *_index) /* added index value */
217 /******************************************************************************/
218 /* Function: Add an element to a hash table. If the table needs to expand, */
219 /* the new table is returned. */
220 /******************************************************************************/
221 {
222  HashLink position = hashIndex(_index); /* calculate the hash slot */
223  /* if the hash slot is empty */
224  if (this->entries[position].index == OREF_NULL)
225  {
226  /* fill in both the value and index */
227  OrefSet(this,this->entries[position].value, _value);
228  OrefSet(this,this->entries[position].index, _index);
229  return OREF_NULL; /* successful addition */
230  }
231  /* go insert */
232  return this->insert(_value, _index, position, FULL_TABLE);
233 }
234 
236  RexxObject *_value, /* added element value */
237  RexxObject *_index) /* added index value */
238 /******************************************************************************/
239 /* Function: Add an element to a hash table. If the table needs to expand, */
240 /* the new table is returned. */
241 /******************************************************************************/
242 {
243  HashLink position = hashPrimitiveIndex(_index); /* calculate the hash slot */
244  /* if the hash slot is empty */
245  if (this->entries[position].index == OREF_NULL)
246  {
247  /* fill in both the value and index */
248  OrefSet(this,this->entries[position].value, _value);
249  OrefSet(this,this->entries[position].index, _index);
250  return OREF_NULL; /* successful addition */
251  }
252  /* go insert */
253  return this->insert(_value, _index, position, PRIMITIVE_TABLE);
254 }
255 
256 
258  RexxObject *_index) /* index to remove */
259 /******************************************************************************/
260 /* Function: Remove an element from a hash table */
261 /******************************************************************************/
262 {
263  HashLink _next; /* next hash position */
264  RexxObject *removed; /* removed item value */
265 
266  HashLink position = hashIndex(_index); /* calculate the hash slot */
267  HashLink previous = NO_LINK; /* no previous slot yet */
268  /* have an entry at this slot */
269  if (this->entries[position].index != OREF_NULL)
270  {
271  do
272  { /* while more items in chain */
273  /* get a match? */
274  if (EQUAL_VALUE(_index, this->entries[position].index))
275  {
276  /* save the current value */
277  removed = this->entries[position].value;
278  /* get the next pointer */
279  _next = this->entries[position].next;
280  if (_next == NO_MORE)
281  { /* end of the chain? */
282  /* clear this slot entry */
283  OrefSet(this,this->entries[position].index,OREF_NULL);
284  OrefSet(this,this->entries[position].value,OREF_NULL);
285  if (previous != NO_LINK) /* if not the first of the chain */
286  {
287  /* IH: In this special case we delete an item from the overhead and
288  therefore might have to increase the free counter, otherwise
289  hash table will be extended unnecessarily !!! */
290  if (position > this->free)
291  {
292  this->free = position;
293  }
294  /* break the link */
295  this->entries[previous].next = NO_MORE;
296  }
297  } /* non-terminal chain element */
298  else
299  {
300  /* close up the link */
301  this->entries[position].next = this->entries[_next].next;
302  /* copy value and index to current */
303  OrefSet(this,this->entries[position].index,this->entries[_next].index);
304  OrefSet(this,this->entries[position].value,this->entries[_next].value);
305  /* clear the next entry */
306  OrefSet(this,this->entries[_next].index,OREF_NULL);
307  OrefSet(this,this->entries[_next].value,OREF_NULL);
308  /* set to "pristine" condition */
309  this->entries[_next].next = NO_MORE;
310  if (this->free < _next) /* new-low water mark? */
311  {
312  this->free = _next; /* reset to this point */
313  }
314  }
315  return removed; /* return removed element value */
316  }
317  else
318  {
319  previous = position; /* remember previous member */
320  }
321  /* step to the next link */
322  } while ((position = this->entries[position].next) != NO_MORE);
323  }
324  return OREF_NULL; /* removed item not found */
325 }
326 
327 
328 /**
329  * Remove all elements with a given index from a hashtable,
330  * returning an array of all items.
331  *
332  * @param _index The target index.
333  *
334  * @return An array of all matching items.
335  */
337 {
338  // get a count of matching items
339  size_t count = countAll(_index);
340  HashLink position = hashIndex(_index); /* calculate the hash slot */
341  RexxArray *result = new_array(count); /* get proper size result array */
342  // only copy if we have something to remove
343  if (count > 0)
344  {
345  size_t i = 1; /* start at the first element */
346  HashLink previous = NO_LINK; /* no previous slot yet */
347  do
348  { /* while more items in chain */
349  /* copy the value into our array */
350  result->put(this->entries[position].value,i++);
351  /* if got a match */
352  if (EQUAL_VALUE(_index, this->entries[position].index))
353  {
354  /* get the next pointer */
355  HashLink _next = this->entries[position].next;
356  if (_next == NO_MORE)
357  { /* end of the chain? */
358  /* clear this slot entry */
359  OrefSet(this,this->entries[position].index,OREF_NULL);
360  OrefSet(this,this->entries[position].value,OREF_NULL);
361  if (previous != NO_LINK) /* if not the first of the chain */
362  {
363  /* IH: In this special case we delete an item from the overhead and
364  therefore might have to increase the free counter, otherwise
365  hash table will be extended unnecessarily !!! */
366  if (position > this->free)
367  {
368  this->free = position;
369  }
370  /* break the link */
371  this->entries[previous].next = NO_MORE;
372  }
373  return result; // we've hit the end of the chain, we're done
374  } /* non-terminal chain element */
375  else
376  {
377  /* close up the link */
378  this->entries[position].next = this->entries[_next].next;
379  /* copy value and index to current */
380  OrefSet(this,this->entries[position].index,this->entries[_next].index);
381  OrefSet(this,this->entries[position].value,this->entries[_next].value);
382  /* clear the next entry */
383  OrefSet(this,this->entries[_next].index,OREF_NULL);
384  OrefSet(this,this->entries[_next].value,OREF_NULL);
385  /* set to "pristine" condition */
386  this->entries[_next].next = NO_MORE;
387  if (this->free < _next) /* new-low water mark? */
388  {
389  this->free = _next; /* reset to this point */
390  }
391 
392  // NOTE: We don't update either previous or position because we'll
393  // be looking at the same link again
394  }
395  }
396  else
397  {
398  // remember the previous position and step to the next one
399  previous = position;
400  position = this->entries[position].next;
401  }
402  /* step to the next link */
403  } while (position != NO_MORE);
404  }
405  return result; /* return the result array */
406 }
407 
409  RexxObject *_index) /* index to remove */
410 /******************************************************************************/
411 /* Function: Remove an element from a hash table */
412 /******************************************************************************/
413 {
414  HashLink _next; /* next hash position */
415  RexxObject *removed; /* removed item value */
416 
417  HashLink position = hashPrimitiveIndex(_index); /* calculate the hash slot */
418 
419  HashLink previous = NO_LINK; /* no previous slot yet */
420  /* have an entry at this slot */
421  if (this->entries[position].index != OREF_NULL)
422  {
423  do
424  { /* while more items in chain */
425  /* get a match? */
426  if (_index == this->entries[position].index)
427  {
428  /* save the current value */
429  removed = this->entries[position].value;
430  /* get the next pointer */
431  _next = this->entries[position].next;
432  if (_next == NO_MORE)
433  { /* end of the chain? */
434  /* clear this slot entry */
435  OrefSet(this,this->entries[position].index,OREF_NULL);
436  OrefSet(this,this->entries[position].value,OREF_NULL);
437  if (previous != NO_LINK) /* if not the first of the chain */
438  {
439  /* IH: In this special case we delete an item from the overhead and
440  therefore might have to increase the free counter, otherwise
441  hash table will be extended unnecessarily !!! */
442  if (position > this->free)
443  {
444  this->free = position;
445  }
446  /* break the link */
447  this->entries[previous].next = NO_MORE;
448  }
449  } /* non-terminal chain element */
450  else
451  {
452  /* close up the link */
453  this->entries[position].next = this->entries[_next].next;
454  /* copy value and index to current */
455  OrefSet(this,this->entries[position].index,this->entries[_next].index);
456  OrefSet(this,this->entries[position].value,this->entries[_next].value);
457  /* clear the next entry */
458  OrefSet(this,this->entries[_next].index,OREF_NULL);
459  OrefSet(this,this->entries[_next].value,OREF_NULL);
460  /* set to "pristine" condition */
461  this->entries[_next].next = NO_MORE;
462  if (this->free < _next) /* new-low water mark? */
463  {
464  this->free = _next; /* reset to this point */
465  }
466  }
467  return removed; /* return removed element value */
468  }
469  else
470  {
471  previous = position; /* remember previous member */
472  }
473  /* step to the next link */
474  } while ((position = this->entries[position].next) != NO_MORE);
475  }
476  return OREF_NULL; /* removed item not found */
477 }
478 
480  RexxObject *_value, /* item to remove */
481  RexxObject *_index ) /* index to remove */
482 /******************************************************************************/
483 /* Function: Remove the tuple (value, item) from the hash table. If */
484 /* the item is not found, .nil is returned. */
485 /******************************************************************************/
486 {
487  HashLink _next; /* next hash position */
488  RexxObject * removed; /* removed item value */
489 
490  HashLink position = hashIndex(_index); /* calculate the hash slot */
491  HashLink previous = NO_LINK; /* no previous slot yet */
492  /* have an entry at this slot */
493  if (this->entries[position].index != OREF_NULL)
494  {
495  do
496  { /* while more items in chain */
497  /* get a match? */
498  if (EQUAL_VALUE(_index, this->entries[position].index) &&
499  EQUAL_VALUE(_value, this->entries[position].value))
500  {
501  /* save the current value */
502  removed = this->entries[position].value;
503  /* get the next pointer */
504  _next = this->entries[position].next;
505  if (_next == NO_MORE)
506  { /* end of the chain? */
507  /* clear this slot entry */
508  OrefSet(this,this->entries[position].index,OREF_NULL);
509  OrefSet(this,this->entries[position].value,OREF_NULL);
510  if (previous != NO_LINK) /* if not the first of the chain */
511  {
512  /* break the link */
513  this->entries[previous].next = NO_MORE;
514  }
515  } /* non-terminal chain element */
516  else
517  {
518  /* close up the link */
519  this->entries[position].next = this->entries[_next].next;
520  /* copy value and index to current */
521  OrefSet(this,this->entries[position].index,this->entries[_next].index);
522  OrefSet(this,this->entries[position].value,this->entries[_next].value);
523  /* clear the next entry */
524  OrefSet(this,this->entries[_next].index,OREF_NULL);
525  OrefSet(this,this->entries[_next].value,OREF_NULL);
526  /* set to "pristine" condition */
527  this->entries[_next].next = NO_MORE;
528  if (this->free < _next) /* new-low water mark? */
529  {
530  this->free = _next; /* reset to this point */
531  }
532  }
533  return removed; /* return removed element value */
534  }
535  else
536  {
537  previous = position; /* remember previous member */
538  }
539  /* step to the next link */
540  } while ((position = this->entries[position].next) != NO_MORE);
541  }
542  return OREF_NULL; /* removed item not found */
543 }
544 
545 
547  RexxObject *_value, /* item to remove */
548  RexxObject *_index ) /* index to remove */
549 /******************************************************************************/
550 /* Function: Remove the tuple (value, item) from the hash table. If */
551 /* the item is not found, .nil is returned. */
552 /******************************************************************************/
553 {
554  HashLink _next; /* next hash position */
555  RexxObject * removed; /* removed item value */
556 
557  HashLink position = hashPrimitiveIndex(_index); /* calculate the hash slot */
558  HashLink previous = NO_LINK; /* no previous slot yet */
559  /* have an entry at this slot */
560  if (this->entries[position].index != OREF_NULL)
561  {
562  do
563  { /* while more items in chain */
564  /* get a match? */
565  if (_index == this->entries[position].index && _value == this->entries[position].value)
566  {
567  /* save the current value */
568  removed = this->entries[position].value;
569  /* get the next pointer */
570  _next = this->entries[position].next;
571  if (_next == NO_MORE)
572  { /* end of the chain? */
573  /* clear this slot entry */
574  OrefSet(this,this->entries[position].index,OREF_NULL);
575  OrefSet(this,this->entries[position].value,OREF_NULL);
576  if (previous != NO_LINK) /* if not the first of the chain */
577  {
578  /* break the link */
579  this->entries[previous].next = NO_MORE;
580  }
581  } /* non-terminal chain element */
582  else
583  {
584  /* close up the link */
585  this->entries[position].next = this->entries[_next].next;
586  /* copy value and index to current */
587  OrefSet(this,this->entries[position].index,this->entries[_next].index);
588  OrefSet(this,this->entries[position].value,this->entries[_next].value);
589  /* clear the next entry */
590  OrefSet(this,this->entries[_next].index,OREF_NULL);
591  OrefSet(this,this->entries[_next].value,OREF_NULL);
592  /* set to "pristine" condition */
593  this->entries[_next].next = NO_MORE;
594  if (this->free < _next) /* new-low water mark? */
595  {
596  this->free = _next; /* reset to this point */
597  }
598  }
599  return removed; /* return removed element value */
600  }
601  else
602  {
603  previous = position; /* remember previous member */
604  }
605  /* step to the next link */
606  } while ((position = this->entries[position].next) != NO_MORE);
607  }
608  return OREF_NULL; /* removed item not found */
609 }
610 
612  RexxObject *_value, /* item to locate */
613  RexxObject *_index ) /* index to locate */
614 /******************************************************************************/
615 /* Function: Determine if a tuple (value, item) pair exists in the hash */
616 /* table. Return true if found, false other wise. */
617 /******************************************************************************/
618 {
619  HashLink position = hashPrimitiveIndex(_index); /* calculate the hash slot */
620  /* have an entry at this slot */
621  if (this->entries[position].index != OREF_NULL)
622  {
623  do
624  { /* while more items in chain */
625  /* get a match? */
626  if (_index == this->entries[position].index && _value == this->entries[position].value)
627  {
628  /* got the one we want */
629  return(RexxObject *)TheTrueObject;
630  }
631  /* step to the next link */
632  } while ((position = this->entries[position].next) != NO_MORE);
633  }
634  return(RexxObject *)TheFalseObject; /* item was not found */
635 }
636 
637 
639  RexxObject *_value) /* item to locate */
640 /******************************************************************************/
641 /* Function: Determine if a tuple (value, item) pair exists in the hash */
642 /* table. Return true if found, false other wise. */
643 /******************************************************************************/
644 {
646 }
647 
648 
650  RexxObject *_value, /* item to locate */
651  RexxObject *_index ) /* index to locate */
652 /******************************************************************************/
653 /* Function: Determine if a tuple (value, item) pair exists in the hash */
654 /* table. Return true if found, false other wise. */
655 /******************************************************************************/
656 {
657  HashLink position = hashIndex(_index); /* calculate the hash slot */
658  /* have an entry at this slot */
659  if (this->entries[position].index != OREF_NULL)
660  {
661  do
662  { /* while more items in chain */
663  /* get a match? */
664  if (EQUAL_VALUE(_index, this->entries[position].index) &&
665  EQUAL_VALUE(_value, this->entries[position].value))
666  {
667  /* got the one we want */
668  return(RexxObject *)TheTrueObject;
669  }
670  /* step to the next link */
671  } while ((position = this->entries[position].next) != NO_MORE);
672  }
673  return(RexxObject *)TheFalseObject; /* item was not found */
674 }
675 
676 
677 /**
678  * Test if an item exists in the hash collection.
679  *
680  * @param value The test value.
681  *
682  * @return .true if it exists, .false otherwise.
683  */
685 {
686  // our size
687  size_t count = this->totalSlotsSize();
688 
689  TABENTRY *ep = this->entries;
690  TABENTRY *endp = ep + count;
691  /* loop through all of the entries */
692  for (; ep < endp; ep++)
693  {
694  // if we have an item, see if it's the one we're looking for.
695  if (ep->index != OREF_NULL)
696  {
697  if (EQUAL_VALUE(_value, ep->value))
698  {
699  return TheTrueObject; // return the index value
700 
701  }
702  }
703  }
704  return TheFalseObject;
705 }
706 
707 
708 /**
709  * Removes an item from the hash table.
710  *
711  * @param value The test value.
712  *
713  * @return .true if it exists, .false otherwise.
714  */
716 {
717  // our size
718  size_t count = this->totalSlotsSize();
719 
720  TABENTRY *ep = this->entries;
721  TABENTRY *endp = ep + count;
722  /* loop through all of the entries */
723  for (; ep < endp; ep++)
724  {
725  // if we have an item, see if it's the one we're looking for.
726  if (ep->index != OREF_NULL)
727  {
728  if (EQUAL_VALUE(_value, ep->value))
729  {
730  // this is complicated, so it's easier to just remove
731  // this using the fully qualified tuple.
732  return removeItem(_value, ep->index);
733  }
734  }
735  }
736  return TheNilObject;
737 }
738 
739 
740 /**
741  * Removes an item from the hash table.
742  *
743  * @param value The test value.
744  *
745  * @return .true if it exists, .false otherwise.
746  */
748 {
749  // our size
750  size_t count = this->totalSlotsSize();
751 
752  TABENTRY *ep = this->entries;
753  TABENTRY *endp = ep + count;
754  /* loop through all of the entries */
755  for (; ep < endp; ep++)
756  {
757  // if we have an item, see if it's the one we're looking for.
758  if (ep->index != OREF_NULL)
759  {
760  if (_value == ep->value)
761  {
762  // this is complicated, so it's easier to just remove
763  // this using the fully qualified tuple.
764  return primitiveRemoveItem(_value, ep->index);
765  }
766  }
767  }
768  return TheNilObject;
769 }
770 
771 
773  RexxObject *_value, /* item to locate */
774  RexxObject *_index ) /* index to locate */
775 /******************************************************************************/
776 /* Function: Return the next item with the key index that follows the */
777 /* given (value index) pair. Used only for superscope lookup. */
778 /* Note: This routine does the comparisons in as fast as way */
779 /* as possible, relying solely on object identify for a match. */
780 /******************************************************************************/
781 {
782  RexxObject *scope; /* returned scope */
783 
784  HashLink position = hashIndex(_index); /* calculate the hash slot */
785  /* have an entry at this slot */
786  if (this->entries[position].index != OREF_NULL)
787  {
788  do
789  { /* while more items in chain */
790  /* get a match? */
791  if (this->entries[position].index == _index && this->entries[position].value == _value)
792  {
793  while ((position = this->entries[position].next) != NO_MORE)
794  {
795  /* same index value? */
796  if (this->entries[position].index == _index)
797  {
798  /* this is the value we want */
799  return this->entries[position].value;
800  }
801  }
802  return TheNilObject; /* didn't find what we wanted */
803  }
804  /* step to the next link */
805  } while ((position = this->entries[position].next) != NO_MORE);
806  /* must be added via setmethod, so */
807  scope = this->primitiveGet(_index);/* return first one for this index */
808  /* truely not there? */
809  if (scope == (RexxObject *)OREF_NULL)
810  {
811  return TheNilObject; /* return a failure */
812  }
813  return scope; /* return the first scope */
814  }
815  return TheNilObject; /* item was not found */
816 }
817 
818 
820  RexxObject *_value, /* item to locate */
821  RexxObject *_index ) /* index to locate */
822 /******************************************************************************/
823 /* Function: Return the next item with the key index that follows the */
824 /* given (value index) pair. Used only for superscope lookup. */
825 /* Note: This routine does the comparisons in as fast as way */
826 /* as possible, relying solely on object identify for a match. */
827 /******************************************************************************/
828 {
829  RexxObject *scope; /* returned scope */
830 
831  HashLink position = hashPrimitiveIndex(_index); /* calculate the hash slot */
832  /* have an entry at this slot */
833  if (this->entries[position].index != OREF_NULL)
834  {
835  do
836  { /* while more items in chain */
837  /* get a match? */
838  if (this->entries[position].index == _index && this->entries[position].value == _value)
839  {
840  while ((position = this->entries[position].next) != NO_MORE)
841  {
842  /* same index value? */
843  if (this->entries[position].index == _index)
844  {
845  /* this is the value we want */
846  return this->entries[position].value;
847  }
848  }
849  return TheNilObject; /* didn't find what we wanted */
850  }
851  /* step to the next link */
852  } while ((position = this->entries[position].next) != NO_MORE);
853  /* must be added via setmethod, so */
854  scope = this->primitiveGet(_index); /* return first one for this index */
855  /* truely not there? */
856  if (scope == (RexxObject *)OREF_NULL)
857  {
858  return TheNilObject; /* return a failure */
859  }
860  return scope; /* return the first scope */
861  }
862  return TheNilObject; /* item was not found */
863 }
864 
866  RexxObject *_index) /* target index */
867 /******************************************************************************/
868 /* Function: Get all elements with a specified index as an array */
869 /******************************************************************************/
870 {
871  // get a count of matching items
872  size_t count = countAll(_index);
873  HashLink position = hashIndex(_index); /* calculate the hash slot */
874  RexxArray *result = new_array(count); /* get proper size result array */
875  // only copy if we have something to copy
876  if (count > 0)
877  {
878  size_t i = 1; /* start at the first element */
879  position = hashIndex(_index); /* calculate the hash slot */
880  do
881  { /* while more items in chain */
882  /* if got a match */
883  if (EQUAL_VALUE(_index, this->entries[position].index))
884  {
885  /* copy the value into our array */
886  result->put(this->entries[position].value,i++);
887  }
888  /* step to the next link */
889  } while ((position = this->entries[position].next) != NO_MORE);
890  }
891  return result; /* return the result array */
892 }
893 
894 /**
895  * Return a count of all items with a given index.
896  *
897  * @param _index The target index
898  *
899  * @return The count of matching items.
900  */
902 {
903  size_t count = 0; /* no items found yet */
904  HashLink position = hashIndex(_index); /* calculate the hash slot */
905  /* have an entry at this slot */
906  if (this->entries[position].index != OREF_NULL)
907  {
908  do
909  { /* while more items in chain */
910  /* if got a match */
911  if (EQUAL_VALUE(_index, this->entries[position].index))
912  {
913  count++; /* bump our counter */
914  }
915  /* step to the next link */
916  } while ((position = this->entries[position].next) != NO_MORE);
917  return count;
918  }
919  else
920  {
921  /* no elements found */
922  return 0;
923  }
924 }
925 
927  RexxObject *_index) /* target index */
928 /******************************************************************************/
929 /* Function: Get all elements with a specified index as an array */
930 /******************************************************************************/
931 {
932  size_t count = 0; /* no items found yet */
933  HashLink position = hashPrimitiveIndex(_index); /* calculate the hash slot */
934  /* have an entry at this slot */
935  if (this->entries[position].index != OREF_NULL)
936  {
937  do
938  { /* while more items in chain */
939  /* if got a match */
940  if (_index == this->entries[position].index)
941  {
942  count++; /* bump our counter */
943  }
944  /* step to the next link */
945  } while ((position = this->entries[position].next) != NO_MORE);
946  }
947  else
948  {
949  /* no elements found */
950  return(RexxArray *)TheNullArray->copy();
951  }
952 
953  RexxArray *result = new_array(count); /* get proper size result array */
954  size_t i = 1; /* start at the first element */
955  position = hashPrimitiveIndex(_index); /* calculate the hash slot */
956  do
957  { /* while more items in chain */
958  /* if got a match */
959  if (_index == this->entries[position].index)
960  {
961  /* copy the value into our array */
962  result->put(this->entries[position].value,i++);
963  }
964  /* step to the next link */
965  } while ((position = this->entries[position].next) != NO_MORE);
966  return result; /* return the result array */
967 }
968 
970  RexxString *_index) /* target index */
971 /******************************************************************************/
972 /* Function: Return an array of all value with the same index (using string */
973 /* lookup semantics) */
974 /******************************************************************************/
975 {
976  const char *data = _index->getStringData(); /* get the string data */
977  sizeB_t length = _index->getBLength(); /* and the length also */
978  size_t count = 0; /* no items found yet */
979  HashLink position = hashStringIndex(_index); /* calculate the hash slot */
980  /* have an entry at this slot */
981  if (this->entries[position].index != OREF_NULL)
982  {
983  do
984  { /* while more items in chain */
985  /* get the entry */
986  RexxString *entry = (RexxString *)this->entries[position].index;
987  /* if got a match */
988  if (_index == entry || entry->memCompare(data, length)) // todo m17n
989  {
990  count++; /* bump our counter */
991  }
992  /* step to the next link */
993  } while ((position = this->entries[position].next) != NO_MORE);
994  }
995  else
996  {
997  /* no elements found */
998  return(RexxArray *)TheNullArray->copy();
999  }
1000 
1001  RexxArray *result = new_array(count); /* get proper size result array */
1002  size_t i = 1; /* start at the first element */
1003  position = hashIndex(_index); /* calculate the hash slot */
1004  do
1005  { /* while more items in chain */
1006  /* get the entry */
1007  RexxString *entry = (RexxString *)this->entries[position].index;
1008  /* if got a match */
1009  if (_index == entry || entry->memCompare(data, length)) // todo m17n
1010  {
1011  /* copy the value into our array */
1012  result->put(this->entries[position].value,i++);
1013  }
1014  /* step to the next link */
1015  } while ((position = this->entries[position].next) != NO_MORE);
1016  return result; /* return the result array */
1017 }
1018 
1020  RexxObject *_value) /* target value item */
1021 /******************************************************************************/
1022 /* Function: Return all index items that match the associated value */
1023 /* item. */
1024 /******************************************************************************/
1025 {
1026  size_t count = 0; /* no items found yet */
1027  size_t i;
1028  /* loop through them all */
1029  for (i = this->totalSlotsSize(); i > 0; i--)
1030  {
1031  /* real entry? */
1032  if (this->entries[i - 1].index != OREF_NULL)
1033  {
1034  /* is this the item we want? */
1035  if (EQUAL_VALUE(_value, this->entries[i - 1].value))
1036  {
1037  count++; /* bump our counter */
1038  }
1039  }
1040  }
1041 
1042  RexxArray *result = new_array(count); /* get proper size result array */
1043  size_t j = 1; /* start at the first element */
1044  /* loop through them all */
1045  for (i = this->totalSlotsSize(); i > 0; i--)
1046  {
1047  /* real entry? */
1048  if (this->entries[i - 1].index != OREF_NULL)
1049  {
1050  /* is this the item we want? */
1051  if (EQUAL_VALUE(_value, this->entries[i - 1].value))
1052  {
1053  /* copy the value into our array */
1054  result->put(this->entries[i - 1].index, j++);
1055  }
1056  }
1057  }
1058  return result; /* return the result array */
1059 }
1060 
1061 
1063  RexxObject *_value) /* target object */
1064 /******************************************************************************/
1065 /* Function: Return an index associated with the supplied item. The result */
1066 /* is undefined for items that are referenced by multiple */
1067 /* indices. */
1068 /******************************************************************************/
1069 {
1070  RexxObject *result = OREF_NULL; /* no item yet */
1071  /* loop through them all */
1072  for (size_t i = this->totalSlotsSize(); i > 0; i--)
1073  {
1074  /* real entry? */
1075  if (this->entries[i - 1].index != OREF_NULL)
1076  {
1077  /* is this the item we want? */
1078  if (EQUAL_VALUE(_value, this->entries[i - 1].value))
1079  {
1080  /* get the index */
1081  result = this->entries[i - 1].index;
1082  break; /* finished */
1083  }
1084  }
1085  }
1086  return result; /* return the count */
1087 }
1088 
1089 
1091  RexxObject *_value) /* target object */
1092 /******************************************************************************/
1093 /* Function: Return an index associated with the supplied item. The result */
1094 /* is undefined for items that are referenced by multiple */
1095 /* indices. */
1096 /******************************************************************************/
1097 {
1098  RexxObject *result = OREF_NULL; /* no item yet */
1099  /* loop through them all */
1100  for (size_t i = this->totalSlotsSize(); i > 0; i--)
1101  {
1102  /* real entry? */
1103  if (this->entries[i - 1].index != OREF_NULL)
1104  {
1105  /* is this the item we want? */
1106  if (_value == this->entries[i - 1].value)
1107  {
1108  /* get the index */
1109  result = this->entries[i - 1].index;
1110  break; /* finished */
1111  }
1112  }
1113  }
1114  return result; /* return the count */
1115 }
1116 
1117 
1119  RexxObject *_index) /* index of target item */
1120 /******************************************************************************/
1121 /* Function: Get an item from a hash table */
1122 /******************************************************************************/
1123 {
1124  HashLink position = hashIndex(_index); /* calculate the hash slot */
1125  /* have an entry at this slot */
1126  if (this->entries[position].index != OREF_NULL)
1127  {
1128  do
1129  { /* while more items in chain */
1130  /* if got a match */
1131  if (EQUAL_VALUE(_index, this->entries[position].index))
1132  {
1133  /* return this item's value */
1134  return this->entries[position].value;
1135  }
1136  /* step to the next link */
1137  } while ((position = this->entries[position].next) != NO_MORE);
1138  }
1139  return OREF_NULL; /* no value found */
1140 }
1141 
1143  RexxObject *_index) /* index of target item */
1144 /******************************************************************************/
1145 /* Function: Get an item from a hash table */
1146 /******************************************************************************/
1147 {
1148  HashLink position = hashPrimitiveIndex(_index); /* calculate the hash slot */
1149  /* have an entry at this slot */
1150  if (this->entries[position].index != OREF_NULL)
1151  {
1152  do
1153  { /* while more items in chain */
1154  /* if got a match */
1155  if (_index == this->entries[position].index)
1156  {
1157  /* return this item's value */
1158  return this->entries[position].value;
1159  }
1160  /* step to the next link */
1161  } while ((position = this->entries[position].next) != NO_MORE);
1162  }
1163  return OREF_NULL; /* no value found */
1164 }
1165 
1167  RexxObject *_value, /* value to insert */
1168  RexxObject * _index, /* index to insert */
1169  HashLink position, /* insertion position */
1170  int type ) /* string type insertion */
1171 /******************************************************************************/
1172 /* Function: Insert an element into an overflow location of a hash table */
1173 /******************************************************************************/
1174 {
1175  HashLink over; /* overflow slot location */
1176  RexxHashTable *newHash; /* newly created hash table */
1177  TABENTRY *primeEntry = &(this->entries[position]);
1178 
1179  HashLink low = this->mainSlotsSize(); /* get low free bound */
1180  for (over = this->free; /* look for overflow slot */
1181  over >= low;
1182  over--)
1183  {
1184  TABENTRY *entry = &(this->entries[over]);
1185  /* find an empty slot? */
1186  if (entry->index == OREF_NULL)
1187  {
1188  /* insert after hash slot */
1189  entry->next = primeEntry->next;
1190  /* copy current index and value */
1191  /* to the overflow slot */
1192  OrefSet(this, entry->value, primeEntry->value);
1193  OrefSet(this, entry->index, primeEntry->index);
1194  /* set the new values in the first */
1195  /* chain entry */
1196  OrefSet(this, primeEntry->value, _value);
1197  OrefSet(this, primeEntry->index, _index);
1198  /* set the overflow location */
1199  primeEntry->next = over;
1200  this->free = over-1; /* update free pointer */
1201  return OREF_NULL; /* this was a successful addition */
1202  }
1203  }
1204  /* allocate a larger hash table */
1205  newHash = new_hashtab(this->totalSlotsSize() * 2);
1206  ProtectedObject p(newHash);
1207  switch (type)
1208  { /* remerge based on the type */
1209 
1210  case STRING_TABLE: /* string based table */
1211  this->stringMerge(newHash); /* do a string merge */
1212  break;
1213 
1214  case PRIMITIVE_TABLE: /* primitive object table */
1215  this->primitiveMerge(newHash); /* do a primitive merge */
1216  break;
1217 
1218  case FULL_TABLE: /* full table look ups */
1219  this->reMerge(newHash); /* do a normal merge */
1220  break;
1221  }
1222 
1223  // primitive tables require a primitive index.
1224  if (type == PRIMITIVE_TABLE)
1225  {
1226  position = newHash->hashPrimitiveIndex(_index);/* calculate the hash slot */
1227  }
1228  else
1229  {
1230 
1231  position = newHash->hashIndex(_index);/* calculate the hash slot */
1232  }
1233  /* if the hash slot is empty */
1234  if (newHash->entries[position].index == OREF_NULL)
1235  {
1236  /* fill in both the value and index */
1237  OrefSet(newHash, newHash->entries[position].value, _value);
1238  OrefSet(newHash, newHash->entries[position].index, _index);
1239  }
1240  else
1241  {
1242  /* try to insert again */
1243  newHash->insert(_value, _index, position, type);
1244  }
1245  return newHash; /* return the new hash */
1246 }
1247 
1249  RexxObject *_value, /* added element value */
1250  RexxString *_index) /* added index value */
1251 /******************************************************************************/
1252 /* Function: Add an element to a hash table, using only string searches */
1253 /******************************************************************************/
1254 {
1255  HashLink position = hashStringIndex(_index); /* calculate the hash slot */
1256  /* if the hash slot is empty */
1257  if (this->entries[position].index == OREF_NULL)
1258  {
1259  /* fill in both the value and index */
1260  OrefSet(this, this->entries[position].value, _value);
1261  OrefSet(this, this->entries[position].index, _index);
1262  return OREF_NULL; /* successful addition */
1263  }
1264  else /* hash slot is full */
1265  {
1266  /* go insert */
1267  return this->insert(_value, _index, position, STRING_TABLE);
1268  }
1269 }
1270 
1272  RexxString *_index) /* index of target item */
1273 /******************************************************************************/
1274 /* Function: Search a hash table, restricting the search to string items. */
1275 /******************************************************************************/
1276 {
1277  const char *data = _index->getStringData(); /* get the string data */
1278  sizeB_t length = _index->getBLength(); /* and the length also */
1279 
1280  HashLink position = hashStringIndex(_index); /* calculate the hash slot */
1281  /* have an entry at this slot */
1282  if (this->entries[position].index != OREF_NULL)
1283  {
1284  do
1285  { /* while more items in chain */
1286  /* get the entry */
1287  RexxString *entry = (RexxString *)this->entries[position].index;
1288  /* if got a match */
1289  if (_index == entry || entry->memCompare(data, size_v(length))) // todo m17n
1290  {
1291  /* return this item's value */
1292  return this->entries[position].value;
1293  }
1294  /* step to the next link */
1295  } while ((position = this->entries[position].next) != NO_MORE);
1296  }
1297  return OREF_NULL; /* no value found */
1298 }
1299 
1301  RexxObject *_value, /* value of the item */
1302  RexxString *_index) /* target index */
1303 /******************************************************************************/
1304 /* Function: Add a value to a table, searching only for character string */
1305 /* matches. */
1306 /******************************************************************************/
1307 {
1308  const char *data = _index->getStringData(); /* get the string data */
1309  sizeB_t length = _index->getBLength(); /* and the length also */
1310 
1311  HashLink position = hashStringIndex(_index); /* calculate the hash slot */
1312  /* have an entry at this slot */
1313  if (this->entries[position].index != OREF_NULL)
1314  {
1315  HashLink front = position; /* save the starting location */
1316  do
1317  { /* while more items in chain */
1318  /* get the entry */
1319  RexxString *entry = (RexxString *)this->entries[position].index;
1320  /* if got a match */
1321  if (_index == entry || entry->memCompare(data, size_v(length))) // todo m17n
1322  {
1323  /* set a new value */
1324  OrefSet(this, this->entries[position].value, _value);
1325  return OREF_NULL; /* indicate success */
1326  }
1327  /* step to the next link */
1328  } while ((position = this->entries[position].next) != NO_MORE);
1329  /* go insert */
1330  return this->insert(_value, _index, front, STRING_TABLE);
1331  }
1332  else
1333  { /* empty at this slot */
1334  /* fill in both the value and index */
1335  OrefSet(this,this->entries[position].value, _value);
1336  OrefSet(this,this->entries[position].index, _index);
1337  return OREF_NULL; /* successful addition */
1338  }
1339 }
1340 
1342  RexxObject *_value, /* value of the item */
1343  RexxObject *_index) /* target index */
1344 /******************************************************************************/
1345 /* Function: Add or replace an entry in the hash table. This will return */
1346 /* a new hash table if there is an overflow situation. */
1347 /******************************************************************************/
1348 {
1349  HashLink position = hashIndex(_index); /* calculate the hash slot */
1350  /* have an entry at this slot */
1351  if (this->entries[position].index != OREF_NULL)
1352  {
1353  HashLink front = position; /* save the starting position */
1354  do
1355  { /* while more items in chain */
1356  /* if got a match */
1357  if (EQUAL_VALUE(_index, this->entries[position].index))
1358  {
1359  /* set a new value */
1360  OrefSet(this,this->entries[position].value, _value);
1361  return OREF_NULL; /* indicate success */
1362  }
1363  /* step to the next link */
1364  } while ((position = this->entries[position].next) != NO_MORE);
1365  /* go insert */
1366  return this->insert(_value, _index, front, FULL_TABLE);
1367  }
1368  else
1369  { /* empty at this slot */
1370  /* fill in both the value and index */
1371  OrefSet(this,this->entries[position].value, _value);
1372  OrefSet(this,this->entries[position].index, _index);
1373  return OREF_NULL; /* successful addition */
1374  }
1375 }
1376 
1378  RexxObject *_value, /* value of the item */
1379  RexxObject *_index) /* target index */
1380 /******************************************************************************/
1381 /* Function: Add or replace an entry in the hash table. This will return */
1382 /* a new hash table if there is an overflow situation. */
1383 /******************************************************************************/
1384 {
1385  HashLink position = hashPrimitiveIndex(_index); /* calculate the hash slot */
1386  /* have an entry at this slot */
1387  if (this->entries[position].index != OREF_NULL)
1388  {
1389  HashLink front = position; /* save the starting position */
1390  do
1391  { /* while more items in chain */
1392  /* if got a match */
1393  if (_index == this->entries[position].index)
1394  {
1395  /* set a new value */
1396  OrefSet(this,this->entries[position].value, _value);
1397  return OREF_NULL; /* indicate success */
1398  }
1399  /* step to the next link */
1400  } while ((position = this->entries[position].next) != NO_MORE);
1401  /* go insert */
1402  return this->insert(_value, _index, front, PRIMITIVE_TABLE);
1403  }
1404  else
1405  { /* empty at this slot */
1406  /* fill in both the value and index */
1407  OrefSet(this,this->entries[position].value, _value);
1408  OrefSet(this,this->entries[position].index, _index);
1409  return OREF_NULL; /* successful addition */
1410  }
1411 }
1412 
1414  RexxObject *_value, /* value of the item */
1415  RexxObject *_index) /* target index */
1416 /******************************************************************************/
1417 /* Function: Add an entry to a hash table, making sure there are no */
1418 /* duplicate entries. */
1419 /******************************************************************************/
1420 {
1421  HashLink position = hashIndex(_index); /* calculate the hash slot */
1422  /* have an entry at this slot */
1423  if (this->entries[position].index != OREF_NULL)
1424  {
1425  HashLink front = position; /* save the starting point */
1426  do
1427  { /* while more items in chain */
1428  /* if got match on index and value */
1429  if (EQUAL_VALUE(_index, this->entries[position].index) && this->entries[position].value == _value)
1430  {
1431  return OREF_NULL; /* indicate success */
1432  }
1433  /* step to the next link */
1434  } while ((position = this->entries[position].next) != NO_MORE);
1435  /* go insert */
1436  return this->insert(_value, _index, front, FULL_TABLE);
1437  }
1438  else
1439  { /* empty at this slot */
1440  /* fill in both the value and index */
1441  OrefSet(this,this->entries[position].value, _value);
1442  OrefSet(this,this->entries[position].index, _index);
1443  return OREF_NULL; /* successful addition */
1444  }
1445 }
1446 
1448  HashLink position) /* target position */
1449 /******************************************************************************/
1450 /* Function: Return the value associated with a numeric index. */
1451 /******************************************************************************/
1452 {
1453  /* within the bounds? */
1454  if (position < this->totalSlotsSize())
1455  {
1456  /* return the entry value */
1457  return this->entries[position].value;
1458  }
1459  else
1460  {
1461  return OREF_NULL; /* return nothing */
1462  }
1463 }
1464 
1466 /******************************************************************************/
1467 /* Function: Return the count of entries in a hash table. */
1468 /******************************************************************************/
1469 {
1470  size_t result = 0; /* no items yet */
1471  /* loop through them all */
1472  for (size_t i = this->totalSlotsSize(); i > 0; i--)
1473  {
1474  /* real entry? */
1475  if (this->entries[i - 1].index != OREF_NULL)
1476  {
1477  result++; /* count it! */
1478  }
1479  }
1480  return result; /* return the count */
1481 }
1482 
1483 
1485  RexxHashTableCollection *target) /* target other collection */
1486 /******************************************************************************/
1487 /* Function: Merge a hash table into another collection target. */
1488 /******************************************************************************/
1489 {
1490  /* loop through them all */
1491  for (size_t i = this->totalSlotsSize(); i > 0; i--)
1492  {
1493  /* is this a real entry? */
1494  if (this->entries[i - 1].index != OREF_NULL)
1495  {
1496  /* merge into the target collection */
1497  target->mergeItem(this->entries[i - 1].value,this->entries[i - 1].index);
1498  }
1499  }
1500  return OREF_NULL; /* always returns nothing */
1501 }
1502 
1503 
1505  RexxHashTable *newHash) /* target other collection */
1506 /******************************************************************************/
1507 /* Function: Merge a hash table into another hash table after a table */
1508 /* expansion. */
1509 /******************************************************************************/
1510 {
1511  /* loop through them all */
1512  for (size_t i = this->totalSlotsSize(); i > 0; i--)
1513  {
1514  /* is this a real entry? */
1515  if (this->entries[i - 1].index != OREF_NULL)
1516  {
1517  /* add this item to the new hash */
1518  newHash->add(this->entries[i - 1].value, this->entries[i - 1].index);
1519  }
1520  }
1521 }
1522 
1524  RexxHashTable *newHash) /* target other collection */
1525 /******************************************************************************/
1526 /* Function: Merge a hash table into another hash table after a table */
1527 /* expansion. */
1528 /******************************************************************************/
1529 {
1530  /* loop through them all */
1531  for (size_t i = this->totalSlotsSize(); i > 0; i--)
1532  {
1533  /* is this a real entry? */
1534  if (this->entries[i - 1].index != OREF_NULL)
1535  {
1536  /* add this item to the new hash */
1537  newHash->primitiveAdd(this->entries[i - 1].value, this->entries[i - 1].index);
1538  }
1539  }
1540 }
1541 
1543  RexxHashTable *target) /* target other collection */
1544 /******************************************************************************/
1545 /* Function: Merge a string based hash table into another */
1546 /******************************************************************************/
1547 {
1548  /* loop through them all */
1549  for (size_t i = this->totalSlotsSize(); i > 0; i--)
1550  {
1551  /* is this a real entry? */
1552  if (this->entries[i - 1].index != OREF_NULL)
1553  {
1554  /* merge into the target collection */
1555  target->stringAdd(this->entries[i - 1].value, (RexxString *)this->entries[i - 1].index);
1556  }
1557  }
1558  return OREF_NULL; /* always returns nothing */
1559 }
1560 
1562 /******************************************************************************/
1563 /* Function: Return the index of the first item in the hash table */
1564 /******************************************************************************/
1565 {
1566  /* loop until first item is found or */
1567  /* we reach the end of the table */
1568  HashLink i;
1569  for (i = 0; i < this->totalSlotsSize() && this->entries[i].index == OREF_NULL; i++) ;
1570  return i; /* return the position */
1571 }
1572 
1574  HashLink position) /* current index position */
1575 /******************************************************************************/
1576 /* Function: Return the index of the "next" item after an index */
1577 /******************************************************************************/
1578 {
1579  /* loop until first item is found or */
1580  /* we reach the end of the table */
1581  HashLink i;
1582  for (i = position+1; i < this->totalSlotsSize() && this->entries[i].index == OREF_NULL; i++) ;
1583  return i; /* return the position */
1584 }
1585 
1587  RexxObject *_value, /* value to add */
1588  RexxObject *_index) /* index location */
1589 /******************************************************************************/
1590 /* Function: Merge an individual item into this hash table */
1591 /******************************************************************************/
1592 {
1593  this->putNodupe(_value, _index); /* add without duplicating */
1594  return OREF_NULL; /* always return nothing */
1595 }
1596 
1598  RexxObject *_value, /* value to replace */
1599  HashLink position) /* position to replace */
1600 /******************************************************************************/
1601 /* Function: Replace an item with a new value */
1602 /******************************************************************************/
1603 {
1604  /* just set the new value */
1605  OrefSet(this,this->entries[position].value, _value);
1606  return OREF_NULL; /* always return nothing */
1607 }
1608 
1610 /******************************************************************************/
1611 /* Function: Create an array containing the hash table values */
1612 /******************************************************************************/
1613 {
1614  RexxArray *result = new_array(items()); /* get a new array */
1615  size_t j = 0; /* set the insertion point */
1616  /* loop through all of the items */
1617  for (size_t i = 0; i < this->totalSlotsSize(); i++)
1618  {
1619  /* real entry? */
1620  if (this->entries[i].index != OREF_NULL)
1621  {
1622  /* copy the value into the array */
1623  result->put(this->entries[i].value, ++j);
1624  }
1625  }
1626  return result; /* return the result array */
1627 }
1628 
1629 
1630 /**
1631  * count the number of items in the hash table.
1632  *
1633  * @return The item count.
1634  */
1636 {
1637  size_t count = 0;
1638 
1639  for (size_t i = 0; i < this->totalSlotsSize(); i++)
1640  {
1641 
1642  if (this->entries[i].index != OREF_NULL)
1643  {
1644  count++;
1645  }
1646  }
1647  return count;
1648 }
1649 
1650 
1651 /**
1652  * Empty an individual hashtable bucket. This will clear
1653  * the entire chain.
1654  *
1655  * @param position The hash table bucket to clear.
1656  */
1658 {
1659  if (this->entries[position].index != OREF_NULL)
1660  {
1661  // we have an initial link, so clear those entries out
1662  OrefSet(this,this->entries[position].index,OREF_NULL);
1663  OrefSet(this,this->entries[position].value,OREF_NULL);
1664  // we have at least a head element, so run the chain
1665  // clearing everything out
1666 
1667  // step to the next link. The remainder are cleared out and
1668  // returned to the free pool.
1669  HashLink _next = entries[position].next;
1670  // and make sure the link is severed.
1671  entries[position].next = NO_MORE;
1672  while (_next != NO_MORE)
1673  {
1674  position = _next;
1675  // clear the entries out
1676  OrefSet(this,this->entries[position].index,OREF_NULL);
1677  OrefSet(this,this->entries[position].value,OREF_NULL);
1678 
1679  // get the next link, and clear the link info in the current
1680  _next = entries[position].next;
1681  entries[position].next = NO_MORE;
1682  // if this creates a new highwater mark, move the free pointer.
1683  if (position > this->free)
1684  {
1685  this->free = position;
1686  }
1687 
1688  }
1689  }
1690 }
1691 
1692 
1693 /**
1694  * Empty a HashTable.
1695  */
1697 {
1698  // run the main hash bucket clearing the links
1699  for (HashLink i = 0; i < mainSlotsSize(); i++)
1700  {
1701  emptySlot(i);
1702  }
1703 }
1704 
1705 
1706 /**
1707  * Test if the hash table is empty.
1708  *
1709  * @return
1710  */
1712 {
1713  return items() == 0;
1714 }
1715 
1716 
1717 
1718 
1720 /******************************************************************************/
1721 /* Function: Create an array containing the hash table indexes. */
1722 /******************************************************************************/
1723 {
1724  // this just returns the index values
1725  return this->allIndexes();
1726 }
1727 
1728 
1730 /******************************************************************************/
1731 /* Function: Create an array containing the hash table indexes. */
1732 /******************************************************************************/
1733 {
1734  RexxArray *result = new_array(items()); /* get a new array */
1735  size_t j = 0; /* set the insertion point */
1736  /* loop through all of the items */
1737  for (size_t i = 0; i < this->totalSlotsSize(); i++)
1738  {
1739  /* real entry? */
1740  if (this->entries[i].index != OREF_NULL)
1741  {
1742  /* copy the index into the array */
1743  result->put(this->entries[i].index, ++j);
1744  }
1745  }
1746  return result; /* return the result array */
1747 }
1748 
1749 /**
1750  * Return an array containing the unique indexes of a
1751  * Relation object.
1752  *
1753  * @return An array with the set of unique index values
1754  */
1756 {
1757  RexxTable *indexSet = new_table();
1758  ProtectedObject p(indexSet);
1759  size_t j = 0; /* set the insertion point */
1760  // loop through all of the items
1761  for (size_t i = 0; i < this->totalSlotsSize(); i++)
1762  {
1763  // add the index for every entry to the accumulator
1764  if (this->entries[i].index != OREF_NULL)
1765  {
1766  indexSet->put(TheNilObject, this->entries[i].index);
1767  }
1768  }
1769  // now return the reduced index set
1770  return indexSet->allIndexes();
1771 }
1772 
1773 
1775 /******************************************************************************/
1776 /* Function: create a supplier from a hash table */
1777 /******************************************************************************/
1778 {
1779  size_t count = items(); /* no items yet */
1780 
1781  RexxArray *values = new_array(count); /* get a new array */
1782  RexxArray *indexes = new_array(count); /* and an index array */
1783  size_t j = 1; /* set the insertion point */
1784  /* loop through all of the items */
1785  for (size_t i = 0; i < this->totalSlotsSize(); i++)
1786  {
1787  /* real entry? */
1788  if (this->entries[i].index != OREF_NULL)
1789  {
1790  /* copy the index into the array */
1791  indexes->put(this->entries[i].index, j);
1792  /* and the value */
1793  values->put(this->entries[i].value, j);
1794  j++; /* step the array location */
1795  }
1796  }
1797  /* return the supplier */
1798  return(RexxSupplier *)new_supplier(values, indexes);
1799 }
1800 
1802  HashLink position) /* return an index item for position */
1803 /******************************************************************************/
1804 /* Function: Return the item associated with a numeric hash table index */
1805 /******************************************************************************/
1806 {
1807  /* if within bounds */
1808  if (position < this->totalSlotsSize())
1809  {
1810  /* return the index item */
1811  return this->entries[position].index;
1812  }
1813  else
1814  {
1815  return OREF_NULL; /* otherwise, no item for this */
1816  }
1817 }
1818 
1820 /******************************************************************************/
1821 /* Function: Rehash the elements of a hash table because of a restore */
1822 /******************************************************************************/
1823 {
1824  /* Assume the same size will work, */
1825  RexxHashTable *newHash = new_hashtab(this->totalSlotsSize());
1826  /* should in MOST cases.... */
1827  for (size_t i = this->totalSlotsSize(); i > 0; i--)
1828  {
1829  if (this->entries[i - 1].index != OREF_NULL)
1830  {
1831  RexxHashTable *expandHash = newHash->add(this->entries[i - 1].value, this->entries[i - 1].index);
1832  if (expandHash != OREF_NULL) /* have a reallocation occur? */
1833  {
1834  newHash = expandHash; /* finish up with the new table */
1835  }
1836  }
1837  }
1838  return newHash; /* Return the updated(rehashed) hashtable*/
1839 }
1840 
RexxArray * new_array(size_t s)
Definition: ArrayClass.hpp:259
@ T_HashTable
#define TheHashTableBehaviour
#define OREF_NULL
Definition: RexxCore.h:60
#define TheNullArray
Definition: RexxCore.h:183
#define OrefSet(o, r, v)
Definition: RexxCore.h:94
#define TheTrueObject
Definition: RexxCore.h:186
#define TheNilObject
Definition: RexxCore.h:181
#define TheFalseObject
Definition: RexxCore.h:185
bool EQUAL_VALUE(RexxObject *value, RexxObject *other)
const HashLink NO_MORE
const HashLink NO_LINK
size_t HashLink
RexxHashTable * new_hashtab(size_t s)
RexxMemory memoryObject
Definition: RexxMemory.cpp:85
#define memory_mark(oref)
Definition: RexxMemory.hpp:445
RexxObject * new_object(size_t s)
Definition: RexxMemory.hpp:431
#define flatten_reference(oref, envel)
Definition: RexxMemory.hpp:493
size_t roundObjectBoundary(size_t n)
Definition: RexxMemory.hpp:95
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:446
#define cleanUpFlatten
Definition: RexxMemory.hpp:479
#define setUpFlatten(type)
Definition: RexxMemory.hpp:473
RexxSupplier * new_supplier(RexxArray *c, RexxArray *f)
RexxTable * new_table()
Definition: TableClass.hpp:76
void put(RexxObject *eref, size_t pos)
Definition: ArrayClass.cpp:208
virtual RexxObject * mergeItem(RexxObject *, RexxObject *)
RexxHashTable * contents
virtual RexxObject * put(RexxObject *, RexxObject *)
RexxSupplier * supplier()
size_t countAll(RexxObject *key)
RexxHashTable * add(RexxObject *value, RexxObject *key)
size_t mainSlotsSize()
RexxObject * primitiveGet(RexxObject *key)
RexxObject * primitiveRemoveItem(RexxObject *value, RexxObject *key)
RexxObject * primitiveRemove(RexxObject *key)
RexxObject * getIndex(RexxObject *value)
RexxHashTable * primitiveAdd(RexxObject *value, RexxObject *key)
RexxObject * merge(RexxHashTableCollection *target)
RexxArray * getAll(RexxObject *key)
RexxArray * primitiveGetAll(RexxObject *key)
RexxHashTable * stringPut(RexxObject *value, RexxString *key)
void reMerge(RexxHashTable *target)
RexxArray * makeArray()
RexxObject * index(HashLink position)
RexxHashTable * putNodupe(RexxObject *value, RexxObject *key)
void primitiveMerge(RexxHashTable *target)
void emptySlot(HashLink)
RexxObject * nextItem(RexxObject *, RexxObject *)
HashLink hashIndex(RexxObject *obj)
RexxObject * primitiveHasItem(RexxObject *, RexxObject *)
RexxObject * stringMerge(RexxHashTable *target)
RexxHashTable * primitivePut(RexxObject *value, RexxObject *key)
size_t totalSlotsSize()
RexxArray * allItems()
HashLink first()
RexxHashTable * stringAdd(RexxObject *value, RexxString *key)
void liveGeneral(int reason)
RexxHashTable * put(RexxObject *value, RexxObject *key)
HashLink hashPrimitiveIndex(RexxObject *obj)
TABENTRY entries[1]
RexxArray * uniqueIndexes()
RexxObject * hasItem(RexxObject *value, RexxObject *key)
RexxObject * mergeItem(RexxObject *value, RexxObject *index)
RexxObject * primitiveNextItem(RexxObject *, RexxObject *)
RexxObject * remove(RexxObject *key)
RexxObject * removeItem(RexxObject *value, RexxObject *key)
RexxArray * allIndexes()
HashLink hashStringIndex(RexxObject *obj)
static RexxTable * newInstance(size_t, size_t, size_t)
RexxObject * get(RexxObject *key)
RexxObject * primitiveGetIndex(RexxObject *value)
RexxObject * value(HashLink position)
RexxArray * stringGetAll(RexxString *key)
void live(size_t)
RexxHashTable * insert(RexxObject *value, RexxObject *index, HashLink position, int type)
RexxObject * stringGet(RexxString *key)
RexxObject * removeAll(RexxObject *key)
RexxHashTable * reHash()
size_t totalEntries()
HashLink next(HashLink position)
RexxArray * allIndex(RexxObject *key)
void flatten(RexxEnvelope *)
RexxObject * replace(RexxObject *value, HashLink position)
void setObjectSize(size_t s)
static void * virtualFunctionTable[]
Definition: RexxMemory.hpp:298
size_t markWord
Definition: RexxMemory.hpp:301
bool isEqual(RexxObject *)
const char * getStringData()
bool memCompare(const char *s, sizeB_t l)
sizeB_t getBLength()
int type
Definition: cmdparse.cpp:383
#define size_v(X)
Definition: rexx.h:237
stringsizeB_t sizeB_t
Definition: rexx.h:248
HashLink next
RexxObject * value
RexxObject * index