/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.Generic; using System.Diagnostics; using VST = Microsoft.VisualStudio.Text; namespace dnSpy.Contracts.Hex { /// /// Hex cell collection /// public readonly struct HexCellCollection { /// /// true if this is a default instance that hasn't been initialized /// public bool IsDefault => cells is null; /// /// Gets the empty collection /// public static readonly HexCellCollection Empty = new HexCellCollection(Array.Empty()); readonly HexCell[] cells; readonly int validStart, validEnd; /// /// Gets the number of elements in this collection /// public int Count => cells.Length; /// /// Gets the span of cells in the collection that have data ( is true) /// public VST.Span HasDataSpan => VST.Span.FromBounds(validStart, validEnd); /// /// Gets a cell /// /// Index /// public HexCell this[int index] => cells[index]; /// /// Constructor /// /// All cells public HexCellCollection(HexCell[] cells) { if (cells is null) throw new ArgumentNullException(nameof(cells)); for (int i = 0; i < cells.Length; i++) { if (cells[i].HasData) { validStart = i; int j = cells.Length - 1; while (!cells[j].HasData) j--; validEnd = j + 1; goto done; } } validStart = 0; validEnd = 0; done:; #if DEBUG for (int i = 0; i < cells.Length; i++) { if (cells[i].Index != i) throw new ArgumentException(); if (cells[i].HasData != (validStart <= i && i < validEnd)) throw new ArgumentException(); } for (int i = validStart + 1; i < validEnd; i++) { if (cells[i - 1].BufferEnd != cells[i].BufferStart) throw new ArgumentException(); if (cells[i - 1].BufferSpan.Length != cells[i].BufferSpan.Length && i + 1 != validEnd) throw new ArgumentException(); } #endif this.cells = cells; } /// /// Gets the cell that contains /// /// Point /// public HexCell? GetCell(HexBufferPoint point) { int index = GetStartIndex(point); if (validStart <= index && index < validEnd) return cells[index]; return null; } /// /// Gets all cells, including unused cells /// /// public IEnumerable GetCells() { foreach (var cell in cells) yield return cell; } /// /// Gets all visible cells /// /// public IEnumerable GetVisibleCells() { for (int i = validStart; i < validEnd; i++) yield return cells[i]; } /// /// Gets all cells that are contained in . The returned cells /// are ordered by index. /// /// Span /// public IEnumerable GetCells(HexBufferSpan span) { int index = GetStartIndex(span.Start); if (index >= validStart) { while (index < validEnd) { var cell = cells[index]; Debug.Assert(cell.HasData); if (span.End <= cell.BufferStart) break; yield return cell; index++; } } } int GetStartIndex(HexBufferPoint position) { var cellsLocal = cells; int lo = validStart, hi = validEnd; if (lo >= hi) return -1; var cellFirst = cellsLocal[lo]; var cellLast = cellsLocal[hi - 1]; if (position < cellFirst.BufferStart || position >= cellLast.BufferEnd) return -1; return lo + (int)((position - cellFirst.BufferStart).ToUInt64() / cellFirst.BufferSpan.Length.ToUInt64()); } } }