Fixed ArrayListEnumerator's NextObject and PreviousObject

Strict

Import assert

#Rem
Monkey Collections Framework
Based loosely on the Java Collections Framework
#End

'''' Top level Collection stuff ''''

#Rem
	AbstractCollection
	Due to limitations with generics in Monkey, ToArray cannot work with an array of type E.  We must return Object[] instead.
#End
Class AbstractCollection<E> Abstract
Private
	' A custom comparator to use for sorting and comparing items.
	Field comparator:AbstractComparator = Null

Public
' Abstract
	Method Add:Bool(o:E) Abstract
	Method AddAll:Bool(c:AbstractCollection<E>) Abstract
	Method Clear:Void() Abstract
	Method Contains:Bool(o:E) Abstract
	Method ContainsAll:Bool(c:AbstractCollection<E>) Abstract
	Method Enumerator:AbstractEnumerator<E>() Abstract
	Method FillArray:Int(arr:Object[]) Abstract ' populates the passed array and returns the number of items filled. best used for android
	Method IsEmpty:Bool() Abstract
	Method Remove:Bool(o:E) Abstract
	Method RemoveAll:Bool(c:AbstractCollection<E>) Abstract
	Method RetainAll:Bool(c:AbstractCollection<E>) Abstract
	Method Size:Int() Property Abstract
	Method Sort:Void(reverse:Bool = False, comp:AbstractComparator = Null) Abstract
	Method ToArray:Object[]() Abstract ' creates a new array of the correct size and returns it

' Methods
	Method ObjectEnumerator:AbstractEnumerator<E>()
		Return Enumerator()
	End

' Properties
	' Property to read comparator
	Method Comparator:AbstractComparator() Property
		Return comparator
	End

	' Property to write comparator
	Method Comparator:Void(comparator:AbstractComparator) Property
		Self.comparator = comparator
	End
End

#Rem
	AbstractEnumerator
	Used in the ObjectEnumerator method for calls to EachIn.
	If retrieved and used manually, the HasPrevious/PreviousObject/Remove/First/Last methods can be called.
#End
Class AbstractEnumerator<E>
' Abstract
	Method HasNext:Bool() Abstract
	Method HasPrevious:Bool() Abstract
	Method NextObject:E() Abstract
	Method PreviousObject:E() Abstract
	Method Remove:Void() Abstract
	Method First:Void() Abstract
	Method Last:Void() Abstract
	Method Reset:Void() Abstract
End

#Rem
	IComparable
	Allows developers to sort a collection without using a Comparator.  Each class is responsible
	for providing its own logic to determine how it should be sorted.
#End
Interface IComparable
	Method Compare:Int(o:Object)
	Method CompareBool:Bool(o:Object)
End

#Rem
	AbstractComparator
	This is a way for developers to provide a custom comparison method for sorting lists.
	It's sort of like a function pointer.
#End
Class AbstractComparator Abstract
' Abstract
	Method Compare:Int(o1:Object, o2:Object) Abstract

' Methods
	Method CompareBool:Bool(o1:Object, o2:Object)
		Return o1 = o2 Or Compare(o1, o2) = 0
	End

	Method HashCode:Int(o:Object)
		Return 0
	End
End

#Rem
	DefaultComparator
	Implements an AbstractComparator to handle primitive wrappers and strings.
#End
Global DEFAULT_COMPARATOR:DefaultComparator = New DefaultComparator
Class DefaultComparator Extends AbstractComparator
' Methods
	' Overrides AbstractComparator
	Method Compare:Int(o1:Object, o2:Object)
		If IntObject(o1) <> Null And IntObject(o2) <> Null Then
			If IntObject(o1).value < IntObject(o2).value Then Return -1
			If IntObject(o1).value > IntObject(o2).value Then Return 1
			Return 0
		ElseIf FloatObject(o1) <> Null And FloatObject(o2) <> Null Then
			If FloatObject(o1).value < FloatObject(o2).value Then Return -1
			If FloatObject(o1).value > FloatObject(o2).value Then Return 1
			Return 0
		ElseIf StringObject(o1) <> Null And StringObject(o2) <> Null Then
			If StringObject(o1).value < StringObject(o2).value Then Return -1
			If StringObject(o1).value > StringObject(o2).value Then Return 1
			Return 0
		End
		If o1 = o2 Then Return 0
		If o1 = Null Then Return -1
		If o2 = Null Then Return 1
		Return 0 ' don't know what to do!
	End

	' Overrides AbstractComparator
	Method CompareBool:Bool(o1:Object, o2:Object)
		If IntObject(o1) <> Null And IntObject(o2) <> Null Then
			Return IntObject(o1).value = IntObject(o2).value
		ElseIf FloatObject(o1) <> Null And FloatObject(o2) <> Null Then
			Return FloatObject(o1).value = FloatObject(o2).value
		ElseIf StringObject(o1) <> Null And StringObject(o2) <> Null Then
			Return StringObject(o1).value = StringObject(o2).value
		End
		Return o1 = o2
	End
End

'''' List stuff ''''

#Rem
	AbstractList
	Extends AbstractCollection to implement some of the abstract methods that apply to any kind of list.
#End
Class AbstractList<E> Extends AbstractCollection<E> Abstract
Private
	' If true, bounds checking should be performed.
#if CONFIG="debug"
	Field rangeChecking:Bool = True
#else
	Field rangeChecking:Bool = False
#end

	' A counter for modifications to the list.  Used for concurrency checks.
	Field modCount:Int = 0

	' Performs a range check.
	Method RangeCheck:Void(index:Int)
		Local size:Int = Self.Size()
		' range check doesn't use assert, for speed
		If index < 0 Or index >= size Then AssertError("AbstractList.RangeCheck: Index out of bounds: " + index + " is not 0<=index<" + size)
	End

Public
' Abstract
	Method AddLast:Bool(o:E) Abstract
	Method RemoveLast:E() Abstract
	Method GetLast:E() Abstract
	Method AddFirst:Bool(o:E) Abstract
	Method RemoveFirst:E() Abstract
	Method GetFirst:E() Abstract
	Method Get:E(index:Int) Abstract
	Method Insert:Void(index:Int, o:E) Abstract
	Method InsertAll:Bool(index:Int, c:AbstractCollection<E>) Abstract
	Method IndexOf:Int(o:E) Abstract
	Method LastIndexOf:Int(o:E) Abstract
	Method RemoveAt:E(index:Int) Abstract ' Can't overload Remove since it's an inherited method, and Monkey doesn't support that.
	Method RemoveRange:Void(fromIndex:Int, toIndex:Int) Abstract
	Method Set:E(index:Int, o:E) Abstract

' Methods
	' Overrides AbstractCollection
	Method Enumerator:AbstractEnumerator<E>()
		Return New ListEnumerator<E>(Self)
	End

' Properties
	' Property to read rangeChecking
	Method RangeChecking:Bool() Property
		Return rangeChecking
	End

	' Property to write rangeChecking
	Method RangeChecking:Void(rangeChecking:Bool) Property
		Self.rangeChecking = rangeChecking
	End
End

#Rem
	ListEnumerator
	Extends AbstractEnumerator to provide support for EachIn.  Blocks concurrent modification, but allows elements to be removed on the fly.
#End
Class ListEnumerator<E> Extends AbstractEnumerator<E>
Private
	Field lst:AbstractList<E>
	Field lastIndex:Int = 0
	Field index:Int = 0
	Field expectedModCount:Int = 0

	Method CheckConcurrency:Void()
		' for speed we don't use assert
		If lst.modCount <> expectedModCount Then AssertError("ListEnumerator.CheckConcurrency: Concurrent list modification")
	End

Public
' Constructors
	Method New(lst:AbstractList<E>)
		Self.lst = lst
		expectedModCount = lst.modCount
	End

' Methods
	' Overrides AbstractEnumerator
	Method HasNext:Bool()
		CheckConcurrency()
		Return index < lst.Size
	End

	' Overrides AbstractEnumerator
	Method HasPrevious:Bool()
		CheckConcurrency()
		Return index > 0
	End

	' Overrides AbstractEnumerator
	Method NextObject:E()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex)
	End

	' Overrides AbstractEnumerator
	Method PreviousObject:E()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex)
	End

	' Overrides AbstractEnumerator
	Method Remove:Void()
		CheckConcurrency()
		lst.RemoveAt(lastIndex)
		If lastIndex < index Then index -= 1
		lastIndex = -1
		expectedModCount = lst.modCount
	End

	' Overrides AbstractEnumerator
	Method First:Void()
		CheckConcurrency()
		index = 0
	End

	' Overrides AbstractEnumerator
	Method Last:Void()
		CheckConcurrency()
		index = lst.Size
	End

	' Overrides AbstractEnumerator
	Method Reset:Void()
		index = 0
		expectedModCount = lst.modCount
	End
End

#Rem
	ArrayListEnumerator
	Extends ListEnumerator to avoid some method calls.
#End
Class ArrayListEnumerator<E> Extends ListEnumerator<E>
Private
	Field alst:ArrayList<E>

Public
' Constructors
	Method New(lst:ArrayList<E>)
		Super.New(lst)
		Self.alst = lst
		expectedModCount = alst.modCount
	End

' Methods
	' Overrides ListEnumerator
	Method HasNext:Bool()
		CheckConcurrency()
		Return index < alst.size
	End

	' Overrides ListEnumerator
	Method NextObject:E()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return E(alst.elements[lastIndex])
	End

	' Overrides ListEnumerator
	Method PreviousObject:E()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return E(alst.elements[lastIndex])
	End
End

Class IntListEnumerator Extends ListEnumerator<IntObject>
' Constructors
	Method New(lst:AbstractList<IntObject>)
		Super.New(lst)
	End

' Methods
	Method NextInt:Int()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousInt:Int()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

Class FloatListEnumerator Extends ListEnumerator<FloatObject>
' Constructors
	Method New(lst:AbstractList<FloatObject>)
		Super.New(lst)
	End

' Methods
	Method NextFloat:Float()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousFloat:Float()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

Class StringListEnumerator Extends ListEnumerator<StringObject>
' Constructors
	Method New(lst:AbstractList<IntObject>)
		Super.New(lst)
	End

' Methods
	Method NextString:String()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousString:String()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

#Rem
	ArrayList
	Concrete implementation of AbstractList that uses a dynamically sized array to store elements.
	Has best performance when it is initialised with a capacity large enough to hold the expected number of elements.
#End
Class ArrayList<E> Extends AbstractList<E>
Private
	' fields
	Field elements:Object[]
	Field size:Int = 0

	' resizes the elements array if necessary to ensure it can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			modCount += 1
		End
	End

	Method RangeCheck:Void(index:Int)
		' range check doesn't use assert, for speed
		If index < 0 Or index >= size Then AssertError("ArrayList.RangeCheck: Index out of bounds: " + index + " is not 0<=index<" + size)
	End

	Field tempArr:Object[] = New Object[128] ' temp array used for internal call to ToArray (so we don't create an object)

Public
' Constructors
	Method New()
		Self.elements = New Object[10]
	End

	Method New(initialCapacity:Int)
		AssertGreaterThanOrEqualInt(initialCapacity, 0, "ArrayList.New: Illegal Capacity:")
		Self.elements = New Object[initialCapacity]
	End

	Method New(c:AbstractCollection<E>)
		elements = c.ToArray()
		size = elements.Length
	End

