/// <summary> /// Creates a union stream reader from the supplied data. /// </summary> /// <param name="streams">all of the tables to combine in the union</param> /// <param name="ownsStream">if this class owns the streams, it will call dispose when <see cref="Dispose"/> is called. /// Otherwise, the streams will not be disposed.</param> public UnionTreeStream(IEnumerable <TreeStream <TKey, TValue> > streams, bool ownsStream) { m_firstStream = null; m_ownsStreams = ownsStream; m_tablesOrigList = streams.Select(x => new BufferedTreeStream(x)).ToArray(); m_sortedArchiveStreams = new UnionTreeStreamSortHelper(m_tablesOrigList); m_readWhileUpperBounds.SetMin(); foreach (var table1 in m_sortedArchiveStreams.Items) { table1.EnsureCache(); } m_sortedArchiveStreams.Sort(); //Remove any duplicates RemoveDuplicatesIfExists(); if (m_sortedArchiveStreams.Items.Length > 0) { m_firstTable = m_sortedArchiveStreams[0]; } else { m_firstTable = null; } SetReadWhileUpperBoundsValue(); }
/// <summary> /// Resorts the entire list. Uses an insertion sort routine /// </summary> public void Sort() { //A insertion sort routine. //Skip first item in list since it will always be sorted correctly for (int itemToInsertIndex = 1; itemToInsertIndex < m_validRecords; itemToInsertIndex++) { BufferedTreeStream itemToInsert = Items[itemToInsertIndex]; int currentIndex = itemToInsertIndex - 1; //While the current item is greater than itemToInsert, shift the value while ((currentIndex >= 0) && (IsLessThan(itemToInsert, Items[currentIndex]))) { Items[currentIndex + 1] = Items[currentIndex]; currentIndex--; } Items[currentIndex + 1] = itemToInsert; } for (int x = m_validRecords - 1; x >= 0; x--) { if (Items[x].IsValid) { m_validRecords = x + 1; break; } if (x == 0) { m_validRecords = 0; } } }
/// <summary> /// Resorts only the item at the specified index assuming: /// 1) all other items are properly sorted /// 2) this items's value increased. /// </summary> /// <param name="index">the index of the item to resort.</param> public void SortAssumingIncreased(int index) { BufferedTreeStream itemToMove = Items[index]; if (!itemToMove.IsValid) { m_validRecords--; for (int x = index; x < m_validRecords; x++) { Items[x] = Items[x + 1]; } Items[m_validRecords] = itemToMove; return; } //ToDo: Consider an exponential search algorithm. int currentIndex = index + 1; while (currentIndex < m_validRecords && Items[currentIndex].CacheKey.IsLessThan(itemToMove.CacheKey)) { Items[currentIndex - 1] = Items[currentIndex]; currentIndex++; } Items[currentIndex - 1] = itemToMove; }
//------------------------------------------------------------- /// <summary> /// Compares two Archive Streams together for proper sorting. /// </summary> /// <param name="item1"></param> /// <param name="item2"></param> /// <returns></returns> private int CompareStreams(BufferedTreeStream item1, BufferedTreeStream item2) { if (!item1.IsValid && !item2.IsValid) { return(0); } if (!item1.IsValid) { return(1); } if (!item2.IsValid) { return(-1); } return(item1.CacheKey.CompareTo(item2.CacheKey));// item1.CurrentKey.CompareTo(item2.CurrentKey); }
private bool IsLessThan(BufferedTreeStream item1, BufferedTreeStream item2) { if (!item1.IsValid && !item2.IsValid) { return(false); } if (!item1.IsValid) { return(false); } if (!item2.IsValid) { return(true); } return(item1.CacheKey.IsLessThan(item2.CacheKey));// item1.CurrentKey.CompareTo(item2.CurrentKey); }
private bool Read2(TKey key, TValue value) { TryAgain: if (m_firstStream == null) { //If m_firstStream == null, this means either: // the value is cached. // or // the end of the stream has occured. if (m_firstTable != null && m_firstTable.IsValid) { //The value is cached. m_firstTable.Read(key, value); m_firstStream = m_firstTable.Stream; return(true); } //The end of the steam has been reached. return(false); } //Condition 1: // The archive stream may no longer be in order and needs to be checked //Response: // Resort the archive stream // //Condition 2: // The end of the frame has been reached //Response: // Advance to the next frame // Also test the edge case where the current point might be equal to the end of the frame // since this is an inclusive filter and ReadWhile is exclusive. // If it's part of the frame, return true after Advancing the frame and the point. // //Since condition 1 and 2 can occur at the same time, verifying the sort of the Archive Stream is a good thing to do. // Will verify that the stream is in the proper order and remove any duplicates that were found. // May be called after every single read, but better to be called // when a ReadWhile function returns false. if (m_sortedArchiveStreams.Items.Length > 1) { //If list is no longer in order int compare = CompareStreams(m_sortedArchiveStreams[0], m_sortedArchiveStreams[1]); if (compare == 0) //A duplicate value was found. { //If a duplicate entry is found, advance the position of the duplicate entry RemoveDuplicatesFromList(); SetReadWhileUpperBoundsValue(); m_firstTable = m_sortedArchiveStreams[0]; } else if (compare > 0) //List is out of order { m_sortedArchiveStreams.SortAssumingIncreased(0); m_firstTable = m_sortedArchiveStreams[0]; SetReadWhileUpperBoundsValue(); } } else { //If only 1 stream, we can't resort, so we are done. if (!m_sortedArchiveStreams[0].IsValid) { return(false); } } m_firstStream = null; //Ensure that the if block is executed when repeating this function call. goto TryAgain; }