
Namespace System
Namespace Collections
Namespace Generic

Namespace Detail
	Class PointerEnumerator<T>
		Implements IEnumerator<T>
	Public
		Sub PointerEnumerator(ptr As *T, count As Long)
			p = ptr
			n = count
			cur = -1
		End Sub

		Function MoveNext() As Boolean
			cur++
			MoveNext = (cur <> n)
		End Function

		Sub Reset()
			n = -1
		End Sub

		Function Current() As T
			Current = p[cur]
		End Function

		Virtual Sub Dispose()
			p = NULL
			n = 0
			cur = -1
		End Sub
	Private
		p As *T
		n As Long
		cur As Long
	End Class
End Namespace

Class List<T>
	Inherits IList<T>

	items As *T
	capacity As Long
	count As Long

	Sub Realloc( allocateSize As Long )
		items = realloc( items, allocateSize * SizeOf(T) )
		capacity = allocateSize
	End Sub

	Sub _Initialize( capacity As Long )
		This.items = GC_malloc( capacity * SizeOf(T) )
		This.capacity = capacity
	End Sub

	Sub SetLeastCapacity( capacity As Long )
		If This.capacity < capacity Then
			Realloc(capacity)
		End If
	End Sub
Public
	Sub List()
		_Initialize(16)
	End Sub

	/*!
	@brief	予め要素数を指定してList<T>を初期化
	@author	NoWest
	@date	2008/07/13
	@param	リストの要素数
	*/
	Sub List( capacity As Long )
		_Initialize( capacity )
	End Sub

	/*!
	@brief	既存の配列List<T>を初期化
	@author	NoWest
	@date	2008/07/13
	@param	インデックス
	*/
	Sub List( array As *T, length As Long )
		_Initialize( length )

		memmove( This.items, array, length * SizeOf(T) )
		This.count = length
	End Sub

	/*!
	@brief	インデクサ
	@author	Daisuke Yamamoto
	@date	2007/08/22
	@param	インデックス
	*/
	Override Sub Operator[] ( index As Long, item As T )
		Item[index] = item
	End Sub
	Override Function Operator[] ( index As Long ) As T
		Return Item[index]
	End Function

	/*!
	@brief	インデクサ
	@author	Egtra
	@date	2008/08/04
	@param	インデックス
	*/
	Override Sub Item( index As Long, item As T )
		If 0 <= index And index < capacity Then
			items[index]=item
		Else
			Throw New ArgumentOutOfRangeException("index")
		End If
	End Sub
	Override Function Item( index As Long ) As T
		If 0 <= index And index < capacity Then
			Return items[index]
		Else
			Throw New ArgumentOutOfRangeException("index")
		End If
	End Function
	/*!
	@brief	ポインタ型へのキャスト
	@author	Daisuke Yamamoto
	@date	2007/08/22
	@param	インデックス
	*/
	Function Operator() As *T
		Return items
	End Function


	'----------------------------------------------------------------
	' パブリック プロパティ
	'----------------------------------------------------------------

	/*!
	@brief	Listに格納されている要素の数を取得する
	@author	Daisuke Yamamoto
	@date	2007/08/22
	*/
	Override Function Count() As Long
		Return This.count
	End Function

	Const Function Capacity() As Long
		Return This.capacity
	End Function

	Sub Capacity(c As Long)
		If c <> capacity Then
			If c < capacity Then
				Throw New ArgumentOutOfRangeException("capacity")
			Else
				Realloc(c)
			End If
		End If
	End Sub
	
	/*!
	@brief	Listが読み込み専用かどうかを取得する
	@author	NoWest
	@date	2008/07/12
	*/
	Override Function IsReadOnly() As Boolean
		Return False
	End Function

	'----------------------------------------------------------------
	' パブリック メソッド
	'----------------------------------------------------------------

	/*!
	@brief	Listの末端に要素を追加する
	@author	Daisuke Yamamoto
	@date	2007/08/22
	@param	追加するオブジェクト
	*/
	Override Sub Add( item As T )
		SetLeastCapacity(This.count + 1)
		This.items[ This.count ] = item
		This.count++
	End Sub

'	Function AsReadOnly() As ReadOnlyCollection

	/*!
	@brief	Listからすべての要素を削除する
	@author	Daisuke Yamamoto
	@date	2007/08/22
	*/
	Override Sub Clear()
		This.count = 0
	End Sub

/*	Override Function Contains ( item As T ) As Boolean
		TODO
	End Function*/

	/*!
	@brief	List内から、最初に出現する値のインデックスを取得する
	@author	Daisuke Yamamoto
	@date	2007/08/22
	@return	インデックス（見つからなかったときは-1）
	*/
	Override Function IndexOf( item As T ) As Long
		Dim i As Long
		For i = 0 To ELM( This.count )
			If items[i].Equals(item) Then
				Return i
			End If
		Next
		Return -1
	End Function

	/*!
	@brief	List内の指定したインデックスの位置に要素を挿入する
	@author	Daisuke Yamamoto
	@date	2007/08/22
	*/
	Override Sub Insert( index As Long, item As T )
		SetLeastCapacity(This.count + 1)
		memmove( items + (index+1)*SizeOf(T), items + index*SizeOf(T), (This.count - index)*SizeOf(T) )
		items[index] = item
		This.count++
	End Sub

	/*!
	@brief	List内で最初に出現する値を削除する
	@author	Daisuke Yamamoto
	@date	2007/09/28
	@return	値が削除されたときはTrue、されなかったときはFlaseが返る
	*/
	Override Function Remove( item As T ) As Boolean
		Dim index = IndexOf( item )
		If index = -1 Then
			Return False
		End If

		removeAtImpl( index )
		Return True
	End Function

	/*!
	@brief	List内の指定したインデックスの要素を削除する
	@author	Daisuke Yamamoto
	@date	2007/10/03
	*/
	Override Sub RemoveAt( index As Long )
		If 0 <= index And index < capacity Then
			removeAtImpl( index )
		Else
			Throw New ArgumentOutOfRangeException("index")
		End If
	End Sub
Private
	Sub removeAtImpl( index As Long )
		memmove( items + index*SizeOf(T), items + (index+1)*SizeOf(T), (This.count - (index+1))*SizeOf(T) )
		This.count--
	End Sub 

Public

	/*!
	@brief  Listの要素を文字列で返す
	@author OverTaker
	@date   2008/6/26
	@return 文字列
	*/
	Override Function ToString() As String
		Dim string = New Text.StringBuilder
		Dim i As Long
		For i = 0 To ELM( This.count )
			string.Append(This[i]).Append(Ex"\r\n")
		Next
		Return string.ToString
	End Function

	/*!
	@brief	実際の要素数が現在の容量の 90% 未満の場合は、容量をその数に設定します
	@author	NoWest
	@date	2008/07/20
	*/
	Sub TrimExcess ()
		If ( This.capacity ) * 0.9 > This.count Then
			Realloc( This.count )
		End If
	End Sub

	/*!
	@brief	IEnumeratorインターフェイスを取得する
	@author	Daisuke Yamamoto
	@date	2007/11/19
	@return	IEnumeratorインターフェイスが返る
	*/
	Override Function GetEnumerator() As IEnumerator<T>
		Return New Detail.PointerEnumerator<T>(items, count)
	End Function
End Class


End Namespace
End Namespace
End Namespace
