[BACK]Return to BTree.h CVS log [TXT][DIR] Up to [Development] / fam / include

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>