/// <summary>Finds the location of an element in the array</summary> /// <param name="value">Value of the element to search for.</param> /// <param name="offset">Receives the offset of the element inside the level if found; otherwise, 0.</param> /// <returns>Level that contains the element if found; otherwise, -1.</returns> public int Find(T value, out int offset, out T actualValue) { if ((m_count & 1) != 0) { // If someone gets the last inserted key, there is a 50% change that it is in the root // (if not, it will the the last one of the first non-empty level) if (m_comparer.Compare(value, m_root[0]) == 0) { offset = 0; actualValue = m_root[0]; return(0); } } var levels = m_levels; for (int i = 1; i < levels.Length; i++) { if (IsFree(i)) { // this segment is not allocated continue; } int p = ColaStore.BinarySearch <T>(levels[i], 0, 1 << i, value, m_comparer); if (p >= 0) { offset = p; actualValue = levels[i][p]; return(i); } } offset = 0; actualValue = default(T); return(NOT_FOUND); }
/// <summary>Search for the smallest element that is larger than a reference element</summary> /// <param name="value">Reference element</param> /// <param name="orEqual">If true, return the position of the value itself if it is found. If false, return the position of the closest value that is smaller.</param> /// <param name="offset">Receive the offset within the level of the next element, or 0 if not found</param> /// <param name="result">Receive the value of the next element, or default(T) if not found</param> /// <returns>Level of the next element, or -1 if <param name="result"/> was already the largest</returns> public static int FindNext <T>(T[][] levels, int count, T value, bool orEqual, IComparer <T> comparer, out int offset, out T result) { int level = NOT_FOUND; T min = default(T); int minOffset = 0; // scan each segment for a value that would be larger, keep track of the smallest found for (int i = 0; i < levels.Length; i++) { if (ColaStore.IsFree(i, count)) { continue; } var segment = levels[i]; int pos = ColaStore.BinarySearch <T>(segment, 0, segment.Length, value, comparer); if (pos >= 0) { // we found an exact match in this segment if (orEqual) { offset = pos; result = segment[pos]; return(i); } // the next item in this segment should be larger ++pos; } else { // we found where it would be stored in this segment pos = ~pos; } if (pos < segment.Length) { if (level == NOT_FOUND || comparer.Compare(segment[pos], min) < 0) { // we found a better candidate min = segment[pos]; level = i; minOffset = pos; } } } offset = minOffset; result = min; return(level); }
/// <summary>Search for the largest element that is smaller than a reference element</summary> /// <param name="value">Reference element</param> /// <param name="orEqual">If true, return the position of the value itself if it is found. If false, return the position of the closest value that is smaller.</param> /// <param name="offset">Receive the offset within the level of the previous element, or 0 if not found</param> /// <param name="result">Receive the value of the previous element, or default(T) if not found</param> /// <returns>Level of the previous element, or -1 if <param name="result"/> was already the smallest</returns> public static int FindPrevious <T>(T[][] levels, int count, T value, bool orEqual, IComparer <T> comparer, out int offset, out T result) { int level = NOT_FOUND; T max = default(T); int maxOffset = 0; // scan each segment for a value that would be smaller, keep track of the smallest found for (int i = 0; i < levels.Length; i++) { if (ColaStore.IsFree(i, count)) { continue; } var segment = levels[i]; int pos = ColaStore.BinarySearch <T>(segment, 0, segment.Length, value, comparer); // the previous item in this segment should be smaller if (pos < 0) { // it is not pos = ~pos; } else if (orEqual) { // we found an exact match in this segment offset = pos; result = segment[pos]; return(i); } --pos; if (pos >= 0) { if (level == NOT_FOUND || comparer.Compare(segment[pos], max) > 0) { // we found a better candidate max = segment[pos]; level = i; maxOffset = pos; } } } offset = maxOffset; result = max; return(level); }
public static IEnumerable <T> FindBetween <T>(T[][] levels, int count, T begin, bool beginOrEqual, T end, bool endOrEqual, int limit, IComparer <T> comparer) { if (limit > 0) { for (int i = 0; i < levels.Length; i++) { if (ColaStore.IsFree(i, count)) { continue; } var segment = levels[i]; int to = ColaStore.BinarySearch <T>(segment, 0, segment.Length, end, comparer); if (to >= 0) { if (!endOrEqual) { to--; } } else { to = ~to; } if (to < 0 || to >= segment.Length) { continue; } int from = ColaStore.BinarySearch <T>(segment, 0, segment.Length, begin, comparer); if (from >= 0) { if (!beginOrEqual) { ++from; } } else { from = ~from; } if (from >= segment.Length) { continue; } if (from > to) { continue; } for (int j = from; j <= to && limit > 0; j++) { yield return(segment[j]); --limit; } if (limit <= 0) { break; } } } }