//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections;
using System.Collections.Generic;
namespace Microsoft.SqlTools.ServiceLayer.Utility
{
///
/// Collection class that permits storage of over int.MaxValue items. This is performed
/// by using a 2D list of lists. The internal lists are only initialized as necessary. This
/// collection implements IEnumerable to make it easier to run LINQ queries against it.
///
///
/// This class is based on code from $\Data Tools\SSMS_Main\sql\ssms\core\DataStorage\ArrayList64.cs
/// with additions to bring it up to .NET 4.5 standards
///
/// Type of the values to store
public class LongList : IEnumerable
{
#region Member Variables
private int expandListSize = int.MaxValue;
private List> expandedList;
private readonly List shortList;
#endregion
///
/// Creates a new long list
///
public LongList()
{
shortList = new List();
Count = 0;
}
#region Properties
///
/// The total number of elements in the array
///
public long Count { get; private set; }
public T this[long index]
{
get
{
return GetItem(index);
}
}
public int ExpandListSize
{
get
{
return this.expandListSize;
}
internal set
{
this.expandListSize = value;
}
}
#endregion
#region Public Methods
///
/// Adds the specified value to the end of the list
///
/// Value to add to the list
/// Index of the item that was just added
public long Add(T val)
{
if (Count <= this.ExpandListSize)
{
shortList.Add(val);
}
else // need to split values into several arrays
{
if (expandedList == null)
{
// very inefficient so delay as much as possible
// immediately add 0th array
expandedList = new List> {shortList};
}
int arrayIndex = (int)(Count / this.ExpandListSize); // 0 based
List arr;
if (expandedList.Count <= arrayIndex) // need to make a new array
{
arr = new List();
expandedList.Add(arr);
}
else // use existing array
{
arr = expandedList[arrayIndex];
}
arr.Add(val);
}
return (++Count);
}
///
/// Returns the item at the specified index
///
/// Index of the item to return
/// The item at the index specified
public T GetItem(long index)
{
T val = default(T);
if (Count <= this.ExpandListSize)
{
int i32Index = Convert.ToInt32(index);
val = shortList[i32Index];
}
else
{
int iArray32Index = (int) (Count / this.ExpandListSize);
if (expandedList.Count > iArray32Index)
{
List arr = expandedList[iArray32Index];
int i32Index = (int) (Count % this.ExpandListSize);
if (arr.Count > i32Index)
{
val = arr[i32Index];
}
}
}
return val;
}
///
/// Removes an item at the specified location and shifts all the items after the provided
/// index up by one.
///
/// The index to remove from the list
public void RemoveAt(long index)
{
if (Count <= this.ExpandListSize)
{
int iArray32MemberIndex = Convert.ToInt32(index); // 0 based
shortList.RemoveAt(iArray32MemberIndex);
}
else // handle the case of multiple arrays
{
// find out which array it is in
int arrayIndex = (int) (index / this.ExpandListSize);
List arr = expandedList[arrayIndex];
// find out index into this array
int iArray32MemberIndex = (int) (index % this.ExpandListSize);
arr.RemoveAt(iArray32MemberIndex);
// now shift members of the array back one
int iArray32TotalIndex = (int) (Count / this.ExpandListSize);
for (int i = arrayIndex + 1; i < iArray32TotalIndex; i++)
{
List arr1 = expandedList[i - 1];
List arr2 = expandedList[i];
arr1.Add(arr2[this.ExpandListSize - 1]);
arr2.RemoveAt(0);
}
}
--Count;
}
#endregion
#region IEnumerable