2 * st-hashed-collection.c
4 * Copyright (C) 2008 Vincent Geddes
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "st-hashed-collection.h"
27 #include "st-small-integer.h"
29 #include "st-universe.h"
30 #include "st-association.h"
31 #include "st-object.h"
32 #include "st-behavior.h"
34 #define DEFAULT_CAPACITY 5
35 #define TALLY(collection) (ST_HASHED_COLLECTION (collection)->tally)
36 #define ARRAY(collection) (ST_HASHED_COLLECTION (collection)->array)
37 #define ARRAY_SIZE(array) (st_smi_value (ST_ARRAYED_OBJECT (array)->size))
39 #define ST_HASHED_COLLECTION(oop) ((struct st_hashed_collection *) ST_POINTER (oop))
41 struct st_hashed_collection
43 struct st_header header
;
50 static st_smi
dict_scan_for_object (st_oop dict
, st_oop object
);
52 static void dict_no_check_add (st_oop dict
, st_oop object
);
54 static void set_no_check_add (st_oop set
, st_oop object
);
56 static st_smi
set_scan_for_object (st_oop set
, st_oop object
);
59 /* Hashed Collection methods */
62 collection_find_element_or_nil (st_oop collection
, st_oop object
)
66 if (st_object_class (collection
) == st_dictionary_class
)
67 index
= dict_scan_for_object (collection
, object
);
68 else if (st_object_class (collection
) == st_set_class
)
69 index
= set_scan_for_object (collection
, object
);
71 st_assert_not_reached ();
76 st_assert_not_reached ();
80 collection_grow_size (st_oop collection
)
82 return MAX (ARRAY_SIZE (ARRAY (collection
)), 2);
86 collection_grow (st_oop collection
)
88 st_oop old_array
= ARRAY (collection
);
90 st_smi new_size
= ARRAY_SIZE (old_array
) + collection_grow_size (collection
);
92 ARRAY (collection
) = st_object_new_arrayed (st_array_class
, new_size
);
94 st_smi n
= ARRAY_SIZE (old_array
);
96 for (st_smi i
= 1; i
<= n
; i
++)
97 if (st_array_at (old_array
, i
) != st_nil
) {
99 if (st_object_class (collection
) == st_dictionary_class
) {
100 dict_no_check_add (collection
, st_array_at (old_array
, i
));
101 } else if (st_object_class (collection
) == st_set_class
) {
102 set_no_check_add (collection
, st_array_at (old_array
, i
));
104 st_assert_not_reached ();
110 collection_full_check (st_oop collection
)
112 st_smi array_size
= ARRAY_SIZE (ARRAY (collection
));
113 st_smi tally
= st_smi_value (TALLY (collection
));
115 if ((array_size
- tally
) < MAX ((array_size
/ 4), 1))
116 collection_grow (collection
);
120 collection_at_new_index_put (st_oop collection
, st_smi index
, st_oop object
)
122 st_array_at_put (ARRAY (collection
), index
, object
);
124 TALLY (collection
) = st_smi_increment (TALLY (collection
));
126 collection_full_check (collection
);
130 collection_initialize (st_oop collection
, st_smi capacity
)
132 st_assert (capacity
> 0);
134 TALLY (collection
) = st_smi_new (0);
135 ARRAY (collection
) = st_object_new_arrayed (st_array_class
, capacity
);
139 dict_scan_for_object (st_oop dict
, st_oop object
)
141 st_smi finish
= ARRAY_SIZE (ARRAY (dict
));
142 st_smi start
= (st_object_hash (object
) % finish
) + 1;
144 for (st_smi i
= start
; i
<= finish
; i
++) {
146 st_oop element
= st_array_at (ARRAY (dict
), i
);
148 if (element
== st_nil
)
150 if (st_object_equal (object
, ST_ASSOCIATION_KEY (element
)))
154 for (st_smi i
= 1; i
<= (start
- 1); i
++) {
156 st_oop element
= st_array_at (ARRAY (dict
), i
);
158 if (element
== st_nil
)
160 if (st_object_equal (object
, ST_ASSOCIATION_KEY (element
)))
169 dict_no_check_add (st_oop dict
, st_oop object
)
171 st_array_at_put (ARRAY (dict
),
172 collection_find_element_or_nil (dict
, ST_ASSOCIATION_KEY (object
)), object
);
176 st_dictionary_at_put (st_oop dict
, st_oop key
, st_oop value
)
178 st_smi index
= collection_find_element_or_nil (dict
, key
);
180 st_oop assoc
= st_array_at (ARRAY (dict
), index
);
182 if (assoc
== st_nil
) {
184 assoc
= st_association_new (key
, value
);
185 collection_at_new_index_put (dict
, index
, assoc
);
188 ST_ASSOCIATION (assoc
)->value
= value
;
193 st_dictionary_at (st_oop dict
, st_oop key
)
195 st_smi index
= collection_find_element_or_nil (dict
, key
);
197 st_oop assoc
= st_array_at (ARRAY (dict
), index
);
200 return ST_ASSOCIATION (assoc
)->value
;
206 st_dictionary_association_at (st_oop dict
, st_oop key
)
208 st_smi index
= collection_find_element_or_nil (dict
, key
);
210 return st_array_at (ARRAY (dict
), index
);
214 st_dictionary_new (void)
216 return st_dictionary_new_with_capacity (DEFAULT_CAPACITY
);
220 st_dictionary_new_with_capacity (st_smi capacity
)
224 dict
= st_object_new (st_dictionary_class
);
226 collection_initialize (dict
, capacity
);
232 set_scan_for_object (st_oop set
, st_oop object
)
234 st_smi finish
= ARRAY_SIZE (ARRAY (set
));
235 st_smi start
= (st_object_hash (object
) % finish
) + 1;
237 for (st_smi i
= start
; i
<= finish
; i
++) {
239 st_oop element
= st_array_at (ARRAY (set
), i
);
241 if (element
== st_nil
)
243 if (st_object_equal (object
, element
))
247 for (st_smi i
= 1; i
<= (start
- 1); i
++) {
249 st_oop element
= st_array_at (ARRAY (set
), i
);
251 if (element
== st_nil
)
253 if (st_object_equal (object
, element
))
262 set_no_check_add (st_oop set
, st_oop object
)
264 st_array_at_put (ARRAY (set
), collection_find_element_or_nil (set
, object
), object
);
268 st_set_add (st_oop set
, st_oop object
)
270 st_smi index
= collection_find_element_or_nil (set
, object
);
272 st_oop element
= st_array_at (ARRAY (set
), index
);
274 if (element
== st_nil
)
275 collection_at_new_index_put (set
, index
, object
);
279 st_set_includes (st_oop set
, st_oop object
)
281 st_smi index
= collection_find_element_or_nil (set
, object
);
283 return st_array_at (ARRAY (set
), index
) != st_nil
;
287 st_set_like (st_oop set
, st_oop object
)
289 st_smi index
= collection_find_element_or_nil (set
, object
);
291 return st_array_at (ARRAY (set
), index
);
295 st_set_new_with_capacity (st_smi capacity
)
299 set
= st_object_new (st_set_class
);
301 collection_initialize (set
, capacity
);
309 return st_set_new_with_capacity (DEFAULT_CAPACITY
);