File: src\Compilers\Core\Portable\InternalUtilities\ArrayExtensions.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Diagnostics;
 
namespace Roslyn.Utilities
{
    internal static class ArrayExtensions
    {
        internal static T[] Copy<T>(this T[] array, int start, int length)
        {
            // It's ok for 'start' to equal 'array.Length'.  In that case you'll
            // just get an empty array back.
            Debug.Assert(start >= 0);
            Debug.Assert(start <= array.Length);
 
            if (start + length > array.Length)
            {
                length = array.Length - start;
            }
 
            T[] newArray = new T[length];
            Array.Copy(array, start, newArray, 0, length);
            return newArray;
        }
 
        internal static T[] InsertAt<T>(this T[] array, int position, T item)
        {
            T[] newArray = new T[array.Length + 1];
            if (position > 0)
            {
                Array.Copy(array, newArray, position);
            }
 
            if (position < array.Length)
            {
                Array.Copy(array, position, newArray, position + 1, array.Length - position);
            }
 
            newArray[position] = item;
            return newArray;
        }
 
        internal static T[] Append<T>(this T[] array, T item)
        {
            return InsertAt(array, array.Length, item);
        }
 
        internal static T[] InsertAt<T>(this T[] array, int position, T[] items)
        {
            T[] newArray = new T[array.Length + items.Length];
            if (position > 0)
            {
                Array.Copy(array, newArray, position);
            }
 
            if (position < array.Length)
            {
                Array.Copy(array, position, newArray, position + items.Length, array.Length - position);
            }
 
            items.CopyTo(newArray, position);
            return newArray;
        }
 
        internal static T[] Append<T>(this T[] array, T[] items)
        {
            return InsertAt(array, array.Length, items);
        }
 
        internal static T[] RemoveAt<T>(this T[] array, int position)
        {
            return RemoveAt(array, position, 1);
        }
 
        internal static T[] RemoveAt<T>(this T[] array, int position, int length)
        {
            if (position + length > array.Length)
            {
                length = array.Length - position;
            }
 
            T[] newArray = new T[array.Length - length];
            if (position > 0)
            {
                Array.Copy(array, newArray, position);
            }
 
            if (position < newArray.Length)
            {
                Array.Copy(array, position + length, newArray, position, newArray.Length - position);
            }
 
            return newArray;
        }
 
        internal static T[] ReplaceAt<T>(this T[] array, int position, T item)
        {
            T[] newArray = new T[array.Length];
            Array.Copy(array, newArray, array.Length);
            newArray[position] = item;
            return newArray;
        }
 
        internal static T[] ReplaceAt<T>(this T[] array, int position, int length, T[] items)
        {
            return InsertAt(RemoveAt(array, position, length), position, items);
        }
 
        internal static void ReverseContents<T>(this T[] array)
        {
            ReverseContents(array, 0, array.Length);
        }
 
        internal static void ReverseContents<T>(this T[] array, int start, int count)
        {
            int end = start + count - 1;
            for (int i = start, j = end; i < j; i++, j--)
            {
                T tmp = array[i];
                array[i] = array[j];
                array[j] = tmp;
            }
        }
 
        // same as Array.BinarySearch, but without using IComparer to compare ints
        internal static int BinarySearch(this int[] array, int value)
        {
            var low = 0;
            var high = array.Length - 1;
 
            while (low <= high)
            {
                var middle = low + ((high - low) >> 1);
                var midValue = array[middle];
 
                if (midValue == value)
                {
                    return middle;
                }
                else if (midValue > value)
                {
                    high = middle - 1;
                }
                else
                {
                    low = middle + 1;
                }
            }
 
            return ~low;
        }
 
        public static bool SequenceEqual<T>(this T[]? first, T[]? second, Func<T, T, bool> comparer)
        {
            RoslynDebug.Assert(comparer != null);
 
            if (first == second)
            {
                return true;
            }
 
            if (first == null || second == null || first.Length != second.Length)
            {
                return false;
            }
 
            for (var i = 0; i < first.Length; i++)
            {
                if (!comparer(first[i], second[i]))
                    return false;
            }
 
            return true;
        }
 
        /// <summary>
        /// Search a sorted integer array for the target value in O(log N) time.
        /// </summary>
        /// <param name="array">The array of integers which must be sorted in ascending order.</param>
        /// <param name="value">The target value.</param>
        /// <returns>An index in the array pointing to the position where <paramref name="value"/> should be
        /// inserted in order to maintain the sorted order. All values to the right of this position will be
        /// strictly greater than <paramref name="value"/>. Note that this may return a position off the end
        /// of the array if all elements are less than or equal to <paramref name="value"/>.</returns>
        internal static int BinarySearchUpperBound(this int[] array, int value)
        {
            int low = 0;
            int high = array.Length - 1;
 
            while (low <= high)
            {
                int middle = low + ((high - low) >> 1);
                if (array[middle] > value)
                {
                    high = middle - 1;
                }
                else
                {
                    low = middle + 1;
                }
            }
 
            return low;
        }
    }
}