|
|
1.1 ! root 1: /*ident "@(#)C++env:lib/new/_arr_map.c 1.3" */ ! 2: /************************************************************************** ! 3: Copyright (c) 1984 AT&T ! 4: All Rights Reserved ! 5: ! 6: THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T ! 7: ! 8: The copyright notice above does not evidence any ! 9: actual or intended publication of such source code. ! 10: ! 11: *****************************************************************************/ ! 12: ! 13: ! 14: // manage the global table of array pointers and counts ! 15: #include <values.h> ! 16: #include <new.h> ! 17: ! 18: // !!!! only works if sizeof(long) >= sizeof(void*) !!!! ! 19: ! 20: typedef void* KEYTYP; // generic array address ! 21: void __insert_new_array(KEYTYP key, int count); ! 22: // key is a pointer to a new array. It must ! 23: // be non-zero ! 24: // not already be in the table ! 25: // count is the number of elements in the array. May be zero ! 26: int __remove_old_array(KEYTYP key); ! 27: // removes an old array from the table. Returns the count or -1 if not found ! 28: ! 29: // choose 2 <= DIGIT_SIZE <= 6 ! 30: // smaller numbers waste less space and are slower, larger numbers waste more ! 31: // space and are faster ! 32: ! 33: // control the size of blocks grabbed from the free store (and frequency of ! 34: // allocations) with RECORDS_BLOCK_COUNT and NODES_BLOCK_COUNT ! 35: ! 36: // a trie based on groups of DIGIT_SIZE bits from the key ! 37: #define DIGIT_SIZE 5 ! 38: // each node contains 2 ** DIGIT_SIZE entries ! 39: #define NODE_SIZE (1 << DIGIT_SIZE) ! 40: #define MASK_BITS (1 << DIGIT_SIZE) - 1 ! 41: // a few low order bits are uninteresting and are rotated around to the top ! 42: #define LOW_BITS 2 ! 43: #define LOW_MASK ((1 << LOW_BITS) - 1) ! 44: // the number of groups in a word ! 45: #define POSITIONS ((BITS(long) - 1) / DIGIT_SIZE + 1) ! 46: // control the size of blocks grabbed from new ! 47: #define RECORDS_BLOCK_COUNT 150 ! 48: #define NODES_BLOCK_COUNT 10 ! 49: ! 50: // avoid name space clashes ! 51: #define pnd __pnd ! 52: #define Node_Pool __Node_Pool ! 53: #define Record_Pool __Record_Pool ! 54: #define pnd_internal_node __pnd_internal_node ! 55: ! 56: class pnd; ! 57: class pnd_internal_node; ! 58: ! 59: class RECORD { ! 60: friend pnd; ! 61: friend void __insert_new_array(KEYTYP addr, int count); ! 62: inline void* operator new(size_t); ! 63: inline void operator delete(void* p, size_t); ! 64: inline RECORD(unsigned long k, int cnt); ! 65: inline ~RECORD(); ! 66: unsigned long key; // rotated address of array ! 67: int count; // number of elements of array ! 68: }; ! 69: ! 70: class Record_Pool; ! 71: ! 72: class Record_shell { ! 73: friend Record_Pool; ! 74: Record_shell* next; ! 75: char dummy[sizeof(RECORD) - sizeof(Record_shell*)]; ! 76: }; ! 77: ! 78: class Record_Pool { ! 79: friend RECORD; ! 80: static Record_shell* top; ! 81: Record_Pool(); ! 82: Record_shell slot[RECORDS_BLOCK_COUNT]; ! 83: static void* alloc() { ! 84: if (top == 0) ! 85: new Record_Pool; ! 86: void* ans = top; ! 87: top = top->next; ! 88: return ans; ! 89: } ! 90: static void free(Record_shell* p) { ! 91: p->next = top; ! 92: top = p; ! 93: } ! 94: }; ! 95: ! 96: inline void* ! 97: RECORD::operator new(size_t) ! 98: { ! 99: return Record_Pool::alloc(); ! 100: } ! 101: inline void ! 102: RECORD::operator delete(void* p, size_t) ! 103: { ! 104: Record_Pool::free((Record_shell*)p); ! 105: } ! 106: ! 107: inline ! 108: RECORD::RECORD(unsigned long k, int cnt) ! 109: : key(k), count(cnt) ! 110: {} ! 111: ! 112: inline RECORD::~RECORD() {} ! 113: ! 114: class pnd_internal_item { ! 115: friend pnd; ! 116: friend pnd_internal_node; ! 117: union { ! 118: RECORD* ext_leaf; ! 119: pnd_internal_node* nodep; ! 120: }; ! 121: int this_is_leaf; ! 122: int is_node() { return !this_is_leaf && nodep; } ! 123: int is_leaf() { return this_is_leaf; } ! 124: int is_null() { return !nodep; } ! 125: pnd_internal_node* next_node() { return nodep; } ! 126: RECORD* external_leaf() { return ext_leaf; } ! 127: void make_leaf(RECORD* p) { this_is_leaf = 1; ext_leaf = p; } ! 128: void make_node(pnd_internal_node* cp) { this_is_leaf = 0; nodep = cp; } ! 129: void make_null() {this_is_leaf = 0; nodep = 0; } ! 130: }; ! 131: ! 132: class Node_Pool; ! 133: ! 134: class pnd_internal_node { ! 135: friend pnd; ! 136: friend void __insert_new_array(KEYTYP key, int count); ! 137: inline void* operator new(size_t i); ! 138: inline void operator delete(void* p, size_t i); ! 139: pnd_internal_node(); ! 140: inline ~pnd_internal_node(); ! 141: pnd_internal_item item[NODE_SIZE]; ! 142: int busy_count; ! 143: }; ! 144: ! 145: class Node_shell { ! 146: friend Node_Pool; ! 147: Node_shell* next; ! 148: char dummy[sizeof(pnd_internal_node) - sizeof(Node_shell*)]; ! 149: }; ! 150: ! 151: class Node_Pool { ! 152: friend pnd_internal_node; ! 153: static Node_shell* top; ! 154: Node_Pool(); ! 155: Node_shell slot[NODES_BLOCK_COUNT]; ! 156: static void* alloc() { ! 157: if (top == 0) ! 158: new Node_Pool; ! 159: void* ans = top; ! 160: top = top->next; ! 161: return ans; ! 162: } ! 163: static void free(void* p) { ! 164: ((Node_shell*)p)->next = top; ! 165: top = (Node_shell*)p; ! 166: } ! 167: }; ! 168: ! 169: inline void* ! 170: pnd_internal_node::operator new(size_t) ! 171: { ! 172: return Node_Pool::alloc(); ! 173: } ! 174: inline void ! 175: pnd_internal_node::operator delete(void* p, size_t) ! 176: { ! 177: Node_Pool::free(p); ! 178: } ! 179: ! 180: inline pnd_internal_node::~pnd_internal_node() {} ! 181: ! 182: class pnd { ! 183: friend void __insert_new_array(KEYTYP key, int count); ! 184: friend int __remove_old_array(KEYTYP key); ! 185: static pnd* the_table; ! 186: pnd_internal_item contents; ! 187: // int sze; ! 188: pnd(); ! 189: static void initialize(); ! 190: void insert(KEYTYP, int); ! 191: int remove(KEYTYP); // returns count or -1 if not found ! 192: }; ! 193: ! 194: void ! 195: __insert_new_array(KEYTYP key, int count) ! 196: { ! 197: if (pnd::the_table == 0) ! 198: pnd::initialize(); ! 199: pnd::the_table->insert(key, count); ! 200: } ! 201: ! 202: int ! 203: __remove_old_array(KEYTYP key) ! 204: { ! 205: return pnd::the_table->remove(key); ! 206: } ! 207: ! 208: pnd_internal_node::pnd_internal_node() ! 209: { ! 210: register pnd_internal_item* itemp = &item[0]; ! 211: register int i = NODE_SIZE; ! 212: while (i--) ! 213: (itemp++)->make_null(); ! 214: busy_count = 0; ! 215: } ! 216: ! 217: void ! 218: pnd::insert(KEYTYP addr, int cnt) ! 219: { ! 220: register unsigned long mask = MASK_BITS; ! 221: register unsigned long key = (unsigned long)addr & LOW_MASK; ! 222: if (key) ! 223: key <<= BITS(long) - LOW_BITS; ! 224: key |= (unsigned long)addr >> LOW_BITS; ! 225: RECORD* new_rec = new RECORD(key, cnt); ! 226: register int unshift = 0; ! 227: register pnd_internal_item* itemp = &contents; ! 228: register pnd_internal_node* nodep = 0; ! 229: for (;; mask <<= DIGIT_SIZE, unshift += DIGIT_SIZE) { ! 230: if (itemp->is_null()) ! 231: break; ! 232: if (itemp->is_leaf()) { ! 233: if (itemp->external_leaf()->key == key){ ! 234: itemp->external_leaf()->count = cnt; ! 235: delete new_rec; // didn't need it after all ! 236: return; // should rarely happen ! 237: } ! 238: break; ! 239: } ! 240: nodep = itemp->next_node(); ! 241: // assert(nodep); ! 242: itemp = &nodep->item[(key & mask) >> unshift]; ! 243: } ! 244: // sze++; ! 245: if (itemp->is_null()) { ! 246: itemp->make_leaf(new_rec); ! 247: if (nodep) ! 248: nodep->busy_count++; ! 249: return; ! 250: } ! 251: // assert(itemp->is_leaf()); ! 252: RECORD* temp = itemp->external_leaf(); ! 253: unsigned long other_key = temp->key; ! 254: // assert(other_key != key); ! 255: unsigned long ind1, ind2; ! 256: for (;; mask <<= DIGIT_SIZE, unshift += DIGIT_SIZE) { ! 257: itemp->make_node(nodep = new pnd_internal_node); ! 258: // assert(pos.curr_depth < POSITIONS); ! 259: ind1 = (other_key & mask) >> unshift; ! 260: ind2 = (key & mask) >> unshift; ! 261: if (ind1 != ind2) break; // I hope so! ! 262: nodep->busy_count = 1; ! 263: itemp = &nodep->item[ind1]; ! 264: } ! 265: nodep->item[ind1].make_leaf(temp); ! 266: nodep->item[ind2].make_leaf(new_rec); ! 267: nodep->busy_count = 2; ! 268: return; ! 269: } ! 270: ! 271: int ! 272: pnd::remove(KEYTYP addr) ! 273: { ! 274: pnd_internal_item* curr_pos[POSITIONS]; ! 275: int curr_depth; ! 276: if (addr == 0) return -1; ! 277: register unsigned long mask = MASK_BITS; ! 278: register unsigned long key = (unsigned long)addr & LOW_MASK; ! 279: if (key) ! 280: key <<= BITS(long) - LOW_BITS; ! 281: key |= (unsigned long)addr >> LOW_BITS; ! 282: register int unshift = 0; ! 283: register pnd_internal_item* itemp = &contents; ! 284: register pnd_internal_node* nodep = 0; ! 285: for (curr_depth = -1;; mask <<= DIGIT_SIZE, unshift += DIGIT_SIZE) { ! 286: // assert(curr_depth < POSITIONS); ! 287: if (itemp->is_null()) ! 288: return -1; ! 289: if (itemp->is_leaf()) ! 290: if (itemp->external_leaf()->key == key) ! 291: break; ! 292: else ! 293: return -1; ! 294: nodep = itemp->next_node(); ! 295: // assert(nodep); ! 296: curr_pos[++curr_depth] = itemp = ! 297: &nodep->item[(key & mask) >> unshift]; ! 298: } ! 299: // assert(itemp->is_leaf()); ! 300: // assert(itemp->external_leaf()->key == key); ! 301: RECORD* old_p = itemp->external_leaf(); ! 302: // sze--; ! 303: int ans = old_p->count; ! 304: delete old_p; ! 305: itemp->make_null(); ! 306: if (curr_depth == -1 || // it was a singleton set ! 307: --(nodep->busy_count) > 1) // easy case ! 308: return ans; ! 309: // assert(nodep->busy_count == 1); ! 310: register pnd_internal_item* itp = &nodep->item[0]; ! 311: while (itp->is_null() || itp == itemp) itp++; ! 312: if (!itp->is_leaf()) // unfortunate case ! 313: return ans; ! 314: RECORD* temp = itp->external_leaf(); ! 315: // assert(temp->key != key); ! 316: for (;;) { ! 317: delete nodep; ! 318: if (curr_depth-- == 0) { ! 319: // assert(sze == 1); ! 320: contents.make_leaf(temp); ! 321: return ans; ! 322: } ! 323: nodep = curr_depth == 0 ? contents.next_node() : ! 324: curr_pos[curr_depth-1]->next_node(); ! 325: if (nodep->busy_count > 1) { ! 326: curr_pos[curr_depth]->make_leaf(temp); ! 327: return ans; ! 328: } ! 329: // assert(nodep->busy_count == 1); ! 330: } ! 331: } ! 332: ! 333: pnd::pnd() ! 334: /* : sze(0) */ ! 335: { ! 336: contents.make_null(); ! 337: } ! 338: ! 339: void ! 340: pnd::initialize() ! 341: { ! 342: the_table = new pnd; ! 343: } ! 344: ! 345: Record_Pool::Record_Pool() ! 346: { ! 347: register int i = RECORDS_BLOCK_COUNT; ! 348: register Record_shell* p = slot; ! 349: register Record_shell* q; ! 350: while (--i) { ! 351: q = p++; ! 352: q->next = p; ! 353: } ! 354: p->next = top; ! 355: top = slot; ! 356: } ! 357: ! 358: Node_Pool::Node_Pool() ! 359: { ! 360: register int i = NODES_BLOCK_COUNT; ! 361: register Node_shell* p = slot; ! 362: register Node_shell* q; ! 363: while (--i) { ! 364: q = p++; ! 365: q->next = p; ! 366: } ! 367: p->next = top; ! 368: top = slot; ! 369: } ! 370: ! 371:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.