public ContainerEntry NearestIndexedContainer(long position) { // We want the first container which ends after the position and starts before it. // All containers ending before position can't contain it. // Find the first container ending after position. int indexAfter = IndexOfFirstEndingAfter(position); // If position was after the last container end, return empty if (indexAfter >= _index.Count) { return(ContainerEntry.Empty); } // Find the first ancestor of the container which starts before position ContainerEntry candidate = this[indexAfter]; while (candidate.StartByteOffset > position) { candidate = Parent(candidate); } // Since all ancestors of indexed containers are indexed, this must be the closest indexed ancestor. return(candidate); }
public void Skip() { // If this container is indexed, skip by seeking if (_containerIndex != null) { ContainerEntry entry = _containerIndex.NearestIndexedContainer(BytesRead); if (entry.StartByteOffset == BytesRead) { _reader.Seek(entry.EndByteOffset, SeekOrigin.Begin); return; } } // Record depth long start = BytesRead; int depth = _currentDepth; // Read one token Read(); // If it wasn't a container, we're done if (depth == _currentDepth) { return; } SkipRest(); long lengthSkipped = BytesRead - start; }
public ContainerEntry Parent(ContainerEntry entry) { if (entry.ParentIndex < 0 || entry.ParentIndex >= _index.Count) { return(ContainerEntry.Empty); } return(_index[entry.ParentIndex]); }
public int Depth(ContainerEntry entry) { int depth = 0; ContainerEntry ancestor = entry; while (ancestor.Index != -1) { depth++; ancestor = Parent(ancestor); } return(depth); }
public void End(long containerEndOffset) { ContainerEntry entry = new ContainerEntry(_currentStack.Pop(), containerEndOffset, _index.Count); int depth = _currentStack.Count; // Index this container if it's long enough, it's far enough away from the last indexed container, or if we indexed a descendant of it if (entry.ByteLength >= ContainerLengthCutoff || containerEndOffset - _lastIndexedEnd >= ContainerLengthCutoff || _mustIndexDepth == depth) { _index.Add(entry); _lastIndexedEnd = containerEndOffset; _mustIndexDepth = depth - 1; } }
public void Read(BionReader reader) { _index.Clear(); reader.Read(BionToken.StartArray); // Read the Container Index long lastEndPosition = 0; while (reader.Read()) { if (reader.TokenType != BionToken.Integer) { break; } long endPosition = lastEndPosition + reader.CurrentInteger(); reader.Read(BionToken.Integer); long byteLength = reader.CurrentInteger(); _index.Add(new ContainerEntry(endPosition - byteLength, endPosition, _index.Count)); lastEndPosition = endPosition; } // Reconstruct the hierarchy for (int i = _index.Count - 2; i >= 0; --i) { ContainerEntry current = _index[i]; // Find the parent - the first container which starts before this one int parentIndex = i + 1; while (parentIndex != -1) { if (_index[parentIndex].StartByteOffset < current.StartByteOffset) { current.ParentIndex = parentIndex; _index[i] = current; break; } parentIndex = _index[parentIndex].ParentIndex; } } // Size exact _index.Capacity = _index.Count; }
public ContainerEntry AncestorAtDepth(ContainerEntry entry, int depth) { int entryDepth = Depth(entry); if (entryDepth < depth) { return(ContainerEntry.Empty); } int currentDepth = entryDepth; ContainerEntry ancestor = entry; while (currentDepth != depth) { ancestor = Parent(ancestor); currentDepth--; } return(ancestor); }