|
|
1.1 ! root 1: /* Sparse Arrays for Objective C dispatch tables ! 2: Copyright (C) 1993 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 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) ! 9: any later version. ! 10: ! 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. ! 15: ! 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. */ ! 19: ! 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. */ ! 25: ! 26: #include "objc/sarray.h" ! 27: #include <stdio.h> ! 28: #include "assert.h" ! 29: ! 30: int nbuckets = 0; ! 31: int nindices = 0; ! 32: int narrays = 0; ! 33: int idxsize = 0; ! 34: ! 35: #ifdef OBJC_SPARSE2 ! 36: const char* __objc_sparse2_id = "2 level sparse indices"; ! 37: #endif ! 38: ! 39: #ifdef OBJC_SPARSE3 ! 40: const char* __objc_sparse3_id = "3 level sparse indices"; ! 41: #endif ! 42: ! 43: #ifdef __alpha__ ! 44: const void *memcpy (void*, const void*, size_t); ! 45: void free (const void*); ! 46: #endif ! 47: ! 48: void ! 49: sarray_at_put(struct sarray* array, sidx index, void* element) ! 50: { ! 51: #ifdef OBJC_SPARSE3 ! 52: struct sindex** the_index; ! 53: #endif ! 54: struct sbucket** the_bucket; ! 55: #ifdef OBJC_SPARSE3 ! 56: size_t ioffset; ! 57: #endif ! 58: size_t boffset; ! 59: size_t eoffset; ! 60: #ifdef PRECOMPUTE_SELECTORS ! 61: union sofftype xx; ! 62: xx.idx = index; ! 63: #ifdef OBJC_SPARSE3 ! 64: ioffset = xx.off.ioffset; ! 65: #endif ! 66: boffset = xx.off.boffset; ! 67: eoffset = xx.off.eoffset; ! 68: #else /* not PRECOMPUTE_SELECTORS */ ! 69: #ifdef OBJC_SPARSE3 ! 70: ioffset = index/INDEX_CAPACITY; ! 71: boffset = (index/BUCKET_SIZE)%INDEX_SIZE; ! 72: eoffset = index%BUCKET_SIZE; ! 73: #else ! 74: boffset = index/BUCKET_SIZE; ! 75: eoffset = index%BUCKET_SIZE; ! 76: #endif ! 77: #endif /* not PRECOMPUTE_SELECTORS */ ! 78: ! 79: assert(soffset_decode(index) < array->capacity); /* Range check */ ! 80: ! 81: #ifdef OBJC_SPARSE3 ! 82: the_index = &(array->indices[ioffset]); ! 83: the_bucket = &((*the_index)->buckets[boffset]); ! 84: #else ! 85: the_bucket = &(array->buckets[boffset]); ! 86: #endif ! 87: ! 88: if ((*the_bucket)->elems[eoffset] == element) ! 89: return; /* great! we just avoided a lazy copy */ ! 90: ! 91: #ifdef OBJC_SPARSE3 ! 92: ! 93: /* First, perform lazy copy/allocation of index if needed */ ! 94: ! 95: if ((*the_index) == array->empty_index) { ! 96: ! 97: /* The index was previously empty, allocate a new */ ! 98: *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex)); ! 99: memcpy(*the_index, array->empty_index, sizeof(struct sindex)); ! 100: (*the_index)->version = array->version; ! 101: the_bucket = &((*the_index)->buckets[boffset]); ! 102: nindices += 1; ! 103: ! 104: } else if ((*the_index)->version != array->version) { ! 105: ! 106: /* This index must be lazy copied */ ! 107: struct sindex* old_index = *the_index; ! 108: *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex)); ! 109: memcpy( *the_index,old_index, sizeof(struct sindex)); ! 110: (*the_index)->version = array->version; ! 111: the_bucket = &((*the_index)->buckets[boffset]); ! 112: nindices += 1; ! 113: ! 114: } ! 115: ! 116: #endif /* OBJC_SPARSE3 */ ! 117: ! 118: /* next, perform lazy allocation/copy of the bucket if needed */ ! 119: ! 120: if ((*the_bucket) == array->empty_bucket) { ! 121: ! 122: /* The bucket was previously empty (or something like that), */ ! 123: /* allocate a new. This is the effect of `lazy' allocation */ ! 124: *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket)); ! 125: memcpy((void *) *the_bucket, (const void*)array->empty_bucket, sizeof(struct sbucket)); ! 126: (*the_bucket)->version = array->version; ! 127: nbuckets += 1; ! 128: ! 129: } else if ((*the_bucket)->version != array->version) { ! 130: ! 131: /* Perform lazy copy. */ ! 132: struct sbucket* old_bucket = *the_bucket; ! 133: *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket)); ! 134: memcpy( *the_bucket,old_bucket, sizeof(struct sbucket)); ! 135: (*the_bucket)->version = array->version; ! 136: nbuckets += 1; ! 137: ! 138: } ! 139: (*the_bucket)->elems[eoffset] = element; ! 140: } ! 141: ! 142: void ! 143: sarray_at_put_safe(struct sarray* array, sidx index, void* element) ! 144: { ! 145: if(soffset_decode(index) >= array->capacity) ! 146: sarray_realloc(array, soffset_decode(index)+1); ! 147: sarray_at_put(array, index, element); ! 148: } ! 149: ! 150: struct sarray* ! 151: sarray_new (int size, void* default_element) ! 152: { ! 153: #ifdef OBJC_SPARSE3 ! 154: size_t num_indices = ((size-1)/(INDEX_CAPACITY))+1; ! 155: #else /* OBJC_SPARSE2 */ ! 156: size_t num_indices = ((size-1)/BUCKET_SIZE)+1; ! 157: #endif ! 158: int counter; ! 159: struct sarray* arr; ! 160: ! 161: assert(size > 0); ! 162: ! 163: /* Allocate core array */ ! 164: arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray)); ! 165: arr->version = 0; ! 166: narrays += 1; ! 167: ! 168: /* Initialize members */ ! 169: #ifdef OBJC_SPARSE3 ! 170: arr->capacity = num_indices*INDEX_CAPACITY; ! 171: arr->indices = (struct sindex**) ! 172: __objc_xmalloc(sizeof(struct sindex*)*num_indices); ! 173: idxsize += num_indices; ! 174: ! 175: arr->empty_index = (struct sindex*) __objc_xmalloc(sizeof(struct sindex)); ! 176: arr->empty_index->version = 0; ! 177: nindices += 1; ! 178: ! 179: #else /* OBJC_SPARSE2 */ ! 180: arr->capacity = num_indices*BUCKET_SIZE; ! 181: arr->buckets = (struct sbucket**) ! 182: __objc_xmalloc(sizeof(struct sbucket*)*num_indices); ! 183: idxsize += num_indices; ! 184: ! 185: #endif ! 186: ! 187: arr->empty_bucket = (struct sbucket*) __objc_xmalloc(sizeof(struct sbucket)); ! 188: arr->empty_bucket->version = 0; ! 189: nbuckets += 1; ! 190: ! 191: arr->ref_count = 1; ! 192: arr->is_copy_of = (struct sarray*)0; ! 193: ! 194: for (counter=0; counter<BUCKET_SIZE; counter++) ! 195: arr->empty_bucket->elems[counter] = default_element; ! 196: ! 197: #ifdef OBJC_SPARSE3 ! 198: for (counter=0; counter<INDEX_SIZE; counter++) ! 199: arr->empty_index->buckets[counter] = arr->empty_bucket; ! 200: ! 201: for (counter=0; counter<num_indices; counter++) ! 202: arr->indices[counter] = arr->empty_index; ! 203: ! 204: #else /* OBJC_SPARSE2 */ ! 205: ! 206: for (counter=0; counter<num_indices; counter++) ! 207: arr->buckets[counter] = arr->empty_bucket; ! 208: ! 209: #endif ! 210: ! 211: return arr; ! 212: } ! 213: ! 214: ! 215: /* Reallocate the sparse array to hold `newsize' entries */ ! 216: ! 217: void ! 218: sarray_realloc(struct sarray* array, int newsize) ! 219: { ! 220: #ifdef OBJC_SPARSE3 ! 221: int old_max_index = (array->capacity-1)/INDEX_CAPACITY; ! 222: int new_max_index = ((newsize-1)/INDEX_CAPACITY); ! 223: int rounded_size = (new_max_index+1)*INDEX_CAPACITY; ! 224: ! 225: #else /* OBJC_SPARSE2 */ ! 226: int old_max_index = (array->capacity-1)/BUCKET_SIZE; ! 227: int new_max_index = ((newsize-1)/BUCKET_SIZE); ! 228: int rounded_size = (new_max_index+1)*BUCKET_SIZE; ! 229: ! 230: #endif ! 231: ! 232: int counter; ! 233: ! 234: assert(newsize > 0); ! 235: ! 236: /* The size is the same, just ignore the request */ ! 237: if(rounded_size == array->capacity) ! 238: return; ! 239: ! 240: assert(array->ref_count == 1); /* stop if lazy copied... */ ! 241: ! 242: if(rounded_size < array->capacity) ! 243: { ! 244: /* update capacity */ ! 245: array->capacity = rounded_size; ! 246: ! 247: /* free buckets above new_max_index */ ! 248: for(counter = old_max_index; counter > new_max_index; counter-- ) { ! 249: #ifdef OBJC_SPARSE3 ! 250: struct sindex* idx = array->indices[counter]; ! 251: if((idx != array->empty_index) && (idx->version == array->version)) { ! 252: int c2; ! 253: for(c2=0; c2<INDEX_SIZE; c2++) { ! 254: struct sbucket* bkt = idx->buckets[c2]; ! 255: if((bkt != array->empty_bucket) && (bkt->version == array->version)) ! 256: { ! 257: free(bkt); ! 258: nbuckets -= 1; ! 259: } ! 260: } ! 261: free(idx); ! 262: nindices -= 1; ! 263: } ! 264: #else /* OBJC_SPARSE2 */ ! 265: struct sbucket* bkt = array->buckets[counter]; ! 266: if ((bkt != array->empty_bucket) && (bkt->version == array->version)) ! 267: { ! 268: free(bkt); ! 269: nbuckets -= 1; ! 270: } ! 271: #endif ! 272: } ! 273: ! 274: #ifdef OBJC_SPARSE3 ! 275: /* realloc to free the space above new_max_index */ ! 276: array->indices = (struct sindex**) ! 277: __objc_xrealloc(array->indices, ! 278: (new_max_index+1)*sizeof(struct sindex*)); ! 279: #else /* OBJC_SPARSE2 */ ! 280: array->buckets = (struct sbucket**) ! 281: __objc_xrealloc(array->buckets, ! 282: (new_max_index+1)*sizeof(struct sbucket*)); ! 283: #endif ! 284: idxsize -= (old_max_index-new_max_index); ! 285: ! 286: return; ! 287: } ! 288: ! 289: /* We are asked to extend the array -- reallocate the bucket table, */ ! 290: /* and insert empty_bucket in newly allocated places. */ ! 291: if(rounded_size > array->capacity) ! 292: { ! 293: /* update capacity */ ! 294: array->capacity = rounded_size; ! 295: ! 296: #ifdef OBJC_SPARSE3 ! 297: /* realloc to make room in table above old_max_index */ ! 298: array->indices = (struct sindex**) ! 299: __objc_xrealloc(array->indices, ! 300: (new_max_index+1)*sizeof(struct sindex*)); ! 301: ! 302: /* reset entries above old_max_index to empty_bucket */ ! 303: for(counter = old_max_index+1; counter <= new_max_index; counter++) ! 304: array->indices[counter] = array->empty_index; ! 305: ! 306: #else /* OBJC_SPARSE2 */ ! 307: ! 308: /* realloc to make room in table above old_max_index */ ! 309: array->buckets = (struct sbucket**) ! 310: __objc_xrealloc(array->buckets, ! 311: (new_max_index+1)*sizeof(struct sbucket*)); ! 312: ! 313: /* reset entries above old_max_index to empty_bucket */ ! 314: for(counter = old_max_index+1; counter <= new_max_index; counter++) ! 315: array->buckets[counter] = array->empty_bucket; ! 316: ! 317: #endif ! 318: idxsize += (new_max_index-old_max_index); ! 319: return; ! 320: } ! 321: } ! 322: ! 323: ! 324: /* Free a sparse array allocated with sarray_new */ ! 325: ! 326: void ! 327: sarray_free(struct sarray* array) { ! 328: #ifdef OBJC_SPARSE3 ! 329: size_t old_max_index = (array->capacity-1)/INDEX_CAPACITY; ! 330: #else ! 331: size_t old_max_index = (array->capacity-1)/BUCKET_SIZE; ! 332: #endif ! 333: int counter = 0; ! 334: ! 335: assert(array->ref_count != 0); /* Freed multiple times!!! */ ! 336: ! 337: if(--(array->ref_count) != 0) /* There exists copies of me */ ! 338: return; ! 339: ! 340: if((array->is_copy_of) && ((array->is_copy_of->ref_count - 1) == 0)) ! 341: sarray_free(array->is_copy_of); ! 342: ! 343: /* Free all entries that do not point to empty_bucket */ ! 344: for(counter = 0; counter <= old_max_index; counter++ ) { ! 345: #ifdef OBJC_SPARSE3 ! 346: struct sindex* idx = array->indices[counter]; ! 347: if((idx != array->empty_index) && (idx->version == array->version)) { ! 348: int c2; ! 349: for(c2=0; c2<INDEX_SIZE; c2++) { ! 350: struct sbucket* bkt = idx->buckets[c2]; ! 351: if((bkt != array->empty_bucket) && (bkt->version == array->version)) ! 352: { ! 353: free(bkt); ! 354: nbuckets -= 1; ! 355: } ! 356: } ! 357: free(idx); ! 358: nindices -= 1; ! 359: } ! 360: #else /* OBJC_SPARSE2 */ ! 361: struct sbucket* bkt = array->buckets[counter]; ! 362: if ((bkt != array->empty_bucket) && (bkt->version == array->version)) ! 363: { ! 364: free(bkt); ! 365: nbuckets -= 1; ! 366: } ! 367: #endif ! 368: } ! 369: ! 370: #ifdef OBJC_SPARSE3 ! 371: /* free empty_index */ ! 372: if(array->empty_index->version == array->version) { ! 373: free(array->empty_index); ! 374: nindices -= 1; ! 375: } ! 376: #endif ! 377: ! 378: /* free empty_bucket */ ! 379: if(array->empty_bucket->version == array->version) { ! 380: free(array->empty_bucket); ! 381: nbuckets -= 1; ! 382: } ! 383: ! 384: #ifdef OBJC_SPARSE3 ! 385: /* free bucket table */ ! 386: free(array->indices); ! 387: idxsize -= (old_max_index+1); ! 388: ! 389: #else ! 390: /* free bucket table */ ! 391: free(array->buckets); ! 392: idxsize -= (old_max_index+1); ! 393: ! 394: #endif ! 395: ! 396: /* free array */ ! 397: free(array); ! 398: narrays -= 1; ! 399: } ! 400: ! 401: /* This is a lazy copy. Only the core of the structure is actually */ ! 402: /* copied. */ ! 403: ! 404: struct sarray* ! 405: sarray_lazy_copy(struct sarray* oarr) ! 406: { ! 407: #ifdef OBJC_SPARSE3 ! 408: size_t num_indices = ((oarr->capacity-1)/INDEX_CAPACITY)+1; ! 409: #else /* OBJC_SPARSE2 */ ! 410: size_t num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1; ! 411: #endif ! 412: struct sarray* arr; ! 413: ! 414: /* Allocate core array */ ! 415: arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray)); ! 416: memcpy( arr,oarr, sizeof(struct sarray)); ! 417: arr->version = oarr->version + 1; ! 418: arr->is_copy_of = oarr; ! 419: oarr->ref_count += 1; ! 420: arr->ref_count = 1; ! 421: ! 422: #ifdef OBJC_SPARSE3 ! 423: /* Copy bucket table */ ! 424: arr->indices = (struct sindex**) ! 425: __objc_xmalloc(sizeof(struct sindex*)*num_indices); ! 426: memcpy( arr->indices,oarr->indices, ! 427: sizeof(struct sindex*)*num_indices); ! 428: #else ! 429: /* Copy bucket table */ ! 430: arr->buckets = (struct sbucket**) ! 431: __objc_xmalloc(sizeof(struct sbucket*)*num_indices); ! 432: memcpy( arr->buckets,oarr->buckets, ! 433: sizeof(struct sbucket*)*num_indices); ! 434: #endif ! 435: ! 436: idxsize += num_indices; ! 437: narrays += 1; ! 438: ! 439: return arr; ! 440: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.