Line data Source code
1 : /**
2 : * \file include/stx/btree.h
3 : * Contains the main B+ tree implementation template class btree.
4 : */
5 :
6 : /*
7 : * STX B+ Tree Template Classes v0.9
8 : * Copyright (C) 2008-2013 Timo Bingmann <tb@panthema.net>
9 : *
10 : * Boost Software License - Version 1.0 - August 17th, 2003
11 : *
12 : * Permission is hereby granted, free of charge, to any person or organization
13 : * obtaining a copy of the software and accompanying documentation covered by
14 : * this license (the "Software") to use, reproduce, display, distribute,
15 : * execute, and transmit the Software, and to prepare derivative works of the
16 : * Software, and to permit third-parties to whom the Software is furnished to
17 : * do so, all subject to the following:
18 : *
19 : * The copyright notices in the Software and this entire statement, including
20 : * the above license grant, this restriction and the following disclaimer, must
21 : * be included in all copies of the Software, in whole or in part, and all
22 : * derivative works of the Software, unless such copies or derivative works are
23 : * solely in the form of machine-executable object code generated by a source
24 : * language processor.
25 : *
26 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 : * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29 : * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30 : * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31 : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 : * DEALINGS IN THE SOFTWARE.
33 : */
34 :
35 : #ifndef _STX_BTREE_H_
36 : #define _STX_BTREE_H_
37 :
38 : // *** Required Headers from the STL
39 :
40 : #include <algorithm>
41 : #include <functional>
42 : #include <istream>
43 : #include <ostream>
44 : #include <memory>
45 : #include <cstddef>
46 : #include <assert.h>
47 :
48 : // *** Debugging Macros
49 :
50 : #ifdef BTREE_DEBUG
51 :
52 : #include <iostream>
53 :
54 : /// Print out debug information to std::cout if BTREE_DEBUG is defined.
55 : #define BTREE_PRINT(x) do { if (debug) (std::cout << x << std::endl); } while(0)
56 :
57 : /// Assertion only if BTREE_DEBUG is defined. This is not used in verify().
58 : #define BTREE_ASSERT(x) do { assert(x); } while(0)
59 :
60 : #else
61 :
62 : /// Print out debug information to std::cout if BTREE_DEBUG is defined.
63 : #define BTREE_PRINT(x) do { } while(0)
64 :
65 : /// Assertion only if BTREE_DEBUG is defined. This is not used in verify().
66 : #define BTREE_ASSERT(x) do { } while(0)
67 :
68 : #endif
69 :
70 : /// The maximum of a and b. Used in some compile-time formulas.
71 : #define BTREE_MAX(a,b) ((a) < (b) ? (b) : (a))
72 :
73 : #ifndef BTREE_FRIENDS
74 : /// The macro BTREE_FRIENDS can be used by outside class to access the B+
75 : /// tree internals. This was added for wxBTreeDemo to be able to draw the
76 : /// tree.
77 : #define BTREE_FRIENDS friend class btree_friend;
78 : #endif
79 :
80 : /// STX - Some Template Extensions namespace
81 : namespace stx {
82 :
83 : /** Generates default traits for a B+ tree used as a set. It estimates leaf and
84 : * inner node sizes by assuming a cache line size of 256 bytes. */
85 : template <typename _Key>
86 : struct btree_default_set_traits
87 : {
88 : /// If true, the tree will self verify it's invariants after each insert()
89 : /// or erase(). The header must have been compiled with BTREE_DEBUG defined.
90 : static const bool selfverify = false;
91 :
92 : /// If true, the tree will print out debug information and a tree dump
93 : /// during insert() or erase() operation. The header must have been
94 : /// compiled with BTREE_DEBUG defined and key_type must be std::ostream
95 : /// printable.
96 : static const bool debug = false;
97 :
98 : /// Number of slots in each leaf of the tree. Estimated so that each node
99 : /// has a size of about 256 bytes.
100 : static const int leafslots = BTREE_MAX( 8, 256 / (sizeof(_Key)) );
101 :
102 : /// Number of slots in each inner node of the tree. Estimated so that each node
103 : /// has a size of about 256 bytes.
104 : static const int innerslots = BTREE_MAX( 8, 256 / (sizeof(_Key) + sizeof(void*)) );
105 :
106 : /// As of stx-btree-0.9, the code does linear search in find_lower() and
107 : /// find_upper() instead of binary_search, unless the node size is larger
108 : /// than this threshold. See notes at
109 : /// http://panthema.net/2013/0504-STX-B+Tree-Binary-vs-Linear-Search
110 : static const size_t binsearch_threshold = 256;
111 : };
112 :
113 : /** Generates default traits for a B+ tree used as a map. It estimates leaf and
114 : * inner node sizes by assuming a cache line size of 256 bytes. */
115 : template <typename _Key, typename _Data>
116 : struct btree_default_map_traits
117 : {
118 : /// If true, the tree will self verify it's invariants after each insert()
119 : /// or erase(). The header must have been compiled with BTREE_DEBUG defined.
120 : static const bool selfverify = false;
121 :
122 : /// If true, the tree will print out debug information and a tree dump
123 : /// during insert() or erase() operation. The header must have been
124 : /// compiled with BTREE_DEBUG defined and key_type must be std::ostream
125 : /// printable.
126 : static const bool debug = false;
127 :
128 : /// Number of slots in each leaf of the tree. Estimated so that each node
129 : /// has a size of about 256 bytes.
130 : static const int leafslots = BTREE_MAX( 8, 256 / (sizeof(_Key) + sizeof(_Data)) );
131 :
132 : /// Number of slots in each inner node of the tree. Estimated so that each node
133 : /// has a size of about 256 bytes.
134 : static const int innerslots = BTREE_MAX( 8, 256 / (sizeof(_Key) + sizeof(void*)) );
135 :
136 : /// As of stx-btree-0.9, the code does linear search in find_lower() and
137 : /// find_upper() instead of binary_search, unless the node size is larger
138 : /// than this threshold. See notes at
139 : /// http://panthema.net/2013/0504-STX-B+Tree-Binary-vs-Linear-Search
140 : static const size_t binsearch_threshold = 256;
141 : };
142 :
143 : /** @brief Basic class implementing a base B+ tree data structure in memory.
144 : *
145 : * The base implementation of a memory B+ tree. It is based on the
146 : * implementation in Cormen's Introduction into Algorithms, Jan Jannink's paper
147 : * and other algorithm resources. Almost all STL-required function calls are
148 : * implemented. The asymptotic time requirements of the STL are not always
149 : * fulfilled in theory, however in practice this B+ tree performs better than a
150 : * red-black tree by using more memory. The insertion function splits the nodes
151 : * on the recursion unroll. Erase is largely based on Jannink's ideas.
152 : *
153 : * This class is specialized into btree_set, btree_multiset, btree_map and
154 : * btree_multimap using default template parameters and facade functions.
155 : */
156 : template <typename _Key, typename _Data,
157 : typename _Value = std::pair<_Key, _Data>,
158 : typename _Compare = std::less<_Key>,
159 : typename _Traits = btree_default_map_traits<_Key, _Data>,
160 : bool _Duplicates = false,
161 : typename _Alloc = std::allocator<_Value>,
162 : bool _UsedAsSet = false >
163 : class btree
164 : {
165 : public:
166 : // *** Template Parameter Types
167 :
168 : /// First template parameter: The key type of the B+ tree. This is stored
169 : /// in inner nodes and leaves
170 : typedef _Key key_type;
171 :
172 : /// Second template parameter: The data type associated with each
173 : /// key. Stored in the B+ tree's leaves
174 : typedef _Data data_type;
175 :
176 : /// Third template parameter: Composition pair of key and data types, this
177 : /// is required by the STL standard. The B+ tree does not store key and
178 : /// data together. If value_type == key_type then the B+ tree implements a
179 : /// set.
180 : typedef _Value value_type;
181 :
182 : /// Fourth template parameter: Key comparison function object
183 : typedef _Compare key_compare;
184 :
185 : /// Fifth template parameter: Traits object used to define more parameters
186 : /// of the B+ tree
187 : typedef _Traits traits;
188 :
189 : /// Sixth template parameter: Allow duplicate keys in the B+ tree. Used to
190 : /// implement multiset and multimap.
191 : static const bool allow_duplicates = _Duplicates;
192 :
193 : /// Seventh template parameter: STL allocator for tree nodes
194 : typedef _Alloc allocator_type;
195 :
196 : /// Eighth template parameter: boolean indicator whether the btree is used
197 : /// as a set. In this case all operations on the data arrays are
198 : /// omitted. This flag is kind of hacky, but required because
199 : /// sizeof(empty_struct) = 1 due to the C standard. Without the flag, lots
200 : /// of superfluous copying would occur.
201 : static const bool used_as_set = _UsedAsSet;
202 :
203 : // The macro BTREE_FRIENDS can be used by outside class to access the B+
204 : // tree internals. This was added for wxBTreeDemo to be able to draw the
205 : // tree.
206 : BTREE_FRIENDS
207 :
208 : public:
209 : // *** Constructed Types
210 :
211 : /// Typedef of our own type
212 : typedef btree<key_type, data_type, value_type, key_compare,
213 : traits, allow_duplicates, allocator_type, used_as_set> btree_self;
214 :
215 : /// Size type used to count keys
216 : typedef size_t size_type;
217 :
218 : /// The pair of key_type and data_type, this may be different from value_type.
219 : typedef std::pair<key_type, data_type> pair_type;
220 :
221 : public:
222 : // *** Static Constant Options and Values of the B+ Tree
223 :
224 : /// Base B+ tree parameter: The number of key/data slots in each leaf
225 : static const unsigned short leafslotmax = traits::leafslots;
226 :
227 : /// Base B+ tree parameter: The number of key slots in each inner node,
228 : /// this can differ from slots in each leaf.
229 : static const unsigned short innerslotmax = traits::innerslots;
230 :
231 : /// Computed B+ tree parameter: The minimum number of key/data slots used
232 : /// in a leaf. If fewer slots are used, the leaf will be merged or slots
233 : /// shifted from it's siblings.
234 : static const unsigned short minleafslots = (leafslotmax / 2);
235 :
236 : /// Computed B+ tree parameter: The minimum number of key slots used
237 : /// in an inner node. If fewer slots are used, the inner node will be
238 : /// merged or slots shifted from it's siblings.
239 : static const unsigned short mininnerslots = (innerslotmax / 2);
240 :
241 : /// Debug parameter: Enables expensive and thorough checking of the B+ tree
242 : /// invariants after each insert/erase operation.
243 : static const bool selfverify = traits::selfverify;
244 :
245 : /// Debug parameter: Prints out lots of debug information about how the
246 : /// algorithms change the tree. Requires the header file to be compiled
247 : /// with BTREE_DEBUG and the key type must be std::ostream printable.
248 : static const bool debug = traits::debug;
249 :
250 : private:
251 : // *** Node Classes for In-Memory Nodes
252 :
253 : /// The header structure of each node in-memory. This structure is extended
254 : /// by inner_node or leaf_node.
255 : struct node
256 678783 : {
257 : /// Level in the b-tree, if level == 0 -> leaf node
258 : unsigned short level;
259 :
260 : /// Number of key slotuse use, so number of valid children or data
261 : /// pointers
262 : unsigned short slotuse;
263 :
264 : /// Delayed initialisation of constructed node
265 1627124 : inline void initialize(const unsigned short l)
266 : {
267 1627124 : level = l;
268 1627124 : slotuse = 0;
269 1627124 : }
270 :
271 : /// True if this is a leaf node
272 630374402 : inline bool isleafnode() const
273 : {
274 630374402 : return (level == 0);
275 : }
276 : };
277 :
278 : /// Extended structure of a inner node in-memory. Contains only keys and no
279 : /// data items.
280 : struct inner_node : public node
281 186508 : {
282 : /// Define an related allocator for the inner_node structs.
283 : typedef typename _Alloc::template rebind<inner_node>::other alloc_type;
284 :
285 : /// Keys of children or data pointers
286 : key_type slotkey[innerslotmax];
287 :
288 : /// Pointers to children
289 : node* childid[innerslotmax+1];
290 :
291 : /// Set variables to initial values
292 186243 : inline void initialize(const unsigned short l)
293 : {
294 186243 : node::initialize(l);
295 186243 : }
296 :
297 : /// True if the node's slots are full
298 131356 : inline bool isfull() const
299 : {
300 131356 : return (node::slotuse == innerslotmax);
301 : }
302 :
303 : /// True if few used entries, less than half full
304 45965 : inline bool isfew() const
305 : {
306 45965 : return (node::slotuse <= mininnerslots);
307 : }
308 :
309 : /// True if node has too few entries
310 92509433 : inline bool isunderflow() const
311 : {
312 92509433 : return (node::slotuse < mininnerslots);
313 : }
314 : };
315 :
316 : /// Extended structure of a leaf node in memory. Contains pairs of keys and
317 : /// data items. Key and data slots are kept in separate arrays, because the
318 : /// key array is traversed very often compared to accessing the data items.
319 : struct leaf_node : public node
320 2119399 : {
321 : /// Define an related allocator for the leaf_node structs.
322 : typedef typename _Alloc::template rebind<leaf_node>::other alloc_type;
323 :
324 : /// Double linked list pointers to traverse the leaves
325 : leaf_node *prevleaf;
326 :
327 : /// Double linked list pointers to traverse the leaves
328 : leaf_node *nextleaf;
329 :
330 : /// Keys of children or data pointers
331 : key_type slotkey[leafslotmax];
332 :
333 : /// Array of data
334 : data_type slotdata[used_as_set ? 1 : leafslotmax];
335 :
336 : /// Set variables to initial values
337 1440881 : inline void initialize()
338 : {
339 1440881 : node::initialize(0);
340 1440881 : prevleaf = nextleaf = NULL;
341 1440881 : }
342 :
343 : /// True if the node's slots are full
344 2709203 : inline bool isfull() const
345 : {
346 2709203 : return (node::slotuse == leafslotmax);
347 : }
348 :
349 : /// True if few used entries, less than half full
350 348157 : inline bool isfew() const
351 : {
352 348157 : return (node::slotuse <= minleafslots);
353 : }
354 :
355 : /// True if node has too few entries
356 514318328 : inline bool isunderflow() const
357 : {
358 514318328 : return (node::slotuse < minleafslots);
359 : }
360 :
361 : /// Set the (key,data) pair in slot. Overloaded function used by
362 : /// bulk_load().
363 5300030 : inline void set_slot(unsigned short slot, const pair_type& value)
364 : {
365 : BTREE_ASSERT(used_as_set == false);
366 5300030 : BTREE_ASSERT(slot < node::slotuse);
367 5300030 : slotkey[slot] = value.first;
368 5300030 : slotdata[slot] = value.second;
369 5300030 : }
370 :
371 : /// Set the key pair in slot. Overloaded function used by
372 : /// bulk_load().
373 5300030 : inline void set_slot(unsigned short slot, const key_type& key)
374 : {
375 : BTREE_ASSERT(used_as_set == true);
376 5300030 : BTREE_ASSERT(slot < node::slotuse);
377 5300030 : slotkey[slot] = key;
378 5300030 : }
379 : };
380 :
381 : private:
382 : // *** Template Magic to Convert a pair or key/data types to a value_type
383 :
384 : /// For sets the second pair_type is an empty struct, so the value_type
385 : /// should only be the first.
386 : template <typename value_type, typename pair_type>
387 : struct btree_pair_to_value
388 : {
389 : /// Convert a fake pair type to just the first component
390 : inline value_type operator()(pair_type& p) const {
391 : return p.first;
392 : }
393 : /// Convert a fake pair type to just the first component
394 587887026 : inline value_type operator()(const pair_type& p) const {
395 587887026 : return p.first;
396 : }
397 : };
398 :
399 : /// For maps value_type is the same as the pair_type
400 : template <typename value_type>
401 : struct btree_pair_to_value<value_type, value_type>
402 : {
403 : /// Identity "convert" a real pair type to just the first component
404 : inline value_type operator()(pair_type& p) const {
405 : return p;
406 : }
407 : /// Identity "convert" a real pair type to just the first component
408 5359702 : inline value_type operator()(const pair_type& p) const {
409 5359702 : return p;
410 : }
411 : };
412 :
413 : /// Using template specialization select the correct converter used by the
414 : /// iterators
415 : typedef btree_pair_to_value<value_type, pair_type> pair_to_value_type;
416 :
417 : public:
418 : // *** Iterators and Reverse Iterators
419 :
420 : class iterator;
421 : class const_iterator;
422 : class reverse_iterator;
423 : class const_reverse_iterator;
424 :
425 : /// STL-like iterator object for B+ tree items. The iterator points to a
426 : /// specific slot number in a leaf.
427 : class iterator
428 6707506 : {
429 : public:
430 : // *** Types
431 :
432 : /// The key type of the btree. Returned by key().
433 : typedef typename btree::key_type key_type;
434 :
435 : /// The data type of the btree. Returned by data().
436 : typedef typename btree::data_type data_type;
437 :
438 : /// The value type of the btree. Returned by operator*().
439 : typedef typename btree::value_type value_type;
440 :
441 : /// The pair type of the btree.
442 : typedef typename btree::pair_type pair_type;
443 :
444 : /// Reference to the value_type. STL required.
445 : typedef value_type& reference;
446 :
447 : /// Pointer to the value_type. STL required.
448 : typedef value_type* pointer;
449 :
450 : /// STL-magic iterator category
451 : typedef std::bidirectional_iterator_tag iterator_category;
452 :
453 : /// STL-magic
454 : typedef ptrdiff_t difference_type;
455 :
456 : /// Our own type
457 : typedef iterator self;
458 :
459 : private:
460 : // *** Members
461 :
462 : /// The currently referenced leaf node of the tree
463 : typename btree::leaf_node* currnode;
464 :
465 : /// Current key/data slot referenced
466 : unsigned short currslot;
467 :
468 : /// Friendly to the const_iterator, so it may access the two data items
469 : /// directly.
470 : friend class const_iterator;
471 :
472 : /// Also friendly to the reverse_iterator, so it may access the two
473 : /// data items directly.
474 : friend class reverse_iterator;
475 :
476 : /// Also friendly to the const_reverse_iterator, so it may access the
477 : /// two data items directly.
478 : friend class const_reverse_iterator;
479 :
480 : /// Also friendly to the base btree class, because erase_iter() needs
481 : /// to read the currnode and currslot values directly.
482 : friend class btree<key_type, data_type, value_type, key_compare,
483 : traits, allow_duplicates, allocator_type, used_as_set>;
484 :
485 : /// Evil! A temporary value_type to STL-correctly deliver operator* and
486 : /// operator->
487 : mutable value_type temp_value;
488 :
489 : // The macro BTREE_FRIENDS can be used by outside class to access the B+
490 : // tree internals. This was added for wxBTreeDemo to be able to draw the
491 : // tree.
492 : BTREE_FRIENDS
493 :
494 : public:
495 : // *** Methods
496 :
497 : /// Default-Constructor of a mutable iterator
498 5 : inline iterator()
499 5 : : currnode(NULL), currslot(0)
500 5 : { }
501 :
502 : /// Initializing-Constructor of a mutable iterator
503 17853594 : inline iterator(typename btree::leaf_node *l, unsigned short s)
504 17853594 : : currnode(l), currslot(s)
505 17853594 : { }
506 :
507 : /// Copy-constructor from a reverse iterator
508 : inline iterator(const reverse_iterator &it)
509 : : currnode(it.currnode), currslot(it.currslot)
510 : { }
511 :
512 : /// Dereference the iterator, this is not a value_type& because key and
513 : /// value are not stored together
514 593165140 : inline reference operator*() const
515 : {
516 593165140 : temp_value = pair_to_value_type()( pair_type(key(),data()) );
517 593165140 : return temp_value;
518 : }
519 :
520 : /// Dereference the iterator. Do not use this if possible, use key()
521 : /// and data() instead. The B+ tree does not stored key and data
522 : /// together.
523 22872 : inline pointer operator->() const
524 : {
525 22872 : temp_value = pair_to_value_type()( pair_type(key(),data()) );
526 22872 : return &temp_value;
527 : }
528 :
529 : /// Key of the current slot
530 593296505 : inline const key_type& key() const
531 : {
532 593296505 : return currnode->slotkey[currslot];
533 : }
534 :
535 : /// Writable reference to the current data object
536 593204396 : inline data_type& data() const
537 : {
538 593204396 : return currnode->slotdata[used_as_set ? 0 : currslot];
539 : }
540 :
541 : /// Prefix++ advance the iterator to the next slot
542 593228501 : inline self& operator++()
543 : {
544 593228501 : if (currslot + 1 < currnode->slotuse) {
545 470407944 : ++currslot;
546 : }
547 122820557 : else if (currnode->nextleaf != NULL) {
548 122758714 : currnode = currnode->nextleaf;
549 122758714 : currslot = 0;
550 : }
551 : else {
552 : // this is end()
553 61843 : currslot = currnode->slotuse;
554 : }
555 :
556 593228501 : return *this;
557 : }
558 :
559 : /// Postfix++ advance the iterator to the next slot
560 2001 : inline self operator++(int)
561 : {
562 2001 : self tmp = *this; // copy ourselves
563 :
564 2001 : if (currslot + 1 < currnode->slotuse) {
565 1502 : ++currslot;
566 : }
567 499 : else if (currnode->nextleaf != NULL) {
568 496 : currnode = currnode->nextleaf;
569 496 : currslot = 0;
570 : }
571 : else {
572 : // this is end()
573 3 : currslot = currnode->slotuse;
574 : }
575 :
576 1001 : return tmp;
577 : }
578 :
579 : /// Prefix-- backstep the iterator to the last slot
580 2007 : inline self& operator--()
581 : {
582 2007 : if (currslot > 0) {
583 1510 : --currslot;
584 : }
585 497 : else if (currnode->prevleaf != NULL) {
586 496 : currnode = currnode->prevleaf;
587 496 : currslot = currnode->slotuse - 1;
588 : }
589 : else {
590 : // this is begin()
591 1 : currslot = 0;
592 : }
593 :
594 2007 : return *this;
595 : }
596 :
597 : /// Postfix-- backstep the iterator to the last slot
598 1999 : inline self operator--(int)
599 : {
600 1999 : self tmp = *this; // copy ourselves
601 :
602 1999 : if (currslot > 0) {
603 1502 : --currslot;
604 : }
605 497 : else if (currnode->prevleaf != NULL) {
606 496 : currnode = currnode->prevleaf;
607 496 : currslot = currnode->slotuse - 1;
608 : }
609 : else {
610 : // this is begin()
611 1 : currslot = 0;
612 : }
613 :
614 1000 : return tmp;
615 : }
616 :
617 : /// Equality of iterators
618 2199794 : inline bool operator==(const self& x) const
619 : {
620 2199794 : return (x.currnode == currnode) && (x.currslot == currslot);
621 : }
622 :
623 : /// Inequality of iterators
624 593304544 : inline bool operator!=(const self& x) const
625 : {
626 593304544 : return (x.currnode != currnode) || (x.currslot != currslot);
627 : }
628 : };
629 :
630 : /// STL-like read-only iterator object for B+ tree items. The iterator
631 : /// points to a specific slot number in a leaf.
632 : class const_iterator
633 : {
634 : public:
635 : // *** Types
636 :
637 : /// The key type of the btree. Returned by key().
638 : typedef typename btree::key_type key_type;
639 :
640 : /// The data type of the btree. Returned by data().
641 : typedef typename btree::data_type data_type;
642 :
643 : /// The value type of the btree. Returned by operator*().
644 : typedef typename btree::value_type value_type;
645 :
646 : /// The pair type of the btree.
647 : typedef typename btree::pair_type pair_type;
648 :
649 : /// Reference to the value_type. STL required.
650 : typedef const value_type& reference;
651 :
652 : /// Pointer to the value_type. STL required.
653 : typedef const value_type* pointer;
654 :
655 : /// STL-magic iterator category
656 : typedef std::bidirectional_iterator_tag iterator_category;
657 :
658 : /// STL-magic
659 : typedef ptrdiff_t difference_type;
660 :
661 : /// Our own type
662 : typedef const_iterator self;
663 :
664 : private:
665 : // *** Members
666 :
667 : /// The currently referenced leaf node of the tree
668 : const typename btree::leaf_node* currnode;
669 :
670 : /// Current key/data slot referenced
671 : unsigned short currslot;
672 :
673 : /// Friendly to the reverse_const_iterator, so it may access the two
674 : /// data items directly
675 : friend class const_reverse_iterator;
676 :
677 : /// Evil! A temporary value_type to STL-correctly deliver operator* and
678 : /// operator->
679 : mutable value_type temp_value;
680 :
681 : // The macro BTREE_FRIENDS can be used by outside class to access the B+
682 : // tree internals. This was added for wxBTreeDemo to be able to draw the
683 : // tree.
684 : BTREE_FRIENDS
685 :
686 : public:
687 : // *** Methods
688 :
689 : /// Default-Constructor of a const iterator
690 5 : inline const_iterator()
691 5 : : currnode(NULL), currslot(0)
692 5 : { }
693 :
694 : /// Initializing-Constructor of a const iterator
695 97 : inline const_iterator(const typename btree::leaf_node *l, unsigned short s)
696 97 : : currnode(l), currslot(s)
697 97 : { }
698 :
699 : /// Copy-constructor from a mutable iterator
700 17700 : inline const_iterator(const iterator &it)
701 17700 : : currnode(it.currnode), currslot(it.currslot)
702 17700 : { }
703 :
704 : /// Copy-constructor from a mutable reverse iterator
705 : inline const_iterator(const reverse_iterator &it)
706 : : currnode(it.currnode), currslot(it.currslot)
707 : { }
708 :
709 : /// Copy-constructor from a const reverse iterator
710 : inline const_iterator(const const_reverse_iterator &it)
711 : : currnode(it.currnode), currslot(it.currslot)
712 : { }
713 :
714 : /// Dereference the iterator. Do not use this if possible, use key()
715 : /// and data() instead. The B+ tree does not stored key and data
716 : /// together.
717 10716 : inline reference operator*() const
718 : {
719 10716 : temp_value = pair_to_value_type()( pair_type(key(),data()) );
720 10716 : return temp_value;
721 : }
722 :
723 : /// Dereference the iterator. Do not use this if possible, use key()
724 : /// and data() instead. The B+ tree does not stored key and data
725 : /// together.
726 8000 : inline pointer operator->() const
727 : {
728 8000 : temp_value = pair_to_value_type()( pair_type(key(),data()) );
729 8000 : return &temp_value;
730 : }
731 :
732 : /// Key of the current slot
733 22740 : inline const key_type& key() const
734 : {
735 22740 : return currnode->slotkey[currslot];
736 : }
737 :
738 : /// Read-only reference to the current data object
739 18716 : inline const data_type& data() const
740 : {
741 18716 : return currnode->slotdata[used_as_set ? 0 : currslot];
742 : }
743 :
744 : /// Prefix++ advance the iterator to the next slot
745 6797 : inline self& operator++()
746 : {
747 6797 : if (currslot + 1 < currnode->slotuse) {
748 5464 : ++currslot;
749 : }
750 1333 : else if (currnode->nextleaf != NULL) {
751 1318 : currnode = currnode->nextleaf;
752 1318 : currslot = 0;
753 : }
754 : else {
755 : // this is end()
756 15 : currslot = currnode->slotuse;
757 : }
758 :
759 6797 : return *this;
760 : }
761 :
762 : /// Postfix++ advance the iterator to the next slot
763 2001 : inline self operator++(int)
764 : {
765 2001 : self tmp = *this; // copy ourselves
766 :
767 2001 : if (currslot + 1 < currnode->slotuse) {
768 1502 : ++currslot;
769 : }
770 499 : else if (currnode->nextleaf != NULL) {
771 496 : currnode = currnode->nextleaf;
772 496 : currslot = 0;
773 : }
774 : else {
775 : // this is end()
776 3 : currslot = currnode->slotuse;
777 : }
778 :
779 1001 : return tmp;
780 : }
781 :
782 : /// Prefix-- backstep the iterator to the last slot
783 1999 : inline self& operator--()
784 : {
785 1999 : if (currslot > 0) {
786 1502 : --currslot;
787 : }
788 497 : else if (currnode->prevleaf != NULL) {
789 496 : currnode = currnode->prevleaf;
790 496 : currslot = currnode->slotuse - 1;
791 : }
792 : else {
793 : // this is begin()
794 1 : currslot = 0;
795 : }
796 :
797 1999 : return *this;
798 : }
799 :
800 : /// Postfix-- backstep the iterator to the last slot
801 1999 : inline self operator--(int)
802 : {
803 1999 : self tmp = *this; // copy ourselves
804 :
805 1999 : if (currslot > 0) {
806 1502 : --currslot;
807 : }
808 497 : else if (currnode->prevleaf != NULL) {
809 496 : currnode = currnode->prevleaf;
810 496 : currslot = currnode->slotuse - 1;
811 : }
812 : else {
813 : // this is begin()
814 1 : currslot = 0;
815 : }
816 :
817 1000 : return tmp;
818 : }
819 :
820 : /// Equality of iterators
821 4846 : inline bool operator==(const self& x) const
822 : {
823 4846 : return (x.currnode == currnode) && (x.currslot == currslot);
824 : }
825 :
826 : /// Inequality of iterators
827 11393 : inline bool operator!=(const self& x) const
828 : {
829 11393 : return (x.currnode != currnode) || (x.currslot != currslot);
830 : }
831 : };
832 :
833 : /// STL-like mutable reverse iterator object for B+ tree items. The
834 : /// iterator points to a specific slot number in a leaf.
835 : class reverse_iterator
836 : {
837 : public:
838 : // *** Types
839 :
840 : /// The key type of the btree. Returned by key().
841 : typedef typename btree::key_type key_type;
842 :
843 : /// The data type of the btree. Returned by data().
844 : typedef typename btree::data_type data_type;
845 :
846 : /// The value type of the btree. Returned by operator*().
847 : typedef typename btree::value_type value_type;
848 :
849 : /// The pair type of the btree.
850 : typedef typename btree::pair_type pair_type;
851 :
852 : /// Reference to the value_type. STL required.
853 : typedef value_type& reference;
854 :
855 : /// Pointer to the value_type. STL required.
856 : typedef value_type* pointer;
857 :
858 : /// STL-magic iterator category
859 : typedef std::bidirectional_iterator_tag iterator_category;
860 :
861 : /// STL-magic
862 : typedef ptrdiff_t difference_type;
863 :
864 : /// Our own type
865 : typedef reverse_iterator self;
866 :
867 : private:
868 : // *** Members
869 :
870 : /// The currently referenced leaf node of the tree
871 : typename btree::leaf_node* currnode;
872 :
873 : /// One slot past the current key/data slot referenced.
874 : unsigned short currslot;
875 :
876 : /// Friendly to the const_iterator, so it may access the two data items
877 : /// directly
878 : friend class iterator;
879 :
880 : /// Also friendly to the const_iterator, so it may access the two data
881 : /// items directly
882 : friend class const_iterator;
883 :
884 : /// Also friendly to the const_iterator, so it may access the two data
885 : /// items directly
886 : friend class const_reverse_iterator;
887 :
888 : /// Evil! A temporary value_type to STL-correctly deliver operator* and
889 : /// operator->
890 : mutable value_type temp_value;
891 :
892 : // The macro BTREE_FRIENDS can be used by outside class to access the B+
893 : // tree internals. This was added for wxBTreeDemo to be able to draw the
894 : // tree.
895 : BTREE_FRIENDS
896 :
897 : public:
898 : // *** Methods
899 :
900 : /// Default-Constructor of a reverse iterator
901 5 : inline reverse_iterator()
902 5 : : currnode(NULL), currslot(0)
903 5 : { }
904 :
905 : /// Initializing-Constructor of a mutable reverse iterator
906 : inline reverse_iterator(typename btree::leaf_node *l, unsigned short s)
907 : : currnode(l), currslot(s)
908 : { }
909 :
910 : /// Copy-constructor from a mutable iterator
911 16048 : inline reverse_iterator(const iterator &it)
912 16048 : : currnode(it.currnode), currslot(it.currslot)
913 16048 : { }
914 :
915 : /// Dereference the iterator, this is not a value_type& because key and
916 : /// value are not stored together
917 13600 : inline reference operator*() const
918 : {
919 13600 : BTREE_ASSERT(currslot > 0);
920 13600 : temp_value = pair_to_value_type()( pair_type(key(),data()) );
921 13600 : return temp_value;
922 : }
923 :
924 : /// Dereference the iterator. Do not use this if possible, use key()
925 : /// and data() instead. The B+ tree does not stored key and data
926 : /// together.
927 14400 : inline pointer operator->() const
928 : {
929 14400 : BTREE_ASSERT(currslot > 0);
930 14400 : temp_value = pair_to_value_type()( pair_type(key(),data()) );
931 14400 : return &temp_value;
932 : }
933 :
934 : /// Key of the current slot
935 28000 : inline const key_type& key() const
936 : {
937 28000 : BTREE_ASSERT(currslot > 0);
938 28000 : return currnode->slotkey[currslot - 1];
939 : }
940 :
941 : /// Writable reference to the current data object
942 28000 : inline data_type& data() const
943 : {
944 28000 : BTREE_ASSERT(currslot > 0);
945 28000 : return currnode->slotdata[used_as_set ? 0 : currslot-1];
946 : }
947 :
948 : /// Prefix++ advance the iterator to the next slot
949 18001 : inline self& operator++()
950 : {
951 18001 : if (currslot > 1) {
952 14647 : --currslot;
953 : }
954 3354 : else if (currnode->prevleaf != NULL) {
955 3346 : currnode = currnode->prevleaf;
956 3346 : currslot = currnode->slotuse;
957 : }
958 : else {
959 : // this is begin() == rend()
960 8 : currslot = 0;
961 : }
962 :
963 18001 : return *this;
964 : }
965 :
966 : /// Postfix++ advance the iterator to the next slot
967 5201 : inline self operator++(int)
968 : {
969 5201 : self tmp = *this; // copy ourselves
970 :
971 5201 : if (currslot > 1) {
972 4131 : --currslot;
973 : }
974 1070 : else if (currnode->prevleaf != NULL) {
975 1066 : currnode = currnode->prevleaf;
976 1066 : currslot = currnode->slotuse;
977 : }
978 : else {
979 : // this is begin() == rend()
980 4 : currslot = 0;
981 : }
982 :
983 4201 : return tmp;
984 : }
985 :
986 : /// Prefix-- backstep the iterator to the last slot
987 2007 : inline self& operator--()
988 : {
989 2007 : if (currslot < currnode->slotuse) {
990 1510 : ++currslot;
991 : }
992 497 : else if (currnode->nextleaf != NULL) {
993 496 : currnode = currnode->nextleaf;
994 496 : currslot = 1;
995 : }
996 : else {
997 : // this is end() == rbegin()
998 1 : currslot = currnode->slotuse;
999 : }
1000 :
1001 2007 : return *this;
1002 : }
1003 :
1004 : /// Postfix-- backstep the iterator to the last slot
1005 1999 : inline self operator--(int)
1006 : {
1007 1999 : self tmp = *this; // copy ourselves
1008 :
1009 1999 : if (currslot < currnode->slotuse) {
1010 1502 : ++currslot;
1011 : }
1012 497 : else if (currnode->nextleaf != NULL) {
1013 496 : currnode = currnode->nextleaf;
1014 496 : currslot = 1;
1015 : }
1016 : else {
1017 : // this is end() == rbegin()
1018 1 : currslot = currnode->slotuse;
1019 : }
1020 :
1021 1000 : return tmp;
1022 : }
1023 :
1024 : /// Equality of iterators
1025 6 : inline bool operator==(const self& x) const
1026 : {
1027 6 : return (x.currnode == currnode) && (x.currslot == currslot);
1028 : }
1029 :
1030 : /// Inequality of iterators
1031 20810 : inline bool operator!=(const self& x) const
1032 : {
1033 20810 : return (x.currnode != currnode) || (x.currslot != currslot);
1034 : }
1035 : };
1036 :
1037 : /// STL-like read-only reverse iterator object for B+ tree items. The
1038 : /// iterator points to a specific slot number in a leaf.
1039 : class const_reverse_iterator
1040 : {
1041 : public:
1042 : // *** Types
1043 :
1044 : /// The key type of the btree. Returned by key().
1045 : typedef typename btree::key_type key_type;
1046 :
1047 : /// The data type of the btree. Returned by data().
1048 : typedef typename btree::data_type data_type;
1049 :
1050 : /// The value type of the btree. Returned by operator*().
1051 : typedef typename btree::value_type value_type;
1052 :
1053 : /// The pair type of the btree.
1054 : typedef typename btree::pair_type pair_type;
1055 :
1056 : /// Reference to the value_type. STL required.
1057 : typedef const value_type& reference;
1058 :
1059 : /// Pointer to the value_type. STL required.
1060 : typedef const value_type* pointer;
1061 :
1062 : /// STL-magic iterator category
1063 : typedef std::bidirectional_iterator_tag iterator_category;
1064 :
1065 : /// STL-magic
1066 : typedef ptrdiff_t difference_type;
1067 :
1068 : /// Our own type
1069 : typedef const_reverse_iterator self;
1070 :
1071 : private:
1072 : // *** Members
1073 :
1074 : /// The currently referenced leaf node of the tree
1075 : const typename btree::leaf_node* currnode;
1076 :
1077 : /// One slot past the current key/data slot referenced.
1078 : unsigned short currslot;
1079 :
1080 : /// Friendly to the const_iterator, so it may access the two data items
1081 : /// directly.
1082 : friend class reverse_iterator;
1083 :
1084 : /// Evil! A temporary value_type to STL-correctly deliver operator* and
1085 : /// operator->
1086 : mutable value_type temp_value;
1087 :
1088 : // The macro BTREE_FRIENDS can be used by outside class to access the B+
1089 : // tree internals. This was added for wxBTreeDemo to be able to draw the
1090 : // tree.
1091 : BTREE_FRIENDS
1092 :
1093 : public:
1094 : // *** Methods
1095 :
1096 : /// Default-Constructor of a const reverse iterator
1097 5 : inline const_reverse_iterator()
1098 5 : : currnode(NULL), currslot(0)
1099 5 : { }
1100 :
1101 : /// Initializing-Constructor of a const reverse iterator
1102 : inline const_reverse_iterator(const typename btree::leaf_node *l, unsigned short s)
1103 : : currnode(l), currslot(s)
1104 : { }
1105 :
1106 : /// Copy-constructor from a mutable iterator
1107 : inline const_reverse_iterator(const iterator &it)
1108 : : currnode(it.currnode), currslot(it.currslot)
1109 : { }
1110 :
1111 : /// Copy-constructor from a const iterator
1112 0 : inline const_reverse_iterator(const const_iterator &it)
1113 0 : : currnode(it.currnode), currslot(it.currslot)
1114 0 : { }
1115 :
1116 : /// Copy-constructor from a mutable reverse iterator
1117 8020 : inline const_reverse_iterator(const reverse_iterator &it)
1118 8020 : : currnode(it.currnode), currslot(it.currslot)
1119 8020 : { }
1120 :
1121 : /// Dereference the iterator. Do not use this if possible, use key()
1122 : /// and data() instead. The B+ tree does not stored key and data
1123 : /// together.
1124 4000 : inline reference operator*() const
1125 : {
1126 4000 : BTREE_ASSERT(currslot > 0);
1127 4000 : temp_value = pair_to_value_type()( pair_type(key(),data()) );
1128 4000 : return temp_value;
1129 : }
1130 :
1131 : /// Dereference the iterator. Do not use this if possible, use key()
1132 : /// and data() instead. The B+ tree does not stored key and data
1133 : /// together.
1134 8000 : inline pointer operator->() const
1135 : {
1136 8000 : BTREE_ASSERT(currslot > 0);
1137 8000 : temp_value = pair_to_value_type()( pair_type(key(),data()) );
1138 8000 : return &temp_value;
1139 : }
1140 :
1141 : /// Key of the current slot
1142 12000 : inline const key_type& key() const
1143 : {
1144 12000 : BTREE_ASSERT(currslot > 0);
1145 12000 : return currnode->slotkey[currslot - 1];
1146 : }
1147 :
1148 : /// Read-only reference to the current data object
1149 12000 : inline const data_type& data() const
1150 : {
1151 12000 : BTREE_ASSERT(currslot > 0);
1152 12000 : return currnode->slotdata[used_as_set ? 0 : currslot-1];
1153 : }
1154 :
1155 : /// Prefix++ advance the iterator to the previous slot
1156 2001 : inline self& operator++()
1157 : {
1158 2001 : if (currslot > 1) {
1159 1502 : --currslot;
1160 : }
1161 499 : else if (currnode->prevleaf != NULL) {
1162 496 : currnode = currnode->prevleaf;
1163 496 : currslot = currnode->slotuse;
1164 : }
1165 : else {
1166 : // this is begin() == rend()
1167 3 : currslot = 0;
1168 : }
1169 :
1170 2001 : return *this;
1171 : }
1172 :
1173 : /// Postfix++ advance the iterator to the previous slot
1174 2001 : inline self operator++(int)
1175 : {
1176 2001 : self tmp = *this; // copy ourselves
1177 :
1178 2001 : if (currslot > 1) {
1179 1502 : --currslot;
1180 : }
1181 499 : else if (currnode->prevleaf != NULL) {
1182 496 : currnode = currnode->prevleaf;
1183 496 : currslot = currnode->slotuse;
1184 : }
1185 : else {
1186 : // this is begin() == rend()
1187 3 : currslot = 0;
1188 : }
1189 :
1190 1001 : return tmp;
1191 : }
1192 :
1193 : /// Prefix-- backstep the iterator to the next slot
1194 1999 : inline self& operator--()
1195 : {
1196 1999 : if (currslot < currnode->slotuse) {
1197 1502 : ++currslot;
1198 : }
1199 497 : else if (currnode->nextleaf != NULL) {
1200 496 : currnode = currnode->nextleaf;
1201 496 : currslot = 1;
1202 : }
1203 : else {
1204 : // this is end() == rbegin()
1205 1 : currslot = currnode->slotuse;
1206 : }
1207 :
1208 1999 : return *this;
1209 : }
1210 :
1211 : /// Postfix-- backstep the iterator to the next slot
1212 1999 : inline self operator--(int)
1213 : {
1214 1999 : self tmp = *this; // copy ourselves
1215 :
1216 1999 : if (currslot < currnode->slotuse) {
1217 1502 : ++currslot;
1218 : }
1219 497 : else if (currnode->nextleaf != NULL) {
1220 496 : currnode = currnode->nextleaf;
1221 496 : currslot = 1;
1222 : }
1223 : else {
1224 : // this is end() == rbegin()
1225 1 : currslot = currnode->slotuse;
1226 : }
1227 :
1228 1000 : return tmp;
1229 : }
1230 :
1231 : /// Equality of iterators
1232 4 : inline bool operator==(const self& x) const
1233 : {
1234 4 : return (x.currnode == currnode) && (x.currslot == currslot);
1235 : }
1236 :
1237 : /// Inequality of iterators
1238 8004 : inline bool operator!=(const self& x) const
1239 : {
1240 8004 : return (x.currnode != currnode) || (x.currslot != currslot);
1241 : }
1242 : };
1243 :
1244 : public:
1245 : // *** Small Statistics Structure
1246 :
1247 : /** A small struct containing basic statistics about the B+ tree. It can be
1248 : * fetched using get_stats(). */
1249 : struct tree_stats
1250 : {
1251 : /// Number of items in the B+ tree
1252 : size_type itemcount;
1253 :
1254 : /// Number of leaves in the B+ tree
1255 : size_type leaves;
1256 :
1257 : /// Number of inner nodes in the B+ tree
1258 : size_type innernodes;
1259 :
1260 : /// Base B+ tree parameter: The number of key/data slots in each leaf
1261 : static const unsigned short leafslots = btree_self::leafslotmax;
1262 :
1263 : /// Base B+ tree parameter: The number of key slots in each inner node.
1264 : static const unsigned short innerslots = btree_self::innerslotmax;
1265 :
1266 : /// Zero initialized
1267 1136565 : inline tree_stats()
1268 : : itemcount(0),
1269 1136565 : leaves(0), innernodes(0)
1270 : {
1271 1136565 : }
1272 :
1273 : /// Return the total number of nodes
1274 : inline size_type nodes() const
1275 : {
1276 : return innernodes + leaves;
1277 : }
1278 :
1279 : /// Return the average fill of leaves
1280 : inline double avgfill_leaves() const
1281 : {
1282 : return static_cast<double>(itemcount) / (leaves * leafslots);
1283 : }
1284 : };
1285 :
1286 : private:
1287 : // *** Tree Object Data Members
1288 :
1289 : /// Pointer to the B+ tree's root node, either leaf or inner node
1290 : node* m_root;
1291 :
1292 : /// Pointer to first leaf in the double linked leaf chain
1293 : leaf_node *m_headleaf;
1294 :
1295 : /// Pointer to last leaf in the double linked leaf chain
1296 : leaf_node *m_tailleaf;
1297 :
1298 : /// Other small statistics about the B+ tree
1299 : tree_stats m_stats;
1300 :
1301 : /// Key comparison object. More comparison functions are generated from
1302 : /// this < relation.
1303 : key_compare m_key_less;
1304 :
1305 : /// Memory allocator.
1306 : allocator_type m_allocator;
1307 :
1308 : public:
1309 : // *** Constructors and Destructor
1310 :
1311 : /// Default constructor initializing an empty B+ tree with the standard key
1312 : /// comparison function
1313 6613 : explicit inline btree(const allocator_type &alloc = allocator_type())
1314 6613 : : m_root(NULL), m_headleaf(NULL), m_tailleaf(NULL), m_allocator(alloc)
1315 : {
1316 6613 : }
1317 :
1318 : /// Constructor initializing an empty B+ tree with a special key
1319 : /// comparison object
1320 1 : explicit inline btree(const key_compare &kcf,
1321 : const allocator_type &alloc = allocator_type())
1322 : : m_root(NULL), m_headleaf(NULL), m_tailleaf(NULL),
1323 1 : m_key_less(kcf), m_allocator(alloc)
1324 : {
1325 1 : }
1326 :
1327 : /// Constructor initializing a B+ tree with the range [first,last). The
1328 : /// range need not be sorted. To create a B+ tree from a sorted range, use
1329 : /// bulk_load().
1330 : template <class InputIterator>
1331 1 : inline btree(InputIterator first, InputIterator last,
1332 : const allocator_type &alloc = allocator_type())
1333 1 : : m_root(NULL), m_headleaf(NULL), m_tailleaf(NULL), m_allocator(alloc)
1334 : {
1335 1 : insert(first, last);
1336 1 : }
1337 :
1338 : /// Constructor initializing a B+ tree with the range [first,last) and a
1339 : /// special key comparison object. The range need not be sorted. To create
1340 : /// a B+ tree from a sorted range, use bulk_load().
1341 : template <class InputIterator>
1342 : inline btree(InputIterator first, InputIterator last, const key_compare &kcf,
1343 : const allocator_type &alloc = allocator_type())
1344 : : m_root(NULL), m_headleaf(NULL), m_tailleaf(NULL),
1345 : m_key_less(kcf), m_allocator(alloc)
1346 : {
1347 : insert(first, last);
1348 : }
1349 :
1350 : /// Frees up all used B+ tree memory pages
1351 6618 : inline ~btree()
1352 : {
1353 6618 : clear();
1354 6618 : }
1355 :
1356 : /// Fast swapping of two identical B+ tree objects.
1357 : void swap(btree_self& from)
1358 : {
1359 : std::swap(m_root, from.m_root);
1360 : std::swap(m_headleaf, from.m_headleaf);
1361 : std::swap(m_tailleaf, from.m_tailleaf);
1362 : std::swap(m_stats, from.m_stats);
1363 : std::swap(m_key_less, from.m_key_less);
1364 : std::swap(m_allocator, from.m_allocator);
1365 : }
1366 :
1367 : public:
1368 : // *** Key and Value Comparison Function Objects
1369 :
1370 : /// Function class to compare value_type objects. Required by the STL
1371 : class value_compare
1372 : {
1373 : protected:
1374 : /// Key comparison function from the template parameter
1375 : key_compare key_comp;
1376 :
1377 : /// Constructor called from btree::value_comp()
1378 0 : inline value_compare(key_compare kc)
1379 : : key_comp(kc)
1380 0 : { }
1381 :
1382 : /// Friendly to the btree class so it may call the constructor
1383 : friend class btree<key_type, data_type, value_type, key_compare,
1384 : traits, allow_duplicates, allocator_type, used_as_set>;
1385 :
1386 : public:
1387 : /// Function call "less"-operator resulting in true if x < y.
1388 : inline bool operator()(const value_type& x, const value_type& y) const
1389 : {
1390 : return key_comp(x.first, y.first);
1391 : }
1392 : };
1393 :
1394 : /// Constant access to the key comparison object sorting the B+ tree
1395 4 : inline key_compare key_comp() const
1396 : {
1397 : return m_key_less;
1398 : }
1399 :
1400 : /// Constant access to a constructed value_type comparison object. Required
1401 : /// by the STL
1402 0 : inline value_compare value_comp() const
1403 : {
1404 0 : return value_compare(m_key_less);
1405 : }
1406 :
1407 : private:
1408 : // *** Convenient Key Comparison Functions Generated From key_less
1409 :
1410 : /// True if a < b ? "constructed" from m_key_less()
1411 129226265 : inline bool key_less(const key_type &a, const key_type b) const
1412 : {
1413 129226265 : return m_key_less(a, b);
1414 : }
1415 :
1416 : /// True if a <= b ? constructed from key_less()
1417 6462256958 : inline bool key_lessequal(const key_type &a, const key_type b) const
1418 : {
1419 6462256958 : return !m_key_less(b, a);
1420 : }
1421 :
1422 : /// True if a > b ? constructed from key_less()
1423 : inline bool key_greater(const key_type &a, const key_type &b) const
1424 : {
1425 : return m_key_less(b, a);
1426 : }
1427 :
1428 : /// True if a >= b ? constructed from key_less()
1429 512836875 : inline bool key_greaterequal(const key_type &a, const key_type b) const
1430 : {
1431 512836875 : return !m_key_less(a, b);
1432 : }
1433 :
1434 : /// True if a == b ? constructed from key_less(). This requires the <
1435 : /// relation to be a total order, otherwise the B+ tree cannot be sorted.
1436 519517025 : inline bool key_equal(const key_type &a, const key_type &b) const
1437 : {
1438 519517025 : return !m_key_less(a, b) && !m_key_less(b, a);
1439 : }
1440 :
1441 : public:
1442 : // *** Allocators
1443 :
1444 : /// Return the base node allocator provided during construction.
1445 4 : allocator_type get_allocator() const
1446 : {
1447 4 : return m_allocator;
1448 : }
1449 :
1450 : private:
1451 : // *** Node Object Allocation and Deallocation Functions
1452 :
1453 : /// Return an allocator for leaf_node objects
1454 2881762 : typename leaf_node::alloc_type leaf_node_allocator()
1455 : {
1456 2881762 : return typename leaf_node::alloc_type(m_allocator);
1457 : }
1458 :
1459 : /// Return an allocator for inner_node objects
1460 372486 : typename inner_node::alloc_type inner_node_allocator()
1461 : {
1462 372486 : return typename inner_node::alloc_type(m_allocator);
1463 : }
1464 :
1465 : /// Allocate and initialize a leaf node
1466 1440881 : inline leaf_node* allocate_leaf()
1467 : {
1468 1440881 : leaf_node *n = new (leaf_node_allocator().allocate(1)) leaf_node();
1469 1440881 : n->initialize();
1470 1440881 : m_stats.leaves++;
1471 1440881 : return n;
1472 : }
1473 :
1474 : /// Allocate and initialize an inner node
1475 186243 : inline inner_node* allocate_inner(unsigned short level)
1476 : {
1477 186243 : inner_node *n = new (inner_node_allocator().allocate(1)) inner_node();
1478 186243 : n->initialize(level);
1479 186243 : m_stats.innernodes++;
1480 186243 : return n;
1481 : }
1482 :
1483 : /// Correctly free either inner or leaf node, destructs all contained key
1484 : /// and value objects
1485 1627124 : inline void free_node(node *n)
1486 : {
1487 1627124 : if (n->isleafnode()) {
1488 1440881 : leaf_node *ln = static_cast<leaf_node*>(n);
1489 1440881 : typename leaf_node::alloc_type a(leaf_node_allocator());
1490 1440881 : a.destroy(ln);
1491 1440881 : a.deallocate(ln, 1);
1492 1440881 : m_stats.leaves--;
1493 : }
1494 : else {
1495 186243 : inner_node *in = static_cast<inner_node*>(n);
1496 186243 : typename inner_node::alloc_type a(inner_node_allocator());
1497 186243 : a.destroy(in);
1498 186243 : a.deallocate(in, 1);
1499 186243 : m_stats.innernodes--;
1500 : }
1501 1627124 : }
1502 :
1503 : /// Convenient template function for conditional copying of slotdata. This
1504 : /// should be used instead of std::copy for all slotdata manipulations.
1505 : template<class InputIterator, class OutputIterator>
1506 622618 : static OutputIterator data_copy (InputIterator first, InputIterator last,
1507 : OutputIterator result)
1508 : {
1509 370981 : if (used_as_set) return result; // no operation
1510 251637 : else return std::copy(first, last, result);
1511 : }
1512 :
1513 : /// Convenient template function for conditional copying of slotdata. This
1514 : /// should be used instead of std::copy for all slotdata manipulations.
1515 : template<class InputIterator, class OutputIterator>
1516 2631788 : static OutputIterator data_copy_backward (InputIterator first, InputIterator last,
1517 : OutputIterator result)
1518 : {
1519 2423298 : if (used_as_set) return result; // no operation
1520 208490 : else return std::copy_backward(first, last, result);
1521 : }
1522 :
1523 : public:
1524 : // *** Fast Destruction of the B+ Tree
1525 :
1526 : /// Frees all key/data pairs and all nodes of the tree
1527 6620 : void clear()
1528 : {
1529 6620 : if (m_root)
1530 : {
1531 6449 : clear_recursive(m_root);
1532 6449 : free_node(m_root);
1533 :
1534 6449 : m_root = NULL;
1535 6449 : m_headleaf = m_tailleaf = NULL;
1536 :
1537 6449 : m_stats = tree_stats();
1538 : }
1539 :
1540 6620 : BTREE_ASSERT(m_stats.itemcount == 0);
1541 6620 : }
1542 :
1543 : private:
1544 : /// Recursively free up nodes
1545 1578455 : void clear_recursive(node *n)
1546 : {
1547 1578455 : if (n->isleafnode())
1548 : {
1549 1398436 : leaf_node *leafnode = static_cast<leaf_node*>(n);
1550 :
1551 1398436 : for (unsigned int slot = 0; slot < leafnode->slotuse; ++slot)
1552 : {
1553 : // data objects are deleted by leaf_node's destructor
1554 : }
1555 : }
1556 : else
1557 : {
1558 180019 : inner_node *innernode = static_cast<inner_node*>(n);
1559 :
1560 1752025 : for (unsigned short slot = 0; slot < innernode->slotuse + 1; ++slot)
1561 : {
1562 1572006 : clear_recursive(innernode->childid[slot]);
1563 1572006 : free_node(innernode->childid[slot]);
1564 : }
1565 : }
1566 1578455 : }
1567 :
1568 : public:
1569 : // *** STL Iterator Construction Functions
1570 :
1571 : /// Constructs a read/data-write iterator that points to the first slot in
1572 : /// the first leaf of the B+ tree.
1573 77890 : inline iterator begin()
1574 : {
1575 77890 : return iterator(m_headleaf, 0);
1576 : }
1577 :
1578 : /// Constructs a read/data-write iterator that points to the first invalid
1579 : /// slot in the last leaf of the B+ tree.
1580 12971732 : inline iterator end()
1581 : {
1582 12971732 : return iterator(m_tailleaf, m_tailleaf ? m_tailleaf->slotuse : 0);
1583 : }
1584 :
1585 : /// Constructs a read-only constant iterator that points to the first slot
1586 : /// in the first leaf of the B+ tree.
1587 62 : inline const_iterator begin() const
1588 : {
1589 62 : return const_iterator(m_headleaf, 0);
1590 : }
1591 :
1592 : /// Constructs a read-only constant iterator that points to the first
1593 : /// invalid slot in the last leaf of the B+ tree.
1594 35 : inline const_iterator end() const
1595 : {
1596 35 : return const_iterator(m_tailleaf, m_tailleaf ? m_tailleaf->slotuse : 0);
1597 : }
1598 :
1599 : /// Constructs a read/data-write reverse iterator that points to the first
1600 : /// invalid slot in the last leaf of the B+ tree. Uses STL magic.
1601 8020 : inline reverse_iterator rbegin()
1602 : {
1603 8020 : return reverse_iterator(end());
1604 : }
1605 :
1606 : /// Constructs a read/data-write reverse iterator that points to the first
1607 : /// slot in the first leaf of the B+ tree. Uses STL magic.
1608 8028 : inline reverse_iterator rend()
1609 : {
1610 8028 : return reverse_iterator(begin());
1611 : }
1612 :
1613 : /// Constructs a read-only reverse iterator that points to the first
1614 : /// invalid slot in the last leaf of the B+ tree. Uses STL magic.
1615 0 : inline const_reverse_iterator rbegin() const
1616 : {
1617 0 : return const_reverse_iterator(end());
1618 : }
1619 :
1620 : /// Constructs a read-only reverse iterator that points to the first slot
1621 : /// in the first leaf of the B+ tree. Uses STL magic.
1622 0 : inline const_reverse_iterator rend() const
1623 : {
1624 0 : return const_reverse_iterator(begin());
1625 : }
1626 :
1627 : private:
1628 : // *** B+ Tree Node Binary Search Functions
1629 :
1630 : /// Searches for the first key in the node n greater or equal to key. Uses
1631 : /// binary search with an optional linear self-verification. This is a
1632 : /// template function, because the slotkey array is located at different
1633 : /// places in leaf_node and inner_node.
1634 : template <typename node_type>
1635 20275209 : inline int find_lower(const node_type *n, const key_type& key) const
1636 : {
1637 : if ( 0 && sizeof(n->slotkey) > traits::binsearch_threshold )
1638 : {
1639 : if (n->slotuse == 0) return 0;
1640 :
1641 : int lo = 0, hi = n->slotuse;
1642 :
1643 : while (lo < hi)
1644 : {
1645 : int mid = (lo + hi) >> 1;
1646 :
1647 : if (key_lessequal(key, n->slotkey[mid])) {
1648 : hi = mid; // key <= mid
1649 : }
1650 : else {
1651 : lo = mid + 1; // key > mid
1652 : }
1653 : }
1654 :
1655 : BTREE_PRINT("btree::find_lower: on " << n << " key " << key << " -> " << lo << " / " << hi);
1656 :
1657 : // verify result using simple linear search
1658 : if (selfverify)
1659 : {
1660 : int i = 0;
1661 : while (i < n->slotuse && key_less(n->slotkey[i],key)) ++i;
1662 :
1663 : BTREE_PRINT("btree::find_lower: testfind: " << i);
1664 : BTREE_ASSERT(i == lo);
1665 : }
1666 :
1667 : return lo;
1668 : }
1669 : else // for nodes <= binsearch_threshold do linear search.
1670 : {
1671 20275209 : int lo = 0;
1672 20275209 : while (lo < n->slotuse && key_less(n->slotkey[lo],key)) ++lo;
1673 20275209 : return lo;
1674 : }
1675 : }
1676 :
1677 : /// Searches for the first key in the node n greater than key. Uses binary
1678 : /// search with an optional linear self-verification. This is a template
1679 : /// function, because the slotkey array is located at different places in
1680 : /// leaf_node and inner_node.
1681 : template <typename node_type>
1682 7700 : inline int find_upper(const node_type *n, const key_type& key) const
1683 : {
1684 : if ( 0 && sizeof(n->slotkey) > traits::binsearch_threshold )
1685 : {
1686 : if (n->slotuse == 0) return 0;
1687 :
1688 : int lo = 0, hi = n->slotuse;
1689 :
1690 : while (lo < hi)
1691 : {
1692 : int mid = (lo + hi) >> 1;
1693 :
1694 : if (key_less(key, n->slotkey[mid])) {
1695 : hi = mid; // key < mid
1696 : }
1697 : else {
1698 : lo = mid + 1; // key >= mid
1699 : }
1700 : }
1701 :
1702 : BTREE_PRINT("btree::find_upper: on " << n << " key " << key << " -> " << lo << " / " << hi);
1703 :
1704 : // verify result using simple linear search
1705 : if (selfverify)
1706 : {
1707 : int i = 0;
1708 : while (i < n->slotuse && key_lessequal(n->slotkey[i],key)) ++i;
1709 :
1710 : BTREE_PRINT("btree::find_upper testfind: " << i);
1711 : BTREE_ASSERT(i == hi);
1712 : }
1713 :
1714 : return lo;
1715 : }
1716 : else // for nodes <= binsearch_threshold do linear search.
1717 : {
1718 7700 : int lo = 0;
1719 7700 : while (lo < n->slotuse && key_lessequal(n->slotkey[lo],key)) ++lo;
1720 7700 : return lo;
1721 : }
1722 : }
1723 :
1724 : public:
1725 : // *** Access Functions to the Item Count
1726 :
1727 : /// Return the number of key/data pairs in the B+ tree
1728 2522584 : inline size_type size() const
1729 : {
1730 2522584 : return m_stats.itemcount;
1731 : }
1732 :
1733 : /// Returns true if there is at least one key/data pair in the B+ tree
1734 6516 : inline bool empty() const
1735 : {
1736 6516 : return (size() == size_type(0));
1737 : }
1738 :
1739 : /// Returns the largest possible size of the B+ Tree. This is just a
1740 : /// function required by the STL standard, the B+ Tree can hold more items.
1741 0 : inline size_type max_size() const
1742 : {
1743 0 : return size_type(-1);
1744 : }
1745 :
1746 : /// Return a const reference to the current statistics.
1747 0 : inline const struct tree_stats& get_stats() const
1748 : {
1749 0 : return m_stats;
1750 : }
1751 :
1752 : public:
1753 : // *** Standard Access Functions Querying the Tree by Descending to a Leaf
1754 :
1755 : /// Non-STL function checking whether a key is in the B+ tree. The same as
1756 : /// (find(k) != end()) or (count() != 0).
1757 497408 : bool exists(const key_type &key) const
1758 : {
1759 497408 : const node *n = m_root;
1760 497408 : if (!n) return false;
1761 :
1762 2429514 : while(!n->isleafnode())
1763 : {
1764 1434698 : const inner_node *inner = static_cast<const inner_node*>(n);
1765 1434698 : int slot = find_lower(inner, key);
1766 :
1767 1434698 : n = inner->childid[slot];
1768 : }
1769 :
1770 497408 : const leaf_node *leaf = static_cast<const leaf_node*>(n);
1771 :
1772 497408 : int slot = find_lower(leaf, key);
1773 497408 : return (slot < leaf->slotuse && key_equal(key, leaf->slotkey[slot]));
1774 : }
1775 :
1776 : /// Tries to locate a key in the B+ tree and returns an iterator to the
1777 : /// key/data slot if found. If unsuccessful it returns end().
1778 2222844 : iterator find(const key_type &key)
1779 : {
1780 2222844 : node *n = m_root;
1781 2222844 : if (!n) return end();
1782 :
1783 8895329 : while(!n->isleafnode())
1784 : {
1785 4449685 : const inner_node *inner = static_cast<const inner_node*>(n);
1786 4449685 : int slot = find_lower(inner, key);
1787 :
1788 4449685 : n = inner->childid[slot];
1789 : }
1790 :
1791 2222822 : leaf_node *leaf = static_cast<leaf_node*>(n);
1792 :
1793 2222822 : int slot = find_lower(leaf, key);
1794 : return (slot < leaf->slotuse && key_equal(key, leaf->slotkey[slot]))
1795 2222822 : ? iterator(leaf, slot) : end();
1796 : }
1797 :
1798 : /// Tries to locate a key in the B+ tree and returns an constant iterator
1799 : /// to the key/data slot if found. If unsuccessful it returns end().
1800 0 : const_iterator find(const key_type &key) const
1801 : {
1802 0 : const node *n = m_root;
1803 0 : if (!n) return end();
1804 :
1805 0 : while(!n->isleafnode())
1806 : {
1807 0 : const inner_node *inner = static_cast<const inner_node*>(n);
1808 0 : int slot = find_lower(inner, key);
1809 :
1810 0 : n = inner->childid[slot];
1811 : }
1812 :
1813 0 : const leaf_node *leaf = static_cast<const leaf_node*>(n);
1814 :
1815 0 : int slot = find_lower(leaf, key);
1816 : return (slot < leaf->slotuse && key_equal(key, leaf->slotkey[slot]))
1817 0 : ? const_iterator(leaf, slot) : end();
1818 : }
1819 :
1820 : /// Tries to locate a key in the B+ tree and returns the number of
1821 : /// identical key entries found.
1822 117920 : size_type count(const key_type &key) const
1823 : {
1824 117920 : const node *n = m_root;
1825 117920 : if (!n) return 0;
1826 :
1827 752828 : while(!n->isleafnode())
1828 : {
1829 516988 : const inner_node *inner = static_cast<const inner_node*>(n);
1830 516988 : int slot = find_lower(inner, key);
1831 :
1832 516988 : n = inner->childid[slot];
1833 : }
1834 :
1835 117920 : const leaf_node *leaf = static_cast<const leaf_node*>(n);
1836 :
1837 117920 : int slot = find_lower(leaf, key);
1838 117920 : size_type num = 0;
1839 :
1840 3748737 : while (leaf && slot < leaf->slotuse && key_equal(key, leaf->slotkey[slot]))
1841 : {
1842 3512897 : ++num;
1843 3512897 : if (++slot >= leaf->slotuse)
1844 : {
1845 850055 : leaf = leaf->nextleaf;
1846 850055 : slot = 0;
1847 : }
1848 : }
1849 :
1850 117920 : return num;
1851 : }
1852 :
1853 : /// Searches the B+ tree and returns an iterator to the first pair
1854 : /// equal to or greater than key, or end() if all keys are smaller.
1855 2420 : iterator lower_bound(const key_type& key)
1856 : {
1857 2420 : node *n = m_root;
1858 2420 : if (!n) return end();
1859 :
1860 10120 : while(!n->isleafnode())
1861 : {
1862 5280 : const inner_node *inner = static_cast<const inner_node*>(n);
1863 5280 : int slot = find_lower(inner, key);
1864 :
1865 5280 : n = inner->childid[slot];
1866 : }
1867 :
1868 2420 : leaf_node *leaf = static_cast<leaf_node*>(n);
1869 :
1870 2420 : int slot = find_lower(leaf, key);
1871 2420 : return iterator(leaf, slot);
1872 : }
1873 :
1874 : /// Searches the B+ tree and returns a constant iterator to the
1875 : /// first pair equal to or greater than key, or end() if all keys
1876 : /// are smaller.
1877 0 : const_iterator lower_bound(const key_type& key) const
1878 : {
1879 0 : const node *n = m_root;
1880 0 : if (!n) return end();
1881 :
1882 0 : while(!n->isleafnode())
1883 : {
1884 0 : const inner_node *inner = static_cast<const inner_node*>(n);
1885 0 : int slot = find_lower(inner, key);
1886 :
1887 0 : n = inner->childid[slot];
1888 : }
1889 :
1890 0 : const leaf_node *leaf = static_cast<const leaf_node*>(n);
1891 :
1892 0 : int slot = find_lower(leaf, key);
1893 0 : return const_iterator(leaf, slot);
1894 : }
1895 :
1896 : /// Searches the B+ tree and returns an iterator to the first pair
1897 : /// greater than key, or end() if all keys are smaller or equal.
1898 2420 : iterator upper_bound(const key_type& key)
1899 : {
1900 2420 : node *n = m_root;
1901 2420 : if (!n) return end();
1902 :
1903 10120 : while(!n->isleafnode())
1904 : {
1905 5280 : const inner_node *inner = static_cast<const inner_node*>(n);
1906 5280 : int slot = find_upper(inner, key);
1907 :
1908 5280 : n = inner->childid[slot];
1909 : }
1910 :
1911 2420 : leaf_node *leaf = static_cast<leaf_node*>(n);
1912 :
1913 2420 : int slot = find_upper(leaf, key);
1914 2420 : return iterator(leaf, slot);
1915 : }
1916 :
1917 : /// Searches the B+ tree and returns a constant iterator to the
1918 : /// first pair greater than key, or end() if all keys are smaller
1919 : /// or equal.
1920 0 : const_iterator upper_bound(const key_type& key) const
1921 : {
1922 0 : const node *n = m_root;
1923 0 : if (!n) return end();
1924 :
1925 0 : while(!n->isleafnode())
1926 : {
1927 0 : const inner_node *inner = static_cast<const inner_node*>(n);
1928 0 : int slot = find_upper(inner, key);
1929 :
1930 0 : n = inner->childid[slot];
1931 : }
1932 :
1933 0 : const leaf_node *leaf = static_cast<const leaf_node*>(n);
1934 :
1935 0 : int slot = find_upper(leaf, key);
1936 0 : return const_iterator(leaf, slot);
1937 : }
1938 :
1939 : /// Searches the B+ tree and returns both lower_bound() and upper_bound().
1940 1210 : inline std::pair<iterator, iterator> equal_range(const key_type& key)
1941 : {
1942 1210 : return std::pair<iterator, iterator>(lower_bound(key), upper_bound(key));
1943 : }
1944 :
1945 : /// Searches the B+ tree and returns both lower_bound() and upper_bound().
1946 0 : inline std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const
1947 : {
1948 0 : return std::pair<const_iterator, const_iterator>(lower_bound(key), upper_bound(key));
1949 : }
1950 :
1951 : public:
1952 : // *** B+ Tree Object Comparison Functions
1953 :
1954 : /// Equality relation of B+ trees of the same type. B+ trees of the same
1955 : /// size and equal elements (both key and data) are considered
1956 : /// equal. Beware of the random ordering of duplicate keys.
1957 27 : inline bool operator==(const btree_self &other) const
1958 : {
1959 27 : return (size() == other.size()) && std::equal(begin(), end(), other.begin());
1960 : }
1961 :
1962 : /// Inequality relation. Based on operator==.
1963 1 : inline bool operator!=(const btree_self &other) const
1964 : {
1965 1 : return !(*this == other);
1966 : }
1967 :
1968 : /// Total ordering relation of B+ trees of the same type. It uses
1969 : /// std::lexicographical_compare() for the actual comparison of elements.
1970 4 : inline bool operator<(const btree_self &other) const
1971 : {
1972 4 : return std::lexicographical_compare(begin(), end(), other.begin(), other.end());
1973 : }
1974 :
1975 : /// Greater relation. Based on operator<.
1976 1 : inline bool operator>(const btree_self &other) const
1977 : {
1978 1 : return other < *this;
1979 : }
1980 :
1981 : /// Less-equal relation. Based on operator<.
1982 1 : inline bool operator<=(const btree_self &other) const
1983 : {
1984 1 : return !(other < *this);
1985 : }
1986 :
1987 : /// Greater-equal relation. Based on operator<.
1988 1 : inline bool operator>=(const btree_self &other) const
1989 : {
1990 1 : return !(*this < other);
1991 : }
1992 :
1993 : public:
1994 : /// *** Fast Copy: Assign Operator and Copy Constructors
1995 :
1996 : /// Assignment operator. All the key/data pairs are copied
1997 1 : inline btree_self& operator= (const btree_self &other)
1998 : {
1999 1 : if (this != &other)
2000 : {
2001 1 : clear();
2002 :
2003 1 : m_key_less = other.key_comp();
2004 1 : m_allocator = other.get_allocator();
2005 :
2006 1 : if (other.size() != 0)
2007 : {
2008 1 : m_stats.leaves = m_stats.innernodes = 0;
2009 1 : if (other.m_root) {
2010 1 : m_root = copy_recursive(other.m_root);
2011 : }
2012 1 : m_stats = other.m_stats;
2013 : }
2014 :
2015 1 : if (selfverify) verify();
2016 : }
2017 1 : return *this;
2018 : }
2019 :
2020 : /// Copy constructor. The newly initialized B+ tree object will contain a
2021 : /// copy of all key/data pairs.
2022 3 : inline btree(const btree_self &other)
2023 : : m_root(NULL), m_headleaf(NULL), m_tailleaf(NULL),
2024 : m_stats( other.m_stats ),
2025 : m_key_less( other.key_comp() ),
2026 3 : m_allocator( other.get_allocator() )
2027 : {
2028 3 : if (size() > 0)
2029 : {
2030 3 : m_stats.leaves = m_stats.innernodes = 0;
2031 3 : if (other.m_root) {
2032 3 : m_root = copy_recursive(other.m_root);
2033 : }
2034 3 : if (selfverify) verify();
2035 : }
2036 3 : }
2037 :
2038 : private:
2039 : /// Recursively copy nodes from another B+ tree object
2040 1474 : struct node* copy_recursive(const node *n)
2041 : {
2042 1474 : if (n->isleafnode())
2043 : {
2044 1254 : const leaf_node *leaf = static_cast<const leaf_node*>(n);
2045 1254 : leaf_node *newleaf = allocate_leaf();
2046 :
2047 1254 : newleaf->slotuse = leaf->slotuse;
2048 1254 : std::copy(leaf->slotkey, leaf->slotkey + leaf->slotuse, newleaf->slotkey);
2049 1254 : data_copy(leaf->slotdata, leaf->slotdata + leaf->slotuse, newleaf->slotdata);
2050 :
2051 1254 : if (m_headleaf == NULL)
2052 : {
2053 4 : m_headleaf = m_tailleaf = newleaf;
2054 4 : newleaf->prevleaf = newleaf->nextleaf = NULL;
2055 : }
2056 : else
2057 : {
2058 1250 : newleaf->prevleaf = m_tailleaf;
2059 1250 : m_tailleaf->nextleaf = newleaf;
2060 1250 : m_tailleaf = newleaf;
2061 : }
2062 :
2063 1254 : return newleaf;
2064 : }
2065 : else
2066 : {
2067 220 : const inner_node *inner = static_cast<const inner_node*>(n);
2068 220 : inner_node *newinner = allocate_inner(inner->level);
2069 :
2070 220 : newinner->slotuse = inner->slotuse;
2071 220 : std::copy(inner->slotkey, inner->slotkey + inner->slotuse, newinner->slotkey);
2072 :
2073 1690 : for (unsigned short slot = 0; slot <= inner->slotuse; ++slot)
2074 : {
2075 1470 : newinner->childid[slot] = copy_recursive(inner->childid[slot]);
2076 : }
2077 :
2078 220 : return newinner;
2079 : }
2080 : }
2081 :
2082 : public:
2083 : // *** Public Insertion Functions
2084 :
2085 : /// Attempt to insert a key/data pair into the B+ tree. If the tree does not
2086 : /// allow duplicate keys, then the insert may fail if it is already
2087 : /// present.
2088 3200 : inline std::pair<iterator, bool> insert(const pair_type& x)
2089 : {
2090 3200 : return insert_start(x.first, x.second);
2091 : }
2092 :
2093 : /// Attempt to insert a key/data pair into the B+ tree. Beware that if
2094 : /// key_type == data_type, then the template iterator insert() is called
2095 : /// instead. If the tree does not allow duplicate keys, then the insert may
2096 : /// fail if it is already present.
2097 : inline std::pair<iterator, bool> insert(const key_type& key, const data_type& data)
2098 : {
2099 : return insert_start(key, data);
2100 : }
2101 :
2102 : /// Attempt to insert a key/data pair into the B+ tree. This function is the
2103 : /// same as the other insert, however if key_type == data_type then the
2104 : /// non-template function cannot be called. If the tree does not allow
2105 : /// duplicate keys, then the insert may fail if it is already present.
2106 2595088 : inline std::pair<iterator, bool> insert2(const key_type& key, const data_type& data)
2107 : {
2108 2595088 : return insert_start(key, data);
2109 : }
2110 :
2111 : /// Attempt to insert a key/data pair into the B+ tree. The iterator hint
2112 : /// is currently ignored by the B+ tree insertion routine.
2113 : inline iterator insert(iterator /* hint */, const pair_type &x)
2114 : {
2115 : return insert_start(x.first, x.second).first;
2116 : }
2117 :
2118 : /// Attempt to insert a key/data pair into the B+ tree. The iterator hint is
2119 : /// currently ignored by the B+ tree insertion routine.
2120 0 : inline iterator insert2(iterator /* hint */, const key_type& key, const data_type& data)
2121 : {
2122 0 : return insert_start(key, data).first;
2123 : }
2124 :
2125 : /// Attempt to insert the range [first,last) of value_type pairs into the
2126 : /// B+ tree. Each key/data pair is inserted individually; to bulk load the
2127 : /// tree, use a constructor with range.
2128 : template <typename InputIterator>
2129 1 : inline void insert(InputIterator first, InputIterator last)
2130 : {
2131 1 : InputIterator iter = first;
2132 3202 : while(iter != last)
2133 : {
2134 3200 : insert(*iter);
2135 3200 : ++iter;
2136 : }
2137 1 : }
2138 :
2139 : private:
2140 : // *** Private Insertion Functions
2141 :
2142 : /// Start the insertion descent at the current root and handle root
2143 : /// splits. Returns true if the item was inserted
2144 2598288 : std::pair<iterator, bool> insert_start(const key_type& key, const data_type& value)
2145 : {
2146 2598288 : node *newchild = NULL;
2147 2598288 : key_type newkey = key_type();
2148 :
2149 2598288 : if (m_root == NULL) {
2150 174 : m_root = m_headleaf = m_tailleaf = allocate_leaf();
2151 : }
2152 :
2153 2598288 : std::pair<iterator, bool> r = insert_descend(m_root, key, value, &newkey, &newchild);
2154 :
2155 2598288 : if (newchild)
2156 : {
2157 437 : inner_node *newroot = allocate_inner(m_root->level + 1);
2158 437 : newroot->slotkey[0] = newkey;
2159 :
2160 437 : newroot->childid[0] = m_root;
2161 437 : newroot->childid[1] = newchild;
2162 :
2163 437 : newroot->slotuse = 1;
2164 :
2165 437 : m_root = newroot;
2166 : }
2167 :
2168 : // increment itemcount if the item was inserted
2169 2598288 : if (r.second) ++m_stats.itemcount;
2170 :
2171 : #ifdef BTREE_DEBUG
2172 : if (debug) print(std::cout);
2173 : #endif
2174 :
2175 : if (selfverify) {
2176 376288 : verify();
2177 376288 : BTREE_ASSERT(exists(key));
2178 : }
2179 :
2180 14872 : return r;
2181 : }
2182 :
2183 : /**
2184 : * @brief Insert an item into the B+ tree.
2185 : *
2186 : * Descend down the nodes to a leaf, insert the key/data pair in a free
2187 : * slot. If the node overflows, then it must be split and the new split
2188 : * node inserted into the parent. Unroll / this splitting up to the root.
2189 : */
2190 9743762 : std::pair<iterator, bool> insert_descend(node* n,
2191 : const key_type& key, const data_type& value,
2192 : key_type* splitkey, node** splitnode)
2193 : {
2194 9743762 : if (!n->isleafnode())
2195 : {
2196 7145474 : inner_node *inner = static_cast<inner_node*>(n);
2197 :
2198 7145474 : key_type newkey = key_type();
2199 7145474 : node *newchild = NULL;
2200 :
2201 7145474 : int slot = find_lower(inner, key);
2202 :
2203 : BTREE_PRINT("btree::insert_descend into " << inner->childid[slot]);
2204 :
2205 : std::pair<iterator, bool> r = insert_descend(inner->childid[slot],
2206 7145474 : key, value, &newkey, &newchild);
2207 :
2208 7145474 : if (newchild)
2209 : {
2210 : BTREE_PRINT("btree::insert_descend newchild with key " << newkey << " node " << newchild << " at slot " << slot);
2211 :
2212 120917 : if (inner->isfull())
2213 : {
2214 10439 : split_inner_node(inner, splitkey, splitnode, slot);
2215 :
2216 : BTREE_PRINT("btree::insert_descend done split_inner: putslot: " << slot << " putkey: " << newkey << " upkey: " << *splitkey);
2217 :
2218 : #ifdef BTREE_DEBUG
2219 : if (debug)
2220 : {
2221 : print_node(std::cout, inner);
2222 : print_node(std::cout, *splitnode);
2223 : }
2224 : #endif
2225 :
2226 : // check if insert slot is in the split sibling node
2227 : BTREE_PRINT("btree::insert_descend switch: " << slot << " > " << inner->slotuse+1);
2228 :
2229 10439 : if (slot == inner->slotuse+1 && inner->slotuse < (*splitnode)->slotuse)
2230 : {
2231 : // special case when the insert slot matches the split
2232 : // place between the two nodes, then the insert key
2233 : // becomes the split key.
2234 :
2235 282 : BTREE_ASSERT(inner->slotuse + 1 < innerslotmax);
2236 :
2237 282 : inner_node *splitinner = static_cast<inner_node*>(*splitnode);
2238 :
2239 : // move the split key and it's datum into the left node
2240 282 : inner->slotkey[inner->slotuse] = *splitkey;
2241 282 : inner->childid[inner->slotuse+1] = splitinner->childid[0];
2242 282 : inner->slotuse++;
2243 :
2244 : // set new split key and move corresponding datum into right node
2245 282 : splitinner->childid[0] = newchild;
2246 282 : *splitkey = newkey;
2247 :
2248 282 : return r;
2249 : }
2250 10157 : else if (slot >= inner->slotuse+1)
2251 : {
2252 : // in case the insert slot is in the newly create split
2253 : // node, we reuse the code below.
2254 :
2255 3220 : slot -= inner->slotuse+1;
2256 3220 : inner = static_cast<inner_node*>(*splitnode);
2257 : BTREE_PRINT("btree::insert_descend switching to splitted node " << inner << " slot " << slot);
2258 : }
2259 : }
2260 :
2261 : // move items and put pointer to child node into correct slot
2262 120635 : BTREE_ASSERT(slot >= 0 && slot <= inner->slotuse);
2263 :
2264 120635 : std::copy_backward(inner->slotkey + slot, inner->slotkey + inner->slotuse,
2265 : inner->slotkey + inner->slotuse+1);
2266 120635 : std::copy_backward(inner->childid + slot, inner->childid + inner->slotuse+1,
2267 : inner->childid + inner->slotuse+2);
2268 :
2269 120635 : inner->slotkey[slot] = newkey;
2270 120635 : inner->childid[slot + 1] = newchild;
2271 120635 : inner->slotuse++;
2272 : }
2273 :
2274 7145192 : return r;
2275 : }
2276 : else // n->isleafnode() == true
2277 : {
2278 2598288 : leaf_node *leaf = static_cast<leaf_node*>(n);
2279 :
2280 2598288 : int slot = find_lower(leaf, key);
2281 :
2282 24100 : if (!allow_duplicates && slot < leaf->slotuse && key_equal(key, leaf->slotkey[slot])) {
2283 0 : return std::pair<iterator, bool>(iterator(leaf, slot), false);
2284 : }
2285 :
2286 2598288 : if (leaf->isfull())
2287 : {
2288 110915 : split_leaf_node(leaf, splitkey, splitnode);
2289 :
2290 : // check if insert slot is in the split sibling node
2291 110915 : if (slot >= leaf->slotuse)
2292 : {
2293 14502 : slot -= leaf->slotuse;
2294 14502 : leaf = static_cast<leaf_node*>(*splitnode);
2295 : }
2296 : }
2297 :
2298 : // move items and put data item into correct data slot
2299 2598288 : BTREE_ASSERT(slot >= 0 && slot <= leaf->slotuse);
2300 :
2301 2598288 : std::copy_backward(leaf->slotkey + slot, leaf->slotkey + leaf->slotuse,
2302 : leaf->slotkey + leaf->slotuse+1);
2303 2598288 : data_copy_backward(leaf->slotdata + slot, leaf->slotdata + leaf->slotuse,
2304 : leaf->slotdata + leaf->slotuse+1);
2305 :
2306 2598288 : leaf->slotkey[slot] = key;
2307 193584 : if (!used_as_set) leaf->slotdata[slot] = value;
2308 2598288 : leaf->slotuse++;
2309 :
2310 2598288 : if (splitnode && leaf != *splitnode && slot == leaf->slotuse-1)
2311 : {
2312 : // special case: the node was split, and the insert is at the
2313 : // last slot of the old node. then the splitkey must be
2314 : // updated.
2315 64484 : *splitkey = key;
2316 : }
2317 :
2318 2598288 : return std::pair<iterator, bool>(iterator(leaf, slot), true);
2319 : }
2320 : }
2321 :
2322 : /// Split up a leaf node into two equally-filled sibling leaves. Returns
2323 : /// the new nodes and it's insertion key in the two parameters.
2324 110915 : void split_leaf_node(leaf_node* leaf, key_type* _newkey, node** _newleaf)
2325 : {
2326 110915 : BTREE_ASSERT(leaf->isfull());
2327 :
2328 110915 : unsigned int mid = (leaf->slotuse >> 1);
2329 :
2330 : BTREE_PRINT("btree::split_leaf_node on " << leaf);
2331 :
2332 110915 : leaf_node *newleaf = allocate_leaf();
2333 :
2334 110915 : newleaf->slotuse = leaf->slotuse - mid;
2335 :
2336 110915 : newleaf->nextleaf = leaf->nextleaf;
2337 110915 : if (newleaf->nextleaf == NULL) {
2338 7750 : BTREE_ASSERT(leaf == m_tailleaf);
2339 7750 : m_tailleaf = newleaf;
2340 : }
2341 : else {
2342 103165 : newleaf->nextleaf->prevleaf = newleaf;
2343 : }
2344 :
2345 110915 : std::copy(leaf->slotkey + mid, leaf->slotkey + leaf->slotuse,
2346 : newleaf->slotkey);
2347 110915 : data_copy(leaf->slotdata + mid, leaf->slotdata + leaf->slotuse,
2348 : newleaf->slotdata);
2349 :
2350 110915 : leaf->slotuse = mid;
2351 110915 : leaf->nextleaf = newleaf;
2352 110915 : newleaf->prevleaf = leaf;
2353 :
2354 110915 : *_newkey = leaf->slotkey[leaf->slotuse-1];
2355 110915 : *_newleaf = newleaf;
2356 110915 : }
2357 :
2358 : /// Split up an inner node into two equally-filled sibling nodes. Returns
2359 : /// the new nodes and it's insertion key in the two parameters. Requires
2360 : /// the slot of the item will be inserted, so the nodes will be the same
2361 : /// size after the insert.
2362 10439 : void split_inner_node(inner_node* inner, key_type* _newkey, node** _newinner, unsigned int addslot)
2363 : {
2364 10439 : BTREE_ASSERT(inner->isfull());
2365 :
2366 10439 : unsigned int mid = (inner->slotuse >> 1);
2367 :
2368 : BTREE_PRINT("btree::split_inner: mid " << mid << " addslot " << addslot);
2369 :
2370 : // if the split is uneven and the overflowing item will be put into the
2371 : // larger node, then the smaller split node may underflow
2372 10439 : if (addslot <= mid && mid > inner->slotuse - (mid + 1))
2373 2595 : mid--;
2374 :
2375 : BTREE_PRINT("btree::split_inner: mid " << mid << " addslot " << addslot);
2376 :
2377 : BTREE_PRINT("btree::split_inner_node on " << inner << " into two nodes " << mid << " and " << inner->slotuse - (mid + 1) << " sized");
2378 :
2379 10439 : inner_node *newinner = allocate_inner(inner->level);
2380 :
2381 10439 : newinner->slotuse = inner->slotuse - (mid + 1);
2382 :
2383 10439 : std::copy(inner->slotkey + mid+1, inner->slotkey + inner->slotuse,
2384 : newinner->slotkey);
2385 10439 : std::copy(inner->childid + mid+1, inner->childid + inner->slotuse+1,
2386 : newinner->childid);
2387 :
2388 10439 : inner->slotuse = mid;
2389 :
2390 10439 : *_newkey = inner->slotkey[mid];
2391 10439 : *_newinner = newinner;
2392 10439 : }
2393 :
2394 : public:
2395 :
2396 : // *** Bulk Loader - Construct Tree from Sorted Sequence
2397 :
2398 : /// Bulk load a sorted range. Loads items into leaves and constructs a
2399 : /// B-tree above them. The tree must be empty when calling this function.
2400 : template <typename Iterator>
2401 6394 : void bulk_load(Iterator ibegin, Iterator iend)
2402 : {
2403 6394 : BTREE_ASSERT(empty());
2404 :
2405 6394 : m_stats.itemcount = iend - ibegin;
2406 :
2407 : // calculate number of leaves needed, round up.
2408 6394 : size_t num_items = iend - ibegin;
2409 6394 : size_t num_leaves = (num_items + leafslotmax-1) / leafslotmax;
2410 :
2411 : BTREE_PRINT("btree::bulk_load, level 0: " << m_stats.itemcount << " items into " << num_leaves << " leaves with up to " << ((iend - ibegin + num_leaves-1) / num_leaves) << " items per leaf.");
2412 :
2413 6394 : Iterator it = ibegin;
2414 1334198 : for (size_t i = 0; i < num_leaves; ++i)
2415 : {
2416 : // allocate new leaf node
2417 1327804 : leaf_node* leaf = allocate_leaf();
2418 :
2419 : // copy keys or (key,value) pairs into leaf nodes, uses template
2420 : // switch leaf->set_slot().
2421 1327804 : leaf->slotuse = static_cast<int>(num_items / (num_leaves-i));
2422 11927864 : for (size_t s = 0; s < leaf->slotuse; ++s, ++it)
2423 10600060 : leaf->set_slot(s, *it);
2424 :
2425 1327804 : if (m_tailleaf != NULL) {
2426 1321410 : m_tailleaf->nextleaf = leaf;
2427 1321410 : leaf->prevleaf = m_tailleaf;
2428 : }
2429 : else {
2430 6394 : m_headleaf = leaf;
2431 : }
2432 1327804 : m_tailleaf = leaf;
2433 :
2434 1327804 : num_items -= leaf->slotuse;
2435 : }
2436 :
2437 6394 : BTREE_ASSERT( it == iend && num_items == 0 );
2438 :
2439 : // if the btree is so small to fit into one leaf, then we're done.
2440 6394 : if (m_headleaf == m_tailleaf) {
2441 6 : m_root = m_headleaf;
2442 6 : return;
2443 : }
2444 :
2445 6388 : BTREE_ASSERT( m_stats.leaves == num_leaves );
2446 :
2447 : // create first level of inner nodes, pointing to the leaves.
2448 6388 : size_t num_parents = (num_leaves + (innerslotmax+1)-1) / (innerslotmax+1);
2449 :
2450 : BTREE_PRINT("btree::bulk_load, level 1: " << num_leaves << " leaves in " << num_parents << " inner nodes with up to " << ((num_leaves + num_parents-1) / num_parents) << " leaves per inner node.");
2451 :
2452 : // save inner nodes and maxkey for next level.
2453 : typedef std::pair<inner_node*, const key_type*> nextlevel_type;
2454 6388 : nextlevel_type* nextlevel = new nextlevel_type[num_parents];
2455 :
2456 6388 : leaf_node* leaf = m_headleaf;
2457 156772 : for (size_t i = 0; i < num_parents; ++i)
2458 : {
2459 : // allocate new inner node at level 1
2460 150384 : inner_node* n = allocate_inner(1);
2461 :
2462 150384 : n->slotuse = static_cast<int>(num_leaves / (num_parents-i));
2463 150384 : BTREE_ASSERT(n->slotuse > 0);
2464 150384 : --n->slotuse; // this counts keys, but an inner node has keys+1 children.
2465 :
2466 : // copy last key from each leaf and set child
2467 1327798 : for (unsigned short s = 0; s < n->slotuse; ++s)
2468 : {
2469 1177414 : n->slotkey[s] = leaf->slotkey[leaf->slotuse-1];
2470 1177414 : n->childid[s] = leaf;
2471 1177414 : leaf = leaf->nextleaf;
2472 : }
2473 150384 : n->childid[n->slotuse] = leaf;
2474 :
2475 : // track max key of any descendant.
2476 150384 : nextlevel[i].first = n;
2477 150384 : nextlevel[i].second = &leaf->slotkey[leaf->slotuse-1];
2478 :
2479 150384 : leaf = leaf->nextleaf;
2480 150384 : num_leaves -= n->slotuse+1;
2481 : }
2482 :
2483 6388 : BTREE_ASSERT( leaf == NULL && num_leaves == 0 );
2484 :
2485 : // recursively build inner nodes pointing to inner nodes.
2486 17764 : for (int level = 2; num_parents != 1; ++level)
2487 : {
2488 11376 : size_t num_children = num_parents;
2489 11376 : num_parents = (num_children + (innerslotmax+1)-1) / (innerslotmax+1);
2490 :
2491 : BTREE_PRINT("btree::bulk_load, level " << level << ": " << num_children << " children in " << num_parents << " inner nodes with up to " << ((num_children + num_parents-1) / num_parents) << " children per inner node.");
2492 :
2493 11376 : size_t inner_index = 0;
2494 36006 : for (size_t i = 0; i < num_parents; ++i)
2495 : {
2496 : // allocate new inner node at level
2497 24630 : inner_node* n = allocate_inner(level);
2498 :
2499 24630 : n->slotuse = static_cast<int>(num_children / (num_parents-i));
2500 24630 : BTREE_ASSERT(n->slotuse > 0);
2501 24630 : --n->slotuse; // this counts keys, but an inner node has keys+1 children.
2502 :
2503 : // copy children and maxkeys from nextlevel
2504 168626 : for (unsigned short s = 0; s < n->slotuse; ++s)
2505 : {
2506 143996 : n->slotkey[s] = *nextlevel[inner_index].second;
2507 143996 : n->childid[s] = nextlevel[inner_index].first;
2508 143996 : ++inner_index;
2509 : }
2510 24630 : n->childid[n->slotuse] = nextlevel[inner_index].first;
2511 :
2512 : // reuse nextlevel array for parents, because we can overwrite
2513 : // slots we've already consumed.
2514 24630 : nextlevel[i].first = n;
2515 24630 : nextlevel[i].second = nextlevel[inner_index].second;
2516 :
2517 24630 : ++inner_index;
2518 24630 : num_children -= n->slotuse+1;
2519 : }
2520 :
2521 11376 : BTREE_ASSERT( num_children == 0 );
2522 : }
2523 :
2524 6388 : m_root = nextlevel[0].first;
2525 6388 : delete [] nextlevel;
2526 :
2527 6388 : if (selfverify) verify();
2528 : }
2529 :
2530 : private:
2531 : // *** Support Class Encapsulating Deletion Results
2532 :
2533 : /// Result flags of recursive deletion.
2534 : enum result_flags_t
2535 : {
2536 : /// Deletion successful and no fix-ups necessary.
2537 : btree_ok = 0,
2538 :
2539 : /// Deletion not successful because key was not found.
2540 : btree_not_found = 1,
2541 :
2542 : /// Deletion successful, the last key was updated so parent slotkeys
2543 : /// need updates.
2544 : btree_update_lastkey = 2,
2545 :
2546 : /// Deletion successful, children nodes were merged and the parent
2547 : /// needs to remove the empty node.
2548 : btree_fixmerge = 4
2549 : };
2550 :
2551 : /// B+ tree recursive deletion has much information which is needs to be
2552 : /// passed upward.
2553 : struct result_t
2554 117241 : {
2555 : /// Merged result flags
2556 : result_flags_t flags;
2557 :
2558 : /// The key to be updated at the parent's slot
2559 : key_type lastkey;
2560 :
2561 : /// Constructor of a result with a specific flag, this can also be used
2562 : /// as for implicit conversion.
2563 1406378 : inline result_t(result_flags_t f = btree_ok)
2564 1406378 : : flags(f), lastkey()
2565 1406378 : { }
2566 :
2567 : /// Constructor with a lastkey value.
2568 4231 : inline result_t(result_flags_t f, const key_type &k)
2569 4231 : : flags(f), lastkey(k)
2570 4231 : { }
2571 :
2572 : /// Test if this result object has a given flag set.
2573 3583325 : inline bool has(result_flags_t f) const
2574 : {
2575 3583325 : return (flags & f) != 0;
2576 : }
2577 :
2578 : /// Merge two results OR-ing the result flags and overwriting lastkeys.
2579 84607 : inline result_t& operator|= (const result_t &other)
2580 : {
2581 84607 : flags = result_flags_t(flags | other.flags);
2582 :
2583 : // we overwrite existing lastkeys on purpose
2584 84607 : if (other.has(btree_update_lastkey))
2585 4231 : lastkey = other.lastkey;
2586 :
2587 84607 : return *this;
2588 : }
2589 : };
2590 :
2591 : public:
2592 : // *** Public Erase Functions
2593 :
2594 : /// Erases one (the first) of the key/data pairs associated with the given
2595 : /// key.
2596 362174 : bool erase_one(const key_type &key)
2597 : {
2598 : BTREE_PRINT("btree::erase_one(" << key << ") on btree size " << size());
2599 :
2600 362174 : if (selfverify) verify();
2601 :
2602 362174 : if (!m_root) return false;
2603 :
2604 362152 : result_t result = erase_one_descend(key, m_root, NULL, NULL, NULL, NULL, NULL, 0);
2605 :
2606 362152 : if (!result.has(btree_not_found))
2607 362152 : --m_stats.itemcount;
2608 :
2609 : #ifdef BTREE_DEBUG
2610 : if (debug) print(std::cout);
2611 : #endif
2612 362152 : if (selfverify) verify();
2613 :
2614 362152 : return !result.has(btree_not_found);
2615 : }
2616 :
2617 : /// Erases all the key/data pairs associated with the given key. This is
2618 : /// implemented using erase_one().
2619 22 : size_type erase(const key_type &key)
2620 : {
2621 22 : size_type c = 0;
2622 :
2623 44 : while( erase_one(key) )
2624 : {
2625 0 : ++c;
2626 0 : if (!allow_duplicates) break;
2627 : }
2628 :
2629 22 : return c;
2630 : }
2631 :
2632 : /// Erase the key/data pair referenced by the iterator.
2633 8192 : void erase(iterator iter)
2634 : {
2635 : BTREE_PRINT("btree::erase_iter(" << iter.currnode << "," << iter.currslot << ") on btree size " << size());
2636 :
2637 8192 : if (selfverify) verify();
2638 :
2639 8192 : if (!m_root) return;
2640 :
2641 8192 : result_t result = erase_iter_descend(iter, m_root, NULL, NULL, NULL, NULL, NULL, 0);
2642 :
2643 8192 : if (!result.has(btree_not_found))
2644 8192 : --m_stats.itemcount;
2645 :
2646 : #ifdef BTREE_DEBUG
2647 : if (debug) print(std::cout);
2648 : #endif
2649 8192 : if (selfverify) verify();
2650 : }
2651 :
2652 : #ifdef BTREE_TODO
2653 : /// Erase all key/data pairs in the range [first,last). This function is
2654 : /// currently not implemented by the B+ Tree.
2655 : void erase(iterator /* first */, iterator /* last */)
2656 : {
2657 : abort();
2658 : }
2659 : #endif
2660 :
2661 : private:
2662 : // *** Private Erase Functions
2663 :
2664 : /** @brief Erase one (the first) key/data pair in the B+ tree matching key.
2665 : *
2666 : * Descends down the tree in search of key. During the descent the parent,
2667 : * left and right siblings and their parents are computed and passed
2668 : * down. Once the key/data pair is found, it is removed from the leaf. If
2669 : * the leaf underflows 6 different cases are handled. These cases resolve
2670 : * the underflow by shifting key/data pairs from adjacent sibling nodes,
2671 : * merging two sibling nodes or trimming the tree.
2672 : */
2673 1251077 : result_t erase_one_descend(const key_type& key,
2674 : node *curr,
2675 : node *left, node *right,
2676 : inner_node *leftparent, inner_node *rightparent,
2677 : inner_node *parent, unsigned int parentslot)
2678 : {
2679 1251077 : if (curr->isleafnode())
2680 : {
2681 362152 : leaf_node *leaf = static_cast<leaf_node*>(curr);
2682 362152 : leaf_node *leftleaf = static_cast<leaf_node*>(left);
2683 362152 : leaf_node *rightleaf = static_cast<leaf_node*>(right);
2684 :
2685 362152 : int slot = find_lower(leaf, key);
2686 :
2687 362152 : if (slot >= leaf->slotuse || !key_equal(key, leaf->slotkey[slot]))
2688 : {
2689 : BTREE_PRINT("Could not find key " << key << " to erase.");
2690 :
2691 0 : return btree_not_found;
2692 : }
2693 :
2694 : BTREE_PRINT("Found key in leaf " << curr << " at slot " << slot);
2695 :
2696 362152 : std::copy(leaf->slotkey + slot+1, leaf->slotkey + leaf->slotuse,
2697 : leaf->slotkey + slot);
2698 362152 : data_copy(leaf->slotdata + slot+1, leaf->slotdata + leaf->slotuse,
2699 : leaf->slotdata + slot);
2700 :
2701 362152 : leaf->slotuse--;
2702 :
2703 362152 : result_t myres = btree_ok;
2704 :
2705 : // if the last key of the leaf was changed, the parent is notified
2706 : // and updates the key of this leaf
2707 362152 : if (slot == leaf->slotuse)
2708 : {
2709 28674 : if (parent && parentslot < parent->slotuse)
2710 : {
2711 25300 : BTREE_ASSERT(parent->childid[parentslot] == curr);
2712 25300 : parent->slotkey[parentslot] = leaf->slotkey[leaf->slotuse - 1];
2713 : }
2714 : else
2715 : {
2716 3374 : if (leaf->slotuse >= 1)
2717 : {
2718 : BTREE_PRINT("Scheduling lastkeyupdate: key " << leaf->slotkey[leaf->slotuse - 1]);
2719 3251 : myres |= result_t(btree_update_lastkey, leaf->slotkey[leaf->slotuse - 1]);
2720 : }
2721 : else
2722 : {
2723 123 : BTREE_ASSERT(leaf == m_root);
2724 : }
2725 : }
2726 : }
2727 :
2728 362152 : if (leaf->isunderflow() && !(leaf == m_root && leaf->slotuse >= 1))
2729 : {
2730 : // determine what to do about the underflow
2731 :
2732 : // case : if this empty leaf is the root, then delete all nodes
2733 : // and set root to NULL.
2734 106071 : if (leftleaf == NULL && rightleaf == NULL)
2735 : {
2736 123 : BTREE_ASSERT(leaf == m_root);
2737 123 : BTREE_ASSERT(leaf->slotuse == 0);
2738 :
2739 123 : free_node(m_root);
2740 :
2741 123 : m_root = leaf = NULL;
2742 123 : m_headleaf = m_tailleaf = NULL;
2743 :
2744 : // will be decremented soon by insert_start()
2745 123 : BTREE_ASSERT(m_stats.itemcount == 1);
2746 123 : BTREE_ASSERT(m_stats.leaves == 0);
2747 123 : BTREE_ASSERT(m_stats.innernodes == 0);
2748 :
2749 123 : return btree_ok;
2750 : }
2751 : // case : if both left and right leaves would underflow in case of
2752 : // a shift, then merging is necessary. choose the more local merger
2753 : // with our parent
2754 105948 : else if ( (leftleaf == NULL || leftleaf->isfew()) && (rightleaf == NULL || rightleaf->isfew()) )
2755 : {
2756 35919 : if (leftparent == parent)
2757 27794 : myres |= merge_leaves(leftleaf, leaf, leftparent);
2758 : else
2759 8125 : myres |= merge_leaves(leaf, rightleaf, rightparent);
2760 : }
2761 : // case : the right leaf has extra data, so balance right with current
2762 70029 : else if ( (leftleaf != NULL && leftleaf->isfew()) && (rightleaf != NULL && !rightleaf->isfew()) )
2763 : {
2764 17076 : if (rightparent == parent)
2765 15038 : myres |= shift_left_leaf(leaf, rightleaf, rightparent, parentslot);
2766 : else
2767 2038 : myres |= merge_leaves(leftleaf, leaf, leftparent);
2768 : }
2769 : // case : the left leaf has extra data, so balance left with current
2770 52953 : else if ( (leftleaf != NULL && !leftleaf->isfew()) && (rightleaf != NULL && rightleaf->isfew()) )
2771 : {
2772 24881 : if (leftparent == parent)
2773 22532 : shift_right_leaf(leftleaf, leaf, leftparent, parentslot - 1);
2774 : else
2775 2349 : myres |= merge_leaves(leaf, rightleaf, rightparent);
2776 : }
2777 : // case : both the leaf and right leaves have extra data and our
2778 : // parent, choose the leaf with more data
2779 28072 : else if (leftparent == rightparent)
2780 : {
2781 22013 : if (leftleaf->slotuse <= rightleaf->slotuse)
2782 13850 : myres |= shift_left_leaf(leaf, rightleaf, rightparent, parentslot);
2783 : else
2784 8163 : shift_right_leaf(leftleaf, leaf, leftparent, parentslot - 1);
2785 : }
2786 : else
2787 : {
2788 6059 : if (leftparent == parent)
2789 2805 : shift_right_leaf(leftleaf, leaf, leftparent, parentslot - 1);
2790 : else
2791 3254 : myres |= shift_left_leaf(leaf, rightleaf, rightparent, parentslot);
2792 : }
2793 : }
2794 :
2795 362029 : return myres;
2796 : }
2797 : else // !curr->isleafnode()
2798 : {
2799 888925 : inner_node *inner = static_cast<inner_node*>(curr);
2800 888925 : inner_node *leftinner = static_cast<inner_node*>(left);
2801 888925 : inner_node *rightinner = static_cast<inner_node*>(right);
2802 :
2803 : node *myleft, *myright;
2804 : inner_node *myleftparent, *myrightparent;
2805 :
2806 888925 : int slot = find_lower(inner, key);
2807 :
2808 888925 : if (slot == 0) {
2809 217559 : myleft = (left == NULL) ? NULL : (static_cast<inner_node*>(left))->childid[left->slotuse - 1];
2810 217559 : myleftparent = leftparent;
2811 : }
2812 : else {
2813 671366 : myleft = inner->childid[slot - 1];
2814 671366 : myleftparent = inner;
2815 : }
2816 :
2817 888925 : if (slot == inner->slotuse) {
2818 138453 : myright = (right == NULL) ? NULL : (static_cast<inner_node*>(right))->childid[0];
2819 138453 : myrightparent = rightparent;
2820 : }
2821 : else {
2822 750472 : myright = inner->childid[slot + 1];
2823 750472 : myrightparent = inner;
2824 : }
2825 :
2826 : BTREE_PRINT("erase_one_descend into " << inner->childid[slot]);
2827 :
2828 : result_t result = erase_one_descend(key,
2829 : inner->childid[slot],
2830 : myleft, myright,
2831 : myleftparent, myrightparent,
2832 888925 : inner, slot);
2833 :
2834 888925 : result_t myres = btree_ok;
2835 :
2836 888925 : if (result.has(btree_not_found))
2837 : {
2838 0 : return result;
2839 : }
2840 :
2841 888925 : if (result.has(btree_update_lastkey))
2842 : {
2843 3200 : if (parent && parentslot < parent->slotuse)
2844 : {
2845 : BTREE_PRINT("Fixing lastkeyupdate: key " << result.lastkey << " into parent " << parent << " at parentslot " << parentslot);
2846 :
2847 2626 : BTREE_ASSERT(parent->childid[parentslot] == curr);
2848 2626 : parent->slotkey[parentslot] = result.lastkey;
2849 : }
2850 : else
2851 : {
2852 : BTREE_PRINT("Forwarding lastkeyupdate: key " << result.lastkey);
2853 574 : myres |= result_t(btree_update_lastkey, result.lastkey);
2854 : }
2855 : }
2856 :
2857 888925 : if (result.has(btree_fixmerge))
2858 : {
2859 : // either the current node or the next is empty and should be removed
2860 45761 : if (inner->childid[slot]->slotuse != 0)
2861 12200 : slot++;
2862 :
2863 : // this is the child slot invalidated by the merge
2864 45761 : BTREE_ASSERT(inner->childid[slot]->slotuse == 0);
2865 :
2866 45761 : free_node(inner->childid[slot]);
2867 :
2868 45761 : std::copy(inner->slotkey + slot, inner->slotkey + inner->slotuse,
2869 : inner->slotkey + slot-1);
2870 45761 : std::copy(inner->childid + slot+1, inner->childid + inner->slotuse+1,
2871 : inner->childid + slot);
2872 :
2873 45761 : inner->slotuse--;
2874 :
2875 45761 : if (inner->level == 1)
2876 : {
2877 : // fix split key for children leaves
2878 40306 : slot--;
2879 40306 : leaf_node *child = static_cast<leaf_node*>(inner->childid[slot]);
2880 40306 : inner->slotkey[slot] = child->slotkey[ child->slotuse-1 ];
2881 : }
2882 : }
2883 :
2884 888925 : if (inner->isunderflow() && !(inner == m_root && inner->slotuse >= 1))
2885 : {
2886 : // case: the inner node is the root and has just one child. that child becomes the new root
2887 14774 : if (leftinner == NULL && rightinner == NULL)
2888 : {
2889 306 : BTREE_ASSERT(inner == m_root);
2890 306 : BTREE_ASSERT(inner->slotuse == 0);
2891 :
2892 306 : m_root = inner->childid[0];
2893 :
2894 306 : inner->slotuse = 0;
2895 306 : free_node(inner);
2896 :
2897 306 : return btree_ok;
2898 : }
2899 : // case : if both left and right leaves would underflow in case of
2900 : // a shift, then merging is necessary. choose the more local merger
2901 : // with our parent
2902 14468 : else if ( (leftinner == NULL || leftinner->isfew()) && (rightinner == NULL || rightinner->isfew()) )
2903 : {
2904 4854 : if (leftparent == parent)
2905 3420 : myres |= merge_inner(leftinner, inner, leftparent, parentslot - 1);
2906 : else
2907 1434 : myres |= merge_inner(inner, rightinner, rightparent, parentslot);
2908 : }
2909 : // case : the right leaf has extra data, so balance right with current
2910 9614 : else if ( (leftinner != NULL && leftinner->isfew()) && (rightinner != NULL && !rightinner->isfew()) )
2911 : {
2912 2821 : if (rightparent == parent)
2913 2512 : shift_left_inner(inner, rightinner, rightparent, parentslot);
2914 : else
2915 309 : myres |= merge_inner(leftinner, inner, leftparent, parentslot - 1);
2916 : }
2917 : // case : the left leaf has extra data, so balance left with current
2918 6793 : else if ( (leftinner != NULL && !leftinner->isfew()) && (rightinner != NULL && rightinner->isfew()) )
2919 : {
2920 3287 : if (leftparent == parent)
2921 2995 : shift_right_inner(leftinner, inner, leftparent, parentslot - 1);
2922 : else
2923 292 : myres |= merge_inner(inner, rightinner, rightparent, parentslot);
2924 : }
2925 : // case : both the leaf and right leaves have extra data and our
2926 : // parent, choose the leaf with more data
2927 3506 : else if (leftparent == rightparent)
2928 : {
2929 2290 : if (leftinner->slotuse <= rightinner->slotuse)
2930 1309 : shift_left_inner(inner, rightinner, rightparent, parentslot);
2931 : else
2932 981 : shift_right_inner(leftinner, inner, leftparent, parentslot - 1);
2933 : }
2934 : else
2935 : {
2936 1216 : if (leftparent == parent)
2937 703 : shift_right_inner(leftinner, inner, leftparent, parentslot - 1);
2938 : else
2939 513 : shift_left_inner(inner, rightinner, rightparent, parentslot);
2940 : }
2941 : }
2942 :
2943 888619 : return myres;
2944 : }
2945 : }
2946 :
2947 : /** @brief Erase one key/data pair referenced by an iterator in the B+
2948 : * tree.
2949 : *
2950 : * Descends down the tree in search of an iterator. During the descent the
2951 : * parent, left and right siblings and their parents are computed and
2952 : * passed down. The difficulty is that the iterator contains only a pointer
2953 : * to a leaf_node, which means that this function must do a recursive depth
2954 : * first search for that leaf node in the subtree containing all pairs of
2955 : * the same key. This subtree can be very large, even the whole tree,
2956 : * though in practice it would not make sense to have so many duplicate
2957 : * keys.
2958 : *
2959 : * Once the referenced key/data pair is found, it is removed from the leaf
2960 : * and the same underflow cases are handled as in erase_one_descend.
2961 : */
2962 41341 : result_t erase_iter_descend(const iterator& iter,
2963 : node *curr,
2964 : node *left, node *right,
2965 : inner_node *leftparent, inner_node *rightparent,
2966 : inner_node *parent, unsigned int parentslot)
2967 : {
2968 41341 : if (curr->isleafnode())
2969 : {
2970 8192 : leaf_node *leaf = static_cast<leaf_node*>(curr);
2971 8192 : leaf_node *leftleaf = static_cast<leaf_node*>(left);
2972 8192 : leaf_node *rightleaf = static_cast<leaf_node*>(right);
2973 :
2974 : // if this is not the correct leaf, get next step in recursive
2975 : // search
2976 8192 : if (leaf != iter.currnode)
2977 : {
2978 0 : return btree_not_found;
2979 : }
2980 :
2981 8192 : if (iter.currslot >= leaf->slotuse)
2982 : {
2983 : BTREE_PRINT("Could not find iterator (" << iter.currnode << "," << iter.currslot << ") to erase. Invalid leaf node?");
2984 :
2985 0 : return btree_not_found;
2986 : }
2987 :
2988 8192 : int slot = iter.currslot;
2989 :
2990 : BTREE_PRINT("Found iterator in leaf " << curr << " at slot " << slot);
2991 :
2992 8192 : std::copy(leaf->slotkey + slot+1, leaf->slotkey + leaf->slotuse,
2993 : leaf->slotkey + slot);
2994 8192 : data_copy(leaf->slotdata + slot+1, leaf->slotdata + leaf->slotuse,
2995 : leaf->slotdata + slot);
2996 :
2997 8192 : leaf->slotuse--;
2998 :
2999 8192 : result_t myres = btree_ok;
3000 :
3001 : // if the last key of the leaf was changed, the parent is notified
3002 : // and updates the key of this leaf
3003 8192 : if (slot == leaf->slotuse)
3004 : {
3005 993 : if (parent && parentslot < parent->slotuse)
3006 : {
3007 744 : BTREE_ASSERT(parent->childid[parentslot] == curr);
3008 744 : parent->slotkey[parentslot] = leaf->slotkey[leaf->slotuse - 1];
3009 : }
3010 : else
3011 : {
3012 249 : if (leaf->slotuse >= 1)
3013 : {
3014 : BTREE_PRINT("Scheduling lastkeyupdate: key " << leaf->slotkey[leaf->slotuse - 1]);
3015 248 : myres |= result_t(btree_update_lastkey, leaf->slotkey[leaf->slotuse - 1]);
3016 : }
3017 : else
3018 : {
3019 1 : BTREE_ASSERT(leaf == m_root);
3020 : }
3021 : }
3022 : }
3023 :
3024 8192 : if (leaf->isunderflow() && !(leaf == m_root && leaf->slotuse >= 1))
3025 : {
3026 : // determine what to do about the underflow
3027 :
3028 : // case : if this empty leaf is the root, then delete all nodes
3029 : // and set root to NULL.
3030 2016 : if (leftleaf == NULL && rightleaf == NULL)
3031 : {
3032 1 : BTREE_ASSERT(leaf == m_root);
3033 1 : BTREE_ASSERT(leaf->slotuse == 0);
3034 :
3035 1 : free_node(m_root);
3036 :
3037 1 : m_root = leaf = NULL;
3038 1 : m_headleaf = m_tailleaf = NULL;
3039 :
3040 : // will be decremented soon by insert_start()
3041 1 : BTREE_ASSERT(m_stats.itemcount == 1);
3042 1 : BTREE_ASSERT(m_stats.leaves == 0);
3043 1 : BTREE_ASSERT(m_stats.innernodes == 0);
3044 :
3045 1 : return btree_ok;
3046 : }
3047 : // case : if both left and right leaves would underflow in case of
3048 : // a shift, then merging is necessary. choose the more local merger
3049 : // with our parent
3050 2015 : else if ( (leftleaf == NULL || leftleaf->isfew()) && (rightleaf == NULL || rightleaf->isfew()) )
3051 : {
3052 2015 : if (leftparent == parent)
3053 992 : myres |= merge_leaves(leftleaf, leaf, leftparent);
3054 : else
3055 1023 : myres |= merge_leaves(leaf, rightleaf, rightparent);
3056 : }
3057 : // case : the right leaf has extra data, so balance right with current
3058 0 : else if ( (leftleaf != NULL && leftleaf->isfew()) && (rightleaf != NULL && !rightleaf->isfew()) )
3059 : {
3060 0 : if (rightparent == parent)
3061 0 : myres |= shift_left_leaf(leaf, rightleaf, rightparent, parentslot);
3062 : else
3063 0 : myres |= merge_leaves(leftleaf, leaf, leftparent);
3064 : }
3065 : // case : the left leaf has extra data, so balance left with current
3066 0 : else if ( (leftleaf != NULL && !leftleaf->isfew()) && (rightleaf != NULL && rightleaf->isfew()) )
3067 : {
3068 0 : if (leftparent == parent)
3069 0 : shift_right_leaf(leftleaf, leaf, leftparent, parentslot - 1);
3070 : else
3071 0 : myres |= merge_leaves(leaf, rightleaf, rightparent);
3072 : }
3073 : // case : both the leaf and right leaves have extra data and our
3074 : // parent, choose the leaf with more data
3075 0 : else if (leftparent == rightparent)
3076 : {
3077 0 : if (leftleaf->slotuse <= rightleaf->slotuse)
3078 0 : myres |= shift_left_leaf(leaf, rightleaf, rightparent, parentslot);
3079 : else
3080 0 : shift_right_leaf(leftleaf, leaf, leftparent, parentslot - 1);
3081 : }
3082 : else
3083 : {
3084 0 : if (leftparent == parent)
3085 0 : shift_right_leaf(leftleaf, leaf, leftparent, parentslot - 1);
3086 : else
3087 0 : myres |= shift_left_leaf(leaf, rightleaf, rightparent, parentslot);
3088 : }
3089 : }
3090 :
3091 8191 : return myres;
3092 : }
3093 : else // !curr->isleafnode()
3094 : {
3095 33149 : inner_node *inner = static_cast<inner_node*>(curr);
3096 33149 : inner_node *leftinner = static_cast<inner_node*>(left);
3097 33149 : inner_node *rightinner = static_cast<inner_node*>(right);
3098 :
3099 : // find first slot below which the searched iterator might be
3100 : // located.
3101 :
3102 33149 : result_t result;
3103 33149 : int slot = find_lower(inner, iter.key());
3104 :
3105 66298 : while (slot <= inner->slotuse)
3106 : {
3107 : node *myleft, *myright;
3108 : inner_node *myleftparent, *myrightparent;
3109 :
3110 33149 : if (slot == 0) {
3111 5545 : myleft = (left == NULL) ? NULL : (static_cast<inner_node*>(left))->childid[left->slotuse - 1];
3112 5545 : myleftparent = leftparent;
3113 : }
3114 : else {
3115 27604 : myleft = inner->childid[slot - 1];
3116 27604 : myleftparent = inner;
3117 : }
3118 :
3119 33149 : if (slot == inner->slotuse) {
3120 14150 : myright = (right == NULL) ? NULL : (static_cast<inner_node*>(right))->childid[0];
3121 14150 : myrightparent = rightparent;
3122 : }
3123 : else {
3124 18999 : myright = inner->childid[slot + 1];
3125 18999 : myrightparent = inner;
3126 : }
3127 :
3128 : BTREE_PRINT("erase_iter_descend into " << inner->childid[slot]);
3129 :
3130 33149 : result = erase_iter_descend(iter,
3131 : inner->childid[slot],
3132 : myleft, myright,
3133 : myleftparent, myrightparent,
3134 : inner, slot);
3135 :
3136 33149 : if (!result.has(btree_not_found))
3137 33149 : break;
3138 :
3139 : // continue recursive search for leaf on next slot
3140 :
3141 0 : if (slot < inner->slotuse && key_less(inner->slotkey[slot],iter.key()))
3142 0 : return btree_not_found;
3143 :
3144 0 : ++slot;
3145 : }
3146 :
3147 33149 : if (slot > inner->slotuse)
3148 0 : return btree_not_found;
3149 :
3150 33149 : result_t myres = btree_ok;
3151 :
3152 33149 : if (result.has(btree_update_lastkey))
3153 : {
3154 375 : if (parent && parentslot < parent->slotuse)
3155 : {
3156 : BTREE_PRINT("Fixing lastkeyupdate: key " << result.lastkey << " into parent " << parent << " at parentslot " << parentslot);
3157 :
3158 217 : BTREE_ASSERT(parent->childid[parentslot] == curr);
3159 217 : parent->slotkey[parentslot] = result.lastkey;
3160 : }
3161 : else
3162 : {
3163 : BTREE_PRINT("Forwarding lastkeyupdate: key " << result.lastkey);
3164 158 : myres |= result_t(btree_update_lastkey, result.lastkey);
3165 : }
3166 : }
3167 :
3168 33149 : if (result.has(btree_fixmerge))
3169 : {
3170 : // either the current node or the next is empty and should be removed
3171 2473 : if (inner->childid[slot]->slotuse != 0)
3172 1159 : slot++;
3173 :
3174 : // this is the child slot invalidated by the merge
3175 2473 : BTREE_ASSERT(inner->childid[slot]->slotuse == 0);
3176 :
3177 2473 : free_node(inner->childid[slot]);
3178 :
3179 2473 : std::copy(inner->slotkey + slot, inner->slotkey + inner->slotuse,
3180 : inner->slotkey + slot-1);
3181 2473 : std::copy(inner->childid + slot+1, inner->childid + inner->slotuse+1,
3182 : inner->childid + slot);
3183 :
3184 2473 : inner->slotuse--;
3185 :
3186 2473 : if (inner->level == 1)
3187 : {
3188 : // fix split key for children leaves
3189 2015 : slot--;
3190 2015 : leaf_node *child = static_cast<leaf_node*>(inner->childid[slot]);
3191 2015 : inner->slotkey[slot] = child->slotkey[ child->slotuse-1 ];
3192 : }
3193 : }
3194 :
3195 33149 : if (inner->isunderflow() && !(inner == m_root && inner->slotuse >= 1))
3196 : {
3197 : // case: the inner node is the root and has just one
3198 : // child. that child becomes the new root
3199 463 : if (leftinner == NULL && rightinner == NULL)
3200 : {
3201 5 : BTREE_ASSERT(inner == m_root);
3202 5 : BTREE_ASSERT(inner->slotuse == 0);
3203 :
3204 5 : m_root = inner->childid[0];
3205 :
3206 5 : inner->slotuse = 0;
3207 5 : free_node(inner);
3208 :
3209 5 : return btree_ok;
3210 : }
3211 : // case : if both left and right leaves would underflow in case of
3212 : // a shift, then merging is necessary. choose the more local merger
3213 : // with our parent
3214 458 : else if ( (leftinner == NULL || leftinner->isfew()) && (rightinner == NULL || rightinner->isfew()) )
3215 : {
3216 458 : if (leftparent == parent)
3217 322 : myres |= merge_inner(leftinner, inner, leftparent, parentslot - 1);
3218 : else
3219 136 : myres |= merge_inner(inner, rightinner, rightparent, parentslot);
3220 : }
3221 : // case : the right leaf has extra data, so balance right with current
3222 0 : else if ( (leftinner != NULL && leftinner->isfew()) && (rightinner != NULL && !rightinner->isfew()) )
3223 : {
3224 0 : if (rightparent == parent)
3225 0 : shift_left_inner(inner, rightinner, rightparent, parentslot);
3226 : else
3227 0 : myres |= merge_inner(leftinner, inner, leftparent, parentslot - 1);
3228 : }
3229 : // case : the left leaf has extra data, so balance left with current
3230 0 : else if ( (leftinner != NULL && !leftinner->isfew()) && (rightinner != NULL && rightinner->isfew()) )
3231 : {
3232 0 : if (leftparent == parent)
3233 0 : shift_right_inner(leftinner, inner, leftparent, parentslot - 1);
3234 : else
3235 0 : myres |= merge_inner(inner, rightinner, rightparent, parentslot);
3236 : }
3237 : // case : both the leaf and right leaves have extra data and our
3238 : // parent, choose the leaf with more data
3239 0 : else if (leftparent == rightparent)
3240 : {
3241 0 : if (leftinner->slotuse <= rightinner->slotuse)
3242 0 : shift_left_inner(inner, rightinner, rightparent, parentslot);
3243 : else
3244 0 : shift_right_inner(leftinner, inner, leftparent, parentslot - 1);
3245 : }
3246 : else
3247 : {
3248 0 : if (leftparent == parent)
3249 0 : shift_right_inner(leftinner, inner, leftparent, parentslot - 1);
3250 : else
3251 0 : shift_left_inner(inner, rightinner, rightparent, parentslot);
3252 : }
3253 : }
3254 :
3255 33144 : return myres;
3256 : }
3257 : }
3258 :
3259 : /// Merge two leaf nodes. The function moves all key/data pairs from right
3260 : /// to left and sets right's slotuse to zero. The right slot is then
3261 : /// removed by the calling parent node.
3262 42321 : result_t merge_leaves(leaf_node* left, leaf_node* right, inner_node* parent)
3263 : {
3264 : BTREE_PRINT("Merge leaf nodes " << left << " and " << right << " with common parent " << parent << ".");
3265 : (void)parent;
3266 :
3267 42321 : BTREE_ASSERT(left->isleafnode() && right->isleafnode());
3268 42321 : BTREE_ASSERT(parent->level == 1);
3269 :
3270 42321 : BTREE_ASSERT(left->slotuse + right->slotuse < leafslotmax);
3271 :
3272 42321 : std::copy(right->slotkey, right->slotkey + right->slotuse,
3273 : left->slotkey + left->slotuse);
3274 42321 : data_copy(right->slotdata, right->slotdata + right->slotuse,
3275 : left->slotdata + left->slotuse);
3276 :
3277 42321 : left->slotuse += right->slotuse;
3278 :
3279 42321 : left->nextleaf = right->nextleaf;
3280 42321 : if (left->nextleaf)
3281 41599 : left->nextleaf->prevleaf = left;
3282 : else
3283 722 : m_tailleaf = left;
3284 :
3285 42321 : right->slotuse = 0;
3286 :
3287 42321 : return btree_fixmerge;
3288 : }
3289 :
3290 : /// Merge two inner nodes. The function moves all key/childid pairs from
3291 : /// right to left and sets right's slotuse to zero. The right slot is then
3292 : /// removed by the calling parent node.
3293 5913 : static result_t merge_inner(inner_node* left, inner_node* right, inner_node* parent, unsigned int parentslot)
3294 : {
3295 : BTREE_PRINT("Merge inner nodes " << left << " and " << right << " with common parent " << parent << ".");
3296 :
3297 5913 : BTREE_ASSERT(left->level == right->level);
3298 5913 : BTREE_ASSERT(parent->level == left->level + 1);
3299 :
3300 5913 : BTREE_ASSERT(parent->childid[parentslot] == left);
3301 :
3302 5913 : BTREE_ASSERT(left->slotuse + right->slotuse < innerslotmax);
3303 :
3304 : if (selfverify)
3305 : {
3306 : // find the left node's slot in the parent's children
3307 5913 : unsigned int leftslot = 0;
3308 23696 : while(leftslot <= parent->slotuse && parent->childid[leftslot] != left)
3309 11870 : ++leftslot;
3310 :
3311 5913 : BTREE_ASSERT(leftslot < parent->slotuse);
3312 5913 : BTREE_ASSERT(parent->childid[leftslot] == left);
3313 5913 : BTREE_ASSERT(parent->childid[leftslot+1] == right);
3314 :
3315 5913 : BTREE_ASSERT(parentslot == leftslot);
3316 : }
3317 :
3318 : // retrieve the decision key from parent
3319 5913 : left->slotkey[left->slotuse] = parent->slotkey[parentslot];
3320 5913 : left->slotuse++;
3321 :
3322 : // copy over keys and children from right
3323 5913 : std::copy(right->slotkey, right->slotkey + right->slotuse,
3324 : left->slotkey + left->slotuse);
3325 5913 : std::copy(right->childid, right->childid + right->slotuse+1,
3326 : left->childid + left->slotuse);
3327 :
3328 5913 : left->slotuse += right->slotuse;
3329 5913 : right->slotuse = 0;
3330 :
3331 5913 : return btree_fixmerge;
3332 : }
3333 :
3334 : /// Balance two leaf nodes. The function moves key/data pairs from right to
3335 : /// left so that both nodes are equally filled. The parent node is updated
3336 : /// if possible.
3337 32142 : static result_t shift_left_leaf(leaf_node *left, leaf_node *right, inner_node *parent, unsigned int parentslot)
3338 : {
3339 32142 : BTREE_ASSERT(left->isleafnode() && right->isleafnode());
3340 32142 : BTREE_ASSERT(parent->level == 1);
3341 :
3342 32142 : BTREE_ASSERT(left->nextleaf == right);
3343 32142 : BTREE_ASSERT(left == right->prevleaf);
3344 :
3345 32142 : BTREE_ASSERT(left->slotuse < right->slotuse);
3346 32142 : BTREE_ASSERT(parent->childid[parentslot] == left);
3347 :
3348 32142 : unsigned int shiftnum = (right->slotuse - left->slotuse) >> 1;
3349 :
3350 : BTREE_PRINT("Shifting (leaf) " << shiftnum << " entries to left " << left << " from right " << right << " with common parent " << parent << ".");
3351 :
3352 32142 : BTREE_ASSERT(left->slotuse + shiftnum < leafslotmax);
3353 :
3354 : // copy the first items from the right node to the last slot in the left node.
3355 :
3356 32142 : std::copy(right->slotkey, right->slotkey + shiftnum,
3357 : left->slotkey + left->slotuse);
3358 32142 : data_copy(right->slotdata, right->slotdata + shiftnum,
3359 : left->slotdata + left->slotuse);
3360 :
3361 32142 : left->slotuse += shiftnum;
3362 :
3363 : // shift all slots in the right node to the left
3364 :
3365 32142 : std::copy(right->slotkey + shiftnum, right->slotkey + right->slotuse,
3366 : right->slotkey);
3367 32142 : data_copy(right->slotdata + shiftnum, right->slotdata + right->slotuse,
3368 : right->slotdata);
3369 :
3370 32142 : right->slotuse -= shiftnum;
3371 :
3372 : // fixup parent
3373 32142 : if (parentslot < parent->slotuse) {
3374 32142 : parent->slotkey[parentslot] = left->slotkey[left->slotuse - 1];
3375 32142 : return btree_ok;
3376 : }
3377 : else { // the update is further up the tree
3378 0 : return result_t(btree_update_lastkey, left->slotkey[left->slotuse - 1]);
3379 : }
3380 : }
3381 :
3382 : /// Balance two inner nodes. The function moves key/data pairs from right
3383 : /// to left so that both nodes are equally filled. The parent node is
3384 : /// updated if possible.
3385 4334 : static void shift_left_inner(inner_node *left, inner_node *right, inner_node *parent, unsigned int parentslot)
3386 : {
3387 4334 : BTREE_ASSERT(left->level == right->level);
3388 4334 : BTREE_ASSERT(parent->level == left->level + 1);
3389 :
3390 4334 : BTREE_ASSERT(left->slotuse < right->slotuse);
3391 4334 : BTREE_ASSERT(parent->childid[parentslot] == left);
3392 :
3393 4334 : unsigned int shiftnum = (right->slotuse - left->slotuse) >> 1;
3394 :
3395 : BTREE_PRINT("Shifting (inner) " << shiftnum << " entries to left " << left << " from right " << right << " with common parent " << parent << ".");
3396 :
3397 4334 : BTREE_ASSERT(left->slotuse + shiftnum < innerslotmax);
3398 :
3399 : if (selfverify)
3400 : {
3401 : // find the left node's slot in the parent's children and compare to parentslot
3402 :
3403 4334 : unsigned int leftslot = 0;
3404 21461 : while(leftslot <= parent->slotuse && parent->childid[leftslot] != left)
3405 12793 : ++leftslot;
3406 :
3407 4334 : BTREE_ASSERT(leftslot < parent->slotuse);
3408 4334 : BTREE_ASSERT(parent->childid[leftslot] == left);
3409 4334 : BTREE_ASSERT(parent->childid[leftslot+1] == right);
3410 :
3411 4334 : BTREE_ASSERT(leftslot == parentslot);
3412 : }
3413 :
3414 : // copy the parent's decision slotkey and childid to the first new key on the left
3415 4334 : left->slotkey[left->slotuse] = parent->slotkey[parentslot];
3416 4334 : left->slotuse++;
3417 :
3418 : // copy the other items from the right node to the last slots in the left node.
3419 :
3420 4334 : std::copy(right->slotkey, right->slotkey + shiftnum-1,
3421 : left->slotkey + left->slotuse);
3422 4334 : std::copy(right->childid, right->childid + shiftnum,
3423 : left->childid + left->slotuse);
3424 :
3425 4334 : left->slotuse += shiftnum - 1;
3426 :
3427 : // fixup parent
3428 4334 : parent->slotkey[parentslot] = right->slotkey[shiftnum - 1];
3429 :
3430 : // shift all slots in the right node
3431 :
3432 4334 : std::copy(right->slotkey + shiftnum, right->slotkey + right->slotuse,
3433 : right->slotkey);
3434 4334 : std::copy(right->childid + shiftnum, right->childid + right->slotuse+1,
3435 : right->childid);
3436 :
3437 4334 : right->slotuse -= shiftnum;
3438 4334 : }
3439 :
3440 : /// Balance two leaf nodes. The function moves key/data pairs from left to
3441 : /// right so that both nodes are equally filled. The parent node is updated
3442 : /// if possible.
3443 33500 : static void shift_right_leaf(leaf_node *left, leaf_node *right, inner_node *parent, unsigned int parentslot)
3444 : {
3445 33500 : BTREE_ASSERT(left->isleafnode() && right->isleafnode());
3446 33500 : BTREE_ASSERT(parent->level == 1);
3447 :
3448 33500 : BTREE_ASSERT(left->nextleaf == right);
3449 33500 : BTREE_ASSERT(left == right->prevleaf);
3450 33500 : BTREE_ASSERT(parent->childid[parentslot] == left);
3451 :
3452 33500 : BTREE_ASSERT(left->slotuse > right->slotuse);
3453 :
3454 33500 : unsigned int shiftnum = (left->slotuse - right->slotuse) >> 1;
3455 :
3456 : BTREE_PRINT("Shifting (leaf) " << shiftnum << " entries to right " << right << " from left " << left << " with common parent " << parent << ".");
3457 :
3458 : if (selfverify)
3459 : {
3460 : // find the left node's slot in the parent's children
3461 33500 : unsigned int leftslot = 0;
3462 235663 : while(leftslot <= parent->slotuse && parent->childid[leftslot] != left)
3463 168663 : ++leftslot;
3464 :
3465 33500 : BTREE_ASSERT(leftslot < parent->slotuse);
3466 33500 : BTREE_ASSERT(parent->childid[leftslot] == left);
3467 33500 : BTREE_ASSERT(parent->childid[leftslot+1] == right);
3468 :
3469 33500 : BTREE_ASSERT(leftslot == parentslot);
3470 : }
3471 :
3472 : // shift all slots in the right node
3473 :
3474 33500 : BTREE_ASSERT(right->slotuse + shiftnum < leafslotmax);
3475 :
3476 33500 : std::copy_backward(right->slotkey, right->slotkey + right->slotuse,
3477 : right->slotkey + right->slotuse + shiftnum);
3478 33500 : data_copy_backward(right->slotdata, right->slotdata + right->slotuse,
3479 : right->slotdata + right->slotuse + shiftnum);
3480 :
3481 33500 : right->slotuse += shiftnum;
3482 :
3483 : // copy the last items from the left node to the first slot in the right node.
3484 33500 : std::copy(left->slotkey + left->slotuse - shiftnum, left->slotkey + left->slotuse,
3485 : right->slotkey);
3486 33500 : data_copy(left->slotdata + left->slotuse - shiftnum, left->slotdata + left->slotuse,
3487 : right->slotdata);
3488 :
3489 33500 : left->slotuse -= shiftnum;
3490 :
3491 33500 : parent->slotkey[parentslot] = left->slotkey[left->slotuse-1];
3492 33500 : }
3493 :
3494 : /// Balance two inner nodes. The function moves key/data pairs from left to
3495 : /// right so that both nodes are equally filled. The parent node is updated
3496 : /// if possible.
3497 4679 : static void shift_right_inner(inner_node *left, inner_node *right, inner_node *parent, unsigned int parentslot)
3498 : {
3499 4679 : BTREE_ASSERT(left->level == right->level);
3500 4679 : BTREE_ASSERT(parent->level == left->level + 1);
3501 :
3502 4679 : BTREE_ASSERT(left->slotuse > right->slotuse);
3503 4679 : BTREE_ASSERT(parent->childid[parentslot] == left);
3504 :
3505 4679 : unsigned int shiftnum = (left->slotuse - right->slotuse) >> 1;
3506 :
3507 : BTREE_PRINT("Shifting (leaf) " << shiftnum << " entries to right " << right << " from left " << left << " with common parent " << parent << ".");
3508 :
3509 : if (selfverify)
3510 : {
3511 : // find the left node's slot in the parent's children
3512 4679 : unsigned int leftslot = 0;
3513 21193 : while(leftslot <= parent->slotuse && parent->childid[leftslot] != left)
3514 11835 : ++leftslot;
3515 :
3516 4679 : BTREE_ASSERT(leftslot < parent->slotuse);
3517 4679 : BTREE_ASSERT(parent->childid[leftslot] == left);
3518 4679 : BTREE_ASSERT(parent->childid[leftslot+1] == right);
3519 :
3520 4679 : BTREE_ASSERT(leftslot == parentslot);
3521 : }
3522 :
3523 : // shift all slots in the right node
3524 :
3525 4679 : BTREE_ASSERT(right->slotuse + shiftnum < innerslotmax);
3526 :
3527 4679 : std::copy_backward(right->slotkey, right->slotkey + right->slotuse,
3528 : right->slotkey + right->slotuse + shiftnum);
3529 4679 : std::copy_backward(right->childid, right->childid + right->slotuse+1,
3530 : right->childid + right->slotuse+1 + shiftnum);
3531 :
3532 4679 : right->slotuse += shiftnum;
3533 :
3534 : // copy the parent's decision slotkey and childid to the last new key on the right
3535 4679 : right->slotkey[shiftnum - 1] = parent->slotkey[parentslot];
3536 :
3537 : // copy the remaining last items from the left node to the first slot in the right node.
3538 4679 : std::copy(left->slotkey + left->slotuse - shiftnum+1, left->slotkey + left->slotuse,
3539 : right->slotkey);
3540 4679 : std::copy(left->childid + left->slotuse - shiftnum+1, left->childid + left->slotuse+1,
3541 : right->childid);
3542 :
3543 : // copy the first to-be-removed key from the left node to the parent's decision slot
3544 4679 : parent->slotkey[parentslot] = left->slotkey[left->slotuse - shiftnum];
3545 :
3546 4679 : left->slotuse -= shiftnum;
3547 4679 : }
3548 :
3549 : #ifdef BTREE_DEBUG
3550 : public:
3551 : // *** Debug Printing
3552 :
3553 : /// Print out the B+ tree structure with keys onto the given ostream. This
3554 : /// function requires that the header is compiled with BTREE_DEBUG and that
3555 : /// key_type is printable via std::ostream.
3556 0 : void print(std::ostream &os) const
3557 : {
3558 0 : if (m_root) {
3559 0 : print_node(os, m_root, 0, true);
3560 : }
3561 0 : }
3562 :
3563 : /// Print out only the leaves via the double linked list.
3564 0 : void print_leaves(std::ostream &os) const
3565 : {
3566 0 : os << "leaves:" << std::endl;
3567 :
3568 0 : const leaf_node *n = m_headleaf;
3569 :
3570 0 : while(n)
3571 : {
3572 0 : os << " " << n << std::endl;
3573 :
3574 0 : n = n->nextleaf;
3575 : }
3576 0 : }
3577 :
3578 : private:
3579 :
3580 : /// Recursively descend down the tree and print out nodes.
3581 0 : static void print_node(std::ostream &os, const node* node, unsigned int depth=0, bool recursive=false)
3582 : {
3583 0 : for(unsigned int i = 0; i < depth; i++) os << " ";
3584 :
3585 0 : os << "node " << node << " level " << node->level << " slotuse " << node->slotuse << std::endl;
3586 :
3587 0 : if (node->isleafnode())
3588 : {
3589 0 : const leaf_node *leafnode = static_cast<const leaf_node*>(node);
3590 :
3591 0 : for(unsigned int i = 0; i < depth; i++) os << " ";
3592 0 : os << " leaf prev " << leafnode->prevleaf << " next " << leafnode->nextleaf << std::endl;
3593 :
3594 0 : for(unsigned int i = 0; i < depth; i++) os << " ";
3595 :
3596 0 : for (unsigned int slot = 0; slot < leafnode->slotuse; ++slot)
3597 : {
3598 0 : os << leafnode->slotkey[slot] << " "; // << "(data: " << leafnode->slotdata[slot] << ") ";
3599 : }
3600 0 : os << std::endl;
3601 : }
3602 : else
3603 : {
3604 0 : const inner_node *innernode = static_cast<const inner_node*>(node);
3605 :
3606 0 : for(unsigned int i = 0; i < depth; i++) os << " ";
3607 :
3608 0 : for (unsigned short slot = 0; slot < innernode->slotuse; ++slot)
3609 : {
3610 0 : os << "(" << innernode->childid[slot] << ") " << innernode->slotkey[slot] << " ";
3611 : }
3612 0 : os << "(" << innernode->childid[innernode->slotuse] << ")" << std::endl;
3613 :
3614 0 : if (recursive)
3615 : {
3616 0 : for (unsigned short slot = 0; slot < innernode->slotuse + 1; ++slot)
3617 : {
3618 0 : print_node(os, innernode->childid[slot], depth + 1, recursive);
3619 : }
3620 : }
3621 : }
3622 0 : }
3623 : #endif
3624 :
3625 : public:
3626 : // *** Verification of B+ Tree Invariants
3627 :
3628 : /// Run a thorough verification of all B+ tree invariants. The program
3629 : /// aborts via assert() if something is wrong.
3630 1123501 : void verify() const
3631 : {
3632 45598 : key_type minkey, maxkey;
3633 1123501 : tree_stats vstats;
3634 :
3635 1123501 : if (m_root)
3636 : {
3637 1123245 : verify_node(m_root, &minkey, &maxkey, vstats);
3638 :
3639 1123245 : assert( vstats.itemcount == m_stats.itemcount );
3640 1123245 : assert( vstats.leaves == m_stats.leaves );
3641 1123245 : assert( vstats.innernodes == m_stats.innernodes );
3642 :
3643 1123245 : verify_leaflinks();
3644 : }
3645 1123501 : }
3646 :
3647 : private:
3648 :
3649 : /// Recursively descend down the tree and verify each node
3650 606658588 : void verify_node(const node* n, key_type* minkey, key_type* maxkey, tree_stats &vstats) const
3651 : {
3652 : BTREE_PRINT("verifynode " << n);
3653 :
3654 606658588 : if (n->isleafnode())
3655 : {
3656 513960120 : const leaf_node *leaf = static_cast<const leaf_node*>(n);
3657 :
3658 513960120 : assert( leaf == m_root || !leaf->isunderflow() );
3659 513960120 : assert( leaf->slotuse > 0 );
3660 :
3661 3278584994 : for(unsigned short slot = 0; slot < leaf->slotuse - 1; ++slot)
3662 : {
3663 2764624874 : assert(key_lessequal(leaf->slotkey[slot], leaf->slotkey[slot + 1]));
3664 : }
3665 :
3666 513960120 : *minkey = leaf->slotkey[0];
3667 513960120 : *maxkey = leaf->slotkey[leaf->slotuse - 1];
3668 :
3669 513960120 : vstats.leaves++;
3670 513960120 : vstats.itemcount += leaf->slotuse;
3671 : }
3672 : else // !n->isleafnode()
3673 : {
3674 92698468 : const inner_node *inner = static_cast<const inner_node*>(n);
3675 92698468 : vstats.innernodes++;
3676 :
3677 92698468 : assert( inner == m_root || !inner->isunderflow() );
3678 92698468 : assert( inner->slotuse > 0 );
3679 :
3680 512836875 : for(unsigned short slot = 0; slot < inner->slotuse - 1; ++slot)
3681 : {
3682 420138407 : assert(key_lessequal(inner->slotkey[slot], inner->slotkey[slot + 1]));
3683 : }
3684 :
3685 698233811 : for(unsigned short slot = 0; slot <= inner->slotuse; ++slot)
3686 : {
3687 605535343 : const node *subnode = inner->childid[slot];
3688 605535343 : key_type subminkey = key_type();
3689 605535343 : key_type submaxkey = key_type();
3690 :
3691 605535343 : assert(subnode->level + 1 == inner->level);
3692 605535343 : verify_node(subnode, &subminkey, &submaxkey, vstats);
3693 :
3694 : BTREE_PRINT("verify subnode " << subnode << ": " << subminkey << " - " << submaxkey);
3695 :
3696 605535343 : if (slot == 0)
3697 92698468 : *minkey = subminkey;
3698 : else
3699 512836875 : assert(key_greaterequal(subminkey, inner->slotkey[slot-1]));
3700 :
3701 605535343 : if (slot == inner->slotuse)
3702 92698468 : *maxkey = submaxkey;
3703 : else
3704 512836875 : assert(key_equal(inner->slotkey[slot], submaxkey));
3705 :
3706 605535343 : if (inner->level == 1 && slot < inner->slotuse)
3707 : {
3708 : // children are leaves and must be linked together in the
3709 : // correct order
3710 436083121 : const leaf_node *leafa = static_cast<const leaf_node*>(inner->childid[slot]);
3711 436083121 : const leaf_node *leafb = static_cast<const leaf_node*>(inner->childid[slot + 1]);
3712 :
3713 436083121 : assert(leafa->nextleaf == leafb);
3714 436083121 : assert(leafa == leafb->prevleaf);
3715 : (void)leafa; (void)leafb;
3716 : }
3717 605535343 : if (inner->level == 2 && slot < inner->slotuse)
3718 : {
3719 : // verify leaf links between the adjacent inner nodes
3720 65234215 : const inner_node *parenta = static_cast<const inner_node*>(inner->childid[slot]);
3721 65234215 : const inner_node *parentb = static_cast<const inner_node*>(inner->childid[slot+1]);
3722 :
3723 65234215 : const leaf_node *leafa = static_cast<const leaf_node*>(parenta->childid[parenta->slotuse]);
3724 65234215 : const leaf_node *leafb = static_cast<const leaf_node*>(parentb->childid[0]);
3725 :
3726 65234215 : assert(leafa->nextleaf == leafb);
3727 65234215 : assert(leafa == leafb->prevleaf);
3728 1697045 : (void)leafa; (void)leafb;
3729 : }
3730 : }
3731 : }
3732 606658588 : }
3733 :
3734 : /// Verify the double linked list of leaves.
3735 1123245 : void verify_leaflinks() const
3736 : {
3737 1123245 : const leaf_node *n = m_headleaf;
3738 :
3739 1123245 : assert(n->level == 0);
3740 1123245 : assert(!n || n->prevleaf == NULL);
3741 :
3742 1123245 : unsigned int testcount = 0;
3743 :
3744 516206610 : while(n)
3745 : {
3746 513960120 : assert(n->level == 0);
3747 513960120 : assert(n->slotuse > 0);
3748 :
3749 3278584994 : for(unsigned short slot = 0; slot < n->slotuse - 1; ++slot)
3750 : {
3751 2764624874 : assert(key_lessequal(n->slotkey[slot], n->slotkey[slot + 1]));
3752 : }
3753 :
3754 513960120 : testcount += n->slotuse;
3755 :
3756 513960120 : if (n->nextleaf)
3757 : {
3758 512836875 : assert(key_lessequal(n->slotkey[n->slotuse-1], n->nextleaf->slotkey[0]));
3759 :
3760 512836875 : assert(n == n->nextleaf->prevleaf);
3761 : }
3762 : else
3763 : {
3764 1123245 : assert(m_tailleaf == n);
3765 : }
3766 :
3767 513960120 : n = n->nextleaf;
3768 : }
3769 :
3770 1123245 : assert(testcount == size());
3771 1123245 : }
3772 :
3773 : private:
3774 : // *** Dump and Restore of B+ Trees
3775 :
3776 : /// A header for the binary image containing the base properties of the B+
3777 : /// tree. These properties have to match the current template
3778 : /// instantiation.
3779 : struct dump_header
3780 : {
3781 : /// "stx-btree", just to stop the restore() function from loading garbage
3782 : char signature[12];
3783 :
3784 : /// Currently 0
3785 : unsigned short version;
3786 :
3787 : /// sizeof(key_type)
3788 : unsigned short key_type_size;
3789 :
3790 : /// sizeof(data_type)
3791 : unsigned short data_type_size;
3792 :
3793 : /// Number of slots in the leaves
3794 : unsigned short leafslots;
3795 :
3796 : /// Number of slots in the inner nodes
3797 : unsigned short innerslots;
3798 :
3799 : /// Allow duplicates
3800 : bool allow_duplicates;
3801 :
3802 : /// The item count of the tree
3803 : size_type itemcount;
3804 :
3805 : /// Fill the struct with the current B+ tree's properties, itemcount is
3806 : /// not filled.
3807 3 : inline void fill()
3808 : {
3809 : // don't want to include string.h just for this signature
3810 3 : signature[0] = 's'; signature[1] = 't'; signature[2] = 'x'; signature[3] = '-';
3811 3 : signature[4] = 'b'; signature[5] = 't'; signature[6] = 'r'; signature[7] = 'e';
3812 3 : signature[8] = 'e'; signature[9] = 0; signature[10] = 0; signature[11] = 0;
3813 :
3814 3 : version = 0;
3815 3 : key_type_size = sizeof(typename btree_self::key_type);
3816 3 : data_type_size = sizeof(typename btree_self::data_type);
3817 3 : leafslots = btree_self::leafslotmax;
3818 3 : innerslots = btree_self::innerslotmax;
3819 3 : allow_duplicates = btree_self::allow_duplicates;
3820 3 : }
3821 :
3822 : /// Returns true if the headers have the same vital properties
3823 2 : inline bool same(const struct dump_header &o) const
3824 : {
3825 : return (signature[0] == 's' && signature[1] == 't' && signature[2] == 'x' && signature[3] == '-' &&
3826 : signature[4] == 'b' && signature[5] == 't' && signature[6] == 'r' && signature[7] == 'e' &&
3827 : signature[8] == 'e' && signature[9] == 0 && signature[10] == 0 && signature[11] == 0)
3828 : && (version == o.version)
3829 : && (key_type_size == o.key_type_size)
3830 : && (data_type_size == o.data_type_size)
3831 : && (leafslots == o.leafslots)
3832 : && (innerslots == o.innerslots)
3833 2 : && (allow_duplicates == o.allow_duplicates);
3834 : }
3835 : };
3836 :
3837 : public:
3838 :
3839 : /// Dump the contents of the B+ tree out onto an ostream as a binary
3840 : /// image. The image contains memory pointers which will be fixed when the
3841 : /// image is restored. For this to work your key_type and data_type must be
3842 : /// integral types and contain no pointers or references.
3843 1 : void dump(std::ostream &os) const
3844 : {
3845 : struct dump_header header;
3846 1 : header.fill();
3847 1 : header.itemcount = size();
3848 :
3849 1 : os.write(reinterpret_cast<char*>(&header), sizeof(header));
3850 :
3851 1 : if (m_root) {
3852 1 : dump_node(os, m_root);
3853 : }
3854 1 : }
3855 :
3856 : /// Restore a binary image of a dumped B+ tree from an istream. The B+ tree
3857 : /// pointers are fixed using the dump order. For dump and restore to work
3858 : /// your key_type and data_type must be integral types and contain no
3859 : /// pointers or references. Returns true if the restore was successful.
3860 2 : bool restore(std::istream &is)
3861 : {
3862 : struct dump_header fileheader;
3863 2 : is.read(reinterpret_cast<char*>(&fileheader), sizeof(fileheader));
3864 2 : if (!is.good()) return false;
3865 :
3866 : struct dump_header myheader;
3867 2 : myheader.fill();
3868 2 : myheader.itemcount = fileheader.itemcount;
3869 :
3870 2 : if (!myheader.same(fileheader))
3871 : {
3872 : BTREE_PRINT("btree::restore: file header does not match instantiation signature.");
3873 1 : return false;
3874 : }
3875 :
3876 1 : clear();
3877 :
3878 1 : if (fileheader.itemcount > 0)
3879 : {
3880 1 : m_root = restore_node(is);
3881 1 : if (m_root == NULL) return false;
3882 :
3883 1 : m_stats.itemcount = fileheader.itemcount;
3884 : }
3885 :
3886 : #ifdef BTREE_DEBUG
3887 : if (debug) print(std::cout);
3888 : #endif
3889 1 : if (selfverify) verify();
3890 :
3891 1 : return true;
3892 : }
3893 :
3894 : private:
3895 :
3896 : /// Recursively descend down the tree and dump each node in a precise order
3897 867 : void dump_node(std::ostream &os, const node* n) const
3898 : {
3899 : BTREE_PRINT("dump_node " << n << std::endl);
3900 :
3901 867 : if (n->isleafnode())
3902 : {
3903 734 : const leaf_node *leaf = static_cast<const leaf_node*>(n);
3904 :
3905 734 : os.write(reinterpret_cast<const char*>(leaf), sizeof(*leaf));
3906 : }
3907 : else // !n->isleafnode()
3908 : {
3909 133 : const inner_node *inner = static_cast<const inner_node*>(n);
3910 :
3911 133 : os.write(reinterpret_cast<const char*>(inner), sizeof(*inner));
3912 :
3913 999 : for(unsigned short slot = 0; slot <= inner->slotuse; ++slot)
3914 : {
3915 866 : const node *subnode = inner->childid[slot];
3916 :
3917 866 : dump_node(os, subnode);
3918 : }
3919 : }
3920 867 : }
3921 :
3922 : /// Read the dump image and construct a tree from the node order in the
3923 : /// serialization.
3924 867 : node* restore_node(std::istream &is)
3925 : {
3926 : union {
3927 : node top;
3928 : leaf_node leaf;
3929 : inner_node inner;
3930 : } nu;
3931 :
3932 : // first read only the top of the node
3933 867 : is.read(reinterpret_cast<char*>(&nu.top), sizeof(nu.top));
3934 867 : if (!is.good()) return NULL;
3935 :
3936 867 : if (nu.top.isleafnode())
3937 : {
3938 : // read remaining data of leaf node
3939 734 : is.read(reinterpret_cast<char*>(&nu.leaf) + sizeof(nu.top), sizeof(nu.leaf) - sizeof(nu.top));
3940 734 : if (!is.good()) return NULL;
3941 :
3942 734 : leaf_node *newleaf = allocate_leaf();
3943 :
3944 : // copy over all data, the leaf nodes contain only their double linked list pointers
3945 734 : *newleaf = nu.leaf;
3946 :
3947 : // reconstruct the linked list from the order in the file
3948 734 : if (m_headleaf == NULL) {
3949 1 : BTREE_ASSERT(newleaf->prevleaf == NULL);
3950 1 : m_headleaf = m_tailleaf = newleaf;
3951 : }
3952 : else {
3953 733 : newleaf->prevleaf = m_tailleaf;
3954 733 : m_tailleaf->nextleaf = newleaf;
3955 733 : m_tailleaf = newleaf;
3956 : }
3957 :
3958 734 : return newleaf;
3959 : }
3960 : else
3961 : {
3962 : // read remaining data of inner node
3963 133 : is.read(reinterpret_cast<char*>(&nu.inner) + sizeof(nu.top), sizeof(nu.inner) - sizeof(nu.top));
3964 133 : if (!is.good()) return NULL;
3965 :
3966 133 : inner_node *newinner = allocate_inner(0);
3967 :
3968 : // copy over all data, the inner nodes contain only pointers to their children
3969 133 : *newinner = nu.inner;
3970 :
3971 999 : for(unsigned short slot = 0; slot <= newinner->slotuse; ++slot)
3972 : {
3973 866 : newinner->childid[slot] = restore_node(is);
3974 : }
3975 :
3976 133 : return newinner;
3977 : }
3978 : }
3979 : };
3980 :
3981 : } // namespace stx
3982 :
3983 : #endif // _STX_BTREE_H_
|