// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : ExtentsUInt.cs // Author(s) : Natalia Portillo // // Component : Extent helpers. // // --[ Description ] ---------------------------------------------------------- // // Provides extents for uint types. // // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License auint with this library; if not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2018 Natalia Portillo // ****************************************************************************/ using System; using System.Collections.Generic; using System.Linq; namespace DiscImageChef.CommonTypes.Extents { /// /// Implements extents for /// public class ExtentsUInt { List> backend; /// /// Initialize an empty list of extents /// public ExtentsUInt() { backend = new List>(); } /// /// Initializes extents with an specific list /// /// List of extents as tuples "start, end" public ExtentsUInt(IEnumerable> list) { backend = list.OrderBy(t => t.Item1).ToList(); } /// /// Gets a count of how many extents are stored /// public int Count => backend.Count; /// /// Adds the specified number to the corresponding extent, or creates a new one /// /// public void Add(uint item) { Tuple removeOne = null; Tuple removeTwo = null; Tuple itemToAdd = null; for(int i = 0; i < backend.Count; i++) { // Already contained in an extent if(item >= backend[i].Item1 && item <= backend[i].Item2) return; // Expands existing extent start if(item == backend[i].Item1 - 1) { removeOne = backend[i]; if(i > 0 && item == backend[i - 1].Item2 + 1) { removeTwo = backend[i - 1]; itemToAdd = new Tuple(backend[i - 1].Item1, backend[i].Item2); } else itemToAdd = new Tuple(item, backend[i].Item2); break; } // Expands existing extent end if(item != backend[i].Item2 + 1) continue; removeOne = backend[i]; if(i < backend.Count - 1 && item == backend[i + 1].Item1 - 1) { removeTwo = backend[i + 1]; itemToAdd = new Tuple(backend[i].Item1, backend[i + 1].Item2); } else itemToAdd = new Tuple(backend[i].Item1, item); break; } if(itemToAdd != null) { backend.Remove(removeOne); backend.Remove(removeTwo); backend.Add(itemToAdd); } else backend.Add(new Tuple(item, item)); // Sort backend = backend.OrderBy(t => t.Item1).ToList(); } /// /// Adds a new extent /// /// First element of the extent /// /// Last element of the extent or if is true how many elements the extent runs /// for /// /// If set to true, indicates how many elements the extent runs for public void Add(uint start, uint end, bool run = false) { uint realEnd; if(run) realEnd = start + end - 1; else realEnd = end; // TODO: Optimize this for(uint t = start; t <= realEnd; t++) Add(t); } /// /// Checks if the specified item is contained by an extent on this instance /// /// Item to seach for /// true if any of the extents on this instance contains the item public bool Contains(uint item) { return backend.Any(extent => item >= extent.Item1 && item <= extent.Item2); } /// /// Removes all extents from this instance /// public void Clear() { backend.Clear(); } /// /// Removes an item from the extents in this instance /// /// Item to remove /// true if the item was contained in a known extent and removed, false otherwise public bool Remove(uint item) { Tuple toRemove = null; Tuple toAddOne = null; Tuple toAddTwo = null; foreach(Tuple extent in backend) { // Extent is contained and not a border if(item > extent.Item1 && item < extent.Item2) { toRemove = extent; toAddOne = new Tuple(extent.Item1, item - 1); toAddTwo = new Tuple(item + 1, extent.Item2); break; } // Extent is left border, but not only element if(item == extent.Item1 && item != extent.Item2) { toRemove = extent; toAddOne = new Tuple(item + 1, extent.Item2); break; } // Extent is right border, but not only element if(item != extent.Item1 && item == extent.Item2) { toRemove = extent; toAddOne = new Tuple(extent.Item1, item - 1); break; } // Extent is only element if(item != extent.Item1 || item != extent.Item2) continue; toRemove = extent; break; } // Item not found if(toRemove == null) return false; backend.Remove(toRemove); if(toAddOne != null) backend.Add(toAddOne); if(toAddTwo != null) backend.Add(toAddTwo); // Sort backend = backend.OrderBy(t => t.Item1).ToList(); return true; } /// /// Converts the list of extents to an array of where T1 is first element of the extent and T2 is /// last element /// /// Array of public Tuple[] ToArray() { return backend.ToArray(); } /// /// Gets the first element of the extent that contains the specified item /// /// Item /// First element of extent /// true if item was found in an extent, false otherwise public bool GetStart(uint item, out uint start) { start = 0; foreach(Tuple extent in backend.Where(extent => item >= extent.Item1 && item <= extent.Item2)) { start = extent.Item1; return true; } return false; } } }