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-dictionary.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 8
35 #define MINIMUM_CAPACITY 4
36 #define SIZE(collection) (ST_HASHED_COLLECTION (collection)->size)
37 #define DELETED(collection) (ST_HASHED_COLLECTION (collection)->deleted)
38 #define ARRAY(collection) (ST_HASHED_COLLECTION (collection)->array)
39 #define ARRAY_SIZE(array) (st_smi_value (ST_ARRAYED_OBJECT (array)->size))
42 #define ADVANCE_SIZE 106720
44 #define ST_HASHED_COLLECTION(oop) ((struct st_hashed_collection *) ST_POINTER (oop))
46 struct st_hashed_collection
48 struct st_header header
;
56 static st_uint
dict_find (st_oop dict
, st_oop object
);
57 static st_uint
set_find (st_oop set
, st_oop object
);
58 static void dict_no_check_add (st_oop dict
, st_oop object
);
59 static void set_no_check_add (st_oop set
, st_oop object
);
66 occupied (st_oop collection
)
68 return st_smi_value (SIZE (collection
)) + st_smi_value (DELETED (collection
));
72 size_for_capacity (st_uint capacity
)
76 size
= MINIMUM_CAPACITY
;
78 while (size
< capacity
)
85 initialize (st_oop collection
, int capacity
)
87 st_assert (capacity
> 0);
89 capacity
= size_for_capacity (capacity
);
91 SIZE (collection
) = st_smi_new (0);
92 DELETED (collection
) = st_smi_new (0);
93 ARRAY (collection
) = st_object_new_arrayed (ST_ARRAY_CLASS
, capacity
);
97 dict_check_grow (st_oop dict
)
102 size
= n
= ARRAY_SIZE (ARRAY (dict
));
104 if (occupied (dict
) * 2 <= size
)
109 ARRAY (dict
) = st_object_new_arrayed (ST_ARRAY_CLASS
, size
);
110 DELETED (dict
) = st_smi_new (0);
112 for (st_uint i
= 1; i
<= n
; i
++) {
113 object
= st_array_at (old
, i
);
114 if (object
!= ST_NIL
) {
115 st_array_at_put (ARRAY (dict
), dict_find (dict
, ST_ASSOCIATION_KEY (object
)), object
);
121 dict_find (st_oop dict
, st_oop key
)
127 mask
= ARRAY_SIZE (ARRAY (dict
)) - 1;
128 i
= (st_object_hash (key
) & mask
) + 1;
131 el
= st_array_at (ARRAY (dict
), i
);
132 if (el
== ST_NIL
|| key
== ST_ASSOCIATION_KEY (el
))
134 i
= ((i
+ ADVANCE_SIZE
) & mask
) + 1;
139 st_dictionary_at_put (st_oop dict
, st_oop key
, st_oop value
)
144 index
= dict_find (dict
, key
);
145 assoc
= st_array_at (ARRAY (dict
), index
);
147 if (assoc
== ST_NIL
) {
148 st_array_at_put (ARRAY (dict
), index
, st_association_new (key
, value
));
149 SIZE (dict
) = st_smi_increment (SIZE (dict
));
150 dict_check_grow (dict
);
152 ST_ASSOCIATION_VALUE (assoc
) = value
;
157 st_dictionary_at (st_oop dict
, st_oop key
)
162 assoc
= st_array_at (ARRAY (dict
), dict_find (dict
, key
));
165 return ST_ASSOCIATION_VALUE (assoc
);
171 st_dictionary_association_at (st_oop dict
, st_oop key
)
173 return st_array_at (ARRAY (dict
), dict_find (dict
, key
));
177 st_dictionary_new (void)
179 return st_dictionary_new_with_capacity (DEFAULT_CAPACITY
);
183 st_dictionary_new_with_capacity (int capacity
)
187 dict
= st_object_new (ST_DICTIONARY_CLASS
);
188 initialize (dict
, capacity
);
194 /* Set implementation */
197 set_find_cstring (st_oop set
, const char *string
)
202 mask
= ARRAY_SIZE (ARRAY (set
)) - 1;
203 i
= (st_string_hash (string
) & mask
) + 1;
206 el
= st_array_at (ARRAY (set
), i
);
207 if (el
== ST_NIL
|| (strcmp (st_byte_array_bytes (el
), string
) == 0))
209 i
= ((i
+ ADVANCE_SIZE
) & mask
) + 1;
214 set_find (st_oop set
, st_oop object
)
219 mask
= ARRAY_SIZE (ARRAY (set
)) - 1;
220 i
= (st_object_hash (object
) & mask
) + 1;
223 el
= st_array_at (ARRAY (set
), i
);
224 if (el
== ST_NIL
|| el
== object
)
226 i
= ((i
+ ADVANCE_SIZE
) & mask
) + 1;
231 set_check_grow (st_oop set
)
236 size
= n
= ARRAY_SIZE (ARRAY (set
));
238 if (occupied (set
) * 2 <= size
)
243 ARRAY (set
) = st_object_new_arrayed (ST_ARRAY_CLASS
, size
);
244 DELETED (set
) = st_smi_new (0);
246 for (st_uint i
= 1; i
<= n
; i
++) {
247 object
= st_array_at (old
, i
);
248 if (object
!= ST_NIL
)
249 st_array_at_put (ARRAY (set
), set_find (set
, object
), object
);
254 st_set_intern_cstring (st_oop set
, const char *string
)
259 st_assert (string
!= NULL
);
261 i
= set_find_cstring (set
, string
);
262 intern
= st_array_at (ARRAY (set
), i
);
263 if (intern
!= ST_NIL
)
266 len
= strlen (string
);
267 intern
= st_object_new_arrayed (ST_SYMBOL_CLASS
, len
);
268 memcpy (st_byte_array_bytes (intern
), string
, len
);
269 st_array_at_put (ARRAY (set
), i
, intern
);
270 SIZE (set
) = st_smi_increment (SIZE (set
));
271 set_check_grow (set
);
277 st_set_add (st_oop set
, st_oop object
)
279 st_array_at_put (ARRAY (set
), set_find (set
, object
), object
);
280 SIZE (set
) = st_smi_increment (SIZE (set
));
281 set_check_grow (set
);
285 st_set_includes (st_oop set
, st_oop object
)
287 return st_array_at (ARRAY (set
), set_find (set
, object
)) != ST_NIL
;
291 st_set_like (st_oop set
, st_oop object
)
293 return st_array_at (ARRAY (set
), set_find (set
, object
));
297 st_set_new_with_capacity (int capacity
)
301 set
= st_object_new (ST_SET_CLASS
);
302 initialize (set
, capacity
);
310 return st_set_new_with_capacity (DEFAULT_CAPACITY
);