' Methods
	' Overrides AbstractCollection
	Method Add:Bool(o:E)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = o
		size+=1
		modCount += 1
		Return True
	End

	' Overrides AbstractCollection
	Method AddAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return False
		Local newItemCount:Int = c.Size
		If size + newItemCount > elements.Length Then EnsureCapacity(size+newItemCount)
		If tempArr.Length < newItemCount Then tempArr = tempArr.Resize(newItemCount)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			elements[size] = tempArr[i]
			size+=1
		End
		modCount += 1
		Return newItemCount <> 0
	End

	' Overrides AbstractCollection
	Method Clear:Void()
		For Local i:Int = 0 Until size
			elements[i] = Null
		Next
		modCount += 1
		size = 0
	End

	' Overrides AbstractCollection
	Method Contains:Bool(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then Return True
		Next
		Return False
	End

	' Overrides AbstractCollection
	Method ContainsAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return True
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Not Self.Contains(E(tempArr[i])) Then Return False
		Next
		Return True
	End

	' Overrides AbstractCollection
	Method Enumerator:AbstractEnumerator<E>()
		Return New ArrayListEnumerator<E>(Self)
	End

	' Overrides AbstractCollection
	Method FillArray:Int(arr:Object[])
		AssertGreaterThanOrEqualInt(arr.Length, size, "ArrayList.FillArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = elements[i]
		Next
		Return size
	End

	' Overrides AbstractCollection
	Method IsEmpty:Bool()
		Return size = 0
	End

	' Overrides AbstractCollection
	Method Remove:Bool(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	' Overrides AbstractCollection
	Method RemoveAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return False
		Local modified:Bool = False
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Self.Contains(E(tempArr[i])) Then
				Self.Remove(E(tempArr[i]))
			End
		Next
		If modified Then modCount += 1
		Return modified
	End

	' Overrides AbstractCollection
	Method RetainAll:Bool(c:AbstractCollection<E>)
		Local modified:Bool = False
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Not Self.Contains(E(tempArr[i])) Then
				Self.Remove(E(tempArr[i]))
				modified = True
			End
		Next
		If modified Then modCount += 1
		Return modified
	End

	' Overrides AbstractCollection
	Method Size:Int() Property
		Return size
	End

	' Overrides AbstractCollection
	Method Sort:Void(reverse:Bool = False, comp:AbstractComparator = Null)
		If size <= 1 Then Return ' can't sort 0 or 1 elements
		If comp = Null Then comp = Self.Comparator
		If comp = Null Then comp = DEFAULT_COMPARATOR
		QuickSort(elements, 0, size-1, comp, reverse)
		modCount += 1
	End

	' Overrides AbstractCollection
	Method ToArray:Object[]()
		Local arr:Object[] = New Object[size]
		For Local i:Int = 0 Until size
			arr[i] = elements[i]
		Next
		Return arr
	End

	' Overrides AbstractList
	Method AddLast:Bool(o:E)
		Return Add(o)
	End

	' Overrides AbstractList
	Method RemoveLast:E()
		Return RemoveAt(size-1)
	End

	' Overrides AbstractList
	Method GetLast:E()
		Return Get(size-1)
	End

	' Overrides AbstractList
	Method AddFirst:Bool(o:E)
		Insert(0, o)
		Return True
	End

	' Overrides AbstractList
	Method RemoveFirst:E()
		Return Remove(0)
	End

	' Overrides AbstractList
	Method GetFirst:E()
		Return Get(0)
	End

	' Overrides AbstractList
	Method Get:E(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return E(elements[index])
	End

	' Overrides AbstractList
	Method Insert:Void(index:Int, o:E)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = o
		size+=1
		modCount += 1
	End

	' Overrides AbstractList
	Method InsertAll:Bool(index:Int, c:AbstractCollection<E>)
		Local newItemCount:Int = c.Size
		If newItemCount = 0 Then Return False
		If size + newItemCount > elements.Length Then EnsureCapacity(size+newItemCount)
		If tempArr.Length < newItemCount Then tempArr = tempArr.Resize(newItemCount)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = size - 1 To index Step -1
			elements[i+newItemCount] = elements[i]
		Next
		For Local i:Int = 0 Until newItemCount
			elements[index+i] = tempArr[i]
		End
		size += newItemCount
		modCount += 1
		Return newItemCount <> 0
	End

	' Overrides AbstractList
	Method IndexOf:Int(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then Return i
		Next
		Return -1
	End

	' Overrides AbstractList
	Method LastIndexOf:Int(o:E)
		For Local i:Int = size-1 To 0 Step -1
			If elements[i] = o Then Return i
		Next
		Return -1
	End

	' Overrides AbstractList
	Method RemoveAt:E(index:Int)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:E = E(elements[index])
		For Local i:Int = index Until size-1
			elements[i] = elements[i+1]
		Next
		elements[size-1] = Null
		size-=1
		modCount += 1
		Return oldValue
	End

	' Overrides AbstractList
	Method RemoveRange:Void(fromIndex:Int, toIndex:Int)
		AssertLessThanOrEqualInt(fromIndex, toIndex, "ArrayList.RemoveRange: fromIndex > toIndex:")
		If rangeChecking Then
			RangeCheck(fromIndex)
			RangeCheck(toIndex)
		End
		For Local i:Int = 0 Until toIndex - fromIndex
			RemoveAt(fromIndex)
		Next
	End

	' Overrides AbstractList
	Method Set:E(index:Int, o:E)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:E = E(elements[index])
		elements[index] = o
		modCount += 1
		Return oldValue
	End
End

' ArrayList wrapper classes

Class IntArrayList Extends ArrayList<IntObject>
' Methods
	Method AddInt:Bool(o:Int)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = New IntObject(o)
		size+=1
		modCount += 1
		Return True
	End

	Method ContainsInt:Bool(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	' Overrides ArrayList
	Method Enumerator:AbstractEnumerator<IntObject>()
		Return New IntListEnumerator(Self)
	End

	Method RemoveInt:Bool(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToIntArray:Int[]()
		Local arr:Int[] = New Int[size]
		For Local i:Int = 0 Until size
			arr[i] = IntObject(elements[i]).value
		Next
		Return arr
	End

	Method GetInt:Int(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return IntObject(elements[index]).value
	End

	Method InsertInt:Void(index:Int, o:Int)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New IntObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfInt:Int(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfInt:Int(o:E)
		For Local i:Int = size-1 To 0 Step -1
			If IntObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetInt:Int(index:Int, o:Int)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:Int = IntObject(elements[index]).value
		If elements[index] <> Null Then
			IntObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillIntArray:Int(arr:Int[])
		AssertLessThanInt(arr.Length, size, "IntArrayList.FillIntArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = IntObject(elements[i]).value
		Next
		Return size
	End
End

Class FloatArrayList Extends ArrayList<FloatObject>
' Methods
	Method AddFloat:Bool(o:Float)
		If size + 1 > elements.Length Then EnsureCapacity(size + 1)
		elements[size] = New FloatObject(o)
		size += 1
		modCount += 1
		Return True
	End

	Method ContainsFloat:Bool(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	' Overrides ArrayList
	Method Enumerator:AbstractEnumerator<FloatObject>()
		Return New FloatListEnumerator(Self)
	End

	Method RemoveFloat:Bool(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToFloatArray:Float[]()
		Local arr:Float[] = New Float[size]
		For Local i:Int = 0 Until size
			arr[i] = FloatObject(elements[i]).value
		Next
		Return arr
	End

	Method GetFloat:Float(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return FloatObject(elements[index]).value
	End

	Method InsertFloat:Void(index:Int, o:Float)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New FloatObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfFloat:Int(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfFloat:Int(o:Float)
		For Local i:Int = size-1 To 0 Step -1
			If FloatObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetFloat:Float(index:Int, o:Float)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:Float = FloatObject(elements[index]).value
		If elements[index] <> Null Then
			FloatObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillFloatArray:Int(arr:Float[])
		AssertLessThanInt(arr.Length, size, "FloatArrayList.FillFloatArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = FloatObject(elements[i]).value
		Next
		Return size
	End
End

Class StringArrayList Extends ArrayList<StringObject>
' Methods
	Method AddString:Bool(o:String)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = New StringObject(o)
		size+=1
		modCount += 1
		Return True
	End

	Method ContainsString:Bool(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	' Overrides ArrayList
	Method Enumerator:AbstractEnumerator<StringObject>()
		Return New StringListEnumerator(Self)
	End

	Method RemoveString:Bool(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToStringArray:String[]()
		Local arr:String[] = New String[size]
		For Local i:Int = 0 Until size
			arr[i] = StringObject(elements[i]).value
		Next
		Return arr
	End

	Method GetString:String(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return StringObject(elements[index]).value
	End

	Method InsertString:Void(index:Int, o:String)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New StringObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfString:Int(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfString:Int(o:String)
		For Local i:Int = size-1 To 0 Step -1
			If StringObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetString:String(index:Int, o:String)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:String = StringObject(elements[index]).value
		If elements[index] <> Null Then
			StringObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillStringArray:Int(arr:String[])
		AssertLessThanInt(arr.Length, size, "StringArrayList.FillStringArray: Array too small:")
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = value Then
				Remove(elements[i])
				modCount += 1
				Return True
			End
		Next
		Return False
	End
End

Class SparseArray<E>
Private
	Field elements:Object[]
	Field indices:Int[]
	Field size:Int
	Field arraySize:Int
	Field defaultValue:E

	' resizes the arrays if necessary to ensure they can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			indices = indices.Resize(newCapacity)
		End
	End

Public
	Method New(arraySize:Int=-1, defaultCapacity:Int=100, defaultValue:E=Null)
		AssertGreaterThanInt(defaultCapacity, 0, "Default capacity must be greater than 0!")
		elements = New Object[defaultCapacity]
		indices = New Int[defaultCapacity]
		Self.arraySize = arraySize
		Self.defaultValue = defaultValue
	End

	Method Size:Int() Property
		Return size
	End

	Method ArraySize:Int() Property
		Return arraySize
	End

	Method ArraySize:Void(arraySize:Int) Property
		AssertGreaterThanInt(arraySize, size, "The SparseArray contains more mappings than the requested size.")
		Self.arraySize = arraySize
	End

	Method DefaultValue:E() Property
		Return defaultValue
	End

	Method DefaultValue:Void(defaultValue:E) Property
		Self.defaultValue = defaultValue
	End

	Method Get:E(index:Int)
		AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		For Local i% = 0 Until size
			If indices[i] = index Then Return E(elements[i])
		Next
		Return defaultValue
	End

	Method Set:E(index:Int, value:E)
		AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		For Local i% = 0 Until size
			If indices[i] = index Then
				Local oldVal:Object = elements[i]
				elements[i] = value
				Return E(oldVal)
			End
		Next
		ResizeArrays()
		indices[size] = index
		elements[size] = value
		size += 1
		Return defaultValue
	End

	Method Clear:Int()
		For Local i% = 0 Until size
			elements[i] = Null
		Next
		Local oldSize:Int = size
		size = 0
		Return oldSize
	End
End

Class SparseIntArray
Private
	Field elements:Int[]
	Field indices:Int[]
	Field size:Int
	Field arraySize:Int
	Field defaultValue:E

	' resizes the arrays if necessary to ensure they can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			indices = indices.Resize(newCapacity)
		End
	End

Public
	Method New(arraySize:Int=-1, defaultCapacity:Int=100, defaultValue:Int=0)
		AssertGreaterThanInt(defaultCapacity, 0, "Default capacity must be greater than 0!")
		elements = New Int[defaultCapacity]
		indices = New Int[defaultCapacity]
		Self.arraySize = arraySize
		Self.defaultValue = defaultValue
	End

	Method Size:Int() Property
		Return size
	End

	Method ArraySize:Int() Property
		Return arraySize
	End

	Method ArraySize:Void(arraySize:Int) Property
		AssertGreaterThanInt(arraySize, size, "The SparseIntArray contains more mappings than the requested size.")
		Self.arraySize = arraySize
	End

	Method DefaultValue:Int() Property
		Return defaultValue
	End

	Method DefaultValue:Void(defaultValue:Int) Property
		Self.defaultValue = defaultValue
	End

	Method Get:Int(index:Int)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then Return elements[i]
		Next
		Return defaultValue
	End

	Method Set:Int(index:Int, value:Int)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then
				Local oldVal:Int = elements[i]
				elements[i] = value
				Return oldVal
			End
		Next
		ResizeArrays()
		indices[size] = index
		elements[size] = value
		size += 1
		Return defaultValue
	End

	Method Clear:Int()
		For Local i% = 0 Until size
			elements[i] = 0
		Next
		Local oldSize:Int = size
		size = 0
		Return oldSize
	End
End

Class SparseStringArray
Private
	Field elements:String[]
	Field indices:Int[]
	Field size:Int
	Field arraySize:Int
	Field defaultValue:String

	' resizes the arrays if necessary to ensure they can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			indices = indices.Resize(newCapacity)
		End
	End

Public
	Method New(arraySize:Int=-1, defaultCapacity:Int=100, defaultValue:String=Null)
		AssertGreaterThanInt(defaultCapacity, 0, "Default capacity must be greater than 0!")
		elements = New String[defaultCapacity]
		indices = New Int[defaultCapacity]
		Self.arraySize = arraySize
		Self.defaultValue = defaultValue
	End

	Method Size:Int() Property
		Return size
	End

	Method ArraySize:Int() Property
		Return arraySize
	End

	Method ArraySize:Void(arraySize:Int) Property
		If arraySize >= 0 Then AssertGreaterThanInt(arraySize, size, "The SparseIntArray contains more mappings than the requested size.")
		Self.arraySize = arraySize
	End

	Method DefaultValue:String() Property
		Return defaultValue
	End

	Method DefaultValue:Void(defaultValue:String) Property
		Self.defaultValue = defaultValue
	End

	Method Get:String(index:Int)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then Return elements[i]
		Next
		Return defaultValue
	End

	Method Set:String(index:Int, value:String)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then
				Local oldVal:String = elements[i]
				elements[i] = value
				Return oldVal
			End
		Next
		ResizeArrays()
		indices[size] = index
		elements[size] = value
		size += 1
		Return defaultValue
	End

	Method Clear:Int()
		For Local i% = 0 Until size
			elements[i] = Null
		Next
		Local oldSize:Int = size
		size = 0
		Return oldSize
	End
End

Class SparseFloatArray
Private
	Field elements:Float[]
	Field indices:Int[]
	Field size:Int
	Field arraySize:Int
	Field defaultValue:Float

	' resizes the arrays if necessary to ensure they can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			indices = indices.Resize(newCapacity)
		End
	End

Public
	Method New(arraySize:Int=-1, defaultCapacity:Int=100, defaultValue:Float=0)
		AssertGreaterThanInt(defaultCapacity, 0, "Default capacity must be greater than 0!")
		elements = New Int[defaultCapacity]
		indices = New Int[defaultCapacity]
		Self.arraySize = arraySize
		Self.defaultValue = defaultValue
	End

	Method Size:Int() Property
		Return size
	End

	Method ArraySize:Int() Property
		Return arraySize
	End

	Method ArraySize:Void(arraySize:Int) Property
		AssertGreaterThanInt(arraySize, size, "The SparseIntArray contains more mappings than the requested size.")
		Self.arraySize = arraySize
	End

	Method DefaultValue:Float() Property
		Return defaultValue
	End

	Method DefaultValue:Void(defaultValue:Float) Property
		Self.defaultValue = defaultValue
	End

	Method Get:Float(index:Int)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then Return elements[i]
		Next
		Return defaultValue
	End

	Method Set:Float(index:Int, value:Float)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then
				Local oldVal:Float = elements[i]
				elements[i] = value
				Return oldVal
			End
		Next
		ResizeArrays()
		indices[size] = index
		elements[size] = value
		size += 1
		Return defaultValue
	End

	Method Clear:Int()
		For Local i% = 0 Until size
			elements[i] = 0
		Next
		Local oldSize:Int = size
		size = 0
		Return oldSize
	End
End

Function QuickSort:Void(arr:Object[], left:Int, right:Int, comp:AbstractComparator, reverse:Bool = False)
	If right > left Then
		Local pivotIndex:Int = left + (right-left)/2
		Local pivotNewIndex:Int = QuickSortPartition(arr, left, right, pivotIndex, comp, reverse)
		QuickSort(arr, left, pivotNewIndex - 1, comp, reverse)
		QuickSort(arr, pivotNewIndex + 1, right, comp, reverse)
	End
End

Function QuickSortPartition:Int(arr:Object[], left:Int, right:Int, pivotIndex:Int, comp:AbstractComparator, reverse:Bool = False)
	Local pivotValue:Object = arr[pivotIndex]
	arr[pivotIndex] = arr[right]
	arr[right] = pivotValue
	Local storeIndex:Int = left, val:Object
	For Local i:Int = left Until right
		If IComparable(arr[i]) <> Null Then
			If Not reverse And IComparable(arr[i]).Compare(pivotValue) <= 0 Or reverse And IComparable(arr[i]).Compare(pivotValue) >= 0 Then
				val = arr[i]
				arr[i] = arr[storeIndex]
				arr[storeIndex] = val
				storeIndex += 1
			End
		Else
			If Not reverse And comp.Compare(arr[i], pivotValue) <= 0 Or reverse And comp.Compare(arr[i], pivotValue) >= 0 Then
				val = arr[i]
				arr[i] = arr[storeIndex]
				arr[storeIndex] = val
				storeIndex += 1
			End
		End
	Next
	val = arr[storeIndex]
	arr[storeIndex] = arr[right]
	arr[right] = val
	Return storeIndex
End

Strict

Import assert

#Rem
Monkey Collections Framework
Based loosely on the Java Collections Framework
#End

'''' Top level Collection stuff ''''

#Rem
	AbstractCollection
	Due to limitations with generics in Monkey, ToArray cannot work with an array of type E.  We must return Object[] instead.
#End
Class AbstractCollection<E> Abstract
Private
	' A custom comparator to use for sorting and comparing items.
	Field comparator:AbstractComparator = Null

Public
' Abstract
	Method Add:Bool(o:E) Abstract
	Method AddAll:Bool(c:AbstractCollection<E>) Abstract
	Method Clear:Void() Abstract
	Method Contains:Bool(o:E) Abstract
	Method ContainsAll:Bool(c:AbstractCollection<E>) Abstract
	Method Enumerator:AbstractEnumerator<E>() Abstract
	Method FillArray:Int(arr:Object[]) Abstract ' populates the passed array and returns the number of items filled. best used for android
	Method IsEmpty:Bool() Abstract
	Method Remove:Bool(o:E) Abstract
	Method RemoveAll:Bool(c:AbstractCollection<E>) Abstract
	Method RetainAll:Bool(c:AbstractCollection<E>) Abstract
	Method Size:Int() Property Abstract
	Method Sort:Void(reverse:Bool = False, comp:AbstractComparator = Null) Abstract
	Method ToArray:Object[]() Abstract ' creates a new array of the correct size and returns it

' Methods
	Method ObjectEnumerator:AbstractEnumerator<E>()
		Return Enumerator()
	End

' Properties
	' Property to read comparator
	Method Comparator:AbstractComparator() Property
		Return comparator
	End

	' Property to write comparator
	Method Comparator:Void(comparator:AbstractComparator) Property
		Self.comparator = comparator
	End
End

#Rem
	AbstractEnumerator
	Used in the ObjectEnumerator method for calls to EachIn.
	If retrieved and used manually, the HasPrevious/PreviousObject/Remove/First/Last methods can be called.
#End
Class AbstractEnumerator<E>
' Abstract
	Method HasNext:Bool() Abstract
	Method HasPrevious:Bool() Abstract
	Method NextObject:E() Abstract
	Method PreviousObject:E() Abstract
	Method Remove:Void() Abstract
	Method First:Void() Abstract
	Method Last:Void() Abstract
	Method Reset:Void() Abstract
End

#Rem
	IComparable
	Allows developers to sort a collection without using a Comparator.  Each class is responsible
	for providing its own logic to determine how it should be sorted.
#End
Interface IComparable
	Method Compare:Int(o:Object)
	Method CompareBool:Bool(o:Object)
End

#Rem
	AbstractComparator
	This is a way for developers to provide a custom comparison method for sorting lists.
	It's sort of like a function pointer.
#End
Class AbstractComparator Abstract
' Abstract
	Method Compare:Int(o1:Object, o2:Object) Abstract

' Methods
	Method CompareBool:Bool(o1:Object, o2:Object)
		Return o1 = o2 Or Compare(o1, o2) = 0
	End

	Method HashCode:Int(o:Object)
		Return 0
	End
End

#Rem
	DefaultComparator
	Implements an AbstractComparator to handle primitive wrappers and strings.
#End
Global DEFAULT_COMPARATOR:DefaultComparator = New DefaultComparator
Class DefaultComparator Extends AbstractComparator
' Methods
	' Overrides AbstractComparator
	Method Compare:Int(o1:Object, o2:Object)
		If IntObject(o1) <> Null And IntObject(o2) <> Null Then
			If IntObject(o1).value < IntObject(o2).value Then Return -1
			If IntObject(o1).value > IntObject(o2).value Then Return 1
			Return 0
		ElseIf FloatObject(o1) <> Null And FloatObject(o2) <> Null Then
			If FloatObject(o1).value < FloatObject(o2).value Then Return -1
			If FloatObject(o1).value > FloatObject(o2).value Then Return 1
			Return 0
		ElseIf StringObject(o1) <> Null And StringObject(o2) <> Null Then
			If StringObject(o1).value < StringObject(o2).value Then Return -1
			If StringObject(o1).value > StringObject(o2).value Then Return 1
			Return 0
		End
		If o1 = o2 Then Return 0
		If o1 = Null Then Return -1
		If o2 = Null Then Return 1
		Return 0 ' don't know what to do!
	End

	' Overrides AbstractComparator
	Method CompareBool:Bool(o1:Object, o2:Object)
		If IntObject(o1) <> Null And IntObject(o2) <> Null Then
			Return IntObject(o1).value = IntObject(o2).value
		ElseIf FloatObject(o1) <> Null And FloatObject(o2) <> Null Then
			Return FloatObject(o1).value = FloatObject(o2).value
		ElseIf StringObject(o1) <> Null And StringObject(o2) <> Null Then
			Return StringObject(o1).value = StringObject(o2).value
		End
		Return o1 = o2
	End
End

'''' List stuff ''''

#Rem
	AbstractList
	Extends AbstractCollection to implement some of the abstract methods that apply to any kind of list.
#End
Class AbstractList<E> Extends AbstractCollection<E> Abstract
Private
	' If true, bounds checking should be performed.
#if CONFIG="debug"
	Field rangeChecking:Bool = True
#else
	Field rangeChecking:Bool = False
#end

	' A counter for modifications to the list.  Used for concurrency checks.
	Field modCount:Int = 0

	' Performs a range check.
	Method RangeCheck:Void(index:Int)
		Local size:Int = Self.Size()
		' range check doesn't use assert, for speed
		If index < 0 Or index >= size Then AssertError("AbstractList.RangeCheck: Index out of bounds: " + index + " is not 0<=index<" + size)
	End

Public
' Abstract
	Method AddLast:Bool(o:E) Abstract
	Method RemoveLast:E() Abstract
	Method GetLast:E() Abstract
	Method AddFirst:Bool(o:E) Abstract
	Method RemoveFirst:E() Abstract
	Method GetFirst:E() Abstract
	Method Get:E(index:Int) Abstract
	Method Insert:Void(index:Int, o:E) Abstract
	Method InsertAll:Bool(index:Int, c:AbstractCollection<E>) Abstract
	Method IndexOf:Int(o:E) Abstract
	Method LastIndexOf:Int(o:E) Abstract
	Method RemoveAt:E(index:Int) Abstract ' Can't overload Remove since it's an inherited method, and Monkey doesn't support that.
	Method RemoveRange:Void(fromIndex:Int, toIndex:Int) Abstract
	Method Set:E(index:Int, o:E) Abstract

' Methods
	' Overrides AbstractCollection
	Method Enumerator:AbstractEnumerator<E>()
		Return New ListEnumerator<E>(Self)
	End

' Properties
	' Property to read rangeChecking
	Method RangeChecking:Bool() Property
		Return rangeChecking
	End

	' Property to write rangeChecking
	Method RangeChecking:Void(rangeChecking:Bool) Property
		Self.rangeChecking = rangeChecking
	End
End

#Rem
	ListEnumerator
	Extends AbstractEnumerator to provide support for EachIn.  Blocks concurrent modification, but allows elements to be removed on the fly.
#End
Class ListEnumerator<E> Extends AbstractEnumerator<E>
Private
	Field lst:AbstractList<E>
	Field lastIndex:Int = 0
	Field index:Int = 0
	Field expectedModCount:Int = 0

	Method CheckConcurrency:Void()
		' for speed we don't use assert
		If lst.modCount <> expectedModCount Then AssertError("ListEnumerator.CheckConcurrency: Concurrent list modification")
	End

Public
' Constructors
	Method New(lst:AbstractList<E>)
		Self.lst = lst
		expectedModCount = lst.modCount
	End

' Methods
	' Overrides AbstractEnumerator
	Method HasNext:Bool()
		CheckConcurrency()
		Return index < lst.Size
	End

	' Overrides AbstractEnumerator
	Method HasPrevious:Bool()
		CheckConcurrency()
		Return index > 0
	End

	' Overrides AbstractEnumerator
	Method NextObject:E()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex)
	End

	' Overrides AbstractEnumerator
	Method PreviousObject:E()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex)
	End

	' Overrides AbstractEnumerator
	Method Remove:Void()
		CheckConcurrency()
		lst.RemoveAt(lastIndex)
		If lastIndex < index Then index -= 1
		lastIndex = -1
		expectedModCount = lst.modCount
	End

	' Overrides AbstractEnumerator
	Method First:Void()
		CheckConcurrency()
		index = 0
	End

	' Overrides AbstractEnumerator
	Method Last:Void()
		CheckConcurrency()
		index = lst.Size
	End

	' Overrides AbstractEnumerator
	Method Reset:Void()
		index = 0
		expectedModCount = lst.modCount
	End
End

#Rem
	ArrayListEnumerator
	Extends ListEnumerator to avoid some method calls.
#End
Class ArrayListEnumerator<E> Extends ListEnumerator<E>
Private
	Field alst:ArrayList<E>

Public
' Constructors
	Method New(lst:ArrayList<E>)
		Super.New(lst)
		Self.alst = lst
		expectedModCount = alst.modCount
	End

' Methods
	' Overrides ListEnumerator
	Method HasNext:Bool()
		CheckConcurrency()
		Return index < alst.size
	End

	' Overrides ListEnumerator
	Method NextObject:E()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return alst.elements[lastIndex]
	End

	' Overrides ListEnumerator
	Method PreviousObject:E()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return alst.elements[lastIndex]
	End
End

Class IntListEnumerator Extends ListEnumerator<IntObject>
' Constructors
	Method New(lst:AbstractList<IntObject>)
		Super.New(lst)
	End

' Methods
	Method NextInt:Int()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousInt:Int()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

Class FloatListEnumerator Extends ListEnumerator<FloatObject>
' Constructors
	Method New(lst:AbstractList<FloatObject>)
		Super.New(lst)
	End

' Methods
	Method NextFloat:Float()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousFloat:Float()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

Class StringListEnumerator Extends ListEnumerator<StringObject>
' Constructors
	Method New(lst:AbstractList<IntObject>)
		Super.New(lst)
	End

' Methods
	Method NextString:String()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousString:String()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

#Rem
	ArrayList
	Concrete implementation of AbstractList that uses a dynamically sized array to store elements.
	Has best performance when it is initialised with a capacity large enough to hold the expected number of elements.
#End
Class ArrayList<E> Extends AbstractList<E>
Private
	' fields
	Field elements:Object[]
	Field size:Int = 0

	' resizes the elements array if necessary to ensure it can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			modCount += 1
		End
	End

	Method RangeCheck:Void(index:Int)
		' range check doesn't use assert, for speed
		If index < 0 Or index >= size Then AssertError("ArrayList.RangeCheck: Index out of bounds: " + index + " is not 0<=index<" + size)
	End

	Field tempArr:Object[] = New Object[128] ' temp array used for internal call to ToArray (so we don't create an object)

Public
' Constructors
	Method New()
		Self.elements = New Object[10]
	End

	Method New(initialCapacity:Int)
		AssertGreaterThanOrEqualInt(initialCapacity, 0, "ArrayList.New: Illegal Capacity:")
		Self.elements = New Object[initialCapacity]
	End

	Method New(c:AbstractCollection<E>)
		elements = c.ToArray()
		size = elements.Length
	End

' Methods
	' Overrides AbstractCollection
	Method Add:Bool(o:E)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = o
		size+=1
		modCount += 1
		Return True
	End

	' Overrides AbstractCollection
	Method AddAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return False
		Local newItemCount:Int = c.Size
		If size + newItemCount > elements.Length Then EnsureCapacity(size+newItemCount)
		If tempArr.Length < newItemCount Then tempArr = tempArr.Resize(newItemCount)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			elements[size] = tempArr[i]
			size+=1
		End
		modCount += 1
		Return newItemCount <> 0
	End

	' Overrides AbstractCollection
	Method Clear:Void()
		For Local i:Int = 0 Until size
			elements[i] = Null
		Next
		modCount += 1
		size = 0
	End

	' Overrides AbstractCollection
	Method Contains:Bool(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then Return True
		Next
		Return False
	End

	' Overrides AbstractCollection
	Method ContainsAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return True
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Not Self.Contains(E(tempArr[i])) Then Return False
		Next
		Return True
	End

	' Overrides AbstractCollection
	Method Enumerator:AbstractEnumerator<E>()
		Return New ArrayListEnumerator<E>(Self)
	End

	' Overrides AbstractCollection
	Method FillArray:Int(arr:Object[])
		AssertGreaterThanOrEqualInt(arr.Length, size, "ArrayList.FillArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = elements[i]
		Next
		Return size
	End

	' Overrides AbstractCollection
	Method IsEmpty:Bool()
		Return size = 0
	End

	' Overrides AbstractCollection
	Method Remove:Bool(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	' Overrides AbstractCollection
	Method RemoveAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return False
		Local modified:Bool = False
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Self.Contains(E(tempArr[i])) Then
				Self.Remove(E(tempArr[i]))
			End
		Next
		If modified Then modCount += 1
		Return modified
	End

	' Overrides AbstractCollection
	Method RetainAll:Bool(c:AbstractCollection<E>)
		Local modified:Bool = False
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Not Self.Contains(E(tempArr[i])) Then
				Self.Remove(E(tempArr[i]))
				modified = True
			End
		Next
		If modified Then modCount += 1
		Return modified
	End

	' Overrides AbstractCollection
	Method Size:Int() Property
		Return size
	End

	' Overrides AbstractCollection
	Method Sort:Void(reverse:Bool = False, comp:AbstractComparator = Null)
		If size <= 1 Then Return ' can't sort 0 or 1 elements
		If comp = Null Then comp = Self.Comparator
		If comp = Null Then comp = DEFAULT_COMPARATOR
		QuickSort(elements, 0, size-1, comp, reverse)
		modCount += 1
	End

	' Overrides AbstractCollection
	Method ToArray:Object[]()
		Local arr:Object[] = New Object[size]
		For Local i:Int = 0 Until size
			arr[i] = elements[i]
		Next
		Return arr
	End

	' Overrides AbstractList
	Method AddLast:Bool(o:E)
		Return Add(o)
	End

	' Overrides AbstractList
	Method RemoveLast:E()
		Return RemoveAt(size-1)
	End

	' Overrides AbstractList
	Method GetLast:E()
		Return Get(size-1)
	End

	' Overrides AbstractList
	Method AddFirst:Bool(o:E)
		Insert(0, o)
		Return True
	End

	' Overrides AbstractList
	Method RemoveFirst:E()
		Return Remove(0)
	End

	' Overrides AbstractList
	Method GetFirst:E()
		Return Get(0)
	End

	' Overrides AbstractList
	Method Get:E(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return E(elements[index])
	End

	' Overrides AbstractList
	Method Insert:Void(index:Int, o:E)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = o
		size+=1
		modCount += 1
	End

	' Overrides AbstractList
	Method InsertAll:Bool(index:Int, c:AbstractCollection<E>)
		Local newItemCount:Int = c.Size
		If newItemCount = 0 Then Return False
		If size + newItemCount > elements.Length Then EnsureCapacity(size+newItemCount)
		If tempArr.Length < newItemCount Then tempArr = tempArr.Resize(newItemCount)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = size - 1 To index Step -1
			elements[i+newItemCount] = elements[i]
		Next
		For Local i:Int = 0 Until newItemCount
			elements[index+i] = tempArr[i]
		End
		size += newItemCount
		modCount += 1
		Return newItemCount <> 0
	End

	' Overrides AbstractList
	Method IndexOf:Int(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then Return i
		Next
		Return -1
	End

	' Overrides AbstractList
	Method LastIndexOf:Int(o:E)
		For Local i:Int = size-1 To 0 Step -1
			If elements[i] = o Then Return i
		Next
		Return -1
	End

	' Overrides AbstractList
	Method RemoveAt:E(index:Int)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:E = E(elements[index])
		For Local i:Int = index Until size-1
			elements[i] = elements[i+1]
		Next
		elements[size-1] = Null
		size-=1
		modCount += 1
		Return oldValue
	End

	' Overrides AbstractList
	Method RemoveRange:Void(fromIndex:Int, toIndex:Int)
		AssertLessThanOrEqualInt(fromIndex, toIndex, "ArrayList.RemoveRange: fromIndex > toIndex:")
		If rangeChecking Then
			RangeCheck(fromIndex)
			RangeCheck(toIndex)
		End
		For Local i:Int = 0 Until toIndex - fromIndex
			RemoveAt(fromIndex)
		Next
	End

	' Overrides AbstractList
	Method Set:E(index:Int, o:E)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:E = E(elements[index])
		elements[index] = o
		modCount += 1
		Return oldValue
	End
End

' ArrayList wrapper classes

Class IntArrayList Extends ArrayList<IntObject>
' Methods
	Method AddInt:Bool(o:Int)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = New IntObject(o)
		size+=1
		modCount += 1
		Return True
	End

	Method ContainsInt:Bool(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	' Overrides ArrayList
	Method Enumerator:AbstractEnumerator<IntObject>()
		Return New IntListEnumerator(Self)
	End

	Method RemoveInt:Bool(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToIntArray:Int[]()
		Local arr:Int[] = New Int[size]
		For Local i:Int = 0 Until size
			arr[i] = IntObject(elements[i]).value
		Next
		Return arr
	End

	Method GetInt:Int(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return IntObject(elements[index]).value
	End

	Method InsertInt:Void(index:Int, o:Int)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New IntObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfInt:Int(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfInt:Int(o:E)
		For Local i:Int = size-1 To 0 Step -1
			If IntObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetInt:Int(index:Int, o:Int)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:Int = IntObject(elements[index]).value
		If elements[index] <> Null Then
			IntObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillIntArray:Int(arr:Int[])
		AssertLessThanInt(arr.Length, size, "IntArrayList.FillIntArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = IntObject(elements[i]).value
		Next
		Return size
	End
End

Class FloatArrayList Extends ArrayList<FloatObject>
' Methods
	Method AddFloat:Bool(o:Float)
		If size + 1 > elements.Length Then EnsureCapacity(size + 1)
		elements[size] = New FloatObject(o)
		size += 1
		modCount += 1
		Return True
	End

	Method ContainsFloat:Bool(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	' Overrides ArrayList
	Method Enumerator:AbstractEnumerator<FloatObject>()
		Return New FloatListEnumerator(Self)
	End

	Method RemoveFloat:Bool(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToFloatArray:Float[]()
		Local arr:Float[] = New Float[size]
		For Local i:Int = 0 Until size
			arr[i] = FloatObject(elements[i]).value
		Next
		Return arr
	End

	Method GetFloat:Float(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return FloatObject(elements[index]).value
	End

	Method InsertFloat:Void(index:Int, o:Float)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New FloatObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfFloat:Int(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfFloat:Int(o:Float)
		For Local i:Int = size-1 To 0 Step -1
			If FloatObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetFloat:Float(index:Int, o:Float)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:Float = FloatObject(elements[index]).value
		If elements[index] <> Null Then
			FloatObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillFloatArray:Int(arr:Float[])
		AssertLessThanInt(arr.Length, size, "FloatArrayList.FillFloatArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = FloatObject(elements[i]).value
		Next
		Return size
	End
End

Class StringArrayList Extends ArrayList<StringObject>
' Methods
	Method AddString:Bool(o:String)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = New StringObject(o)
		size+=1
		modCount += 1
		Return True
	End

	Method ContainsString:Bool(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	' Overrides ArrayList
	Method Enumerator:AbstractEnumerator<StringObject>()
		Return New StringListEnumerator(Self)
	End

	Method RemoveString:Bool(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToStringArray:String[]()
		Local arr:String[] = New String[size]
		For Local i:Int = 0 Until size
			arr[i] = StringObject(elements[i]).value
		Next
		Return arr
	End

	Method GetString:String(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return StringObject(elements[index]).value
	End

	Method InsertString:Void(index:Int, o:String)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New StringObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfString:Int(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfString:Int(o:String)
		For Local i:Int = size-1 To 0 Step -1
			If StringObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetString:String(index:Int, o:String)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:String = StringObject(elements[index]).value
		If elements[index] <> Null Then
			StringObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillStringArray:Int(arr:String[])
		AssertLessThanInt(arr.Length, size, "StringArrayList.FillStringArray: Array too small:")
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = value Then
				Remove(elements[i])
				modCount += 1
				Return True
			End
		Next
		Return False
	End
End

Class SparseArray<E>
Private
	Field elements:Object[]
	Field indices:Int[]
	Field size:Int
	Field arraySize:Int
	Field defaultValue:E

	' resizes the arrays if necessary to ensure they can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			indices = indices.Resize(newCapacity)
		End
	End

Public
	Method New(arraySize:Int=-1, defaultCapacity:Int=100, defaultValue:E=Null)
		AssertGreaterThanInt(defaultCapacity, 0, "Default capacity must be greater than 0!")
		elements = New Object[defaultCapacity]
		indices = New Int[defaultCapacity]
		Self.arraySize = arraySize
		Self.defaultValue = defaultValue
	End

	Method Size:Int() Property
		Return size
	End

	Method ArraySize:Int() Property
		Return arraySize
	End

	Method ArraySize:Void(arraySize:Int) Property
		AssertGreaterThanInt(arraySize, size, "The SparseArray contains more mappings than the requested size.")
		Self.arraySize = arraySize
	End

	Method DefaultValue:E() Property
		Return defaultValue
	End

	Method DefaultValue:Void(defaultValue:E) Property
		Self.defaultValue = defaultValue
	End

	Method Get:E(index:Int)
		AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		For Local i% = 0 Until size
			If indices[i] = index Then Return E(elements[i])
		Next
		Return defaultValue
	End

	Method Set:E(index:Int, value:E)
		AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		For Local i% = 0 Until size
			If indices[i] = index Then
				Local oldVal:Object = elements[i]
				elements[i] = value
				Return E(oldVal)
			End
		Next
		ResizeArrays()
		indices[size] = index
		elements[size] = value
		size += 1
		Return defaultValue
	End

	Method Clear:Int()
		For Local i% = 0 Until size
			elements[i] = Null
		Next
		Local oldSize:Int = size
		size = 0
		Return oldSize
	End
End

Class SparseIntArray
Private
	Field elements:Int[]
	Field indices:Int[]
	Field size:Int
	Field arraySize:Int
	Field defaultValue:E

	' resizes the arrays if necessary to ensure they can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			indices = indices.Resize(newCapacity)
		End
	End

Public
	Method New(arraySize:Int=-1, defaultCapacity:Int=100, defaultValue:Int=0)
		AssertGreaterThanInt(defaultCapacity, 0, "Default capacity must be greater than 0!")
		elements = New Int[defaultCapacity]
		indices = New Int[defaultCapacity]
		Self.arraySize = arraySize
		Self.defaultValue = defaultValue
	End

	Method Size:Int() Property
		Return size
	End

	Method ArraySize:Int() Property
		Return arraySize
	End

	Method ArraySize:Void(arraySize:Int) Property
		AssertGreaterThanInt(arraySize, size, "The SparseIntArray contains more mappings than the requested size.")
		Self.arraySize = arraySize
	End

	Method DefaultValue:Int() Property
		Return defaultValue
	End

	Method DefaultValue:Void(defaultValue:Int) Property
		Self.defaultValue = defaultValue
	End

	Method Get:Int(index:Int)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then Return elements[i]
		Next
		Return defaultValue
	End

	Method Set:Int(index:Int, value:Int)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then
				Local oldVal:Int = elements[i]
				elements[i] = value
				Return oldVal
			End
		Next
		ResizeArrays()
		indices[size] = index
		elements[size] = value
		size += 1
		Return defaultValue
	End

	Method Clear:Int()
		For Local i% = 0 Until size
			elements[i] = 0
		Next
		Local oldSize:Int = size
		size = 0
		Return oldSize
	End
End

Class SparseStringArray
Private
	Field elements:String[]
	Field indices:Int[]
	Field size:Int
	Field arraySize:Int
	Field defaultValue:String

	' resizes the arrays if necessary to ensure they can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			indices = indices.Resize(newCapacity)
		End
	End

Public
	Method New(arraySize:Int=-1, defaultCapacity:Int=100, defaultValue:String=Null)
		AssertGreaterThanInt(defaultCapacity, 0, "Default capacity must be greater than 0!")
		elements = New String[defaultCapacity]
		indices = New Int[defaultCapacity]
		Self.arraySize = arraySize
		Self.defaultValue = defaultValue
	End

	Method Size:Int() Property
		Return size
	End

	Method ArraySize:Int() Property
		Return arraySize
	End

	Method ArraySize:Void(arraySize:Int) Property
		If arraySize >= 0 Then AssertGreaterThanInt(arraySize, size, "The SparseIntArray contains more mappings than the requested size.")
		Self.arraySize = arraySize
	End

	Method DefaultValue:String() Property
		Return defaultValue
	End

	Method DefaultValue:Void(defaultValue:String) Property
		Self.defaultValue = defaultValue
	End

	Method Get:String(index:Int)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then Return elements[i]
		Next
		Return defaultValue
	End

	Method Set:String(index:Int, value:String)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then
				Local oldVal:String = elements[i]
				elements[i] = value
				Return oldVal
			End
		Next
		ResizeArrays()
		indices[size] = index
		elements[size] = value
		size += 1
		Return defaultValue
	End

	Method Clear:Int()
		For Local i% = 0 Until size
			elements[i] = Null
		Next
		Local oldSize:Int = size
		size = 0
		Return oldSize
	End
End

Class SparseFloatArray
Private
	Field elements:Float[]
	Field indices:Int[]
	Field size:Int
	Field arraySize:Int
	Field defaultValue:Float

	' resizes the arrays if necessary to ensure they can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			indices = indices.Resize(newCapacity)
		End
	End

Public
	Method New(arraySize:Int=-1, defaultCapacity:Int=100, defaultValue:Float=0)
		AssertGreaterThanInt(defaultCapacity, 0, "Default capacity must be greater than 0!")
		elements = New Int[defaultCapacity]
		indices = New Int[defaultCapacity]
		Self.arraySize = arraySize
		Self.defaultValue = defaultValue
	End

	Method Size:Int() Property
		Return size
	End

	Method ArraySize:Int() Property
		Return arraySize
	End

	Method ArraySize:Void(arraySize:Int) Property
		AssertGreaterThanInt(arraySize, size, "The SparseIntArray contains more mappings than the requested size.")
		Self.arraySize = arraySize
	End

	Method DefaultValue:Float() Property
		Return defaultValue
	End

	Method DefaultValue:Void(defaultValue:Float) Property
		Self.defaultValue = defaultValue
	End

	Method Get:Float(index:Int)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then Return elements[i]
		Next
		Return defaultValue
	End

	Method Set:Float(index:Int, value:Float)
		If arraySize >= 0 Then
			AssertRangeInt(index, 0, arraySize, "Array index out of bounds.")
		Else
			AssertGreaterThanOrEqualInt(index, 0, "Array index out of bounds.")
		End
		For Local i% = 0 Until size
			If indices[i] = index Then
				Local oldVal:Float = elements[i]
				elements[i] = value
				Return oldVal
			End
		Next
		ResizeArrays()
		indices[size] = index
		elements[size] = value
		size += 1
		Return defaultValue
	End

	Method Clear:Int()
		For Local i% = 0 Until size
			elements[i] = 0
		Next
		Local oldSize:Int = size
		size = 0
		Return oldSize
	End
End

Function QuickSort:Void(arr:Object[], left:Int, right:Int, comp:AbstractComparator, reverse:Bool = False)
	If right > left Then
		Local pivotIndex:Int = left + (right-left)/2
		Local pivotNewIndex:Int = QuickSortPartition(arr, left, right, pivotIndex, comp, reverse)
		QuickSort(arr, left, pivotNewIndex - 1, comp, reverse)
		QuickSort(arr, pivotNewIndex + 1, right, comp, reverse)
	End
End

Function QuickSortPartition:Int(arr:Object[], left:Int, right:Int, pivotIndex:Int, comp:AbstractComparator, reverse:Bool = False)
	Local pivotValue:Object = arr[pivotIndex]
	arr[pivotIndex] = arr[right]
	arr[right] = pivotValue
	Local storeIndex:Int = left, val:Object
	For Local i:Int = left Until right
		If IComparable(arr[i]) <> Null Then
			If Not reverse And IComparable(arr[i]).Compare(pivotValue) <= 0 Or reverse And IComparable(arr[i]).Compare(pivotValue) >= 0 Then
				val = arr[i]
				arr[i] = arr[storeIndex]
				arr[storeIndex] = val
				storeIndex += 1
			End
		Else
			If Not reverse And comp.Compare(arr[i], pivotValue) <= 0 Or reverse And comp.Compare(arr[i], pivotValue) >= 0 Then
				val = arr[i]
				arr[i] = arr[storeIndex]
				arr[storeIndex] = val
				storeIndex += 1
			End
		End
	Next
	val = arr[storeIndex]
	arr[storeIndex] = arr[right]
	arr[right] = val
	Return storeIndex
End


Fixed an old resizing bug with 'PublicDataStream' objects.

Strict

Public

' Preprocessor related:
#IOUTIL_PUBLICDATASTREAM_LEGACY_BIG_ENDIAN = True

' Imports (Public):
Import regal.byteorder

' BRL:
Import brl.stream

' Imports (Private):
Private

Import regal.util

' BRL:
Import brl.databuffer

Public

' Classes:
Class PublicDataStream Extends Stream Implements IOnLoadDataComplete
	' Constant variable(s):
	Const NOLIMIT:Int = 0 ' -1

	' Defaults:
	Const Default_ResizeScalar:Float = 1.5 ' 2.0

	' Booleans / Flags:
	Const Default_BigEndianStorage:Bool = False

	' Constructor(s) (Public):

	' The specified size must be at least 2 bytes large.
	Method New(Size:Int, BigEndianStorage:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		GenerateBuffer(Size)

		Self.BigEndianStorage = BigEndianStorage
		Self.ShouldResize = Resizable
		Self.SizeLimit = SizeLimit
	End

	Method New(B:DataBuffer, Length:Int, Offset:Int=0, Copy:Bool=False, BigEndianStorage:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		If (Copy) Then
			GenerateBuffer(B)

			OwnsBuffer = True
		Else
			Self.Data = B
		Endif

		Self.Offset = Offset
		Self._Length = Length

		Self.RawSize = Length

		Self.BigEndianStorage = BigEndianStorage
		Self.ShouldResize = Resizable
		Self.SizeLimit = SizeLimit
	End

	Method New(Path:String, BigEndianStorage:Bool=Default_BigEndianStorage, Async:Bool=False)
		If (Not Async) Then
			OnLoadDataComplete(DataBuffer.Load(Path), Path)
		Else
			DataBuffer.LoadAsync(Path, Self)
		Endif

		Self.BigEndianStorage = BigEndianStorage
	End

	' Constructor(s) (Protected):
	Protected

	Method New()
		' Nothing so far.
	End

	Method GenerateBuffer:Void(Size:Int)
		Self.Data = New DataBuffer(Size)
		Self.RawSize = Size
		Self.OwnsBuffer = True

		Return
	End

	' This will copy the contents of 'B' into an internally managed buffer.
	Method GenerateBuffer:Void(B:DataBuffer)
		GenerateBuffer(B.Length)

		B.CopyBytes(0, Data, 0, Data.Length)

		Return
	End

	Public

	' Destructor(s) (Protected):
	Protected

	Method DestructDetails:Void()
		Self.Offset = 0
		Self._Position = 0

		Return
	End

	Public

	' Destructor(s) (Public):
	Method FreeBuffer:Void(DiscardBuffer:Bool=True)
		If (Data <> Null) Then
			If (DiscardBuffer) Then
				Data.Discard()
			Endif

			Data = Null
		Endif

		OwnsBuffer = False

		RawSize = 0

		Return
	End

	Method Close:Void()
		FreeBuffer(OwnsBuffer)
		DestructDetails()

		Return
	End

	' The resulting 'DataBuffer' represents the 'Data'
	' property before destruction takes place.
	Method CloseWithoutBuffer:DataBuffer()
		Local OutputBuffer:= Data

		FreeBuffer(False)
		DestructDetails()

		Return OutputBuffer
	End

	' Methods:

	' This creates a 'DataBuffer' by copying 'Data' based on the contents described by this point.
	' This is useful for handling storage semantics; copies.
	Method ToDataBuffer:DataBuffer()
		Local outBuffer:= New DataBuffer(Length)

		Data.CopyBytes(Offset, outBuffer, 0, Length)

		Return outBuffer
	End

	Method Seek:Int(Input:Int=0)
		Self._Position = Clamp(Input, 0, DataLength)

		Return Self._Position
	End

	Method Reset:Void()
		Seek()
		ResetLength()

		Return
	End

	' This states if the number of bytes specified may be read safely.
	Method WillOverReach:Bool(Bytes:Int)
		Return ReadWillOverReach(Bytes)
	End

	Method ReadWillOverReach:Bool(Bytes:Int)
		Return (Position+Bytes > Length)
	End

	Method WriteWillOverReach:Bool(Bytes:Int)
		Return (Position+Bytes > DataLength) ' Length
	End

	Method ReadShort:Int()
		If (BigEndianStorage) Then
			Local Value:= Super.ReadShort()

			#If IOUTIL_PUBLICDATASTREAM_LEGACY_BIG_ENDIAN
				Return NToHS(Value)
			#Else
				Return NToHS_S(Value)
			#End
		Endif

		Return Super.ReadShort()
	End

	Method ReadInt:Int()
		If (BigEndianStorage) Then
			Return NToHL(Super.ReadInt())
		Endif

		Return Super.ReadInt()
	End

	Method ReadFloat:Float()
		If (BigEndianStorage) Then
			Return NToHF(Super.ReadInt())
		Endif

		Return Super.ReadFloat()
	End

	Method WriteShort:Void(Value:Int)
		If (BigEndianStorage) Then
			Super.WriteShort(HToNS(Value))
		Else
			Super.WriteShort(Value)
		Endif

		Return
	End

	Method WriteInt:Void(Value:Int)
		If (BigEndianStorage) Then
			Super.WriteInt(HToNL(Value))
		Else
			Super.WriteInt(Value)
		Endif

		Return
	End

	Method WriteFloat:Void(Value:Float)
		If (BigEndianStorage) Then
			Super.WriteInt(HToNF(Value))
		Else
			Super.WriteFloat(Value)
		Endif

		Return
	End

	Method Read:Int(Buf:DataBuffer, Offset:Int, Count:Int)
		If (WillOverReach(Count)) Then
			Count = Self.BytesLeft
		Endif

		#Rem
			For Local Index:= 0 Until Count
				Buf.PokeByte(Offset+Index, Self.Data.PeekByte(Offset+Position+Index))
			Next
		#End

		Self.Data.CopyBytes(Self.DataOffset, Buf, Offset, Count)

		Self._Position += Count

		Return Count
	End

	Method Write:Int(Buf:DataBuffer, Offset:Int, Count:Int)
		Local NewPosition:= (Count+Position)

		If (NewPosition > DataLength) Then
			If (ShouldResize) Then
				AutoResize(Count)
			Else
				Count = (DataLength-Position) ' Max(..., 0)
			Endif
		Endif

		Buf.CopyBytes(Offset, Self.Data, Self.DataOffset, Count)

		Self._Position = NewPosition

		SetLengthSafe(NewPosition)

		Return Count
	End

	' This transfers a raw segment of the internal buffer into 'S'. (Use at your own risk)
	Method TransferSegment:Void(S:Stream, Bytes:Int, Offset:Int)
		S.WriteAll(Data, Offset, Bytes)

		Return
	End

	' This may be used to transfer the internal data of this stream to another.
	Method TransferTo:Void(S:Stream, Offset:Int=0)
		Local ReadOffset:= (Self.Offset+Offset)

		TransferSegment(S, Length, ReadOffset)

		Return
	End

	' This may be used to transfer what has already been read.
	Method TransferPastData:Void(S:Stream, Offset:Int=0)
		Local ReadOffset:= (Self.Offset+Offset)

		TransferSegment(S, (Position-ReadOffset), ReadOffset)

		Return
	End

	' This may be used to read the number of bytes specified, from this stream then transfer it to another.
	Method TransferAmount:Void(S:Stream, Bytes:Int, Offset:Int=0)
		Local P:= S.Position

		TransferSegment(S, Bytes, (Self.Offset+Self.Position+Offset))

		S.Seek(P)

		Return
	End

	Method AutoResize:Bool(MinBytes:Int=0)
		If (Not OwnsBuffer) Then
			Return False
		Endif

		Return Resize(Max(Int(Float(Data.Length) * ResizeScalar), MinBytes))
	End

	Method SmartResize:Bool(MinBytes:Int)
		If (MinBytes <= DataLength) Then
			Return True
		Endif

		Return Resize(MinBytes)
	End

	Method Resize:Bool(NewSize:Int, Force:Bool=False)
		If (Not OwnsBuffer) Then
			Return False
		Endif

		If (SizeLimit <> NOLIMIT) Then
			If (NewSize > SizeLimit) Then
				If (Force) Then
					NewSize = Min(NewSize, SizeLimit)
				Else
					Return False
				Endif
			Endif
		Endif

		Data = ResizeBuffer(Data, NewSize, True, True, True)

		If (Data <> Null) Then
			RawSize = NewSize ' Data.Length

			Return True
		Endif

		Return False
	End

	Method SetLength:Void(Value:Int)
		Self._Length = Min(Value, DataLength)

		Return
	End

	Method SetLengthSafe:Void(Value:Int)
		SetLength(Max(Value, Self._Length))

		Return
	End

	' This sets the internal length to the current position.
	Method ClampToPosition:Void()
		SetLength(Position)

		Return
	End

	Method ResetLength:Void()
		SetLength(0)

		Return
	End

	' Call-backs:
	Method OnLoadDataComplete:Void(Data:DataBuffer, Path:String)
		If (Self.Data = Null) Then
			Self.Data = Data
			Self._Length = Data.Length
		Endif

		Return
	End

	' Properties (Public):

	' The internal I/O buffer.
	Method Data:DataBuffer() Property
		Return Self._Data
	End

	Method Eof:Int() Property
		Return (Position >= Length)
	End

	' The furthest this stream has written.
	Method Length:Int() Property
		Return Self._Length
	End

	' The number of bytes into the buffer this stream is.
	Method Position:Int() Property
		Return Self._Position
	End

	' The overall length of the 'Data' buffer. (Taking 'Offset' into account)
	Method RawSize:Int() Property
		Return Self._RawSize
	End

	' This will return the 'RawSize' property adjusted to the internal offset.
	Method DataLength:Int() Property
		Return (RawSize - Offset)
	End

	' The real position in the 'Data' buffer. (After 'Offset')
	Method DataOffset:Int() Property
		Return (Offset+Position)
	End

	' The number of bytes left in 'Data'. (Input only)
	Method BytesLeft:Int() Property
		Return Max(Length - Position, 0)
	End

	' This specifies the number of bytes left.
	' (Based on 'RawSize' and 'DataOffset'; use at your own risk)
	Method RealBytesLeft:Int() Property
		Return Max(RawSize - DataOffset, 0)
	End

	' This may be used for asynchronous buffer-loading.
	Method DataReady:Bool() Property
		Return (Data <> Null)
	End

	' Properties (Protected):
	Protected

	Method Data:Void(Input:DataBuffer) Property
		Self._Data = Input

		Return
	End

	Method RawSize:Void(Input:Int) Property
		Self._RawSize = Input

		Return
	End

	Public

	' Fields (Public):

	' Please use any corresponding properties when possible:

	' This acts as an internal offset inside the 'Data' buffer.
	Field Offset:Int

	' The (Local) position of the stream.
	Field _Position:Int

	' The furthest point we have written in the internal buffer.
	Field _Length:Int

	' The internal buffer's size-limit. (Used when resizing)
	Field SizeLimit:Int = NOLIMIT

	' A floating-point scalar used when a resize-operation occurs.
	' Numbers will be rounded as the hardware sees fit. (Usually rounds down)
	Field ResizeScalar:Float = Default_ResizeScalar

	' Booleans / Flags:

	' This may be used to toggle resizing the internal buffer.
	Field ShouldResize:Bool

	' This specifies if big-endian byte-order should be used.
	Field BigEndianStorage:Bool

	' This specifies if this stream owns the internal buffer.
	Field OwnsBuffer:Bool

	' Fields (Protected):
	Protected

	Field _Data:DataBuffer
	Field _RawSize:Int

	Public
End

Strict

Public

' Preprocessor related:
#IOUTIL_PUBLICDATASTREAM_LEGACY_BIG_ENDIAN = True

' Imports (Public):
Import regal.byteorder

' BRL:
Import brl.stream

' Imports (Private):
Private

Import regal.util

' BRL:
Import brl.databuffer

Public

' Classes:
Class PublicDataStream Extends Stream Implements IOnLoadDataComplete
	' Constant variable(s):
	Const NOLIMIT:Int = 0 ' -1

	' Defaults:
	Const Default_ResizeScalar:Float = 1.5 ' 2.0

	' Booleans / Flags:
	Const Default_BigEndianStorage:Bool = False

	' Constructor(s) (Public):
	Method New(Size:Int, BigEndianStorage:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		GenerateBuffer(Size)

		Self.BigEndianStorage = BigEndianStorage
		Self.ShouldResize = Resizable
		Self.SizeLimit = SizeLimit
	End

	Method New(B:DataBuffer, Length:Int, Offset:Int=0, Copy:Bool=False, BigEndianStorage:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		If (Copy) Then
			GenerateBuffer(B)

			OwnsBuffer = True
		Else
			Self.Data = B
		Endif

		Self.Offset = Offset
		Self._Length = Length

		Self.RawSize = Length

		Self.BigEndianStorage = BigEndianStorage
		Self.ShouldResize = Resizable
		Self.SizeLimit = SizeLimit
	End

	Method New(Path:String, BigEndianStorage:Bool=Default_BigEndianStorage, Async:Bool=False)
		If (Not Async) Then
			OnLoadDataComplete(DataBuffer.Load(Path), Path)
		Else
			DataBuffer.LoadAsync(Path, Self)
		Endif

		Self.BigEndianStorage = BigEndianStorage
	End

	' Constructor(s) (Protected):
	Protected

	Method New()
		' Nothing so far.
	End

	Method GenerateBuffer:Void(Size:Int)
		Self.Data = New DataBuffer(Size)
		Self.RawSize = Size
		Self.OwnsBuffer = True

		Return
	End

	' This will copy the contents of 'B' into an internally managed buffer.
	Method GenerateBuffer:Void(B:DataBuffer)
		GenerateBuffer(B.Length)

		B.CopyBytes(0, Data, 0, Data.Length)

		Return
	End

	Public

	' Destructor(s) (Protected):
	Protected

	Method DestructDetails:Void()
		Self.Offset = 0
		Self._Position = 0

		Return
	End

	Public

	' Destructor(s) (Public):
	Method FreeBuffer:Void(DiscardBuffer:Bool=True)
		If (Data <> Null) Then
			If (DiscardBuffer) Then
				Data.Discard()
			Endif

			Data = Null
		Endif

		OwnsBuffer = False

		RawSize = 0

		Return
	End

	Method Close:Void()
		FreeBuffer(OwnsBuffer)
		DestructDetails()

		Return
	End

	' The resulting 'DataBuffer' represents the 'Data'
	' property before destruction takes place.
	Method CloseWithoutBuffer:DataBuffer()
		Local OutputBuffer:= Data

		FreeBuffer(False)
		DestructDetails()

		Return OutputBuffer
	End

	' Methods:

	' This creates a 'DataBuffer' by copying 'Data' based on the contents described by this point.
	' This is useful for handling storage semantics; copies.
	Method ToDataBuffer:DataBuffer()
		Local outBuffer:= New DataBuffer(Length)

		Data.CopyBytes(Offset, outBuffer, 0, Length)

		Return outBuffer
	End

	Method Seek:Int(Input:Int=0)
		Self._Position = Clamp(Input, 0, DataLength)

		Return Self._Position
	End

	Method Reset:Void()
		Seek()
		ResetLength()

		Return
	End

	' This states if the number of bytes specified may be read safely.
	Method WillOverReach:Bool(Bytes:Int)
		Return ReadWillOverReach(Bytes)
	End

	Method ReadWillOverReach:Bool(Bytes:Int)
		Return (Position+Bytes > Length)
	End

	Method WriteWillOverReach:Bool(Bytes:Int)
		Return (Position+Bytes > DataLength) ' Length
	End

	Method ReadShort:Int()
		If (BigEndianStorage) Then
			Local Value:= Super.ReadShort()

			#If IOUTIL_PUBLICDATASTREAM_LEGACY_BIG_ENDIAN
				Return NToHS(Value)
			#Else
				Return NToHS_S(Value)
			#End
		Endif

		Return Super.ReadShort()
	End

	Method ReadInt:Int()
		If (BigEndianStorage) Then
			Return NToHL(Super.ReadInt())
		Endif

		Return Super.ReadInt()
	End

	Method ReadFloat:Float()
		If (BigEndianStorage) Then
			Return NToHF(Super.ReadInt())
		Endif

		Return Super.ReadFloat()
	End

	Method WriteShort:Void(Value:Int)
		If (BigEndianStorage) Then
			Super.WriteShort(HToNS(Value))
		Else
			Super.WriteShort(Value)
		Endif

		Return
	End

	Method WriteInt:Void(Value:Int)
		If (BigEndianStorage) Then
			Super.WriteInt(HToNL(Value))
		Else
			Super.WriteInt(Value)
		Endif

		Return
	End

	Method WriteFloat:Void(Value:Float)
		If (BigEndianStorage) Then
			Super.WriteInt(HToNF(Value))
		Else
			Super.WriteFloat(Value)
		Endif

		Return
	End

	Method Read:Int(Buf:DataBuffer, Offset:Int, Count:Int)
		If (WillOverReach(Count)) Then
			Count = Self.BytesLeft
		Endif

		#Rem
			For Local Index:= 0 Until Count
				Buf.PokeByte(Offset+Index, Self.Data.PeekByte(Offset+Position+Index))
			Next
		#End

		Self.Data.CopyBytes(Self.DataOffset, Buf, Offset, Count)

		Self._Position += Count

		Return Count
	End

	Method Write:Int(Buf:DataBuffer, Offset:Int, Count:Int)
		Local NewPosition:= (Count+Position)

		If (NewPosition > DataLength) Then
			If (ShouldResize) Then
				AutoResize(Count)
			Else
				Count = (DataLength-Position) ' Max(..., 0)
			Endif
		Endif

		Buf.CopyBytes(Offset, Self.Data, Self.DataOffset, Count)

		Self._Position = NewPosition

		SetLengthSafe(NewPosition)

		Return Count
	End

	' This transfers a raw segment of the internal buffer into 'S'. (Use at your own risk)
	Method TransferSegment:Void(S:Stream, Bytes:Int, Offset:Int)
		S.WriteAll(Data, Offset, Bytes)

		Return
	End

	' This may be used to transfer the internal data of this stream to another.
	Method TransferTo:Void(S:Stream, Offset:Int=0)
		Local ReadOffset:= (Self.Offset+Offset)

		TransferSegment(S, Length, ReadOffset)

		Return
	End

	' This may be used to transfer what has already been read.
	Method TransferPastData:Void(S:Stream, Offset:Int=0)
		Local ReadOffset:= (Self.Offset+Offset)

		TransferSegment(S, (Position-ReadOffset), ReadOffset)

		Return
	End

	' This may be used to read the number of bytes specified, from this stream then transfer it to another.
	Method TransferAmount:Void(S:Stream, Bytes:Int, Offset:Int=0)
		Local P:= S.Position

		TransferSegment(S, Bytes, (Self.Offset+Self.Position+Offset))

		S.Seek(P)

		Return
	End

	Method AutoResize:Bool(MinBytes:Int=0)
		If (Not OwnsBuffer) Then
			Return False
		Endif

		Return Resize(Max(Int(Float(Data.Length) * ResizeScalar), MinBytes))
	End

	Method SmartResize:Bool(MinBytes:Int)
		If (MinBytes <= DataLength) Then
			Return True
		Endif

		Return Resize(MinBytes)
	End

	Method Resize:Bool(NewSize:Int, Force:Bool=False)
		If (Not OwnsBuffer) Then
			Return False
		Endif

		If (SizeLimit <> NOLIMIT) Then
			If (NewSize > SizeLimit) Then
				If (Force) Then
					NewSize = Min(NewSize, SizeLimit)
				Else
					Return False
				Endif
			Endif
		Endif

		Data = ResizeBuffer(Data, NewSize, True, True, True)

		Return (Data <> Null)
	End

	Method SetLength:Void(Value:Int)
		Self._Length = Min(Value, DataLength)

		Return
	End

	Method SetLengthSafe:Void(Value:Int)
		SetLength(Max(Value, Self._Length))

		Return
	End

	' This sets the internal length to the current position.
	Method ClampToPosition:Void()
		SetLength(Position)

		Return
	End

	Method ResetLength:Void()
		SetLength(0)

		Return
	End

	' Call-backs:
	Method OnLoadDataComplete:Void(Data:DataBuffer, Path:String)
		If (Self.Data = Null) Then
			Self.Data = Data
			Self._Length = Data.Length
		Endif

		Return
	End

	' Properties (Public):

	' The internal I/O buffer.
	Method Data:DataBuffer() Property
		Return Self._Data
	End

	Method Eof:Int() Property
		Return (Position >= Length)
	End

	' The furthest this stream has written.
	Method Length:Int() Property
		Return Self._Length
	End

	' The number of bytes into the buffer this stream is.
	Method Position:Int() Property
		Return Self._Position
	End

	' The overall length of the 'Data' buffer. (Taking 'Offset' into account)
	Method RawSize:Int() Property
		Return Self._RawSize
	End

	' This will return the 'RawSize' property adjusted to the internal offset.
	Method DataLength:Int() Property
		Return (RawSize - Offset)
	End

	' The real position in the 'Data' buffer. (After 'Offset')
	Method DataOffset:Int() Property
		Return (Offset+Position)
	End

	' The number of bytes left in 'Data'. (Input only)
	Method BytesLeft:Int() Property
		Return Max(Length - Position, 0)
	End

	' This specifies the number of bytes left.
	' (Based on 'RawSize' and 'DataOffset'; use at your own risk)
	Method RealBytesLeft:Int() Property
		Return Max(RawSize - DataOffset, 0)
	End

	' This may be used for asynchronous buffer-loading.
	Method DataReady:Bool() Property
		Return (Data <> Null)
	End

	' Properties (Protected):
	Protected

	Method Data:Void(Input:DataBuffer) Property
		Self._Data = Input

		Return
	End

	Method RawSize:Void(Input:Int) Property
		Self._RawSize = Input

		Return
	End

	Public

	' Fields (Public):

	' Please use any corresponding properties when possible:

	' This acts as an internal offset inside the 'Data' buffer.
	Field Offset:Int

	' The (Local) position of the stream.
	Field _Position:Int

	' The furthest point we have written in the internal buffer.
	Field _Length:Int

	' The internal buffer's size-limit. (Used when resizing)
	Field SizeLimit:Int = NOLIMIT

	' A floating-point scalar used when a resize-operation occurs.
	' Numbers will be rounded as the hardware sees fit. (Usually rounds down)
	Field ResizeScalar:Float = Default_ResizeScalar

	' Booleans / Flags:

	' This may be used to toggle resizing the internal buffer.
	Field ShouldResize:Bool

	' This specifies if big-endian byte-order should be used.
	Field BigEndianStorage:Bool

	' This specifies if this stream owns the internal buffer.
	Field OwnsBuffer:Bool

	' Fields (Protected):
	Protected

	Field _Data:DataBuffer
	Field _RawSize:Int

	Public
End


Add Size:Vector2d() to bono.utils.Device

Private

Import "native/device.${TARGET}.${LANG}"
Import mojo.graphics
Import vector2d

Private

Class DeviceNonNative Abstract
    Function Size:Vector2D()
        Return New Vector2D(DeviceWidth(), DeviceHeight())
    End
End

Extern

Class Device Extends DeviceNonNative Abstract
#If TARGET="ios" Or TARGET="glfw"
    Function GetTimestamp:Int()="Device::GetTimestamp"
    Function OpenUrl:Void(url:String)="Device::OpenUrl"
#Else
    Function GetTimestamp:Int()="Device.GetTimestamp"
    Function OpenUrl:Void(url:String)="Device.OpenUrl"
#End
End

Private

Import "native/device.${TARGET}.${LANG}"

Public

Extern

Class Device Abstract
#If TARGET="ios" Or TARGET="glfw"
    Function GetTimestamp:Int()="Device::GetTimestamp"
    Function OpenUrl:Void(url:String)="Device::OpenUrl"
#Else
    Function GetTimestamp:Int()="Device.GetTimestamp"
    Function OpenUrl:Void(url:String)="Device.OpenUrl"
#End
End


Small fixes IndexOf method

Small fixes IndexOf method

#rem
	header:This module contains the FlxGroup class.
#end

Import flxbasic

Class FlxGroup Extends FlxBasic

	Const ASCENDING:Bool = True

	Const DESCENDING:Bool = False

Private
	Field _members:FlxBasicStack

	Field _maxSize:Int

	Field _marker:Int

	Field _isFragmented:Bool

	Field _length:Int

Public
	Method New(maxSize:Int = 0)
		Super.New()
		_members = New FlxBasicStack()
		_maxSize = maxSize
		_marker = 0
		_isFragmented = False
		_length = 0
	End Method

	Method Members:Stack<FlxBasic>() Property
		Return _members
	End Method

	Method Length:Int() Property
		Return _members.Length
	End Method

	Method Destroy:Void()
		If (_members <> Null) Then
			For Local basic:FlxBasic = EachIn _members
				If (basic <> Null) basic.Destroy()
			Next

			_members.Clear()
			_members = null
		End If
	End Method

	Method Update:Void()
		For Local basic:FlxBasic = EachIn _members
			If (basic <> Null And basic.exists And basic.active) Then
				basic.PreUpdate()
				basic.Update()
				basic.PostUpdate()
			End If
		Next
	End Method

	Method Draw:Void()
		For Local basic:FlxBasic = EachIn _members
			If (basic <> Null And basic.exists And basic.visible) basic.Draw()
		Next
	End Method

	Method MaxSize:Int() Property
		Return _maxSize
	End Method

	Method MaxSize:Void(size:Int) Property
		_maxSize = size

		If (_marker >= _maxSize) _marker = 0
		If (_maxSize = 0 Or _members = Null Or _maxSize >= members.Length) Return

		Local basic:FlxBasic
		For Local i:Int = _memebers.Length - 1 To _maxSize Step -1
			basic = _members.Pop()
			If (basic <> Null) basic.Destroy()
		Next
	End Method

	Method Add:FlxBasic(object:FlxBasic)
		If ((_maxSize > 0 And _length >= _maxSize) Or _members.Contains(object)) Return object

		If (_isFragmented) Then
			If (_length < _members.Length) Then
				Local l:Int = _members.Length - 1
				Local basic:FlxBasic = new FlxBasic()

				For Local i = 0 To l
					basic = _members.Get(i)
					If (basic = Null) Then
						_members.Set(i, object)
						_length+=1
						Return object
					End if
				Next
			End If

			_isFragmented = False
		End If

		_members.Push(object)
		_length+=1
		Return object
	End Method

	Method Recycle(objectClass:FlxBasicClass = null)

	End Method

	Method Remove:FlxBasic(object:FlxBasic, splice:Bool = False)
		Local index:Int = _members.IndexOf(object)

		If (index < 0) Return Null

		If (splice) Then
			_members.Remove(index)
		Else
			_members.Set(index, Null)
			_isFragmented = True
		End If

		_length-=1
		Return object
	End Method

	Method GetFirstAvailable(objectClass:FlxBasicClass = null)

	End Method

End Class

Interface FlxGroupCaller

	Method Call(obj:FlxBasic)

End Interface

Interface FlxGroupComparator

	Method Compare:Int(lhs:FlxBasic,rhs:FlxBasic)

End Interface

Private
Class FlxBasicStack Extends Stack<FlxBasic>

	Field comparator:FlxGroupComparator

	Method Compare:Int(lhs:FlxBasic, rhs:FlxBasic)
		Return comparator.Compare(lhs, rhs)
	End Method

	Method IndexOf:Int(object:FlxBasic)
		Local i:Int = 0
		For Local basic:FlxBasic = EachIn Self
			If Equals(basic, object) Return i
			i+=1
		Next

		Return -1
	End

End Class

#rem
	header:This module contains the FlxGroup class.
#end

Import flxbasic

Class FlxGroup Extends FlxBasic

	Const ASCENDING:Bool = True

	Const DESCENDING:Bool = False

Private
	Field _members:FlxBasicStack

	Field _maxSize:Int

	Field _marker:Int

	Field _isFragmented:Bool

	Field _length:Int

Public
	Method New(maxSize:Int = 0)
		Super.New()
		_members = New FlxBasicStack()
		_maxSize = maxSize
		_marker = 0
		_isFragmented = False
		_length = 0
	End Method

	Method Members:Stack<FlxBasic>() Property
		Return _members
	End Method

	Method Length:Int() Property
		Return _members.Length
	End Method

	Method Destroy:Void()
		If (_members <> Null) Then
			For Local basic:FlxBasic = EachIn _members
				If (basic <> Null) basic.Destroy()
			Next

			_members.Clear()
			_members = null
		End If
	End Method

	Method Update:Void()
		For Local basic:FlxBasic = EachIn _members
			If (basic <> Null And basic.exists And basic.active) Then
				basic.PreUpdate()
				basic.Update()
				basic.PostUpdate()
			End If
		Next
	End Method

	Method Draw:Void()
		For Local basic:FlxBasic = EachIn _members
			If (basic <> Null And basic.exists And basic.visible) basic.Draw()
		Next
	End Method

	Method MaxSize:Int() Property
		Return _maxSize
	End Method

	Method MaxSize:Void(size:Int) Property
		_maxSize = size

		If (_marker >= _maxSize) _marker = 0
		If (_maxSize = 0 Or _members = Null Or _maxSize >= members.Length) Return

		Local basic:FlxBasic
		For Local i:Int = _memebers.Length - 1 To _maxSize Step -1
			basic = _members.Pop()
			If (basic <> Null) basic.Destroy()
		Next
	End Method

	Method Add:FlxBasic(object:FlxBasic)
		If ((_maxSize > 0 And _length >= _maxSize) Or _members.Contains(object)) Return object

		If (_isFragmented) Then
			If (_length < _members.Length) Then
				Local l:Int = _members.Length - 1
				Local basic:FlxBasic = new FlxBasic()

				For Local i = 0 To l
					basic = _members.Get(i)
					If (basic = Null) Then
						_members.Set(i, object)
						_length+=1
						Return object
					End if
				Next
			End If

			_isFragmented = False
		End If

		_members.Push(object)
		_length+=1
		Return object
	End Method

	Method Recycle(objectClass:FlxBasicClass = null)

	End Method

	Method Remove:FlxBasic(object:FlxBasic, splice:Bool = False)
		Local index:Int = _members.IndexOf(object)

		If (index < 0) Return Null

		If (splice) Then
			_members.Remove(index)
		Else
			_members.Set(index, Null)
			_isFragmented = True
		End If

		_length-=1
		Return object
	End Method

	Method GetFirstAvailable(objectClass:FlxBasicClass = null)

	End Method

End Class

Interface FlxGroupCaller

	Method Call(obj:FlxBasic)

End Interface

Interface FlxGroupComparator

	Method Compare:Int(lhs:FlxBasic,rhs:FlxBasic)

End Interface

Private
Class FlxBasicStack Extends Stack<FlxBasic>

	Field comparator:FlxGroupComparator

	Method Compare:Int(lhs:FlxBasic, rhs:FlxBasic)
		Return comparator.Compare(lhs, rhs)
	End Method

	Method IndexOf:Int(value:FlxBasic)
		Local i:Int = 0
		For Local basic:FlxBasic = EachIn Self
			If Equals(Get(i), value) Return i
			i+=1
		Next

		Return -1
	End

End Class


Modes within Align.AdjustVertial fixed

Modes within Align.AdjustVertial fixed

Strict

Private

Import bono.utils
Import sizeable

Public

Class Align Abstract
    Const TOP:Int = 0
    Const BOTTOM:Int = 1
    Const LEFT:Int = 2
    Const RIGHT:Int = 3
    Const CENTER:Int = 4

    Function AdjustHorizontal:Void(pos:Vector2D, object:Sizeable, mode:Int)
        Select mode
        Case LEFT
            ' Default alignment - nothing to do here
        Case RIGHT
            pos.x -= object.size.x
        Case CENTER
            pos.x -= object.size.x / 2
        Default
            Error("Invalid alignment mode (" + mode + ") given")
        End
    End

    Function AdjustVertical:Void(pos:Vector2D, object:Sizeable, mode:Int)
        Select mode
        Case TOP
            ' Default alignment - nothing to do here
        Case BOTTOM
            pos.y -= object.size.y
        Case CENTER
            pos.y -= object.size.y / 2
        Default
            Error("Invalid alignment mode (" + mode + ") given")
        End
    End
End

Strict

Private

Import bono.utils
Import sizeable

Public

Class Align Abstract
    Const TOP:Int = 0
    Const BOTTOM:Int = 1
    Const LEFT:Int = 2
    Const RIGHT:Int = 3
    Const CENTER:Int = 4

    Function AdjustHorizontal:Void(pos:Vector2D, object:Sizeable, mode:Int)
        Select mode
        Case LEFT
            ' Default alignment - nothing to do here
        Case RIGHT
            pos.x -= object.size.x
        Case CENTER
            pos.x -= object.size.x / 2
        Default
            Error("Invalid alignment mode (" + mode + ") given")
        End
    End

    Function AdjustVertical:Void(pos:Vector2D, object:Sizeable, mode:Int)
        Select mode
        Case LEFT
            ' Default alignment - nothing to do here
        Case RIGHT
            pos.y -= object.size.y
        Case CENTER
            pos.y -= object.size.y / 2
        Default
            Error("Invalid alignment mode (" + mode + ") given")
        End
    End
End