/* 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.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Text; namespace dnSpy.Contracts.Hex { /// /// Normalized collection /// public sealed class NormalizedHexSpanCollection : ReadOnlyCollection, IEquatable { /// /// An empty collection /// public static readonly NormalizedHexSpanCollection Empty = new NormalizedHexSpanCollection(); /// /// Constructor /// public NormalizedHexSpanCollection() : base(Array.Empty()) { } /// /// Constructor /// /// Span public NormalizedHexSpanCollection(HexSpan span) : base(new HexSpan[1] { span }) { } /// /// Constructor /// /// Spans public NormalizedHexSpanCollection(IEnumerable spans) : base(Normalize(spans)) { } static HexSpan[] Normalize(IEnumerable spans) { if (spans is null) throw new ArgumentNullException(nameof(spans)); var list = new List(spans); if (list.Count <= 1) return list.ToArray(); list.Sort(HexSpanComparer.Instance); int index = 0; var start = list[0].Start; var end = list[0].End; for (int i = 1; i < list.Count; i++) { var span = list[i]; if (end < span.Start) { list[index++] = HexSpan.FromBounds(start, end); start = span.Start; end = span.End; } else end = HexPosition.Max(end, span.End); } list[index++] = HexSpan.FromBounds(start, end); var ary = new HexSpan[index]; list.CopyTo(0, ary, 0, ary.Length); return ary; } sealed class HexSpanComparer : IComparer { public static readonly HexSpanComparer Instance = new HexSpanComparer(); public int Compare([AllowNull] HexSpan x, [AllowNull] HexSpan y) => x.Start.CompareTo(y.Start); } /// /// Returns true if any of the spans in this instance overlaps with /// /// Span /// public bool OverlapsWith(HexSpan span) { for (int i = 0; i < Count; i++) { if (this[i].OverlapsWith(span)) return true; } return false; } /// /// Returns true if any of the spans in this instance intersects with /// /// Span /// public bool IntersectsWith(HexSpan span) { for (int i = 0; i < Count; i++) { if (this[i].IntersectsWith(span)) return true; } return false; } /// /// operator ==() /// /// /// /// public static bool operator ==(NormalizedHexSpanCollection? left, NormalizedHexSpanCollection? right) { if ((object?)left == right) return true; if (left is null || right is null) return false; return left.Equals(right); } /// /// operator !=() /// /// /// /// public static bool operator !=(NormalizedHexSpanCollection? left, NormalizedHexSpanCollection? right) => !(left == right); /// /// Equals() /// /// Other instance /// public bool Equals(NormalizedHexSpanCollection? other) { if (other is null) return false; if (Count != other.Count) return false; for (int i = 0; i < Count; i++) { if (this[i] != other[i]) return false; } return true; } /// /// Equals() /// /// Object /// public override bool Equals(object? obj) => Equals(obj as NormalizedHexSpanCollection); /// /// GetHashCode() /// /// public override int GetHashCode() { int hc = 0; for (int i = 0; i < Count; i++) hc ^= this[i].GetHashCode(); return hc; } /// /// ToString() /// /// public override string ToString() { var sb = new StringBuilder(); sb.Append('{'); foreach (var span in this) sb.Append(span.ToString()); sb.Append('}'); return sb.ToString(); } } }