Annotation of fam/include/BTree.h, Revision 1.1
1.1 ! trev 1: // Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved.
! 2: //
! 3: // This program is free software; you can redistribute it and/or modify it
! 4: // under the terms of version 2.1 of the GNU Lesser General Public License
! 5: // as published by the Free Software Foundation.
! 6: //
! 7: // This program is distributed in the hope that it would be useful, but
! 8: // WITHOUT ANY WARRANTY; without even the implied warranty of
! 9: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any
! 10: // license provided herein, whether implied or otherwise, is limited to
! 11: // this program in accordance with the express provisions of the GNU Lesser
! 12: // General Public License. Patent licenses, if any, provided herein do not
! 13: // apply to combinations of this program with other product or programs, or
! 14: // any other product whatsoever. This program is distributed without any
! 15: // warranty that the program is delivered free of the rightful claim of any
! 16: // third person by way of infringement or the like. See the GNU Lesser
! 17: // General Public License for more details.
! 18: //
! 19: // You should have received a copy of the GNU General Public License along
! 20: // with this program; if not, write the Free Software Foundation, Inc., 59
! 21: // Temple Place - Suite 330, Boston MA 02111-1307, USA.
! 22:
! 23: #ifndef BTree_included
! 24: #define BTree_included
! 25:
! 26: #include "Boolean.h"
! 27:
! 28: // This is an in-core B-Tree implementation.
! 29: //
! 30: // The public interface is fairly sparse: find, insert and remove
! 31: // are the provided functions. insert() and remove() return true
! 32: // on success, false on failure. find() returns 0 on failure.
! 33: //
! 34: // size() returns the number of key/value pairs in the tree.
! 35: //
! 36: // sizeofnode() returns the size of a BTree node, in bytes.
! 37: //
! 38: // BTree is instantiated by
! 39: //
! 40: // libfam/Client.h:
! 41: // BTree<int, void *> *userData;
! 42: // BTree<int, bool> *endExist;
! 43: // fam/Listener.c++:
! 44: // BTree<int, NegotiatingClient *> negotiating_clients;
! 45: // fam/RequestMap.h:
! 46: // typedef BTree<Request, ClientInterest *> RequestMap;
! 47: // fam/Set.h:
! 48: // template <class T> class Set : public BTree<T, bool>
! 49: // typedef BTree<T, bool> inherited;
! 50: //
! 51: // Set (derived from BTree) is instantiated by
! 52: //
! 53: // fam/TCP_Client.h:
! 54: // Set<Interest *> to_be_scanned;
! 55: // fam/Pollster.h:
! 56: // static Set<Interest *> polled_interests;
! 57: // static Set<ServerHost *> polled_hosts;
! 58: // fam/FileSystem.h:
! 59: // typedef Set<ClientInterest *> Interests;
! 60: //
! 61: template <class Key, class Value> class BTree {
! 62:
! 63: public:
! 64:
! 65: BTree();
! 66: virtual ~BTree();
! 67:
! 68: Value find(const Key& k) const;
! 69: bool insert(const Key& k, const Value& v);
! 70: bool remove(const Key& k);
! 71:
! 72: Key first() const;
! 73: Key next(const Key& k) const;
! 74:
! 75: unsigned size() const { return npairs; }
! 76:
! 77: static unsigned sizeofnode() { return sizeof (Node); }
! 78:
! 79: private:
! 80:
! 81: enum { fanout = 32 };
! 82: enum Status { OK, NO, OVER, UNDER };
! 83:
! 84: struct Node;
! 85: struct Closure {
! 86:
! 87: Closure(Status s) : status(s), key(0),
! 88: value(0), link(0) { }
! 89: Closure(Key k, Value v, Node *l) : status(OVER), key(k), value(v),
! 90: link(l) { }
! 91: Closure(Status s, const Closure& i) : status(s), key(i.key),
! 92: value(i.value), link(i.link) { }
! 93: Closure(Status s, const Key& k) : status(s), key(k),
! 94: value(0), link(0) { }
! 95: operator Status () { return status; }
! 96:
! 97: Status status;
! 98: Key key;
! 99: Value value;
! 100: Node *link;
! 101:
! 102: };
! 103:
! 104: struct Node {
! 105:
! 106: Node(Node *, const Closure&);
! 107: Node(Node *, unsigned index);
! 108: ~Node();
! 109:
! 110: unsigned find(const Key&) const;
! 111: Closure next(const Key&) const;
! 112: bool insert(unsigned, const Closure&);
! 113: Closure remove(unsigned);
! 114: void join(const Closure&, Node *);
! 115:
! 116: unsigned n;
! 117: Key key [fanout];
! 118: Node *link [fanout + 1];
! 119: Value value[fanout];
! 120:
! 121: private:
! 122:
! 123: Node(const Node&); // Do not copy
! 124: Node& operator = (const Node&); // or assign.
! 125:
! 126: };
! 127:
! 128: // Instance Variables
! 129:
! 130: Node *root;
! 131: unsigned npairs;
! 132:
! 133: Closure insert(Node *, const Key&, const Value&);
! 134: Status remove(Node *, const Key&);
! 135: Status underflow(Node *, unsigned);
! 136: Closure remove_rightmost(Node *);
! 137:
! 138: BTree(const BTree&); // Do not copy
! 139: BTree& operator = (const BTree&); // or assign.
! 140:
! 141: };
! 142:
! 143: // Construct a Node from a Node and a Closure. New node
! 144: // has a single key-value pair, its left child
! 145: // is the other node, and its right child is the link
! 146: // field of the closure.
! 147:
! 148: template <class K, class V>
! 149: BTree<K, V>::Node::Node(Node *p, const Closure& closure)
! 150: {
! 151: n = 1;
! 152: link[0] = p;
! 153: key[0] = closure.key;
! 154: value[0] = closure.value;
! 155: link[1] = closure.link;
! 156: }
! 157:
! 158: // Construct a Node from a Node and an index. Steals
! 159: // the elements index..n of other Node for itself.
! 160: // When this constructor is done, both this->link[0] and
! 161: // that->link[that->n] point to the same place. The caller
! 162: // must resolve that.
! 163:
! 164: template <class K, class V>
! 165: BTree<K, V>::Node::Node(Node *that, unsigned index)
! 166: {
! 167: n = that->n - index;
! 168: for (int i = 0; i < n; i++)
! 169: { key[i] = that->key[index + i];
! 170: value[i] = that->value[index + i];
! 171: link[i] = that->link[index + i];
! 172: }
! 173: link[n] = that->link[index + n];
! 174: that->n = index;
! 175: }
! 176:
! 177: // Node destructor. Recursively deletes subnodes.
! 178:
! 179: template <class K, class V>
! 180: BTree<K, V>::Node::~Node()
! 181: {
! 182: for (int i = 0; i <= n; i++)
! 183: delete link[i];
! 184: }
! 185:
! 186: // Node::find() uses binary search to find the nearest key.
! 187: // return index of key that matches or of next key to left.
! 188: //
! 189: // E.g., if find() returns 3 then either key[3] matches or
! 190: // key passed in is between key[3] and key[4].
! 191:
! 192: template <class Key, class Value>
! 193: unsigned
! 194: BTree<Key, Value>::Node::find(const Key& k) const
! 195: {
! 196: unsigned l = 0, r = n;
! 197: while (l < r)
! 198: { int m = (l + r) / 2;
! 199: if (k == key[m])
! 200: return m;
! 201: else if (k < key[m])
! 202: r = m;
! 203: else // (k > key[m])
! 204: l = m + 1;
! 205: }
! 206: assert(l == n || k < key[l]);
! 207: return l;
! 208: }
! 209:
! 210: // Node::insert() inserts key/value into j'th position in node.
! 211: // Inserts closure's link to the right. Returns true if successful,
! 212: // false if node is already full.
! 213:
! 214: template <class K, class V>
! 215: bool
! 216: BTree<K, V>::Node::insert(unsigned j, const Closure& closure)
! 217: {
! 218: if (n < fanout)
! 219: { for (int i = n; i > j; --i)
! 220: { key[i] = key[i - 1];
! 221: value[i] = value[i - 1];
! 222: link[i + 1] = link[i];
! 223: }
! 224: key[j] = closure.key; value[j] = closure.value;
! 225: link[j + 1] = closure.link;
! 226: n++;
! 227: assert(j == 0 || key[j - 1] < key[j]);
! 228: assert(j == n - 1 || key[j] < key[j + 1]);
! 229: return true;
! 230: }
! 231: else
! 232: return false;
! 233: }
! 234:
! 235: // Node::remove extracts the j'th key/value and the link
! 236: // to the right and returns them.
! 237:
! 238: template <class Key, class Value>
! 239: BTree<Key, Value>::Closure
! 240: BTree<Key, Value>::Node::remove(unsigned j)
! 241: {
! 242: Key k = key[j];
! 243: Value v = value[j];
! 244: Node *l = link[j + 1];
! 245: for (unsigned i = j + 1; i < n; i++)
! 246: { key[i - 1] = key[i];
! 247: value[i - 1] = value[i];
! 248: link[i] = link[i + 1];
! 249: }
! 250: --n;
! 251: return Closure(k, v, l);
! 252: }
! 253:
! 254: // Node::join() copies key/value from closure and moves all
! 255: // key/value/links from other Node into this node.
! 256: // Other Node is modified to contain no keys, no values, no links.
! 257:
! 258: template <class K, class V>
! 259: void
! 260: BTree<K, V>::Node::join(const Closure& it, Node *that)
! 261: {
! 262: assert(that);
! 263: assert(n + that->n <= fanout - 1);
! 264: key[n] = it.key;
! 265: value[n] = it.value;
! 266: for (int i = 0, j = n + 1; i < that->n; i++, j++)
! 267: { key[j] = that->key[i];
! 268: value[j] = that->value[i];
! 269: link[j] = that->link[i];
! 270: }
! 271: n += that->n + 1;
! 272: link[n] = that->link[that->n];
! 273: that->n = 0;
! 274: that->link[0] = NULL;
! 275: }
! 276:
! 277: ///////////////////////////////////////////////////////////////////////////////
! 278:
! 279: // BTB constructor -- check that fanout is even.
! 280:
! 281: template <class K, class V>
! 282: BTree<K, V>::BTree()
! 283: : root(NULL), npairs(0)
! 284: {
! 285: assert(!(fanout % 2));
! 286: }
! 287:
! 288: // BTB destructor -- delete all Nodes.
! 289:
! 290: template <class K, class V>
! 291: BTree<K, V>::~BTree()
! 292: {
! 293: delete root;
! 294: }
! 295:
! 296: // BTB::find() -- search BTB for Key, return matching value.
! 297:
! 298: template <class Key, class Value>
! 299: Value
! 300: BTree<Key, Value>::find(const Key& key) const
! 301: {
! 302: for (Node *p = root; p; )
! 303: { int i = p->find(key);
! 304: if (i < p->n && key == p->key[i])
! 305: return p->value[i];
! 306: else
! 307: p = p->link[i];
! 308: }
! 309: return Value(0);
! 310: }
! 311:
! 312: template <class Key, class Value>
! 313: Key
! 314: BTree<Key, Value>::first() const
! 315: {
! 316: if (!root)
! 317: return 0;
! 318: assert(root->n);
! 319:
! 320: Node *p, *q;
! 321: for (p = root; q = p->link[0]; p = q)
! 322: continue;
! 323: return p->key[0];
! 324: }
! 325:
! 326: template <class Key, class Value>
! 327: Key
! 328: BTree<Key, Value>::next(const Key& pred) const
! 329: {
! 330: if (!root)
! 331: return 0;
! 332:
! 333: assert(root->n);
! 334:
! 335: Closure it = root->next(pred);
! 336: switch (Status(it))
! 337: {
! 338: case OK:
! 339: return it.key;
! 340:
! 341: case OVER:
! 342: return 0; // All done.
! 343:
! 344: default:
! 345: assert(0);
! 346: return 0;
! 347: }
! 348: }
! 349:
! 350: template <class Key, class Value>
! 351: BTree<Key, Value>::Closure
! 352: BTree<Key, Value>::Node::next(const Key& pred) const
! 353: {
! 354: if (!this)
! 355: return OVER;
! 356:
! 357: unsigned i = find(pred);
! 358: assert(i <= n);
! 359: if (i < n && key[i] == pred)
! 360: i++;
! 361: Closure it = link[i]->next(pred);
! 362: if (Status(it) != OVER)
! 363: return it;
! 364: if (i == n)
! 365: return OVER;
! 366: else
! 367: return Closure(OK, key[i]);
! 368: }
! 369:
! 370: // BTB::insert() -- insert a new key/value pair
! 371: // into the tree. Fails and returns false if key is already
! 372: // in tree.
! 373: //
! 374: // This code is the only place that makes the tree taller.
! 375:
! 376:
! 377: template <class Key, class Value>
! 378: bool
! 379: BTree<Key, Value>::insert(const Key& key, const Value& value)
! 380: {
! 381: Closure it = insert(root, key, value);
! 382: switch (Status(it))
! 383: {
! 384: case OK:
! 385: npairs++;
! 386: return true;
! 387:
! 388: case NO:
! 389: return false;
! 390:
! 391: case OVER:
! 392: root = new Node(root, it);
! 393: npairs++;
! 394: return true;
! 395:
! 396: default:
! 397: assert(0);
! 398: return false;
! 399: }
! 400: }
! 401:
! 402: // BTB::insert(Node *, ...) -- helper function for
! 403: // BTB::insert(Key&, ...) Recurses to the appropriate leaf, splits
! 404: // nodes as necessary on the way back.
! 405:
! 406: template <class Key, class Value>
! 407: BTree<Key, Value>::Closure
! 408: BTree<Key, Value>::insert(Node *p, const Key& key, const Value& value)
! 409: {
! 410: if (!p) return Closure(key, value, NULL);
! 411: // If you're running Purify on a client linking with libfam, and it says
! 412: // that line is causing a 3-byte UMR for BTree<int, bool>::insert() in
! 413: // FAMNextEvent() ("Reading 8 bytes from 0x... on the stack (3 bytes at
! 414: // 0x... uninit)"), and sizeof(bool) == 1, it's actually OK. Those 3
! 415: // bytes are the padding between the bool Value and the Node *link in
! 416: // BTree<int, bool>::Closure.
! 417:
! 418: int i = p->find(key);
! 419: if (i < p->n && key == p->key[i])
! 420: return NO; // key already exists.
! 421:
! 422: Closure it = insert(p->link[i], key, value);
! 423:
! 424: if (Status(it) == OVER)
! 425: { if (p->insert(i, it))
! 426: return Closure(OK);
! 427: else
! 428: { if (i > fanout / 2)
! 429: { Node *np = new Node(p, fanout / 2 + 1);
! 430: np->insert(i - fanout / 2 - 1, it);
! 431: assert(p->n > fanout / 2);
! 432: it = p->remove(fanout / 2);
! 433: return Closure(it.key, it.value, np);
! 434: }
! 435: else if (i < fanout / 2)
! 436: {
! 437: Node *np = new Node(p, fanout / 2);
! 438: p->insert(i, it);
! 439: assert(p->n > fanout / 2);
! 440: it = p->remove(fanout / 2);
! 441: return Closure(it.key, it.value, np);
! 442: }
! 443: else // (i == fanout / 2)
! 444: {
! 445: Node *np = new Node(p, fanout / 2);
! 446: np->link[0] = it.link;
! 447: return Closure(it.key, it.value, np);
! 448: }
! 449: }
! 450: }
! 451:
! 452: return it;
! 453: }
! 454:
! 455: // BTB::remove() -- remove a key/value from the tree.
! 456: // This function is the only one that makes the tree shorter.
! 457:
! 458: template <class Key, class Value>
! 459: bool
! 460: BTree<Key, Value>::remove(const Key& key)
! 461: {
! 462: Status s = remove(root, key);
! 463: switch (s)
! 464: {
! 465: case OK:
! 466: assert(npairs);
! 467: --npairs;
! 468: assert(!root || root->n);
! 469: return true;
! 470:
! 471: case NO:
! 472: assert(!root || root->n);
! 473: return false;
! 474:
! 475: case UNDER:
! 476: if (root->n == 0)
! 477: { Node *nr = root->link[0];
! 478: root->link[0] = NULL; // don't delete subtree
! 479: delete root;
! 480: root = nr;
! 481: }
! 482: assert(npairs);
! 483: --npairs;
! 484: assert(!root || root->n);
! 485: return true;
! 486:
! 487: default:
! 488: assert(0);
! 489: return false;
! 490: }
! 491: }
! 492:
! 493: // BTB::underflow -- helper function to BTB::remove() When a node
! 494: // has too few elements (less than fanout / 2), this function is
! 495: // invoked. It tries to join i'th child of node p with one of its
! 496: // adjacent siblings, then tries to move entries from an adjacent
! 497: // sibling to child node.
! 498: //
! 499: // Returns UNDER if node p is too small afterward, OK otherwise.
! 500:
! 501: template <class Key, class Value>
! 502: BTree<Key, Value>::Status
! 503: BTree<Key, Value>::underflow(Node *p, unsigned i)
! 504: {
! 505: assert(p);
! 506: assert(i <= p->n);
! 507: Node *cp = p->link[i];
! 508: assert(cp);
! 509:
! 510: Node *rp = i < p->n ? p->link[i + 1] : NULL;
! 511: Node *lp = i > 0 ? p->link[i - 1] : NULL;
! 512: assert(!rp || rp->n >= fanout / 2);
! 513: assert(!lp || lp->n >= fanout / 2);
! 514:
! 515: if (rp && rp->n == fanout / 2)
! 516: {
! 517: // join cp w/ rp;
! 518: cp->join(p->remove(i), rp);
! 519: delete rp;
! 520: }
! 521: else if (lp && lp->n == fanout / 2)
! 522: {
! 523: // join lp w/ cp;
! 524: lp->join(p->remove(i - 1), cp);
! 525: delete cp;
! 526: }
! 527: else if (lp)
! 528: {
! 529: // shuffle from lp to cp;
! 530: Closure li = lp->remove(lp->n - 1);
! 531: cp->insert(0, Closure(p->key[i - 1], p->value[i - 1], cp->link[0]));
! 532: cp->link[0] = li.link;
! 533: p->key[i - 1] = li.key;
! 534: p->value[i - 1] = li.value;
! 535: return OK;
! 536: }
! 537: else if (rp)
! 538: {
! 539: // shuffle from rp to cp;
! 540: Closure ri = rp->remove(0);
! 541: cp->insert(cp->n, Closure(p->key[i], p->value[i], rp->link[0]));
! 542: p->key[i] = ri.key;
! 543: p->value[i] = ri.value;
! 544: rp->link[0] = ri.link;
! 545: return OK;
! 546: }
! 547:
! 548: return p->n >= fanout / 2 ? OK : UNDER;
! 549: }
! 550:
! 551: // BTB::remove_rightmost() -- helper to BTB::remove().
! 552: //
! 553: // Removes rightmost leaf key/value from subtree and returns them.
! 554: // If Nodes become too small in the process, invokes Node::underflow()
! 555: // to fix them up. Return status is either OK or UNDER, indicating
! 556: // root of subtree is too small.
! 557:
! 558:
! 559: template <class Key, class Value>
! 560: BTree<Key, Value>::Closure
! 561: BTree<Key, Value>::remove_rightmost(Node *p)
! 562: {
! 563: int i = p->n;
! 564: Node *cp = p->link[i];
! 565: if (cp)
! 566: { Closure it = remove_rightmost(cp);
! 567: if (Status(it) == UNDER)
! 568: return Closure(underflow(p, i), it);
! 569: else
! 570: return it;
! 571: }
! 572: else
! 573: { Closure it = p->remove(p->n - 1);
! 574: if (p->n >= fanout / 2)
! 575: return Closure(OK, it);
! 576: else
! 577: return Closure(UNDER, it);
! 578: }
! 579: }
! 580:
! 581: // BTB::remove(Node *, ...) -- helper to BTB::remove(const Key&).
! 582: //
! 583: // Recurses into tree to find key/value to delete. When it finds
! 584: // them, it pulls the rightmost leaf key/value off the branch to
! 585: // the left and replaces the removed k/v with them. Watches for
! 586: // Node underflows from BTB::remove_rightmost() and propagates them
! 587: // back up.
! 588:
! 589: template <class Key, class Value>
! 590: BTree<Key, Value>::Status
! 591: BTree<Key, Value>::remove(Node *p, const Key& key)
! 592: {
! 593: if (!p)
! 594: return NO; // key not found
! 595: int i = p->find(key);
! 596: if (i < p->n && key == p->key[i])
! 597: {
! 598: // Delete this one.
! 599:
! 600: Closure it = p->remove(i);
! 601: if (p->link[i])
! 602: { Closure rm = remove_rightmost(p->link[i]);
! 603: assert(!rm.link);
! 604: p->insert(i, Closure(rm.key, rm.value, it.link));
! 605: if (Status(rm) == UNDER)
! 606: return underflow(p, i);
! 607: }
! 608: return p->n >= fanout / 2 ? OK : UNDER;
! 609: }
! 610: else
! 611: { Node *cp = p->link[i];
! 612: Status s = remove(cp, key);
! 613: if (s == UNDER)
! 614: return underflow(p, i);
! 615: else
! 616: return s;
! 617: }
! 618: }
! 619:
! 620:
! 621:
! 622: //#ifndef NDEBUG
! 623: //
! 624: //template <class K, class V>
! 625: //BTree<K, V>::BTree()
! 626: //{
! 627: // //assert(sizeof K <= sizeof BTB::Key);
! 628: // //assert(sizeof V <= sizeof BTB::Value);
! 629: //}
! 630: //
! 631: //#endif /* !NDEBUG */
! 632:
! 633:
! 634: #endif /* !BTree_included */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>