private IEnumerable <T> EnumerateRecords(BTree2Node <T> node, ushort nodeLevel) { // This method could be rearranged to accept a BTree2NodePointer (instead of the root node). // In that case it would be possible to simplify the double check for internal/leaf node. // internal node var internalNode = node as BTree2InternalNode <T>; if (internalNode is not null) { var records = node.Records .Cast <T>() .ToList(); var nodePointers = internalNode.NodePointers; for (int i = 0; i < nodePointers.Length; i++) { // there is one more node pointer than records if (i < records.Count) { yield return(records[i]); } var nodePointer = nodePointers[i]; this.Reader.Seek((long)nodePointer.Address, SeekOrigin.Begin); var childNodeLevel = (ushort)(nodeLevel - 1); IEnumerable <T> childRecords; // internal node if (childNodeLevel > 0) { var childNode = new BTree2InternalNode <T>(this.Reader, _superblock, this, nodePointer.RecordCount, childNodeLevel, _decodeKey); childRecords = this.EnumerateRecords(childNode, childNodeLevel); } // leaf node else { var childNode = new BTree2LeafNode <T>(this.Reader, this, nodePointer.RecordCount, _decodeKey); childRecords = childNode.Records; } foreach (var record in childRecords) { yield return(record); } } } // leaf node else { foreach (var record in node.Records) { yield return(record); } } }
public bool TryFindRecord(out T result, Func <T, int> compare) { /* H5B2.c (H5B2_find) */ int cmp; uint index = 0; BTree2NodePosition curr_pos; result = default; /* Make copy of the root node pointer to start search with */ var currentNodePointer = this.RootNodePointer; /* Check for empty tree */ if (currentNodePointer.RecordCount == 0) { return(false); } #warning Optimizations missing. /* Current depth of the tree */ var depth = this.Depth; /* Walk down B-tree to find record or leaf node where record is located */ cmp = -1; curr_pos = BTree2NodePosition.Root; while (depth > 0) { this.Reader.Seek((long)currentNodePointer.Address, SeekOrigin.Begin); var internalNode = new BTree2InternalNode <T>(this.Reader, _superblock, this, currentNodePointer.RecordCount, depth, _decodeKey); if (internalNode is null) { throw new Exception("Unable to load B-tree internal node."); } /* Locate node pointer for child */ (index, cmp) = this.LocateRecord(internalNode.Records, compare); if (cmp > 0) { index++; } if (cmp != 0) { /* Get node pointer for next node to search */ var nextNodePointer = internalNode.NodePointers[index]; /* Set the position of the next node */ if (curr_pos != BTree2NodePosition.Middle) { if (index == 0) { if (curr_pos == BTree2NodePosition.Left || curr_pos == BTree2NodePosition.Root) { curr_pos = BTree2NodePosition.Left; } else { curr_pos = BTree2NodePosition.Middle; } } else if (index == internalNode.Records.Length) { if (curr_pos == BTree2NodePosition.Right || curr_pos == BTree2NodePosition.Root) { curr_pos = BTree2NodePosition.Right; } else { curr_pos = BTree2NodePosition.Middle; } } else { curr_pos = BTree2NodePosition.Middle; } } currentNodePointer = nextNodePointer; } else { result = internalNode.Records[index]; return(true); } /* Decrement depth we're at in B-tree */ depth--; } { this.Reader.Seek((long)currentNodePointer.Address, SeekOrigin.Begin); var leafNode = new BTree2LeafNode <T>(this.Reader, this, currentNodePointer.RecordCount, _decodeKey); /* Locate record */ (index, cmp) = this.LocateRecord(leafNode.Records, compare); if (cmp == 0) { result = leafNode.Records[index]; return(true); #warning Optimizations missing. } } return(false); }