added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / bptree.hpp
1 /*************************************************************************
2  *
3  * Copyright 2016 Realm Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  **************************************************************************/
18
19 #ifndef REALM_BPTREE_HPP
20 #define REALM_BPTREE_HPP
21
22 #include <memory> // std::unique_ptr
23 #include <realm/array.hpp>
24 #include <realm/array_basic.hpp>
25 #include <realm/column_type_traits.hpp>
26 #include <realm/impl/destroy_guard.hpp>
27 #include <realm/impl/output_stream.hpp>
28
29 namespace realm {
30
31 /// Specialize BpTree to implement column types.
32 template <class T>
33 class BpTree;
34
35 class ArrayInteger;
36 class ArrayIntNull;
37
38 class BpTreeNode : public Array {
39 public:
40     using Array::Array;
41     /// Get the number of elements in the B+-tree rooted at this array
42     /// node. The root must not be a leaf.
43     ///
44     /// Please avoid using this function (consider it deprecated). It
45     /// will have to be removed if we choose to get rid of the last
46     /// element of the main array of an inner B+-tree node that stores
47     /// the total number of elements in the subtree. The motivation
48     /// for removing it, is that it will significantly improve the
49     /// efficiency when inserting after, and erasing the last element.
50     size_t get_bptree_size() const noexcept;
51
52     /// The root must not be a leaf.
53     static size_t get_bptree_size_from_header(const char* root_header) noexcept;
54
55
56     /// Find the leaf node corresponding to the specified element
57     /// index index. The specified element index must refer to an
58     /// element that exists in the tree. This function must be called
59     /// on an inner B+-tree node, never a leaf. Note that according to
60     /// invar:bptree-nonempty-inner and invar:bptree-nonempty-leaf, an
61     /// inner B+-tree node can never be empty.
62     ///
63     /// This function is not obliged to instantiate intermediate array
64     /// accessors. For this reason, this function cannot be used for
65     /// operations that modify the tree, as that requires an unbroken
66     /// chain of parent array accessors between the root and the
67     /// leaf. Thus, despite the fact that the returned MemRef object
68     /// appears to allow modification of the referenced memory, the
69     /// caller must handle the memory reference as if it was
70     /// const-qualified.
71     ///
72     /// \return (`leaf_header`, `ndx_in_leaf`) where `leaf_header`
73     /// points to the the header of the located leaf, and
74     /// `ndx_in_leaf` is the local index within that leaf
75     /// corresponding to the specified element index.
76     std::pair<MemRef, size_t> get_bptree_leaf(size_t elem_ndx) const noexcept;
77
78
79     class NodeInfo;
80     class VisitHandler;
81
82     /// Visit leaves of the B+-tree rooted at this inner node,
83     /// starting with the leaf that contains the element at the
84     /// specified element index start offset, and ending when the
85     /// handler returns false. The specified element index offset must
86     /// refer to an element that exists in the tree. This function
87     /// must be called on an inner B+-tree node, never a leaf. Note
88     /// that according to invar:bptree-nonempty-inner and
89     /// invar:bptree-nonempty-leaf, an inner B+-tree node can never be
90     /// empty.
91     ///
92     /// \param elem_ndx_offset The start position (must be valid).
93     ///
94     /// \param elems_in_tree The total number of elements in the tree.
95     ///
96     /// \param handler The callback which will get called for each leaf.
97     ///
98     /// \return True if, and only if the handler has returned true for
99     /// all visited leafs.
100     bool visit_bptree_leaves(size_t elem_ndx_offset, size_t elems_in_tree, VisitHandler& handler);
101
102
103     class UpdateHandler;
104
105     /// Call the handler for every leaf. This function must be called
106     /// on an inner B+-tree node, never a leaf.
107     void update_bptree_leaves(UpdateHandler&);
108
109     /// Call the handler for the leaf that contains the element at the
110     /// specified index. This function must be called on an inner
111     /// B+-tree node, never a leaf.
112     void update_bptree_elem(size_t elem_ndx, UpdateHandler&);
113
114
115     class EraseHandler;
116
117     /// Erase the element at the specified index in the B+-tree with
118     /// the specified root. When erasing the last element, you must
119     /// pass npos in place of the index. This function must be called
120     /// with a root that is an inner B+-tree node, never a leaf.
121     ///
122     /// This function is guaranteed to succeed (not throw) if the
123     /// specified element was inserted during the current transaction,
124     /// and no other modifying operation has been carried out since
125     /// then (noexcept:bptree-erase-alt).
126     ///
127     /// FIXME: ExceptionSafety: The exception guarantee explained
128     /// above is not as powerfull as we would like it to be. Here is
129     /// what we would like: This function is guaranteed to succeed
130     /// (not throw) if the specified element was inserted during the
131     /// current transaction (noexcept:bptree-erase). This must be true
132     /// even if the element is modified after insertion, and/or if
133     /// other elements are inserted or erased around it. There are two
134     /// aspects of the current design that stand in the way of this
135     /// guarantee: (A) The fact that the node accessor, that is cached
136     /// in the column accessor, has to be reallocated/reinstantiated
137     /// when the root switches between being a leaf and an inner
138     /// node. This problem would go away if we always cached the last
139     /// used leaf accessor in the column accessor instead. (B) The
140     /// fact that replacing one child ref with another can fail,
141     /// because it may require reallocation of memory to expand the
142     /// bit-width. This can be fixed in two ways: Either have the
143     /// inner B+-tree nodes always have a bit-width of 64, or allow
144     /// the root node to be discarded and the column ref to be set to
145     /// zero in Table::m_columns.
146     static void erase_bptree_elem(BpTreeNode* root, size_t elem_ndx, EraseHandler&);
147
148     template <class TreeTraits>
149     struct TreeInsert : TreeInsertBase {
150         typename TreeTraits::value_type m_value;
151         bool m_nullable;
152     };
153
154     /// Same as bptree_insert() but insert after the last element.
155     template <class TreeTraits>
156     ref_type bptree_append(TreeInsert<TreeTraits>& state);
157
158     /// Insert an element into the B+-subtree rooted at this array
159     /// node. The element is inserted before the specified element
160     /// index. This function must be called on an inner B+-tree node,
161     /// never a leaf. If this inner node had to be split, this
162     /// function returns the `ref` of the new sibling.
163     template <class TreeTraits>
164     ref_type bptree_insert(size_t elem_ndx, TreeInsert<TreeTraits>& state);
165
166 protected:
167     /// Insert a new child after original. If the parent has to be
168     /// split, this function returns the `ref` of the new parent node.
169     ref_type insert_bptree_child(Array& offsets, size_t orig_child_ndx, ref_type new_sibling_ref,
170                                  TreeInsertBase& state);
171
172     void ensure_bptree_offsets(Array& offsets);
173     void create_bptree_offsets(Array& offsets, int_fast64_t first_value);
174
175     bool do_erase_bptree_elem(size_t elem_ndx, EraseHandler&);
176 };
177
178 class BpTreeBase {
179 public:
180     struct unattached_tag {
181     };
182
183     // Disable copying, this is not allowed.
184     BpTreeBase& operator=(const BpTreeBase&) = delete;
185     BpTreeBase(const BpTreeBase&) = delete;
186
187     // Accessor concept:
188     Allocator& get_alloc() const noexcept;
189     void destroy() noexcept;
190     void detach();
191     bool is_attached() const noexcept;
192     void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept;
193     size_t get_ndx_in_parent() const noexcept;
194     void set_ndx_in_parent(size_t ndx) noexcept;
195     void update_from_parent(size_t old_baseline) noexcept;
196     MemRef clone_deep(Allocator& alloc) const;
197
198     // BpTree interface:
199     const Array& root() const noexcept;
200     Array& root() noexcept;
201     bool root_is_leaf() const noexcept;
202     BpTreeNode& root_as_node();
203     const BpTreeNode& root_as_node() const;
204     void introduce_new_root(ref_type new_sibling_ref, TreeInsertBase& state, bool is_append);
205     void replace_root(std::unique_ptr<Array> leaf);
206
207 protected:
208     explicit BpTreeBase(std::unique_ptr<Array> root);
209     explicit BpTreeBase(BpTreeBase&&) = default;
210     BpTreeBase& operator=(BpTreeBase&&) = default;
211     std::unique_ptr<Array> m_root;
212
213     struct SliceHandler {
214         virtual MemRef slice_leaf(MemRef leaf_mem, size_t offset, size_t size, Allocator& target_alloc) = 0;
215         ~SliceHandler() noexcept
216         {
217         }
218     };
219     static ref_type write_subtree(const BpTreeNode& root, size_t slice_offset, size_t slice_size, size_t table_size,
220                                   SliceHandler&, _impl::OutputStream&);
221     friend class ColumnBase;
222     friend class ColumnBaseSimple;
223
224 private:
225     struct WriteSliceHandler;
226
227     // FIXME: Move B+Tree functionality from Array to this class.
228 };
229
230
231 // Default implementation of BpTree. This should work for all types that have monomorphic
232 // leaves (i.e. all leaves are of the same type).
233 template <class T>
234 class BpTree : public BpTreeBase {
235 public:
236     using value_type = T;
237     using LeafType = typename ColumnTypeTraits<T>::leaf_type;
238
239     /// LeafInfo is used by get_leaf() to provide access to a leaf
240     /// without instantiating unnecessary nodes along the way.
241     /// Upon return, out_leaf with hold a pointer to the leaf containing
242     /// the index given to get_leaf(). If the index happens to be
243     /// in the root node (i.e., the root is a leaf), it will point
244     /// to the root node.
245     /// If the index isn't in the root node, fallback will be initialized
246     /// to represent the leaf holding the node, and out_leaf will be set
247     /// to point to fallback.
248     struct LeafInfo {
249         const LeafType** out_leaf;
250         LeafType* fallback;
251     };
252
253     BpTree();
254     explicit BpTree(BpTreeBase::unattached_tag);
255     explicit BpTree(Allocator& alloc);
256     REALM_DEPRECATED("Initialize with MemRef instead")
257     explicit BpTree(std::unique_ptr<Array> init_root)
258         : BpTreeBase(std::move(init_root))
259     {
260     }
261     explicit BpTree(Allocator& alloc, MemRef mem)
262         : BpTreeBase(std::unique_ptr<Array>(new LeafType(alloc)))
263     {
264         init_from_mem(alloc, mem);
265     }
266     BpTree(BpTree&&) = default;
267     BpTree& operator=(BpTree&&) = default;
268
269     // Disable copying, this is not allowed.
270     BpTree& operator=(const BpTree&) = delete;
271     BpTree(const BpTree&) = delete;
272
273     void init_from_ref(Allocator& alloc, ref_type ref);
274     void init_from_mem(Allocator& alloc, MemRef mem);
275     void init_from_parent();
276
277     size_t size() const noexcept;
278     bool is_empty() const noexcept
279     {
280         return size() == 0;
281     }
282
283     T get(size_t ndx) const noexcept;
284     bool is_null(size_t ndx) const noexcept;
285     void set(size_t, T value);
286     void set_null(size_t);
287     void insert(size_t ndx, T value, size_t num_rows = 1);
288     void erase(size_t ndx, bool is_last = false);
289     void move_last_over(size_t ndx, size_t last_row_ndx);
290     void clear();
291     T front() const noexcept;
292     T back() const noexcept;
293
294     size_t find_first(T value, size_t begin = 0, size_t end = npos) const;
295     void find_all(IntegerColumn& out_indices, T value, size_t begin = 0, size_t end = npos) const;
296
297     static MemRef create_leaf(Array::Type leaf_type, size_t size, T value, Allocator&);
298
299     /// See LeafInfo for information about what to put in the inout_leaf
300     /// parameter.
301     ///
302     /// This function cannot be used for modifying operations as it
303     /// does not ensure the presence of an unbroken chain of parent
304     /// accessors. For this reason, the identified leaf should always
305     /// be accessed through the returned const-qualified reference,
306     /// and never directly through the specfied fallback accessor.
307     void get_leaf(size_t ndx, size_t& out_ndx_in_leaf, LeafInfo& inout_leaf) const noexcept;
308
309     void update_each(BpTreeNode::UpdateHandler&);
310     void update_elem(size_t, BpTreeNode::UpdateHandler&);
311
312     void adjust(size_t ndx, T diff);
313     void adjust(T diff);
314     void adjust_ge(T limit, T diff);
315
316     ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream& out) const;
317
318 #if defined(REALM_DEBUG)
319     void verify() const;
320     static size_t verify_leaf(MemRef mem, Allocator& alloc);
321 #endif
322     static void leaf_to_dot(MemRef mem, ArrayParent* parent, size_t ndx_in_parent, std::ostream& out,
323                             Allocator& alloc);
324
325 private:
326     LeafType& root_as_leaf();
327     const LeafType& root_as_leaf() const;
328
329     std::unique_ptr<Array> create_root_from_ref(Allocator& alloc, ref_type ref);
330     std::unique_ptr<Array> create_root_from_mem(Allocator& alloc, MemRef mem);
331
332     struct EraseHandler;
333     struct UpdateHandler;
334     struct SetNullHandler;
335     struct SliceHandler;
336     struct AdjustHandler;
337     struct AdjustGEHandler;
338
339     struct LeafValueInserter;
340     struct LeafNullInserter;
341
342     template <class TreeTraits>
343     void bptree_insert(size_t row_ndx, BpTreeNode::TreeInsert<TreeTraits>& state, size_t num_rows);
344 };
345
346
347 class BpTreeNode::NodeInfo {
348 public:
349     MemRef m_mem;
350     Array* m_parent;
351     size_t m_ndx_in_parent;
352     size_t m_offset, m_size;
353 };
354
355 class BpTreeNode::VisitHandler {
356 public:
357     virtual bool visit(const NodeInfo& leaf_info) = 0;
358     virtual ~VisitHandler() noexcept
359     {
360     }
361 };
362
363
364 class BpTreeNode::UpdateHandler {
365 public:
366     virtual void update(MemRef, ArrayParent*, size_t leaf_ndx_in_parent, size_t elem_ndx_in_leaf) = 0;
367     virtual ~UpdateHandler() noexcept
368     {
369     }
370 };
371
372
373 class BpTreeNode::EraseHandler {
374 public:
375     /// If the specified leaf has more than one element, this function
376     /// must erase the specified element from the leaf and return
377     /// false. Otherwise, when the leaf has a single element, this
378     /// function must return true without modifying the leaf. If \a
379     /// elem_ndx_in_leaf is `npos`, it refers to the last element in
380     /// the leaf. The implementation of this function must be
381     /// exception safe. This function is guaranteed to be called at
382     /// most once during each execution of Array::erase_bptree_elem(),
383     /// and *exactly* once during each *successful* execution of
384     /// Array::erase_bptree_elem().
385     virtual bool erase_leaf_elem(MemRef, ArrayParent*, size_t leaf_ndx_in_parent, size_t elem_ndx_in_leaf) = 0;
386
387     virtual void destroy_leaf(MemRef leaf_mem) noexcept = 0;
388
389     /// Must replace the current root with the specified leaf. The
390     /// implementation of this function must not destroy the
391     /// underlying root node, or any of its children, as that will be
392     /// done by Array::erase_bptree_elem(). The implementation of this
393     /// function must be exception safe.
394     virtual void replace_root_by_leaf(MemRef leaf_mem) = 0;
395
396     /// Same as replace_root_by_leaf(), but must replace the root with
397     /// an empty leaf. Also, if this function is called during an
398     /// execution of Array::erase_bptree_elem(), it is guaranteed that
399     /// it will be preceeded by a call to erase_leaf_elem().
400     virtual void replace_root_by_empty_leaf() = 0;
401
402     virtual ~EraseHandler() noexcept
403     {
404     }
405 };
406
407
408 /// Implementation:
409
410 inline BpTreeBase::BpTreeBase(std::unique_ptr<Array> init_root)
411     : m_root(std::move(init_root))
412 {
413 }
414
415 inline Allocator& BpTreeBase::get_alloc() const noexcept
416 {
417     return m_root->get_alloc();
418 }
419
420 inline void BpTreeBase::destroy() noexcept
421 {
422     if (m_root)
423         m_root->destroy_deep();
424 }
425
426 inline void BpTreeBase::detach()
427 {
428     m_root->detach();
429 }
430
431 inline bool BpTreeBase::is_attached() const noexcept
432 {
433     return m_root->is_attached();
434 }
435
436 inline bool BpTreeBase::root_is_leaf() const noexcept
437 {
438     return !m_root->is_inner_bptree_node();
439 }
440
441 inline BpTreeNode& BpTreeBase::root_as_node()
442 {
443     REALM_ASSERT_DEBUG(!root_is_leaf());
444     REALM_ASSERT_DEBUG(dynamic_cast<BpTreeNode*>(m_root.get()) != nullptr);
445     return static_cast<BpTreeNode&>(root());
446 }
447
448 inline const BpTreeNode& BpTreeBase::root_as_node() const
449 {
450     Array* arr = m_root.get();
451     REALM_ASSERT_DEBUG(!root_is_leaf());
452     REALM_ASSERT_DEBUG(dynamic_cast<const BpTreeNode*>(arr) != nullptr);
453     return static_cast<const BpTreeNode&>(*arr);
454 }
455
456 inline void BpTreeBase::set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept
457 {
458     m_root->set_parent(parent, ndx_in_parent);
459 }
460
461 inline size_t BpTreeBase::get_ndx_in_parent() const noexcept
462 {
463     return m_root->get_ndx_in_parent();
464 }
465
466 inline void BpTreeBase::set_ndx_in_parent(size_t ndx) noexcept
467 {
468     m_root->set_ndx_in_parent(ndx);
469 }
470
471 inline void BpTreeBase::update_from_parent(size_t old_baseline) noexcept
472 {
473     m_root->update_from_parent(old_baseline);
474 }
475
476 inline MemRef BpTreeBase::clone_deep(Allocator& alloc) const
477 {
478     return m_root->clone_deep(alloc);
479 }
480
481 inline const Array& BpTreeBase::root() const noexcept
482 {
483     return *m_root;
484 }
485
486 inline Array& BpTreeBase::root() noexcept
487 {
488     return *m_root;
489 }
490
491 inline size_t BpTreeNode::get_bptree_size() const noexcept
492 {
493     REALM_ASSERT_DEBUG(is_inner_bptree_node());
494     int_fast64_t v = back();
495     return size_t(v / 2); // v = 1 + 2*total_elems_in_tree
496 }
497
498 inline size_t BpTreeNode::get_bptree_size_from_header(const char* root_header) noexcept
499 {
500     REALM_ASSERT_DEBUG(get_is_inner_bptree_node_from_header(root_header));
501     size_t root_size = get_size_from_header(root_header);
502     int_fast64_t v = get(root_header, root_size - 1);
503     return size_t(v / 2); // v = 1 + 2*total_elems_in_tree
504 }
505
506 inline void BpTreeNode::ensure_bptree_offsets(Array& offsets)
507 {
508     int_fast64_t first_value = get(0);
509     if (first_value % 2 == 0) {
510         offsets.init_from_ref(to_ref(first_value));
511     }
512     else {
513         create_bptree_offsets(offsets, first_value); // Throws
514     }
515     offsets.set_parent(this, 0);
516 }
517
518
519 template <class TreeTraits>
520 ref_type BpTreeNode::bptree_append(TreeInsert<TreeTraits>& state)
521 {
522     // FIXME: Consider exception safety. Especially, how can the split
523     // be carried out in an exception safe manner?
524     //
525     // Can split be done as a separate preparation step, such that if
526     // the actual insert fails, the split will still have occured.
527     //
528     // Unfortunately, it requires a rather significant rearrangement
529     // of the insertion flow. Instead of returning the sibling ref
530     // from insert functions, the leaf-insert functions must instead
531     // call the special bptree_insert() function on the parent, which
532     // will then cascade the split towards the root as required.
533     //
534     // At each level where a split is required (starting at the leaf):
535     //
536     //  1. Create the new sibling.
537     //
538     //  2. Copy relevant entries over such that new sibling is in
539     //     its final state.
540     //
541     //  3. Call Array::bptree_insert() on parent with sibling ref.
542     //
543     //  4. Rearrange entries in original sibling and truncate as
544     //     required (must not throw).
545     //
546     // What about the 'offsets' array? It will always be
547     // present. Consider this carefully.
548
549     REALM_ASSERT_DEBUG(size() >= 1 + 1 + 1); // At least one child
550
551     ArrayParent& childs_parent = *this;
552     size_t child_ref_ndx = size() - 2;
553     ref_type child_ref = get_as_ref(child_ref_ndx), new_sibling_ref;
554     char* child_header = static_cast<char*>(m_alloc.translate(child_ref));
555
556     bool child_is_leaf = !get_is_inner_bptree_node_from_header(child_header);
557     if (child_is_leaf) {
558         size_t elem_ndx_in_child = npos; // Append
559         new_sibling_ref = TreeTraits::leaf_insert(MemRef(child_header, child_ref, m_alloc), childs_parent,
560                                                   child_ref_ndx, m_alloc, elem_ndx_in_child, state); // Throws
561     }
562     else {
563         BpTreeNode child(m_alloc);
564         child.init_from_mem(MemRef(child_header, child_ref, m_alloc));
565         child.set_parent(&childs_parent, child_ref_ndx);
566         new_sibling_ref = child.bptree_append(state); // Throws
567     }
568
569     if (REALM_LIKELY(!new_sibling_ref)) {
570         // +2 because stored value is 1 + 2*total_elems_in_subtree
571         adjust(size() - 1, +2); // Throws
572         return 0;               // Child was not split, so parent was not split either
573     }
574
575     Array offsets(m_alloc);
576     int_fast64_t first_value = get(0);
577     if (first_value % 2 == 0) {
578         // Offsets array is present (general form)
579         offsets.init_from_ref(to_ref(first_value));
580         offsets.set_parent(this, 0);
581     }
582     size_t child_ndx = child_ref_ndx - 1;
583     return insert_bptree_child(offsets, child_ndx, new_sibling_ref, state); // Throws
584 }
585
586
587 template <class TreeTraits>
588 ref_type BpTreeNode::bptree_insert(size_t elem_ndx, TreeInsert<TreeTraits>& state)
589 {
590     REALM_ASSERT_3(size(), >=, 1 + 1 + 1); // At least one child
591
592     // Conversion to general form if in compact form. Since this
593     // conversion will occur from root to leaf, it will maintain
594     // invar:bptree-node-form.
595     Array offsets(m_alloc);
596     ensure_bptree_offsets(offsets); // Throws
597
598     size_t child_ndx, elem_ndx_in_child;
599     if (elem_ndx == 0) {
600         // Optimization for prepend
601         child_ndx = 0;
602         elem_ndx_in_child = 0;
603     }
604     else {
605         // There is a choice to be made when the element is to be
606         // inserted between two subtrees. It can either be appended to
607         // the first subtree, or it can be prepended to the second
608         // one. We currently always append to the first subtree. It is
609         // essentially a matter of using the lower vs. the upper bound
610         // when searching through the offsets array.
611         child_ndx = offsets.lower_bound_int(elem_ndx);
612         REALM_ASSERT_3(child_ndx, <, size() - 2);
613         size_t elem_ndx_offset = child_ndx == 0 ? 0 : to_size_t(offsets.get(child_ndx - 1));
614         elem_ndx_in_child = elem_ndx - elem_ndx_offset;
615     }
616
617     ArrayParent& childs_parent = *this;
618     size_t child_ref_ndx = child_ndx + 1;
619     ref_type child_ref = get_as_ref(child_ref_ndx), new_sibling_ref;
620     char* child_header = static_cast<char*>(m_alloc.translate(child_ref));
621     bool child_is_leaf = !get_is_inner_bptree_node_from_header(child_header);
622     if (child_is_leaf) {
623         REALM_ASSERT_3(elem_ndx_in_child, <=, REALM_MAX_BPNODE_SIZE);
624         new_sibling_ref = TreeTraits::leaf_insert(MemRef(child_header, child_ref, m_alloc), childs_parent,
625                                                   child_ref_ndx, m_alloc, elem_ndx_in_child, state); // Throws
626     }
627     else {
628         BpTreeNode child(m_alloc);
629         child.init_from_mem(MemRef(child_header, child_ref, m_alloc));
630         child.set_parent(&childs_parent, child_ref_ndx);
631         new_sibling_ref = child.bptree_insert(elem_ndx_in_child, state); // Throws
632     }
633
634     if (REALM_LIKELY(!new_sibling_ref)) {
635         // +2 because stored value is 1 + 2*total_elems_in_subtree
636         adjust(size() - 1, +2); // Throws
637         offsets.adjust(child_ndx, offsets.size(), +1);
638         return 0; // Child was not split, so parent was not split either
639     }
640
641     return insert_bptree_child(offsets, child_ndx, new_sibling_ref, state); // Throws
642 }
643
644 template <class T>
645 BpTree<T>::BpTree()
646     : BpTree(Allocator::get_default())
647 {
648 }
649
650 template <class T>
651 BpTree<T>::BpTree(Allocator& alloc)
652     : BpTreeBase(std::unique_ptr<Array>(new LeafType(alloc)))
653 {
654 }
655
656 template <class T>
657 BpTree<T>::BpTree(BpTreeBase::unattached_tag)
658     : BpTreeBase(nullptr)
659 {
660 }
661
662 template <class T>
663 std::unique_ptr<Array> BpTree<T>::create_root_from_mem(Allocator& alloc, MemRef mem)
664 {
665     const char* header = mem.get_addr();
666     std::unique_ptr<Array> new_root;
667     bool is_inner_bptree_node = Array::get_is_inner_bptree_node_from_header(header);
668
669     bool can_reuse_root_accessor =
670         m_root && &m_root->get_alloc() == &alloc && m_root->is_inner_bptree_node() == is_inner_bptree_node;
671     if (can_reuse_root_accessor) {
672         if (is_inner_bptree_node) {
673             m_root->init_from_mem(mem);
674         }
675         else {
676             static_cast<LeafType&>(*m_root).init_from_mem(mem);
677         }
678         return std::move(m_root); // Same root will be reinstalled.
679     }
680
681     // Not reusing root note, allocating a new one.
682     if (is_inner_bptree_node) {
683         new_root.reset(new BpTreeNode{alloc});
684         new_root->init_from_mem(mem);
685     }
686     else {
687         std::unique_ptr<LeafType> leaf{new LeafType{alloc}};
688         leaf->init_from_mem(mem);
689         new_root = std::move(leaf);
690     }
691     return new_root;
692 }
693
694 template <class T>
695 std::unique_ptr<Array> BpTree<T>::create_root_from_ref(Allocator& alloc, ref_type ref)
696 {
697     MemRef mem = MemRef{alloc.translate(ref), ref, alloc};
698     return create_root_from_mem(alloc, mem);
699 }
700
701 template <class T>
702 void BpTree<T>::init_from_ref(Allocator& alloc, ref_type ref)
703 {
704     auto new_root = create_root_from_ref(alloc, ref);
705     replace_root(std::move(new_root));
706 }
707
708 template <class T>
709 void BpTree<T>::init_from_mem(Allocator& alloc, MemRef mem)
710 {
711     auto new_root = create_root_from_mem(alloc, mem);
712     replace_root(std::move(new_root));
713 }
714
715 template <class T>
716 void BpTree<T>::init_from_parent()
717 {
718     ref_type ref = root().get_ref_from_parent();
719     if (ref) {
720         ArrayParent* parent = m_root->get_parent();
721         size_t ndx_in_parent = m_root->get_ndx_in_parent();
722         auto new_root = create_root_from_ref(get_alloc(), ref);
723         new_root->set_parent(parent, ndx_in_parent);
724         m_root = std::move(new_root);
725     }
726     else {
727         m_root->detach();
728     }
729 }
730
731 template <class T>
732 typename BpTree<T>::LeafType& BpTree<T>::root_as_leaf()
733 {
734     REALM_ASSERT_DEBUG(root_is_leaf());
735     REALM_ASSERT_DEBUG(dynamic_cast<LeafType*>(m_root.get()) != nullptr);
736     return static_cast<LeafType&>(root());
737 }
738
739 template <class T>
740 const typename BpTree<T>::LeafType& BpTree<T>::root_as_leaf() const
741 {
742     REALM_ASSERT_DEBUG(root_is_leaf());
743     REALM_ASSERT_DEBUG(dynamic_cast<const LeafType*>(m_root.get()) != nullptr);
744     return static_cast<const LeafType&>(root());
745 }
746
747 template <class T>
748 size_t BpTree<T>::size() const noexcept
749 {
750     if (root_is_leaf()) {
751         return root_as_leaf().size();
752     }
753     return root_as_node().get_bptree_size();
754 }
755
756 template <class T>
757 T BpTree<T>::back() const noexcept
758 {
759     // FIXME: slow
760     return get(size() - 1);
761 }
762
763 namespace _impl {
764
765 // NullableOrNothing encapsulates the behavior of nullable and
766 // non-nullable leaf types, so that non-nullable leaf types
767 // don't have to implement is_null/set_null but BpTree can still
768 // support the interface (and return false / assert when null
769 // is not supported).
770 template <class Leaf>
771 struct NullableOrNothing {
772     static bool is_null(const Leaf& leaf, size_t ndx)
773     {
774         return leaf.is_null(ndx);
775     }
776     static void set_null(Leaf& leaf, size_t ndx)
777     {
778         leaf.set_null(ndx);
779     }
780 };
781 template <>
782 struct NullableOrNothing<ArrayInteger> {
783     static bool is_null(const ArrayInteger&, size_t)
784     {
785         return false;
786     }
787     static void set_null(ArrayInteger&, size_t)
788     {
789         REALM_ASSERT_RELEASE(false);
790     }
791 };
792 }
793
794 template <class T>
795 bool BpTree<T>::is_null(size_t ndx) const noexcept
796 {
797     if (root_is_leaf()) {
798         return _impl::NullableOrNothing<LeafType>::is_null(root_as_leaf(), ndx);
799     }
800     LeafType fallback(get_alloc());
801     const LeafType* leaf;
802     LeafInfo leaf_info{&leaf, &fallback};
803     size_t ndx_in_leaf;
804     get_leaf(ndx, ndx_in_leaf, leaf_info);
805     return _impl::NullableOrNothing<LeafType>::is_null(*leaf, ndx_in_leaf);
806 }
807
808 template <class T>
809 T BpTree<T>::get(size_t ndx) const noexcept
810 {
811     REALM_ASSERT_DEBUG_EX(ndx < size(), ndx, size());
812     if (root_is_leaf()) {
813         return root_as_leaf().get(ndx);
814     }
815
816     // Use direct getter to avoid initializing leaf array:
817     std::pair<MemRef, size_t> p = root_as_node().get_bptree_leaf(ndx);
818     const char* leaf_header = p.first.get_addr();
819     size_t ndx_in_leaf = p.second;
820     return LeafType::get(leaf_header, ndx_in_leaf);
821 }
822
823 template <class T>
824 template <class TreeTraits>
825 void BpTree<T>::bptree_insert(size_t row_ndx, BpTreeNode::TreeInsert<TreeTraits>& state, size_t num_rows)
826 {
827     ref_type new_sibling_ref;
828     for (size_t i = 0; i < num_rows; ++i) {
829         size_t row_ndx_2 = row_ndx == realm::npos ? realm::npos : row_ndx + i;
830         if (root_is_leaf()) {
831             REALM_ASSERT_DEBUG(row_ndx_2 == realm::npos || row_ndx_2 < REALM_MAX_BPNODE_SIZE);
832             new_sibling_ref = root_as_leaf().bptree_leaf_insert(row_ndx_2, state.m_value, state);
833         }
834         else {
835             if (row_ndx_2 == realm::npos) {
836                 new_sibling_ref = root_as_node().bptree_append(state); // Throws
837             }
838             else {
839                 new_sibling_ref = root_as_node().bptree_insert(row_ndx_2, state); // Throws
840             }
841         }
842
843         if (REALM_UNLIKELY(new_sibling_ref)) {
844             bool is_append = row_ndx_2 == realm::npos;
845             introduce_new_root(new_sibling_ref, state, is_append);
846         }
847     }
848 }
849
850 template <class T>
851 struct BpTree<T>::LeafValueInserter {
852     using value_type = T;
853     T m_value;
854     LeafValueInserter(T value)
855         : m_value(std::move(value))
856     {
857     }
858
859     // TreeTraits concept:
860     static ref_type leaf_insert(MemRef leaf_mem, ArrayParent& parent, size_t ndx_in_parent, Allocator& alloc,
861                                 size_t ndx_in_leaf, BpTreeNode::TreeInsert<LeafValueInserter>& state)
862     {
863         LeafType leaf{alloc};
864         leaf.init_from_mem(leaf_mem);
865         leaf.set_parent(&parent, ndx_in_parent);
866         // Should not move out of m_value, because the same inserter may be used to perform
867         // multiple insertions (for example, if num_rows > 1).
868         return leaf.bptree_leaf_insert(ndx_in_leaf, state.m_value, state);
869     }
870 };
871
872 template <class T>
873 struct BpTree<T>::LeafNullInserter {
874     using value_type = null;
875     // TreeTraits concept:
876     static ref_type leaf_insert(MemRef leaf_mem, ArrayParent& parent, size_t ndx_in_parent, Allocator& alloc,
877                                 size_t ndx_in_leaf, BpTreeNode::TreeInsert<LeafNullInserter>& state)
878     {
879         LeafType leaf{alloc};
880         leaf.init_from_mem(leaf_mem);
881         leaf.set_parent(&parent, ndx_in_parent);
882         return leaf.bptree_leaf_insert(ndx_in_leaf, null{}, state);
883     }
884 };
885
886 template <class T>
887 void BpTree<T>::insert(size_t row_ndx, T value, size_t num_rows)
888 {
889     REALM_ASSERT_DEBUG(row_ndx == npos || row_ndx < size());
890     BpTreeNode::TreeInsert<LeafValueInserter> inserter;
891     inserter.m_value = std::move(value);
892     inserter.m_nullable = std::is_same<T, util::Optional<int64_t>>::value; // FIXME
893     bptree_insert(row_ndx, inserter, num_rows);                            // Throws
894 }
895
896 template <class T>
897 struct BpTree<T>::UpdateHandler : BpTreeNode::UpdateHandler {
898     LeafType m_leaf;
899     const T m_value;
900     UpdateHandler(BpTreeBase& tree, T value) noexcept
901         : m_leaf(tree.get_alloc())
902         , m_value(std::move(value))
903     {
904     }
905     void update(MemRef mem, ArrayParent* parent, size_t ndx_in_parent, size_t elem_ndx_in_leaf) override
906     {
907         m_leaf.init_from_mem(mem);
908         m_leaf.set_parent(parent, ndx_in_parent);
909         m_leaf.set(elem_ndx_in_leaf, m_value); // Throws
910     }
911 };
912
913 template <class T>
914 struct BpTree<T>::SetNullHandler : BpTreeNode::UpdateHandler {
915     LeafType m_leaf;
916     SetNullHandler(BpTreeBase& tree) noexcept
917         : m_leaf(tree.get_alloc())
918     {
919     }
920     void update(MemRef mem, ArrayParent* parent, size_t ndx_in_parent, size_t elem_ndx_in_leaf) override
921     {
922         m_leaf.init_from_mem(mem);
923         m_leaf.set_parent(parent, ndx_in_parent);
924         _impl::NullableOrNothing<LeafType>::set_null(m_leaf, elem_ndx_in_leaf); // Throws
925     }
926 };
927
928 template <class T>
929 void BpTree<T>::set(size_t ndx, T value)
930 {
931     if (root_is_leaf()) {
932         root_as_leaf().set(ndx, std::move(value));
933     }
934     else {
935         UpdateHandler set_leaf_elem(*this, std::move(value));
936         static_cast<BpTreeNode*>(m_root.get())->update_bptree_elem(ndx, set_leaf_elem); // Throws
937     }
938 }
939
940 template <class T>
941 void BpTree<T>::set_null(size_t ndx)
942 {
943     if (root_is_leaf()) {
944         _impl::NullableOrNothing<LeafType>::set_null(root_as_leaf(), ndx);
945     }
946     else {
947         SetNullHandler set_leaf_elem(*this);
948         static_cast<BpTreeNode*>(m_root.get())->update_bptree_elem(ndx, set_leaf_elem); // Throws;
949     }
950 }
951
952 template <class T>
953 struct BpTree<T>::EraseHandler : BpTreeNode::EraseHandler {
954     BpTreeBase& m_tree;
955     LeafType m_leaf;
956     bool m_leaves_have_refs; // FIXME: Should be able to eliminate this.
957     EraseHandler(BpTreeBase& tree) noexcept
958         : m_tree(tree)
959         , m_leaf(tree.get_alloc())
960         , m_leaves_have_refs(false)
961     {
962     }
963     bool erase_leaf_elem(MemRef leaf_mem, ArrayParent* parent, size_t leaf_ndx_in_parent,
964                          size_t elem_ndx_in_leaf) override
965     {
966         m_leaf.init_from_mem(leaf_mem);
967         REALM_ASSERT_3(m_leaf.size(), >=, 1);
968         size_t last_ndx = m_leaf.size() - 1;
969         if (last_ndx == 0) {
970             m_leaves_have_refs = m_leaf.has_refs();
971             return true;
972         }
973         m_leaf.set_parent(parent, leaf_ndx_in_parent);
974         size_t ndx = elem_ndx_in_leaf;
975         if (ndx == npos)
976             ndx = last_ndx;
977         m_leaf.erase(ndx); // Throws
978         return false;
979     }
980     void destroy_leaf(MemRef leaf_mem) noexcept override
981     {
982         // FIXME: Seems like this would cause file space leaks if
983         // m_leaves_have_refs is true, but consider carefully how
984         // m_leaves_have_refs get its value.
985         m_tree.get_alloc().free_(leaf_mem);
986     }
987     void replace_root_by_leaf(MemRef leaf_mem) override
988     {
989         std::unique_ptr<LeafType> leaf{new LeafType(m_tree.get_alloc())}; // Throws
990         leaf->init_from_mem(leaf_mem);
991         m_tree.replace_root(std::move(leaf)); // Throws
992     }
993     void replace_root_by_empty_leaf() override
994     {
995         std::unique_ptr<LeafType> leaf{new LeafType(m_tree.get_alloc())};            // Throws
996         leaf->create(m_leaves_have_refs ? Array::type_HasRefs : Array::type_Normal); // Throws
997         m_tree.replace_root(std::move(leaf));                                        // Throws
998     }
999 };
1000
1001 template <class T>
1002 void BpTree<T>::erase(size_t ndx, bool is_last)
1003 {
1004     REALM_ASSERT_DEBUG_EX(ndx < size(), ndx, size());
1005     REALM_ASSERT_DEBUG(is_last == (ndx == size() - 1));
1006     if (root_is_leaf()) {
1007         root_as_leaf().erase(ndx);
1008     }
1009     else {
1010         size_t ndx_2 = is_last ? npos : ndx;
1011         EraseHandler handler(*this);
1012         BpTreeNode::erase_bptree_elem(&root_as_node(), ndx_2, handler);
1013     }
1014 }
1015
1016 template <class T>
1017 void BpTree<T>::move_last_over(size_t row_ndx, size_t last_row_ndx)
1018 {
1019     // Copy value from last row over
1020     T value = get(last_row_ndx);
1021     set(row_ndx, value);
1022     erase(last_row_ndx, true);
1023 }
1024
1025 template <class T>
1026 void BpTree<T>::clear()
1027 {
1028     if (root_is_leaf()) {
1029         if (std::is_same<T, int64_t>::value && root().get_type() == Array::type_HasRefs) {
1030             // FIXME: This is because some column types rely on integer columns
1031             // to contain refs.
1032             root().clear_and_destroy_children();
1033         }
1034         else {
1035             root_as_leaf().clear();
1036         }
1037     }
1038     else {
1039         Allocator& alloc = get_alloc();
1040         root().destroy_deep();
1041
1042         std::unique_ptr<LeafType> new_root(new LeafType(alloc));
1043         new_root->create();
1044         replace_root(std::move(new_root));
1045     }
1046 }
1047
1048
1049 template <class T>
1050 struct BpTree<T>::AdjustHandler : BpTreeNode::UpdateHandler {
1051     LeafType m_leaf;
1052     const T m_diff;
1053     AdjustHandler(BpTreeBase& tree, T diff)
1054         : m_leaf(tree.get_alloc())
1055         , m_diff(diff)
1056     {
1057     }
1058
1059     void update(MemRef mem, ArrayParent* parent, size_t ndx_in_parent, size_t) final
1060     {
1061         m_leaf.init_from_mem(mem);
1062         m_leaf.set_parent(parent, ndx_in_parent);
1063         m_leaf.adjust(0, m_leaf.size(), m_diff);
1064     }
1065 };
1066
1067 template <class T>
1068 void BpTree<T>::adjust(T diff)
1069 {
1070     if (root_is_leaf()) {
1071         root_as_leaf().adjust(0, m_root->size(), std::move(diff)); // Throws
1072     }
1073     else {
1074         AdjustHandler adjust_leaf_elem(*this, std::move(diff));
1075         root_as_node().update_bptree_leaves(adjust_leaf_elem); // Throws
1076     }
1077 }
1078
1079 template <class T>
1080 void BpTree<T>::adjust(size_t ndx, T diff)
1081 {
1082     static_assert(std::is_arithmetic<T>::value, "adjust is undefined for non-arithmetic trees");
1083     set(ndx, get(ndx) + diff);
1084 }
1085
1086 template <class T>
1087 struct BpTree<T>::AdjustGEHandler : BpTreeNode::UpdateHandler {
1088     LeafType m_leaf;
1089     const T m_limit, m_diff;
1090
1091     AdjustGEHandler(BpTreeBase& tree, T limit, T diff)
1092         : m_leaf(tree.get_alloc())
1093         , m_limit(limit)
1094         , m_diff(diff)
1095     {
1096     }
1097
1098     void update(MemRef mem, ArrayParent* parent, size_t ndx_in_parent, size_t) final
1099     {
1100         m_leaf.init_from_mem(mem);
1101         m_leaf.set_parent(parent, ndx_in_parent);
1102         m_leaf.adjust_ge(m_limit, m_diff);
1103     }
1104 };
1105
1106 template <class T>
1107 void BpTree<T>::adjust_ge(T limit, T diff)
1108 {
1109     if (root_is_leaf()) {
1110         root_as_leaf().adjust_ge(std::move(limit), std::move(diff)); // Throws
1111     }
1112     else {
1113         AdjustGEHandler adjust_leaf_elem(*this, std::move(limit), std::move(diff));
1114         root_as_node().update_bptree_leaves(adjust_leaf_elem); // Throws
1115     }
1116 }
1117
1118 template <class T>
1119 struct BpTree<T>::SliceHandler : public BpTreeBase::SliceHandler {
1120 public:
1121     SliceHandler(Allocator& alloc)
1122         : m_leaf(alloc)
1123     {
1124     }
1125     MemRef slice_leaf(MemRef leaf_mem, size_t offset, size_t size, Allocator& target_alloc) override
1126     {
1127         m_leaf.init_from_mem(leaf_mem);
1128         return m_leaf.slice_and_clone_children(offset, size, target_alloc); // Throws
1129     }
1130
1131 private:
1132     LeafType m_leaf;
1133 };
1134
1135 template <class T>
1136 ref_type BpTree<T>::write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream& out) const
1137 {
1138     ref_type ref;
1139     if (root_is_leaf()) {
1140         Allocator& alloc = Allocator::get_default();
1141         MemRef mem = root_as_leaf().slice_and_clone_children(slice_offset, slice_size, alloc); // Throws
1142         Array slice(alloc);
1143         _impl::DeepArrayDestroyGuard dg(&slice);
1144         slice.init_from_mem(mem);
1145         bool deep = true;
1146         bool only_when_modified = false;
1147         ref = slice.write(out, deep, only_when_modified); // Throws
1148     }
1149     else {
1150         SliceHandler handler(get_alloc());
1151         ref = write_subtree(root_as_node(), slice_offset, slice_size, table_size, handler, out); // Throws
1152     }
1153     return ref;
1154 }
1155
1156 template <class T>
1157 MemRef BpTree<T>::create_leaf(Array::Type leaf_type, size_t size, T value, Allocator& alloc)
1158 {
1159     bool context_flag = false;
1160     MemRef mem = LeafType::create_array(leaf_type, context_flag, size, std::move(value), alloc);
1161     return mem;
1162 }
1163
1164 template <class T>
1165 void BpTree<T>::get_leaf(size_t ndx, size_t& ndx_in_leaf, LeafInfo& inout_leaf_info) const noexcept
1166 {
1167     if (root_is_leaf()) {
1168         ndx_in_leaf = ndx;
1169         *inout_leaf_info.out_leaf = &root_as_leaf();
1170         return;
1171     }
1172     std::pair<MemRef, size_t> p = root_as_node().get_bptree_leaf(ndx);
1173     inout_leaf_info.fallback->init_from_mem(p.first);
1174     ndx_in_leaf = p.second;
1175     *inout_leaf_info.out_leaf = inout_leaf_info.fallback;
1176 }
1177
1178 template <class T>
1179 size_t BpTree<T>::find_first(T value, size_t begin, size_t end) const
1180 {
1181     if (root_is_leaf()) {
1182         return root_as_leaf().find_first(value, begin, end);
1183     }
1184
1185     // FIXME: It would be better to always require that 'end' is
1186     // specified explicitly, since Table has the size readily
1187     // available, and Array::get_bptree_size() is deprecated.
1188     if (end == npos)
1189         end = size();
1190
1191     LeafType leaf_cache(get_alloc());
1192     size_t ndx_in_tree = begin;
1193     while (ndx_in_tree < end) {
1194         const LeafType* leaf;
1195         LeafInfo leaf_info{&leaf, &leaf_cache};
1196         size_t ndx_in_leaf;
1197         get_leaf(ndx_in_tree, ndx_in_leaf, leaf_info);
1198         size_t leaf_offset = ndx_in_tree - ndx_in_leaf;
1199         size_t end_in_leaf = std::min(leaf->size(), end - leaf_offset);
1200         size_t ndx = leaf->find_first(value, ndx_in_leaf, end_in_leaf); // Throws (maybe)
1201         if (ndx != not_found)
1202             return leaf_offset + ndx;
1203         ndx_in_tree = leaf_offset + end_in_leaf;
1204     }
1205
1206     return not_found;
1207 }
1208
1209 template <class T>
1210 void BpTree<T>::find_all(IntegerColumn& result, T value, size_t begin, size_t end) const
1211 {
1212     if (root_is_leaf()) {
1213         root_as_leaf().find_all(&result, value, 0, begin, end); // Throws
1214         return;
1215     }
1216
1217     // FIXME: It would be better to always require that 'end' is
1218     // specified explicitely, since Table has the size readily
1219     // available, and Array::get_bptree_size() is deprecated.
1220     if (end == npos)
1221         end = size();
1222
1223     LeafType leaf_cache(get_alloc());
1224     size_t ndx_in_tree = begin;
1225     while (ndx_in_tree < end) {
1226         const LeafType* leaf;
1227         LeafInfo leaf_info{&leaf, &leaf_cache};
1228         size_t ndx_in_leaf;
1229         get_leaf(ndx_in_tree, ndx_in_leaf, leaf_info);
1230         size_t leaf_offset = ndx_in_tree - ndx_in_leaf;
1231         size_t end_in_leaf = std::min(leaf->size(), end - leaf_offset);
1232         leaf->find_all(&result, value, leaf_offset, ndx_in_leaf, end_in_leaf); // Throws
1233         ndx_in_tree = leaf_offset + end_in_leaf;
1234     }
1235 }
1236
1237 #if defined(REALM_DEBUG)
1238 template <class T>
1239 size_t BpTree<T>::verify_leaf(MemRef mem, Allocator& alloc)
1240 {
1241     LeafType leaf(alloc);
1242     leaf.init_from_mem(mem);
1243     leaf.verify();
1244     return leaf.size();
1245 }
1246
1247 template <class T>
1248 void BpTree<T>::verify() const
1249 {
1250     if (root_is_leaf()) {
1251         root_as_leaf().verify();
1252     }
1253     else {
1254         root().verify_bptree(&verify_leaf);
1255     }
1256 }
1257 #endif // REALM_DEBUG
1258
1259 template <class T>
1260 void BpTree<T>::leaf_to_dot(MemRef leaf_mem, ArrayParent* parent, size_t ndx_in_parent, std::ostream& out,
1261                             Allocator& alloc)
1262 {
1263     LeafType leaf(alloc);
1264     leaf.init_from_mem(leaf_mem);
1265     leaf.set_parent(parent, ndx_in_parent);
1266     leaf.to_dot(out);
1267 }
1268
1269 } // namespace realm
1270
1271 #endif // REALM_BPTREE_HPP