Changeset 2749 in webkit for trunk/JavaScriptCore/kjs/property_map.cpp
- Timestamp:
- Nov 18, 2002, 10:53:35 PM (23 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/property_map.cpp
r2740 r2749 2 2 /* 3 3 * This file is part of the KDE libraries 4 * Copyright (C) 200 1 Peter Kelly (pmk@post.com)4 * Copyright (C) 2002 Darin Adler (darin@apple.com) 5 5 * 6 6 * This library is free software; you can redistribute it and/or … … 21 21 */ 22 22 23 24 23 #include "property_map.h" 25 24 … … 27 26 #include "reference_list.h" 28 27 29 #include <string.h>30 #include <assert.h>31 #include <stdio.h>32 33 28 namespace KJS { 34 29 35 // ------------------------------ PropertyMapNode ------------------------------ 36 37 class PropertyMapNode { 38 public: 39 PropertyMapNode(const UString &n, ValueImp *v, int att, PropertyMapNode *p) 40 : name(n), value(v), attr(att), left(0), right(0), parent(p), height(1) {} 41 42 UString name; 43 ValueImp *value; 44 int attr; 45 46 void setLeft(PropertyMapNode *newLeft); 47 void setRight(PropertyMapNode *newRight); 48 PropertyMapNode *findMax(); 49 PropertyMapNode *findMin(); 50 51 PropertyMapNode *next(); 52 53 PropertyMapNode *left; 54 PropertyMapNode *right; 55 PropertyMapNode *parent; 56 int height; 57 58 private: 59 void setParent(PropertyMapNode *newParent); 60 }; 61 62 void PropertyMapNode::setLeft(PropertyMapNode *newLeft) 63 { 64 if (left) 65 left->setParent(0); 66 left = newLeft; 67 if (left) 68 left->setParent(this); 69 } 70 71 void PropertyMapNode::setRight(PropertyMapNode *newRight) 72 { 73 if (right) 74 right->setParent(0); 75 right = newRight; 76 if (right) 77 right->setParent(this); 78 } 79 80 void PropertyMapNode::setParent(PropertyMapNode *newParent) 81 { 82 if (parent) { 83 //assert(this == parent->left || this == parent->right); 84 if (this == parent->left) 85 parent->left = 0; 86 else 87 parent->right = 0; 88 } 89 parent = newParent; 90 } 91 92 PropertyMapNode *PropertyMapNode::findMax() 93 { 94 PropertyMapNode *max = this; 95 while (max->right) 96 max = max->right; 97 return max; 98 } 99 100 PropertyMapNode *PropertyMapNode::findMin() 101 { 102 PropertyMapNode *min = this; 103 while (min->left) 104 min = min->left; 105 return min; 106 } 107 108 PropertyMapNode *PropertyMapNode::next() 109 { 110 // find the next node, going from lowest name to highest name 111 112 // We have a right node. Starting from our right node, keep going left as far as we can 113 if (right) { 114 PropertyMapNode *n = right; 115 while (n->left) 116 n = n->left; 117 return n; 118 } 119 120 // We have no right node. Keep going up to the left, until we find a node that has a parent 121 // to the right. If we find one, go to it. Otherwise, we have reached the end. 122 PropertyMapNode *n = this; 123 while (n->parent && n->parent->right == n) { 124 // parent is to our left 125 n = n->parent; 126 } 127 if (n->parent && n->parent->left == n) { 128 // parent is to our right 129 return n->parent; 130 } 131 132 return 0; 133 } 134 135 // ------------------------------ PropertyMap ---------------------------------- 136 137 int KJS::uscompare(const UString &s1, const UString &s2) 138 { 139 int len1 = s1.size(); 140 int len2 = s2.size(); 141 if (len1 < len2) 142 return -1; 143 else if (len1 > len2) 144 return 1; 145 else 146 return memcmp(s1.data(), s2.data(), len1*sizeof(UChar)); 147 } 148 149 PropertyMap::PropertyMap() 150 { 151 root = 0; 30 // Algorithm concepts from Algorithms in C++, Sedgewick. 31 32 PropertyMap::PropertyMap() : _tableSize(0), _table(0), _keyCount(0) 33 { 152 34 } 153 35 154 36 PropertyMap::~PropertyMap() 155 37 { 156 clear(); 157 } 158 159 void PropertyMap::put(const UString &name, ValueImp *value, int attr) 160 { 161 // if not root; make the root the new node 162 if (!root) { 163 root = new PropertyMapNode(name, value, attr, 0); 164 return; 165 } 166 167 // try to find the parent node 168 PropertyMapNode *parent = root; 169 int isLeft = false; 170 while (true) { 171 int cmp = uscompare(name, parent->name); 172 if (cmp < 0) { 173 // traverse to left node (if any) 174 isLeft = true; 175 if (!parent->left) 176 break; 177 else 178 parent = parent->left; 179 } 180 else if (cmp > 0) { 181 // traverse to right node (if any) 182 isLeft = false; 183 if (!parent->right) 184 break; 185 else 186 parent = parent->right; 187 } 188 else { 189 // a node with this name already exists; just replace the value 190 parent->value = value; 191 return; 192 } 193 } 194 195 // we found the parent 196 //assert(parent); 197 198 if (isLeft) { 199 //assert(!parent->left); 200 parent->left = new PropertyMapNode(name, value, attr, parent); 201 } 202 else { 203 //assert(!parent->right); 204 parent->right = new PropertyMapNode(name, value, attr, parent); 205 } 206 updateHeight(parent); 207 208 209 PropertyMapNode *node = parent; 210 while (node) { 211 PropertyMapNode *p = node->parent; 212 balance(node); // may change node 213 node = p; 214 } 38 //printf("key count is %d\n", _keyCount); 39 UString::Rep *key = _singleEntry.key; 40 if (key) 41 key->deref(); 42 for (int i = 0; i < _tableSize; i++) { 43 key = _table[i].key; 44 if (key) 45 key->deref(); 46 } 47 free(_table); 48 } 49 50 void PropertyMap::clear() 51 { 52 UString::Rep *key = _singleEntry.key; 53 if (key) { 54 key->deref(); 55 _singleEntry.key = 0; 56 } 57 for (int i = 0; i < _tableSize; i++) { 58 UString::Rep *key = _table[i].key; 59 if (key) { 60 key->deref(); 61 _table[i].key = 0; 62 } 63 } 64 _keyCount = 0; 65 } 66 67 int PropertyMap::hash(const UString::Rep *s) const 68 { 69 int h = 0; 70 int length = s->len; 71 int prefixLength = length < 8 ? length : 8; 72 for (int i = 0; i < prefixLength; i++) 73 h = (127 * h + s->dat[i].unicode()) & _tableSizeHashMask; 74 int suffixPosition = length < 16 ? 8 : length - 8; 75 for (int i = suffixPosition; i < length; i++) 76 h = (127 * h + s->dat[i].unicode()) & _tableSizeHashMask; 77 return h; 78 } 79 80 bool PropertyMap::keysMatch(const UString::Rep *a, const UString::Rep *b) 81 { 82 if (a == b) 83 return true; 84 85 int len = a->len; 86 if (len != b->len) 87 return false; 88 89 for (int i = 0; i != len; ++i) 90 if (a->dat[i].unicode() != b->dat[i].unicode()) 91 return false; 92 93 return true; 94 } 95 96 ValueImp *PropertyMap::get(const UString &name, int &attributes) const 97 { 98 if (!_table) { 99 UString::Rep *key = _singleEntry.key; 100 if (key && keysMatch(name.rep, key)) { 101 attributes = _singleEntry.attributes; 102 return _singleEntry.value; 103 } 104 return 0; 105 } 106 107 int i = hash(name.rep); 108 while (UString::Rep *key = _table[i].key) { 109 if (keysMatch(name.rep, key)) { 110 attributes = _table[i].attributes; 111 return _table[i].value; 112 } 113 i = (i + 1) % _tableSize; 114 } 115 return 0; 116 } 117 118 ValueImp *PropertyMap::get(const UString &name) const 119 { 120 if (!_table) { 121 UString::Rep *key = _singleEntry.key; 122 if (key && keysMatch(name.rep, key)) 123 return _singleEntry.value; 124 return 0; 125 } 126 127 int i = hash(name.rep); 128 while (UString::Rep *key = _table[i].key) { 129 if (keysMatch(name.rep, key)) 130 return _table[i].value; 131 i = (i + 1) % _tableSize; 132 } 133 return 0; 134 } 135 136 void PropertyMap::put(const UString &name, ValueImp *value, int attributes) 137 { 138 if (!_table) { 139 UString::Rep *key = _singleEntry.key; 140 if (key) { 141 if (keysMatch(name.rep, key)) { 142 _singleEntry.value = value; 143 return; 144 } 145 } else { 146 name.rep->ref(); 147 _singleEntry.key = name.rep; 148 _singleEntry.value = value; 149 _singleEntry.attributes = attributes; 150 _keyCount = 1; 151 return; 152 } 153 } 154 155 if (_keyCount >= _tableSize / 2) 156 expand(); 157 158 int i = hash(name.rep); 159 while (UString::Rep *key = _table[i].key) { 160 if (keysMatch(name.rep, key)) { 161 // Put a new value in an existing hash table entry. 162 _table[i].value = value; 163 // Attributes are intentionally not updated. 164 return; 165 } 166 i = (i + 1) % _tableSize; 167 } 168 169 // Create a new hash table entry. 170 name.rep->ref(); 171 _table[i].key = name.rep; 172 _table[i].value = value; 173 _table[i].attributes = attributes; 174 ++_keyCount; 175 } 176 177 inline void PropertyMap::insert(UString::Rep *key, ValueImp *value, int attributes) 178 { 179 int i = hash(key); 180 while (_table[i].key) 181 i = (i + 1) % _tableSize; 182 183 _table[i].key = key; 184 _table[i].value = value; 185 _table[i].attributes = attributes; 186 } 187 188 void PropertyMap::expand() 189 { 190 int oldTableSize = _tableSize; 191 Entry *oldTable = _table; 192 193 _tableSize = oldTableSize ? oldTableSize * 2 : 16; 194 _tableSizeHashMask = _tableSize - 1; 195 _table = (Entry *)calloc(_tableSize, sizeof(Entry)); 196 197 UString::Rep *key = _singleEntry.key; 198 if (key) { 199 insert(key, _singleEntry.value, _singleEntry.attributes); 200 _singleEntry.key = 0; 201 } 202 203 for (int i = 0; i != oldTableSize; ++i) { 204 key = oldTable[i].key; 205 if (key) 206 insert(key, oldTable[i].value, oldTable[i].attributes); 207 } 208 209 free(oldTable); 215 210 } 216 211 217 212 void PropertyMap::remove(const UString &name) 218 213 { 219 PropertyMapNode *node = getNode(name); 220 if (!node) // name not in tree 221 return; 222 223 PropertyMapNode *removed = remove(node); 224 if (removed) 225 delete node; 226 } 227 228 ValueImp *PropertyMap::get(const UString &name) const 229 { 230 const PropertyMapNode *n = getNode(name); 231 return n ? n->value : 0; 232 } 233 234 ValueImp *PropertyMap::get(const UString &name, int &attributes) const 235 { 236 const PropertyMapNode *n = getNode(name); 237 attributes = n ? n->attr : 0; 238 return n ? n->value : 0; 239 } 240 241 void PropertyMap::clear() 242 { 243 clear(0); 244 } 245 246 void PropertyMap::mark() 247 { 248 PropertyMapNode *node = first(); 249 while (node) { 250 if (!node->value->marked()) 251 node->value->mark(); 252 node = node->next(); 253 } 214 UString::Rep *key; 215 216 if (!_table) { 217 key = _singleEntry.key; 218 if (key && keysMatch(name.rep, key)) { 219 key->deref(); 220 _singleEntry.key = 0; 221 _keyCount = 0; 222 } 223 return; 224 } 225 226 // Find the thing to remove. 227 int i = hash(name.rep); 228 while ((key = _table[i].key)) { 229 if (keysMatch(name.rep, key)) 230 break; 231 i = (i + 1) % _tableSize; 232 } 233 if (!key) 234 return; 235 236 // Remove the one key. 237 key->deref(); 238 _table[i].key = 0; 239 --_keyCount; 240 241 // Reinsert all the items to the right in the same cluster. 242 while (1) { 243 i = (i + 1) % _tableSize; 244 key = _table[i].key; 245 if (!key) 246 break; 247 _table[i].key = 0; 248 insert(key, _table[i].value, _table[i].attributes); 249 } 250 } 251 252 void PropertyMap::mark() const 253 { 254 if (_singleEntry.key) { 255 ValueImp *v = _singleEntry.value; 256 if (!v->marked()) 257 v->mark(); 258 } 259 for (int i = 0; i != _tableSize; ++i) { 260 if (_table[i].key) { 261 ValueImp *v = _table[i].value; 262 if (!v->marked()) 263 v->mark(); 264 } 265 } 254 266 } 255 267 256 268 void PropertyMap::addEnumerablesToReferenceList(ReferenceList &list, const Object &base) const 257 269 { 258 PropertyMapNode *node = first(); 259 while (node) { 260 if (!(node->attr & DontEnum)) 261 list.append(Reference(base, node->name)); 262 node = node->next(); 263 } 264 } 265 266 void PropertyMap::clear(PropertyMapNode *node) 267 { 268 if (node == 0) 269 node = root; 270 if (node == 0) // nothing to do 271 return; 272 273 if (node->left) 274 clear(node->left); 275 if (node->right) 276 clear(node->right); 277 if (node == root) 278 root = 0; 279 delete node; 280 } 281 282 void PropertyMap::dump(const PropertyMapNode *node, int indent) const 283 { 284 if (!node && indent > 0) 285 return; 286 if (!node) 287 node = root; 288 if (!node) 289 return; 290 291 assert(!node->right || node->right->parent == node); 292 dump(node->right, indent+1); 293 for (int i = 0; i < indent; i++) { 294 printf(" "); 295 } 296 printf("[%d] %s\n", node->height, node->name.ascii()); 297 assert(!node->left || node->left->parent == node); 298 dump(node->left, indent+1); 299 } 300 301 void PropertyMap::checkTree(const PropertyMapNode *node) const 302 { 303 if (!root) 304 return; 305 if (node == 0) 306 node = root; 307 if (node == root) { 308 assert(!node->parent); 309 } 310 assert(!node->right || node->right->parent == node); 311 assert(!node->left || node->left->parent == node); 312 assert(node->left != node); 313 assert(node->right != node); 314 if (node->left && node->right) 315 assert(node->left != node->right); 316 317 PropertyMapNode *n = node->parent; 318 while (n) { 319 assert(n != node); 320 n = n->parent; 321 } 322 323 if (node->right) 324 checkTree(node->right); 325 if (node->left) 326 checkTree(node->left); 327 } 328 329 PropertyMapNode *PropertyMap::getNode(const UString &name) const 330 { 331 PropertyMapNode *node = root; 332 333 while (true) { 334 if (!node) 335 return 0; 336 337 int cmp = uscompare(name, node->name); 338 if (cmp < 0) 339 node = node->left; 340 else if (cmp > 0) 341 node = node->right; 342 else 343 return node; 344 } 345 } 346 347 PropertyMapNode *PropertyMap::first() const 348 { 349 if (!root) 350 return 0; 351 352 PropertyMapNode *node = root; 353 while (node->left) 354 node = node->left; 355 return node; 356 } 357 358 PropertyMapNode * PropertyMap::remove(PropertyMapNode *node) 359 { 360 PropertyMapNode *parent = node->parent; 361 //assert(!parent || (node == parent->left || node == parent->right)); 362 bool isLeft = (parent && node == parent->left); 363 364 PropertyMapNode *replace = 0; 365 if (node->left && node->right) { 366 PropertyMapNode *maxLeft = node->left->findMax(); 367 if (maxLeft == node->left) { 368 maxLeft->setRight(node->right); 369 replace = maxLeft; 370 } 371 else { 372 remove(maxLeft); 373 374 maxLeft->setLeft(node->left); 375 maxLeft->setRight(node->right); 376 replace = maxLeft; 377 } 378 // removing maxLeft could have re-balanced the tree, so recalculate 379 // parent again 380 parent = node->parent; 381 //assert(!parent || (node == parent->left || node == parent->right)); 382 isLeft = (parent && node == parent->left); 383 } 384 else if (node->left) { 385 replace = node->left; 386 } 387 else if (node->right) { 388 replace = node->right; 389 } 390 else { 391 replace = 0; 392 } 393 394 if (parent) { 395 if (isLeft) 396 parent->setLeft(replace); 397 else 398 parent->setRight(replace); 399 } 400 else { 401 root = replace; 402 if (replace) 403 replace->parent = 0; 404 } 405 406 if (replace) 407 updateHeight(replace); // will also update parent's height 408 else if (parent) 409 updateHeight(parent); 410 else if (root) 411 updateHeight(root); 412 413 414 // balance the tree 415 PropertyMapNode *bal = parent; 416 while (bal) { 417 PropertyMapNode *p = bal->parent; 418 balance(bal); // may change bal 419 bal = p; 420 } 421 422 return node; 423 } 424 425 void PropertyMap::balance(PropertyMapNode* node) 426 { 427 int lheight = node->left ? node->left->height : 0; 428 int rheight = node->right ? node->right->height : 0; 429 430 int bal = rheight-lheight; 431 432 if (bal < -1) { 433 //assert(node->left); 434 int llheight = node->left->left ? node->left->left->height : 0; 435 int lrheight = node->left->right ? node->left->right->height : 0; 436 int lbal = lrheight - llheight; 437 438 if (lbal < 0) { 439 rotateLL(node); // LL rotation 440 } 441 else { 442 // lbal >= 0 443 rotateLR(node); 444 } 445 } 446 else if (bal > 1) { 447 int rlheight = node->right->left ? node->right->left->height : 0; 448 int rrheight = node->right->right ? node->right->right->height : 0; 449 int rbal = rrheight - rlheight; 450 if (rbal < 0) { 451 rotateRL(node); 452 } 453 else { 454 // rbal >= 0 455 rotateRR(node); // RR rotateion 456 } 457 } 458 } 459 460 void PropertyMap::updateHeight(PropertyMapNode* &node) 461 { 462 int lheight = node->left ? node->left->height : 0; 463 int rheight = node->right ? node->right->height : 0; 464 if (lheight > rheight) 465 node->height = lheight+1; 466 else 467 node->height = rheight+1; 468 //assert(node->parent != node); 469 if (node->parent) 470 updateHeight(node->parent); 471 } 472 473 void PropertyMap::rotateRR(PropertyMapNode* &node) 474 { 475 /* 476 Perform a RR ("single left") rotation, e.g. 477 478 a b 479 / \ / \ 480 X b --> a Z 481 / \ / \ 482 Y Z X Y 483 */ 484 485 // Here, node is initially a, will be replaced with b 486 487 PropertyMapNode *a = node; 488 PropertyMapNode *b = node->right; 489 490 PropertyMapNode *parent = a->parent; 491 //assert(!parent || (a == parent->left || a == parent->right)); 492 bool isLeft = (parent && a == parent->left); 493 494 // do the rotation 495 a->setRight(b->left); 496 b->setLeft(a); 497 498 // now node is b 499 node = b; 500 if (parent) { 501 if (isLeft) 502 parent->setLeft(b); 503 else 504 parent->setRight(b); 505 } 506 else { 507 // a was the root node 508 root = b; 509 } 510 511 updateHeight(a); 512 updateHeight(b); 513 } 514 515 516 void PropertyMap::rotateLL(PropertyMapNode* &node) 517 { 518 /* 519 Perform a LL ("single right") rotation, e.g. 520 521 522 a b 523 / \ / \ 524 b Z --> X a 525 / \ / \ 526 X Y Y Z 527 */ 528 529 // Here, node is initially a, will be replaced with b 530 531 PropertyMapNode *a = node; 532 PropertyMapNode *b = node->left; 533 534 PropertyMapNode *parent = a->parent; 535 //assert(!parent || (a == parent->left || a == parent->right)); 536 bool isLeft = (parent && a == parent->left); 537 538 // do the rotation 539 a->setLeft(b->right); 540 b->setRight(a); 541 542 // now node is b 543 node = b; 544 if (parent) { 545 if (isLeft) 546 parent->setLeft(b); 547 else 548 parent->setRight(b); 549 } 550 else { 551 // a was the root node 552 root = b; 553 } 554 555 updateHeight(a); 556 updateHeight(b); 557 } 558 559 void PropertyMap::rotateRL(PropertyMapNode* &node) 560 { 561 /* 562 Perform a RL ("double left") rotation, e.g. 563 564 a a b 565 / \ LL on c / \ RR on b / \ 566 W c --> W b --> a c 567 / \ / \ / \ / \ 568 b Z X c W X Y Z 569 / \ / \ 570 X Y Y Z 571 572 */ 573 574 PropertyMapNode *a = node; 575 PropertyMapNode *c = node->right; 576 PropertyMapNode *b = node->right->left; 577 578 rotateLL(c); 579 rotateRR(b); 580 581 updateHeight(a); 582 updateHeight(c); 583 updateHeight(b); 584 } 585 586 void PropertyMap::rotateLR(PropertyMapNode* &node) 587 { 588 /* 589 Perform a LR ("double right") rotation, e.g. 590 591 a a b 592 / \ RR on c / \ LL on a / \ 593 c Z --> b Z --> c a 594 / \ / \ / \ / \ 595 W b c Y W X Y Z 596 / \ / \ 597 X Y W X 598 */ 599 600 PropertyMapNode *a = node; 601 PropertyMapNode *c = node->left; 602 PropertyMapNode *b = node->left->right; 603 604 rotateRR(c); 605 rotateLL(a); 606 607 updateHeight(c); 608 updateHeight(a); 609 updateHeight(b); 270 UString::Rep *key = _singleEntry.key; 271 if (key && !(_singleEntry.attributes & DontEnum)) 272 list.append(Reference(base, key)); 273 for (int i = 0; i != _tableSize; ++i) { 274 UString::Rep *key = _table[i].key; 275 if (key && !(_table[i].attributes & DontEnum)) 276 list.append(Reference(base, key)); 277 } 610 278 } 611 279
Note:
See TracChangeset
for help on using the changeset viewer.