1 /* Sparse Arrays for Objective C dispatch tables
2 Copyright (C) 1993 Free Software Foundation, Inc.
4 This file is part of GNU CC.
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* As a special exception, if you link this library with files
21 compiled with GCC to produce an executable, this does not cause
22 the resulting executable to be covered by the GNU General Public License.
23 This exception does not however invalidate any other reasons why
24 the executable file might be covered by the GNU General Public License. */
26 #include "objc/sarray.h"
36 const char* __objc_sparse2_id
= "2 level sparse indices";
40 const char* __objc_sparse3_id
= "3 level sparse indices";
44 sarray_at_put(struct sarray
* array
, sidx index
, void* element
)
47 struct sindex
** the_index
;
49 struct sbucket
** the_bucket
;
55 #ifdef PRECOMPUTE_SELECTORS
59 ioffset
= xx
.off
.ioffset
;
61 boffset
= xx
.off
.boffset
;
62 eoffset
= xx
.off
.eoffset
;
63 #else /* not PRECOMPUTE_SELECTORS */
65 ioffset
= index
/INDEX_CAPACITY
;
66 boffset
= (index
/BUCKET_SIZE
)%INDEX_SIZE
;
67 eoffset
= index
%BUCKET_SIZE
;
69 boffset
= index
/BUCKET_SIZE
;
70 eoffset
= index
%BUCKET_SIZE
;
72 #endif /* not PRECOMPUTE_SELECTORS */
74 assert(soffset_decode(index
) < array
->capacity
); /* Range check */
77 the_index
= &(array
->indices
[ioffset
]);
78 the_bucket
= &((*the_index
)->buckets
[boffset
]);
80 the_bucket
= &(array
->buckets
[boffset
]);
83 if ((*the_bucket
)->elems
[eoffset
] == element
)
84 return; /* great! we just avoided a lazy copy */
88 /* First, perform lazy copy/allocation of index if needed */
90 if ((*the_index
) == array
->empty_index
) {
92 /* The index was previously empty, allocate a new */
93 *the_index
= (struct sindex
*)__objc_xmalloc(sizeof(struct sindex
));
94 memcpy(*the_index
, array
->empty_index
, sizeof(struct sindex
));
95 (*the_index
)->version
= array
->version
;
96 the_bucket
= &((*the_index
)->buckets
[boffset
]);
99 } else if ((*the_index
)->version
!= array
->version
) {
101 /* This index must be lazy copied */
102 struct sindex
* old_index
= *the_index
;
103 *the_index
= (struct sindex
*)__objc_xmalloc(sizeof(struct sindex
));
104 memcpy( *the_index
,old_index
, sizeof(struct sindex
));
105 (*the_index
)->version
= array
->version
;
106 the_bucket
= &((*the_index
)->buckets
[boffset
]);
111 #endif /* OBJC_SPARSE3 */
113 /* next, perform lazy allocation/copy of the bucket if needed */
115 if ((*the_bucket
) == array
->empty_bucket
) {
117 /* The bucket was previously empty (or something like that), */
118 /* allocate a new. This is the effect of `lazy' allocation */
119 *the_bucket
= (struct sbucket
*)__objc_xmalloc(sizeof(struct sbucket
));
120 memcpy( *the_bucket
,array
->empty_bucket
, sizeof(struct sbucket
));
121 (*the_bucket
)->version
= array
->version
;
124 } else if ((*the_bucket
)->version
!= array
->version
) {
126 /* Perform lazy copy. */
127 struct sbucket
* old_bucket
= *the_bucket
;
128 *the_bucket
= (struct sbucket
*)__objc_xmalloc(sizeof(struct sbucket
));
129 memcpy( *the_bucket
,old_bucket
, sizeof(struct sbucket
));
130 (*the_bucket
)->version
= array
->version
;
134 (*the_bucket
)->elems
[eoffset
] = element
;
138 sarray_at_put_safe(struct sarray
* array
, sidx index
, void* element
)
140 if(soffset_decode(index
) >= array
->capacity
)
141 sarray_realloc(array
, soffset_decode(index
)+1);
142 sarray_at_put(array
, index
, element
);
146 sarray_new (int size
, void* default_element
)
149 size_t num_indices
= ((size
-1)/(INDEX_CAPACITY
))+1;
150 #else /* OBJC_SPARSE2 */
151 size_t num_indices
= ((size
-1)/BUCKET_SIZE
)+1;
158 /* Allocate core array */
159 arr
= (struct sarray
*) __objc_xmalloc(sizeof(struct sarray
));
163 /* Initialize members */
165 arr
->capacity
= num_indices
*INDEX_CAPACITY
;
166 arr
->indices
= (struct sindex
**)
167 __objc_xmalloc(sizeof(struct sindex
*)*num_indices
);
168 idxsize
+= num_indices
;
170 arr
->empty_index
= (struct sindex
*) __objc_xmalloc(sizeof(struct sindex
));
171 arr
->empty_index
->version
= 0;
174 #else /* OBJC_SPARSE2 */
175 arr
->capacity
= num_indices
*BUCKET_SIZE
;
176 arr
->buckets
= (struct sbucket
**)
177 __objc_xmalloc(sizeof(struct sbucket
*)*num_indices
);
178 idxsize
+= num_indices
;
182 arr
->empty_bucket
= (struct sbucket
*) __objc_xmalloc(sizeof(struct sbucket
));
183 arr
->empty_bucket
->version
= 0;
187 arr
->is_copy_of
= (struct sarray
*)0;
189 for (counter
=0; counter
<BUCKET_SIZE
; counter
++)
190 arr
->empty_bucket
->elems
[counter
] = default_element
;
193 for (counter
=0; counter
<INDEX_SIZE
; counter
++)
194 arr
->empty_index
->buckets
[counter
] = arr
->empty_bucket
;
196 for (counter
=0; counter
<num_indices
; counter
++)
197 arr
->indices
[counter
] = arr
->empty_index
;
199 #else /* OBJC_SPARSE2 */
201 for (counter
=0; counter
<num_indices
; counter
++)
202 arr
->buckets
[counter
] = arr
->empty_bucket
;
210 /* Reallocate the sparse array to hold `newsize' entries */
213 sarray_realloc(struct sarray
* array
, int newsize
)
216 int old_max_index
= (array
->capacity
-1)/INDEX_CAPACITY
;
217 int new_max_index
= ((newsize
-1)/INDEX_CAPACITY
);
218 int rounded_size
= (new_max_index
+1)*INDEX_CAPACITY
;
220 #else /* OBJC_SPARSE2 */
221 int old_max_index
= (array
->capacity
-1)/BUCKET_SIZE
;
222 int new_max_index
= ((newsize
-1)/BUCKET_SIZE
);
223 int rounded_size
= (new_max_index
+1)*BUCKET_SIZE
;
231 /* The size is the same, just ignore the request */
232 if(rounded_size
== array
->capacity
)
235 assert(array
->ref_count
== 1); /* stop if lazy copied... */
237 if(rounded_size
< array
->capacity
)
239 /* update capacity */
240 array
->capacity
= rounded_size
;
242 /* free buckets above new_max_index */
243 for(counter
= old_max_index
; counter
> new_max_index
; counter
-- ) {
245 struct sindex
* idx
= array
->indices
[counter
];
246 if((idx
!= array
->empty_index
) && (idx
->version
== array
->version
)) {
248 for(c2
=0; c2
<INDEX_SIZE
; c2
++) {
249 struct sbucket
* bkt
= idx
->buckets
[c2
];
250 if((bkt
!= array
->empty_bucket
) && (bkt
->version
== array
->version
))
259 #else /* OBJC_SPARSE2 */
260 struct sbucket
* bkt
= array
->buckets
[counter
];
261 if ((bkt
!= array
->empty_bucket
) && (bkt
->version
== array
->version
))
270 /* realloc to free the space above new_max_index */
271 array
->indices
= (struct sindex
**)
272 __objc_xrealloc(array
->indices
,
273 (new_max_index
+1)*sizeof(struct sindex
*));
274 #else /* OBJC_SPARSE2 */
275 array
->buckets
= (struct sbucket
**)
276 __objc_xrealloc(array
->buckets
,
277 (new_max_index
+1)*sizeof(struct sbucket
*));
279 idxsize
-= (old_max_index
-new_max_index
);
284 /* We are asked to extend the array -- reallocate the bucket table, */
285 /* and insert empty_bucket in newly allocated places. */
286 if(rounded_size
> array
->capacity
)
288 /* update capacity */
289 array
->capacity
= rounded_size
;
292 /* realloc to make room in table above old_max_index */
293 array
->indices
= (struct sindex
**)
294 __objc_xrealloc(array
->indices
,
295 (new_max_index
+1)*sizeof(struct sindex
*));
297 /* reset entries above old_max_index to empty_bucket */
298 for(counter
= old_max_index
+1; counter
<= new_max_index
; counter
++)
299 array
->indices
[counter
] = array
->empty_index
;
301 #else /* OBJC_SPARSE2 */
303 /* realloc to make room in table above old_max_index */
304 array
->buckets
= (struct sbucket
**)
305 __objc_xrealloc(array
->buckets
,
306 (new_max_index
+1)*sizeof(struct sbucket
*));
308 /* reset entries above old_max_index to empty_bucket */
309 for(counter
= old_max_index
+1; counter
<= new_max_index
; counter
++)
310 array
->buckets
[counter
] = array
->empty_bucket
;
313 idxsize
+= (new_max_index
-old_max_index
);
319 /* Free a sparse array allocated with sarray_new */
322 sarray_free(struct sarray
* array
) {
324 size_t old_max_index
= (array
->capacity
-1)/INDEX_CAPACITY
;
326 size_t old_max_index
= (array
->capacity
-1)/BUCKET_SIZE
;
330 assert(array
->ref_count
!= 0); /* Freed multiple times!!! */
332 if(--(array
->ref_count
) != 0) /* There exists copies of me */
335 if((array
->is_copy_of
) && ((array
->is_copy_of
->ref_count
- 1) == 0))
336 sarray_free(array
->is_copy_of
);
338 /* Free all entries that do not point to empty_bucket */
339 for(counter
= 0; counter
<= old_max_index
; counter
++ ) {
341 struct sindex
* idx
= array
->indices
[counter
];
342 if((idx
!= array
->empty_index
) && (idx
->version
== array
->version
)) {
344 for(c2
=0; c2
<INDEX_SIZE
; c2
++) {
345 struct sbucket
* bkt
= idx
->buckets
[c2
];
346 if((bkt
!= array
->empty_bucket
) && (bkt
->version
== array
->version
))
355 #else /* OBJC_SPARSE2 */
356 struct sbucket
* bkt
= array
->buckets
[counter
];
357 if ((bkt
!= array
->empty_bucket
) && (bkt
->version
== array
->version
))
366 /* free empty_index */
367 if(array
->empty_index
->version
== array
->version
) {
368 free(array
->empty_index
);
373 /* free empty_bucket */
374 if(array
->empty_bucket
->version
== array
->version
) {
375 free(array
->empty_bucket
);
380 /* free bucket table */
381 free(array
->indices
);
382 idxsize
-= (old_max_index
+1);
385 /* free bucket table */
386 free(array
->buckets
);
387 idxsize
-= (old_max_index
+1);
396 /* This is a lazy copy. Only the core of the structure is actually */
400 sarray_lazy_copy(struct sarray
* oarr
)
403 size_t num_indices
= ((oarr
->capacity
-1)/INDEX_CAPACITY
)+1;
404 #else /* OBJC_SPARSE2 */
405 size_t num_indices
= ((oarr
->capacity
-1)/BUCKET_SIZE
)+1;
409 /* Allocate core array */
410 arr
= (struct sarray
*) __objc_xmalloc(sizeof(struct sarray
));
411 memcpy( arr
,oarr
, sizeof(struct sarray
));
412 arr
->version
= oarr
->version
+ 1;
413 arr
->is_copy_of
= oarr
;
414 oarr
->ref_count
+= 1;
418 /* Copy bucket table */
419 arr
->indices
= (struct sindex
**)
420 __objc_xmalloc(sizeof(struct sindex
*)*num_indices
);
421 memcpy( arr
->indices
,oarr
->indices
,
422 sizeof(struct sindex
*)*num_indices
);
424 /* Copy bucket table */
425 arr
->buckets
= (struct sbucket
**)
426 __objc_xmalloc(sizeof(struct sbucket
*)*num_indices
);
427 memcpy( arr
->buckets
,oarr
->buckets
,
428 sizeof(struct sbucket
*)*num_indices
);
431 idxsize
+= num_indices
;