Minor comment cleanup in 'bufferview'.

Minor comment cleanup in 'bufferview'.

Strict

Public

#Rem
	TODO:
		* Replace uses of 'Int' and 'Float' with 'Long' and 'Double'.
			('LongArrayView', 'DoubleArrayView', etc)
#End

' Preprocessor related:
#REGAL_UTIL_BUFFERVIEW = True

#REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS = True

'#If CONFIG = "debug"
	'#REGAL_UTIL_BUFFERVIEW_SAFE = True
'#End

' Imports (Public):
Import brl.databuffer

' Imports (Private):
Private

Import memory

Import regal.sizeof
Import regal.typetool

Import monkey.math

Public

' Interfaces:
Interface BufferView
	' Constant variable(s):
	Const MAX_VIEW_ELEMENTS:= 0 ' -1

	' Methods:
	' Nothing so far.

	' Properties:
	Method Data:DataBuffer() Property
	Method Offset:UInt() Property ' Int
End

Interface ElementView Extends BufferView
	' Methods:

	' This converts 'Index' into a "raw address";
	' used for internal memory operations.
	' For details, view the 'ArrayView.OffsetIndexToAddress' command.
	Method IndexToRawAddress:UInt(Index:UInt)

	' Properties:

	' This supplies the raw size of this view.
	' For details, view the 'ArrayView.Size' property.
	Method Size:UInt() Property ' Int

	' This specifies the size of each element in this view.
	Method ElementSize:UInt() Property ' Int
End

' Classes:
Class ArrayView<ValueType> Implements ElementView Abstract ' BufferView
	' Constant variable(s) (Public):
	Const MAX_VIEW_ELEMENTS:= BufferView.MAX_VIEW_ELEMENTS

	' Global variable(s) (Protected):
	Protected

	Global NIL:ValueType

	Public

	' Constructor(s) (Public):

	#Rem
		NOTES:
			* The 'ElementCount' argument(s) is/are bound by the amount of memory given to the view.
				This means the segment of a buffer that you intend to map must be at least the
				length you specify, scaled according to the requested size for each element.

				An invalid size will result in an exception.
	#End

	Method New(ElementSize:UInt, ElementCount:UInt, __Direct:Bool=False)
		Self.ElementSize = ElementSize

		InitializeCustomBuffer(ElementSize, ElementCount, __Direct)
	End

	Method New(ElementSize:UInt, Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Self.Offset = OffsetInBytes
		Self.ElementSize = ElementSize
		Self.Data = Data

		Self.Size = GetSize(Data, ElementSize, ElementCount)
	End

	' The 'ExtraOffset' argument is used to offset from the 'View' object's offset.
	Method New(ElementSize:UInt, View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Self.ElementSize = ElementSize

		Self.Offset = (View.Offset + ExtraOffset)

		Self.Data = View.Data

		Self.Size = GetSize(Self.Data, ElementSize, ElementCount)
	End

	' Constructor(s) (Private):
	Private

	Method GetSize:UInt(Data:DataBuffer, ElementSize:UInt, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		If (ElementCount = MAX_VIEW_ELEMENTS) Then
			Return Data.Length
		Endif

		Local IntendedSize:= (ElementCount * ElementSize) ' CountInBytes(ElementCount)

		' Make sure the intended size is correct.
		If (IntendedSize < ElementSize Or IntendedSize > Data.Length) Then
			' The intended size is either too large, or too small.
			Throw New InvalidViewMappingOperation(Self, Offset, IntendedSize)
		Endif

		Return IntendedSize
	End

	' NOTE: It is considered unsafe to call this constructor before assigning a value to the 'ElementSize' property.
	Method InitializeCustomBuffer:Void(ElementSize:UInt, ElementCount:UInt, __Direct:Bool=False) Final
		If (ElementSize = 0 Or ElementCount = 0) Then
			Throw New BulkAllocationException<BufferView>(Self, 0) ' IntendedSize
		Endif

		Local IntendedSize:= (ElementCount * ElementSize)

		Self.Data = New DataBuffer(IntendedSize, __Direct) ' CountInBytes(ElementCount)

		Self.Offset = 0
		Self.Size = Self.Data.Length
	End

	Public

	' Methods (Public):

	' If overridden, these methods must respect the 'Offset' property:
	Method Get:ValueType(Index:UInt)
		Return GetRaw(Offset + IndexToAddress(Index))
	End

	Method Set:Void(Index:UInt, Value:ValueType)
		SetRaw(Offset + IndexToAddress(Index), Value)

		Return
	End

	' This performs a raw memory transfer/copy from this view to 'Output'.
	' This means the output is not casted, but rather a mapped copy of the data.
	Method Transfer:Bool(InputIndex:UInt, Output:ElementView, OutputIndex:Int, Count:UInt) ' ArrayView
		Return ArrayViewOperation<ArrayView, ElementView>.Transfer(Self, InputIndex, Output, OutputIndex, Count) ' ArrayView<ValueType>
	End

	' This performs an element-level transfer/copy from 'Input' to this view.
	' This means that each element is casted from their source type/size to the destination type/size.
	Method Copy:Bool(Index:UInt, Input:ArrayView, InputIndex:Int, Count:UInt) ' ArrayView<ValueType>
		Return ArrayViewOperation<ArrayView, ArrayView>.Copy(Input, InputIndex, Self, Index, Count) ' ArrayView<ValueType>
	End

	Method Copy:Bool(Index:UInt, Input:ArrayView, InputIndex:Int=0)
		Return Copy(Index, Input, InputIndex, Min(Self.Length, Input.Length))
	End

	Method Copy:Bool(Input:ArrayView)
		Return Copy(0, Input, 0)
	End

	' This returns 'False' if the bounds specified are considered invalid.
	Method GetArray:Bool(Index:UInt, Output:ValueType[], Count:UInt, OutputOffset:UInt=0)
		' Calculate the end-point we'll be reaching.
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		' Make sure the end-point fits within our buffer-segment.
		If (ByteBounds > Size) Then
			Return False
		Endif

		' This will be used to store our current write-location in 'Output'.
		Local OutputPosition:= OutputOffset

		' The current raw address in the internal buffer.
		Local Address:= OffsetIndexToAddress(Index)

		' Continue until we've reached our described bounds.
		While (Address < ByteBounds)
			' Copy the value located at 'Address' into the output.
			Output[OutputPosition] = GetRaw_Unsafe(Address)

			' Move to the next target-location for the output-data.
			OutputPosition += 1

			' Move forward by one entry.
			Address += ElementSize
		Wend

		' Return the default response.
		Return True
	End

	Method GetArray:ValueType[](Index:UInt, Count:UInt, _ArrOff:UInt=0)
		Local Output:= New ValueType[_ArrOff + Count]

		If (Not GetArray(Index, Output, Count, _ArrOff)) Then
			Return []
		Endif

		Return Output
	End

	Method GetArray:ValueType[]()
		Return GetArray(0, Length)
	End

	' This returns 'False' if the bounds specified are considered invalid.
	Method SetArray:Bool(Index:UInt, Input:ValueType[], Count:UInt, InputOffset:UInt=0)
		' Calculate the end-point we'll be reaching.
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		' Make sure the end-point fits within our buffer-segment.
		If (ByteBounds > Size) Then
			Return False
		Endif

		' This will store our current position in the 'Input' array.
		Local InputPosition:= InputOffset

		' The current raw address in the internal buffer.
		Local Address:= OffsetIndexToAddress(Index)

		' The amount 'Address' will move by on each iteration.
		Local Stride:= ElementSize

		' Continue until we've reached our described bounds.
		While (Address < ByteBounds)
			' Write a value at the current address using an entry from the input-data.
			SetRaw_Unsafe(Address, Input[InputPosition])

			' Move to the next entry in the input-data.
			InputPosition += 1

			' Move forward by one entry.
			Address += Stride
		Wend

		' Return the default response.
		Return True
	End

	Method SetArray:Bool(Index:UInt, Input:ValueType[])
		Return SetArray(Index, Input, Input.Length)
	End

	' TODO: Optimize this overload to bypass index conversion.
	Method SetArray:Bool(Input:ValueType[])
		Return SetArray(0, Input)
	End

	' This returns 'False' if the bounds specified are considered invalid.
	Method Clear:Bool(Index:UInt, Count:UInt, Value:ValueType)
		' Calculate the end-point we'll be reaching.
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		' Make sure the end-point fits within our buffer-segment.
		If (ByteBounds > ViewBounds) Then
			Return False
		Endif

		' The current raw address in the internal buffer.
		Local Address:= OffsetIndexToAddress(Index)

		' The amount 'Address' will move by on each iteration.
		Local Stride:= ElementSize

		' Continue until we've reached our described bounds.
		While (Address < ByteBounds)
			' Clear an entry at our current location in the buffer.
			SetRaw(Address, Value)

			' Move forward by one entry.
			Address += Stride
		Wend

		' Return the default response.
		Return True
	End

	' This calls 'Clear' using the value of 'NIL'.
	Method Clear:Bool(Index:UInt, Count:UInt)
		Return Clear(Index, Count, NIL)
	End

	' This clears the entire view using the value specified.
	Method Clear:Bool(Value:ValueType)
		Return Clear(0, Length, Value)
	End

	' TODO: Optimize this overload to bypass either index conversion or standard assignment.
	Method Clear:Bool()
		Return Clear(NIL)
	End

	Method Add:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) + Value)

		Set(Index, Result)

		Return Result
	End

	Method Subtract:ValueType(Index:UInt, Value:ValueType)
		Return Add(Index, -Value)
	End

	' This supplies the raw size of 'Count' elements in bytes.
	Method CountInBytes:UInt(Count:Int)
		Return IndexToAddress(Count) ' (Count * ElementSize)
	End

	' This converts an index to a raw address for use with the internal buffer.
	Method IndexToAddress:UInt(Index:UInt)
		#If REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Index
			Endif
		#End

		Return (Index * ElementSize)
	End

	' This converts a raw address to an index.
	Method AddressToIndex:UInt(Address:UInt)
		#If REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Address
			Endif
		#End

		Return (Address / ElementSize)
	End

	#Rem
		The result of this method is a non-convertible raw address.
		By definition, this address may not be used with commands like
		'AddressToIndex', as the value would be skewed.

		To fix this address for such commands, subtract a stored result gathered
		from the 'Offset' property at the time this method was called.

		Because the value of 'Offset' can be changed, you must always ensure that
		the offset you apply to restore the appropriate value corresponds with the
		original value associated with this object's 'Offset' property.

		This type of address manipulation is not recommended,
		and should be avoided wherever possible.
	#End

	Method OffsetIndexToAddress:UInt(Index:UInt) Final
		Return (IndexToAddress(Index) + Offset)
	End

	' This method is an extension, which should only be used when converting
	' a value from a real address to a convertible address.
	' This command is not recommended, and is subject to deletion.
	Method __OffsetAddressToIndex:UInt(_Address:UInt) Final
		Return AddressToIndex(_Address - Offset)
	End

	' Methods (Protected):
	Protected

	' Abstract:

	' These two methods operate on raw addresses.
	' This means the input should not be an index,
	' nor should it be a non-offset address.
	' Implementations should not bother with out-of-bounds checks.
	Method GetRaw_Unsafe:ValueType(RawAddress:UInt) Abstract
	Method SetRaw_Unsafe:Void(RawAddress:UInt, Value:ValueType) Abstract

	' Implemented:

	' This method wraps 'OffsetIndexToAddress' for compatibility with the 'ElementView' interface.
	Method IndexToRawAddress:UInt(Index:UInt) Final
		Return OffsetIndexToAddress(Index)
	End

	Method SetRaw:Void(Address:UInt, Value:ValueType) Final
		Local ElementSize:= Self.ElementSize

		If ((Address + ElementSize) > ViewBounds) Then
			Throw New InvalidViewWriteOperation(Self, Address, ElementSize)
		Endif

		SetRaw_Unsafe(Address, Value)

		Return
	End

	Method GetRaw:ValueType(Address:UInt) Final
		Local ElementSize:= Self.ElementSize

		If ((Address + ElementSize) > ViewBounds) Then
			Throw New InvalidViewReadOperation(Self, Address, ElementSize)
		Endif

		Return GetRaw_Unsafe(Address)
	End

	Public

	' Properties (Public):

	' This provides the number of elements in this view.
	Method Length:UInt() Property
		#If REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Size
			Endif
		#End

		Return (Size / ElementSize)
	End

	' This describes the address of the absolute furthest into the internal buffer this view reaches.
	' This is mainly useful for raw bounds checks that already account for offsets.
	' For a good example of this, view the 'GetArray' command's implementation(s).
	Method ViewBounds:UInt() Property
		Return (Size + Offset)
	End

	' This returns the raw size of the internal buffer area (In bytes), without adjusting for offsets.
	' This is useful when the literal size (In bytes) of this view is required.
	Method Size:UInt() Property ' Int
		Return Self._Size ' UInt(Data.Length)
	End

	' This specifies the size of an element.
	Method ElementSize:UInt() Property
		Return Self._ElementSize
	End

	' This provides access to the internal buffer-offset.
	' Note: This is already accounted for when calculating 'Size'.
	Method Offset:UInt() Property ' Int
		Return Self._Offset
	End

	Method Offset:Void(Value:UInt) Property
		Self._Offset = Value

		#If REGAL_UTIL_BUFFERVIEW_SAFE
			' Nothing so far.
		#End

		Return
	End

	' This provides access to the internal buffer.
	Method Data:DataBuffer() Property ' Final
		Return Self._Data
	End

	' Properties (Protected):
	Protected

	Method Size:Void(Value:UInt) Property
		Self._Size = Value

		Return
	End

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

		Return
	End

	Method ElementSize:Void(Value:UInt) Property
		Self._ElementSize = Value

		Return
	End

	Public

	' Fields (Protected):
	Protected

	Field _ElementSize:UInt ' Int
	Field _Offset:UInt ' Int
	Field _Size:UInt ' Int
	Field _Data:DataBuffer

	Public
End

' This is an intermediate class which defines mathematical routines for both integral and floating-point types.
Class MathArrayView<ValueType> Extends ArrayView<ValueType> Abstract
	' Constructor(s):
	Method New(ElementSize:UInt, ElementCount:UInt, __Direct:Bool=False)
		Super.New(ElementSize, ElementCount, __Direct)
	End

	Method New(ElementSize:UInt, Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(ElementSize, Data, OffsetInBytes, ElementCount)
	End

	Method New(ElementSize:UInt, View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(ElementSize, View, ElementCount, ExtraOffset)
	End

	' Methods:

	' This increments the value located at 'Index' by one.
	Method Increment:ValueType(Index:UInt)
		Return Add(Index, ValueType(1))
	End

	' This decrements the value located at 'Index' by one.
	Method Decrement:ValueType(Index:UInt)
		Return Subtract(Index, ValueType(1))
	End

	' This multiplies the value located at 'Index' using the value specified.
	' The result is written into memory, then returned.
	Method Multiply:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) * Value)

		Set(Index, Result)

		Return Result
	End

	' This divides the value located at 'Index' using the value specified.
	' The result is written into memory, then returned.
	Method Divide:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) / Value)

		Set(Index, Result)

		Return Result
	End

	' This squares the value located at 'Index'.
	' The result is both returned by the method, and
	' written into memory at the specified location.
	Method Sq:ValueType(Index:UInt) ' Square
		Local Value:= Get(Index)
		Local Result:= (Value * Value)

		Set(Index, Result)

		Return Result
	End

	' This calculates the square-root of the value located at 'Index'.
	' The result is both returned by this method, and
	' written into memory at the specified location.
	Method Sqrt:ValueType(Index:UInt) ' SquareRoot
		Local Result:= Sqrt(Get(Index))

		Set(Index, Result)

		Return Result
	End
End

Class IntArrayView Extends MathArrayView<Int> ' ArrayView<Long> ' Int ' LongArrayView
	' Constant variable(s):
	Const Type_Size:= SizeOf_Integer ' 4

	' Constructor(s) (Public):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	' Constructor(s) (Protected):
	Protected

	Method New(Type_Size:UInt, ElementCount:UInt, __Direct:Bool=False)
		Super.New(Type_Size, ElementCount, __Direct)
	End

	Method New(Type_Size:UInt, Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(Type_Size:UInt, View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	Public

	' Methods (Public):
	Method GetUnsigned:Int(Index:UInt)
		Return (Get(Index) & $FFFFFFFF)
	End

	Method SetUnsigned:Void(Index:UInt, Value:Int)
		Set(Index, (Value & $FFFFFFFF))

		Return
	End

	' Methods (Protected):
	Protected

	Method GetRaw_Unsafe:Int(Address:UInt) ' Final
		Return Data.PeekInt(Address)
	End

	Method SetRaw_Unsafe:Void(Address:UInt, Value:Int) ' Final
		Data.PokeInt(Address, Value)

		Return
	End

	Public
End

Class ShortArrayView Extends IntArrayView ' ArrayView<Int> ' Short
	' Constant variable(s):
	Const Type_Size:= SizeOf_Short

	' Constructor(s) (Public):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	' Constructor(s) (Protected):
	Protected

	Method New(Type_Size:UInt, ElementCount:UInt, __Direct:Bool=False)
		Super.New(Type_Size, ElementCount, __Direct)
	End

	Method New(Type_Size:UInt, Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(Type_Size:UInt, View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	Public

	' Methods (Public):
	Method GetUnsigned:Int(Index:UInt) ' Short
		Return (Get(Index) & $FFFF)
	End

	Method SetUnsigned:Void(Index:UInt, Value:Int) ' Short
		Set(Index, (Value & $FFFF))

		Return
	End

	' Methods (Protected):
	Protected

	Method GetRaw_Unsafe:Int(Address:UInt) ' Final ' Short
		Return Data.PeekShort(Address)
	End

	Method SetRaw_Unsafe:Void(Address:UInt, Value:Int) ' Final ' Short
		Data.PokeShort(Address, Value)

		Return
	End

	Public
End

Class ByteArrayView Extends ShortArrayView ' ArrayView<Int> ' Byte
	' Constant variable(s):
	Const Type_Size:= SizeOf_Byte

	' Constructor(s):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	' Methods (Public):
	#If REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS
		' These two methods follow the integrity rules of 'Offset':
		Method Get:Int(Address:UInt) ' Byte
			Return GetRaw(Offset + Address)
		End

		Method Set:Void(Address:UInt, Value:Int) ' Byte
			SetRaw(Offset + Address, Value)

			Return
		End

		#Rem
			Method IndexToAddress:UInt(Address:UInt) ' Index:UInt
				Return Address
			End

			Method AddressToIndex:UInt(Address:UInt)
				Return Address
			End
		#End
	#End

	Method GetUnsigned:Int(Address:UInt) ' Byte
		Return (Get(Address) & $FF)
	End

	Method SetUnsigned:Void(Index:UInt, Value:Int) ' Byte
		Set(Index, (Value & $FF))

		Return
	End

	' Methods (Protected):
	Protected

	Method GetRaw_Unsafe:Int(Address:UInt) ' Final ' Byte
		Return Data.PeekByte(Address)
	End

	Method SetRaw_Unsafe:Void(Address:UInt, Value:Int) ' Final ' Byte
		Data.PokeByte(Address, Value)

		Return
	End

	Public
End

Class FloatArrayView Extends MathArrayView<Float> ' DoubleArrayView
	' Constant variable(s):
	Const Type_Size:= SizeOf_Float ' 4 ' 8

	' Constructor(s):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	' Methods (Protected):
	Protected

	Method GetRaw_Unsafe:Float(Address:UInt) ' Final ' Double
		Return Data.PeekFloat(Address)
	End

	Method SetRaw_Unsafe:Void(Address:UInt, Value:Float) ' Final ' Double
		Data.PokeFloat(Address, Value)

		Return
	End

	Public
End

' This class contains generic utilities for 'ArrayView' objects.
Class ArrayViewOperation<A, B> Abstract
	#Rem
		This performs a raw memory copy from one view to another.

		Address translations are performed before copy-operations
		take place, and are checked accordingly.

		The 'Count' argument specifies the number of elements to be copied from 'Input'.

		If preliminary bounds checks fail, this command will return 'False'.
	#End

	Function Transfer:Bool(Input:A, InputIndex:UInt, Output:B, OutputIndex:Int, Count:UInt) ' ArrayView ' ElementView
		' Get the appropriate element size.
		Local ElementSize:= Input.ElementSize ' Min(Input.ElementSize, Output.ElementSize)
		Local BytesToTransfer:= (ElementSize * Count)

		' Calculate the end-points we'll be reaching:
		Local InByteBounds:= Input.IndexToRawAddress(InputIndex + Count)
		Local OutByteBounds:= Output.IndexToRawAddress(OutputIndex) + BytesToTransfer ' Output.IndexToRawAddress(OutputIndex + Count)

		' Make sure the end-points fit within our buffer segments:
		If (InByteBounds > Input.Size Or OutByteBounds > Output.Size) Then
			Return False
		Endif

		' The starting raw address in the output buffer.
		Local OutputAddress:= Output.IndexToRawAddress(OutputIndex)

		' The starting raw address in the input buffer.
		Local InputAddress:= Input.IndexToRawAddress(InputIndex)

		' Perform a raw memory copy from 'Input.Data' to 'Output.Data'.
		Input.Data.CopyBytes(InputAddress, Output.Data, OutputAddress, BytesToTransfer)

		' Return the default response.
		Return True
	End

	' This performs an element-level copy from one view to another.
	' If preliminary bounds checks fail, this command will return 'False'.
	Function Copy:Bool(Input:A, InputIndex:UInt, Output:B, OutputIndex:Int, Count:UInt) ' ArrayView ' ElementView
		' Calculate the appropriate element size.
		Local InElementSize:= Input.ElementSize
		Local OutElementSize:= Output.ElementSize

		' Calculate the end-points we'll be reaching:
		Local InByteBounds:= Input.IndexToRawAddress(InputIndex + Count)
		Local OutByteBounds:= Output.IndexToRawAddress(OutputIndex + Count)

		' Make sure the end-points fit within our buffer segments:
		If (InByteBounds > Input.Size Or OutByteBounds > Output.Size) Then
			Return False
		Endif

		' The starting raw address in the output buffer.
		Local OutputAddress:= Output.IndexToRawAddress(OutputIndex)

		' The starting raw address in the input buffer.
		Local InputAddress:= Input.IndexToRawAddress(InputIndex)

		' Continue until we've reached our described bounds:
		While (InputAddress < InByteBounds)
			#If CONFIG = "debug"
				If (OutputAddress >= OutByteBounds) Then
					Exit
				Endif
			#End

			' Copy the value located at 'InputAddress' into the output at 'OutputAddress'.
			Output.SetRaw_Unsafe(OutputAddress, Input.GetRaw_Unsafe(InputAddress))

			' Move forward by one entry on each address:
			InputAddress += InElementSize
			OutputAddress += OutElementSize
		Wend

		' Return the default response.
		Return True
	End

	' Constructor(s) (Private):
	Private

	Method New() ' Final
		' This constructor is reserved.
	End

	Public
End

Class ElementViewOperation Extends ArrayViewOperation<ElementView, ElementView>
	' Nothing so far.
End

Strict

Public

#Rem
	TODO:
		* Replace uses of 'Int' and 'Float' with 'Long' and 'Double'.
			('LongArrayView', 'DoubleArrayView', etc)
#End

' Preprocessor related:
#REGAL_UTIL_BUFFERVIEW = True

#REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS = True

'#If CONFIG = "debug"
	'#REGAL_UTIL_BUFFERVIEW_SAFE = True
'#End

' Imports (Public):
Import brl.databuffer

' Imports (Private):
Private

Import memory

Import regal.sizeof
Import regal.typetool

Import monkey.math

Public

' Interfaces:
Interface BufferView
	' Constant variable(s):
	Const MAX_VIEW_ELEMENTS:= 0 ' -1

	' Methods:
	' Nothing so far.

	' Properties:
	Method Data:DataBuffer() Property
	Method Offset:UInt() Property ' Int
End

Interface ElementView Extends BufferView
	' Methods:

	' This converts 'Index' into a "raw address";
	' used for internal memory operations.
	' For details, view the 'ArrayView.OffsetIndexToAddress' command.
	Method IndexToRawAddress:UInt(Index:UInt)

	' Properties:

	' This supplies the raw size of this view.
	' For details, view the 'ArrayView.Size' property.
	Method Size:UInt() Property ' Int

	' This specifies the size of each element in this view.
	Method ElementSize:UInt() Property ' Int
End

' Classes:
Class ArrayView<ValueType> Implements ElementView Abstract ' BufferView
	' Constant variable(s) (Public):
	Const MAX_VIEW_ELEMENTS:= BufferView.MAX_VIEW_ELEMENTS

	' Global variable(s) (Protected):
	Protected

	Global NIL:ValueType

	Public

	' Constructor(s) (Public):

	#Rem
		NOTES:
			* The 'ElementCount' argument(s) is/are bound by the amount of memory given to the view.
				This means the segment of a buffer that you intend to map must be at least the
				length you specify, scaled according to the requested size for each element.

				An invalid size will result in an exception.
	#End

	Method New(ElementSize:UInt, ElementCount:UInt, __Direct:Bool=False)
		Self.ElementSize = ElementSize

		InitializeCustomBuffer(ElementSize, ElementCount, __Direct)
	End

	Method New(ElementSize:UInt, Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Self.Offset = OffsetInBytes
		Self.ElementSize = ElementSize
		Self.Data = Data

		Self.Size = GetSize(Data, ElementSize, ElementCount)
	End

	' The 'ExtraOffset' argument is used to offset from the 'View' object's offset.
	Method New(ElementSize:UInt, View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Self.ElementSize = ElementSize

		Self.Offset = (View.Offset + ExtraOffset)

		Self.Data = View.Data

		Self.Size = GetSize(Self.Data, ElementSize, ElementCount)
	End

	' Constructor(s) (Private):
	Private

	Method GetSize:UInt(Data:DataBuffer, ElementSize:UInt, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		If (ElementCount = MAX_VIEW_ELEMENTS) Then
			Return Data.Length
		Endif

		Local IntendedSize:= (ElementCount * ElementSize) ' CountInBytes(ElementCount)

		' Make sure the intended size is correct.
		If (IntendedSize < ElementSize Or IntendedSize > Data.Length) Then
			' The intended size is either too large, or too small.
			Throw New InvalidViewMappingOperation(Self, Offset, IntendedSize)
		Endif

		Return IntendedSize
	End

	' NOTE: It is considered unsafe to call this constructor before assigning a value to the 'ElementSize' property.
	Method InitializeCustomBuffer:Void(ElementSize:UInt, ElementCount:UInt, __Direct:Bool=False) Final
		If (ElementSize = 0 Or ElementCount = 0) Then
			Throw New BulkAllocationException<BufferView>(Self, 0) ' IntendedSize
		Endif

		Local IntendedSize:= (ElementCount * ElementSize)

		Self.Data = New DataBuffer(IntendedSize, __Direct) ' CountInBytes(ElementCount)

		Self.Offset = 0
		Self.Size = Self.Data.Length
	End

	Public

	' Methods (Public):

	' If overridden, these methods must respect the 'Offset' property:
	Method Get:ValueType(Index:UInt)
		Return GetRaw(Offset + IndexToAddress(Index))
	End

	Method Set:Void(Index:UInt, Value:ValueType)
		SetRaw(Offset + IndexToAddress(Index), Value)

		Return
	End

	' This performs a raw memory transfer/copy from this view to 'Output'.
	' This means the output is not casted, but rather a mapped copy of the data.
	Method Transfer:Bool(InputIndex:UInt, Output:ElementView, OutputIndex:Int, Count:UInt) ' ArrayView
		Return ArrayViewOperation<ArrayView, ElementView>.Transfer(Self, InputIndex, Output, OutputIndex, Count) ' ArrayView<ValueType>
	End

	' This performs an element-level transfer/copy from 'Input' to this view.
	' This means that each element is casted from their source type/size to the destination type/size.
	Method Copy:Bool(Index:UInt, Input:ArrayView, InputIndex:Int, Count:UInt) ' ArrayView<ValueType>
		Return ArrayViewOperation<ArrayView, ArrayView>.Copy(Input, InputIndex, Self, Index, Count) ' ArrayView<ValueType>
	End

	Method Copy:Bool(Index:UInt, Input:ArrayView, InputIndex:Int=0)
		Return Copy(Index, Input, InputIndex, Min(Self.Length, Input.Length))
	End

	Method Copy:Bool(Input:ArrayView)
		Return Copy(0, Input, 0)
	End

	' This returns 'False' if the bounds specified are considered invalid.
	Method GetArray:Bool(Index:UInt, Output:ValueType[], Count:UInt, OutputOffset:UInt=0)
		' Calculate the end-point we'll be reaching.
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		' Make sure the end-point fits within our buffer-segment.
		If (ByteBounds > Size) Then
			Return False
		Endif

		' This will be used to store our current write-location in 'Output'.
		Local OutputPosition:= OutputOffset

		' The current raw address in the internal buffer.
		Local Address:= OffsetIndexToAddress(Index)

		' Continue until we've reached our described bounds.
		While (Address < ByteBounds)
			' Copy the value located at 'Address' into the output.
			Output[OutputPosition] = GetRaw_Unsafe(Address)

			' Move to the next target-location for the output-data.
			OutputPosition += 1

			' Move forward by one entry.
			Address += ElementSize
		Wend

		' Return the default response.
		Return True
	End

	Method GetArray:ValueType[](Index:UInt, Count:UInt, _ArrOff:UInt=0)
		Local Output:= New ValueType[_ArrOff + Count]

		If (Not GetArray(Index, Output, Count, _ArrOff)) Then
			Return []
		Endif

		Return Output
	End

	Method GetArray:ValueType[]()
		Return GetArray(0, Length)
	End

	' This returns 'False' if the bounds specified are considered invalid.
	Method SetArray:Bool(Index:UInt, Input:ValueType[], Count:UInt, InputOffset:UInt=0)
		' Calculate the end-point we'll be reaching.
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		' Make sure the end-point fits within our buffer-segment.
		If (ByteBounds > Size) Then
			Return False
		Endif

		' This will store our current position in the 'Input' array.
		Local InputPosition:= InputOffset

		' The current raw address in the internal buffer.
		Local Address:= OffsetIndexToAddress(Index)

		' The amount 'Address' will move by on each iteration.
		Local Stride:= ElementSize

		' Continue until we've reached our described bounds.
		While (Address < ByteBounds)
			' Write a value at the current address using an entry from the input-data.
			SetRaw_Unsafe(Address, Input[InputPosition])

			' Move to the next entry in the input-data.
			InputPosition += 1

			' Move forward by one entry.
			Address += Stride
		Wend

		' Return the default response.
		Return True
	End

	Method SetArray:Bool(Index:UInt, Input:ValueType[])
		Return SetArray(Index, Input, Input.Length)
	End

	' TODO: Optimize this overload to bypass index conversion.
	Method SetArray:Bool(Input:ValueType[])
		Return SetArray(0, Input)
	End

	' This returns 'False' if the bounds specified are considered invalid.
	Method Clear:Bool(Index:UInt, Count:UInt, Value:ValueType)
		' Calculate the end-point we'll be reaching.
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		' Make sure the end-point fits within our buffer-segment.
		If (ByteBounds > ViewBounds) Then
			Return False
		Endif

		' The current raw address in the internal buffer.
		Local Address:= OffsetIndexToAddress(Index)

		' The amount 'Address' will move by on each iteration.
		Local Stride:= ElementSize

		' Continue until we've reached our described bounds.
		While (Address < ByteBounds)
			' Clear an entry at our current location in the buffer.
			SetRaw(Address, Value)

			' Move forward by one entry.
			Address += Stride
		Wend

		' Return the default response.
		Return True
	End

	' This calls 'Clear' using the value of 'NIL'.
	Method Clear:Bool(Index:UInt, Count:UInt)
		Return Clear(Index, Count, NIL)
	End

	' This clears the entire view using the value specified.
	Method Clear:Bool(Value:ValueType)
		Return Clear(0, Length, Value)
	End

	' TODO: Optimize this overload to bypass either index conversion or standard assignment.
	Method Clear:Bool()
		Return Clear(NIL)
	End

	Method Add:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) + Value)

		Set(Index, Result)

		Return Result
	End

	Method Subtract:ValueType(Index:UInt, Value:ValueType)
		Return Add(Index, -Value)
	End

	' This supplies the raw size of 'Count' elements in bytes.
	Method CountInBytes:UInt(Count:Int)
		Return IndexToAddress(Count) ' (Count * ElementSize)
	End

	' This converts an index to a raw address for use with the internal buffer.
	Method IndexToAddress:UInt(Index:UInt)
		#If REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Index
			Endif
		#End

		Return (Index * ElementSize)
	End

	' This converts a raw address to an index.
	Method AddressToIndex:UInt(Address:UInt)
		#If REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Address
			Endif
		#End

		Return (Address / ElementSize)
	End

	#Rem
		The result of this method is a non-convertible raw address.
		By definition, this address may not be used with commands like
		'AddressToIndex', as the value would be skewed.

		To fix this address for such commands, subtract a stored result gathered
		from the 'Offset' property at the time this method was called.

		Because the value of 'Offset' can be changed, you must always ensure that
		the offset you apply to restore the appropriate value corresponds with the
		original value associated with this object's 'Offset' property.

		This type of address manipulation is not recommended,
		and should be avoided wherever possible.
	#End

	Method OffsetIndexToAddress:UInt(Index:UInt) Final
		Return (IndexToAddress(Index) + Offset)
	End

	' This method is an extension, which should only be used when converting
	' a value from a real address to a convertible address.
	' This command is not recommended, and is subject to deletion.
	Method __OffsetAddressToIndex:UInt(_Address:UInt) Final
		Return AddressToIndex(_Address - Offset)
	End

	' Methods (Protected):
	Protected

	' Abstract:

	' These two methods operate on raw addresses.
	' This means the input should not be an index,
	' nor should it be a non-offset address.
	' Implementations should not bother with out-of-bounds checks.
	Method GetRaw_Unsafe:ValueType(RawAddress:UInt) Abstract
	Method SetRaw_Unsafe:Void(RawAddress:UInt, Value:ValueType) Abstract

	' Implemented:

	' This method wraps 'OffsetIndexToAddress' for compatibility with the 'ElementView' interface.
	Method IndexToRawAddress:UInt(Index:UInt) Final
		Return OffsetIndexToAddress(Index)
	End

	Method SetRaw:Void(Address:UInt, Value:ValueType) Final
		Local ElementSize:= Self.ElementSize

		If ((Address + ElementSize) > ViewBounds) Then
			Throw New InvalidViewWriteOperation(Self, Address, ElementSize)
		Endif

		SetRaw_Unsafe(Address, Value)

		Return
	End

	Method GetRaw:ValueType(Address:UInt) Final
		Local ElementSize:= Self.ElementSize

		If ((Address + ElementSize) > ViewBounds) Then
			Throw New InvalidViewReadOperation(Self, Address, ElementSize)
		Endif

		Return GetRaw_Unsafe(Address)
	End

	Public

	' Properties (Public):

	' This provides the number of elements in this view.
	Method Length:UInt() Property
		#If REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Size
			Endif
		#End

		Return (Size / ElementSize)
	End

	' This describes the address of the absolute furthest into the internal buffer this view reaches.
	' This is mainly useful for raw bounds checks that already account for offsets.
	' For a good example of this, view the 'GetArray' command's implementation(s).
	Method ViewBounds:UInt() Property
		Return (Size + Offset)
	End

	' This returns the raw size of the internal buffer area (In bytes), without adjusting for offsets.
	' This is useful when the literal size (In bytes) of this view is required.
	Method Size:UInt() Property ' Int
		Return Self._Size ' UInt(Data.Length)
	End

	' This specifies the size of an element.
	Method ElementSize:UInt() Property
		Return Self._ElementSize
	End

	' This provides access to the internal buffer-offset.
	' Note: This is already accounted for when calculating 'Size'.
	Method Offset:UInt() Property ' Int
		Return Self._Offset
	End

	Method Offset:Void(Value:UInt) Property
		Self._Offset = Value

		#If REGAL_UTIL_BUFFERVIEW_SAFE
			' Nothing so far.
		#End

		Return
	End

	' This provides access to the internal buffer.
	Method Data:DataBuffer() Property ' Final
		Return Self._Data
	End

	' Properties (Protected):
	Protected

	Method Size:Void(Value:UInt) Property
		Self._Size = Value

		Return
	End

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

		Return
	End

	Method ElementSize:Void(Value:UInt) Property
		Self._ElementSize = Value

		Return
	End

	Public

	' Fields (Protected):
	Protected

	Field _ElementSize:UInt ' Int
	Field _Offset:UInt ' Int
	Field _Size:UInt ' Int
	Field _Data:DataBuffer

	Public
End

' This is an intermediate class which defines mathematical routines for both integral and floating-point types.
Class MathArrayView<ValueType> Extends ArrayView<ValueType> Abstract
	' Constructor(s):
	Method New(ElementSize:UInt, ElementCount:UInt, __Direct:Bool=False)
		Super.New(ElementSize, ElementCount, __Direct)
	End

	Method New(ElementSize:UInt, Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(ElementSize, Data, OffsetInBytes, ElementCount)
	End

	Method New(ElementSize:UInt, View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(ElementSize, View, ElementCount, ExtraOffset)
	End

	' Methods:

	' This increments the value located at 'Index' by one.
	Method Increment:ValueType(Index:UInt)
		Return Add(Index, ValueType(1))
	End

	' This decrements the value located at 'Index' by one.
	Method Decrement:ValueType(Index:UInt)
		Return Subtract(Index, ValueType(1))
	End

	' This multiplies the value located at 'Index' using the value specified.
	' The result is written into memory, then returned.
	Method Multiply:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) * Value)

		Set(Index, Result)

		Return Result
	End

	' This divides the value located at 'Index' using the value specified.
	' The result is written into memory, then returned.
	Method Divide:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) / Value)

		Set(Index, Result)

		Return Result
	End

	' This squares the value located at 'Index'.
	' The result is both returned by the method, and
	' written into memory at the specified location.
	Method Sq:ValueType(Index:UInt) ' Square
		Local Value:= Get(Index)
		Local Result:= (Value * Value)

		Set(Index, Result)

		Return Result
	End

	' This calculates the square-root of the value located at 'Index'.
	' The result is both returned by this method, and
	' written into memory at the specified location.
	Method Sqrt:ValueType(Index:UInt) ' SquareRoot
		Local Result:= Sqrt(Get(Index))

		Set(Index, Result)

		Return Result
	End
End

Class IntArrayView Extends MathArrayView<Int> ' ArrayView<Long> ' Int ' LongArrayView
	' Constant variable(s):
	Const Type_Size:= SizeOf_Integer ' 4

	' Constructor(s) (Public):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	' Constructor(s) (Protected):
	Protected

	Method New(Type_Size:UInt, ElementCount:UInt, __Direct:Bool=False)
		Super.New(Type_Size, ElementCount, __Direct)
	End

	Method New(Type_Size:UInt, Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(Type_Size:UInt, View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	Public

	' Methods (Public):
	Method GetUnsigned:Int(Index:UInt)
		Return (Get(Index) & $FFFFFFFF)
	End

	Method SetUnsigned:Void(Index:UInt, Value:Int)
		Set(Index, (Value & $FFFFFFFF))

		Return
	End

	' Methods (Protected):
	Protected

	Method GetRaw_Unsafe:Int(Address:UInt) ' Final
		Return Data.PeekInt(Address)
	End

	Method SetRaw_Unsafe:Void(Address:UInt, Value:Int) ' Final
		Data.PokeInt(Address, Value)

		Return
	End

	Public
End

Class ShortArrayView Extends IntArrayView ' ArrayView<Int> ' Short
	' Constant variable(s):
	Const Type_Size:= SizeOf_Short

	' Constructor(s) (Public):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	' Constructor(s) (Protected):
	Protected

	Method New(Type_Size:UInt, ElementCount:UInt, __Direct:Bool=False)
		Super.New(Type_Size, ElementCount, __Direct)
	End

	Method New(Type_Size:UInt, Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(Type_Size:UInt, View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	Public

	' Methods (Public):
	Method GetUnsigned:Int(Index:UInt) ' Short
		Return (Get(Index) & $FFFF)
	End

	Method SetUnsigned:Void(Index:UInt, Value:Int) ' Short
		Set(Index, (Value & $FFFF))

		Return
	End

	' Methods (Protected):
	Protected

	Method GetRaw_Unsafe:Int(Address:UInt) ' Final ' Short
		Return Data.PeekShort(Address)
	End

	Method SetRaw_Unsafe:Void(Address:UInt, Value:Int) ' Final ' Short
		Data.PokeShort(Address, Value)

		Return
	End

	Public
End

Class ByteArrayView Extends ShortArrayView ' ArrayView<Int> ' Byte
	' Constant variable(s):
	Const Type_Size:= SizeOf_Byte

	' Constructor(s):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	' Methods (Public):
	#If REGAL_UTIL_BUFFERVIEW_BYTE_OPTIMIZATIONS
		' These two methods follow the integrity rules of 'Offset':
		Method Get:Int(Address:UInt) ' Byte
			Return GetRaw(Offset + Address)
		End

		Method Set:Void(Address:UInt, Value:Int) ' Byte
			SetRaw(Offset + Address, Value)

			Return
		End

		#Rem
			Method IndexToAddress:UInt(Address:UInt) ' Index:UInt
				Return Address
			End

			Method AddressToIndex:UInt(Address:UInt)
				Return Address
			End
		#End
	#End

	Method GetUnsigned:Int(Address:UInt) ' Byte
		Return (Get(Address) & $FF)
	End

	Method SetUnsigned:Void(Index:UInt, Value:Int) ' Byte
		Set(Index, (Value & $FF))

		Return
	End

	' Methods (Protected):
	Protected

	Method GetRaw_Unsafe:Int(Address:UInt) ' Final ' Byte
		Return Data.PeekByte(Address)
	End

	Method SetRaw_Unsafe:Void(Address:UInt, Value:Int) ' Final ' Byte
		Data.PokeByte(Address, Value)

		Return
	End

	Public
End

Class FloatArrayView Extends MathArrayView<Float> ' DoubleArrayView
	' Constant variable(s):
	Const Type_Size:= SizeOf_Float ' 4 ' 8

	' Constructor(s):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0, ElementCount:UInt=MAX_VIEW_ELEMENTS)
		Super.New(Type_Size, Data, OffsetInBytes, ElementCount)
	End

	Method New(View:BufferView, ElementCount:UInt=MAX_VIEW_ELEMENTS, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ElementCount, ExtraOffset)
	End

	' Methods (Protected):
	Protected

	Method GetRaw_Unsafe:Float(Address:UInt) ' Final ' Double
		Return Data.PeekFloat(Address)
	End

	Method SetRaw_Unsafe:Void(Address:UInt, Value:Float) ' Final ' Double
		Data.PokeFloat(Address, Value)

		Return
	End

	Public
End

' This class contains generic utilities for 'ArrayView' objects.
Class ArrayViewOperation<A, B> Abstract
	#Rem
		This performs a raw memory copy from one view to another.

		Address translations are performed before copy-operations
		take place, and are checked accordingly.

		The 'Count' argument specifies the number of elements to be copied from 'Input'.

		If preliminary bounds checks fail, this command will return 'False'.
	#End

	Function Transfer:Bool(Input:A, InputIndex:UInt, Output:B, OutputIndex:Int, Count:UInt) ' ArrayView ' ElementView
		' Get the appropriate element size.
		Local ElementSize:= Input.ElementSize ' Min(Input.ElementSize, Output.ElementSize)
		Local BytesToTransfer:= (ElementSize * Count)

		' Calculate the end-points we'll be reaching:
		Local InByteBounds:= Input.IndexToRawAddress(InputIndex + Count)
		Local OutByteBounds:= Output.IndexToRawAddress(OutputIndex) + BytesToTransfer ' Output.IndexToRawAddress(OutputIndex + Count)

		' Make sure the end-point fits within our buffer segments:
		If (InByteBounds > Input.Size Or OutByteBounds > Output.Size) Then
			Return False
		Endif

		' The starting raw address in the output buffer.
		Local OutputAddress:= Output.IndexToRawAddress(OutputIndex)

		' The starting raw address in the input buffer.
		Local InputAddress:= Input.IndexToRawAddress(InputIndex)

		Input.Data.CopyBytes(InputAddress, Output.Data, OutputAddress, BytesToTransfer)

		' Return the default response.
		Return True
	End

	' This performs an element-level copy from one view to another.
	' If preliminary bounds checks fail, this command will return 'False'.
	Function Copy:Bool(Input:A, InputIndex:UInt, Output:B, OutputIndex:Int, Count:UInt) ' ArrayView ' ElementView
		' Calculate the appropriate element size.
		Local InElementSize:= Input.ElementSize
		Local OutElementSize:= Output.ElementSize

		' Calculate the end-points we'll be reaching:
		Local InByteBounds:= Input.IndexToRawAddress(InputIndex + Count)
		Local OutByteBounds:= Output.IndexToRawAddress(OutputIndex + Count)

		' Make sure the end-point fits within our buffer segments:
		If (InByteBounds > Input.Size Or OutByteBounds > Output.Size) Then
			Return False
		Endif

		' The starting raw address in the output buffer.
		Local OutputAddress:= Output.IndexToRawAddress(OutputIndex)

		' The starting raw address in the input buffer.
		Local InputAddress:= Input.IndexToRawAddress(InputIndex)

		' Continue until we've reached our described bounds.
		While (InputAddress < InByteBounds)
			#If CONFIG = "debug"
				If (OutputAddress >= OutByteBounds) Then
					Exit
				Endif
			#End

			' Copy the value located at 'Address' into the output.
			Output.SetRaw_Unsafe(OutputAddress, Input.GetRaw_Unsafe(InputAddress))

			' Move forward by one entry.
			InputAddress += InElementSize
			OutputAddress += OutElementSize
		Wend

		' Return the default response.
		Return True
	End

	' Constructor(s) (Private):
	Private

	Method New() ' Final
		' This constructor is reserved.
	End

	Public
End

Class ElementViewOperation Extends ArrayViewOperation<ElementView, ElementView>
	' Nothing so far.
End


Update flxresourcesmanager.monkey

Update flxresourcesmanager.monkey

Constructor is not private anymore

Strict

Class FlxResource<T> Abstract

	Field name:String

	Method New(name:String)
		Self.name = name
	End Method

	Method Load:T() Abstract

	Method Use:T() Abstract

	Method Discard:Void() Abstract

End Class

Class FlxResourcesManager<T>

Private
	Field _resources:StringMap<FlxResource<T>>

Public
	Method New()
		_resources = New StringMap<FlxResource<T>>()
	End Method

	Method GetResource:T(name:String, resource:FlxResource<T>)
		If (_resources.Contains(name)) Then
			Return _resources.Get(name).Use()
		End If

		Local raw:T = resource.Load()
		If (raw = Null) Error("Resource " + name + " can't be loaded")

		_resources.Set(name, resource)
		Return raw
	End Method

	Method RemoveResource:Void(name:String)
		If (_resources.Contains(name)) Then
			_resources.Get(name).Discard()
			_resources.Remove(name)
		End If
	End Method

	Method CheckResource:Bool(name:String)
		Return _resources.Contains(name)
	End Method

	Method Clear:Void()
		If (_resources.IsEmpty()) Return

		For Local res:FlxResource<T> = EachIn _resources.Values()
			res.Discard()
		Next

		_resources.Clear()
	End Method

End Class

Strict

Class FlxResource<T> Abstract

	Field name:String

	Method New(name:String)
		Self.name = name
	End Method

	Method Load:T() Abstract

	Method Use:T() Abstract

	Method Discard:Void() Abstract

End Class

Class FlxResourcesManager<T>

Private
	Field _resources:StringMap<FlxResource<T>>

	Method New()
		_resources = New StringMap<FlxResource<T>>()
	End Method

Public
	Method GetResource:T(name:String, resource:FlxResource<T>)
		If (_resources.Contains(name)) Then
			Return _resources.Get(name).Use()
		End If

		Local raw:T = resource.Load()
		If (raw = Null) Error("Resource " + name + " can't be loaded")

		_resources.Set(name, resource)
		Return raw
	End Method

	Method RemoveResource:Void(name:String)
		If (_resources.Contains(name)) Then
			_resources.Get(name).Discard()
			_resources.Remove(name)
		End If
	End Method

	Method CheckResource:Bool(name:String)
		Return _resources.Contains(name)
	End Method

	Method Clear:Void()
		If (_resources.IsEmpty()) Return

		For Local res:FlxResource<T> = EachIn _resources.Values()
			res.Discard()
		Next

		_resources.Clear()
	End Method

End Class


Added a validity check to 'WrapperStream'. (Now throws an exception by default when using an invalid stream)

#Rem
	THIS MODULE IS CURRENTLY EXPERIMENTAL; USE AT YOUR OWN RISK.
#End

Strict

Public

' Preprocessor related:
'#REGAL_IOUTIL_WRAPPERSTREAM_SAFE = True

' Imports (Public):
Import brl.stream

' Imports (Private):
Private

Import brl.databuffer

Public

' Classes:
Class WrapperStream<StreamType> Extends Stream
	' Constructor(s):
	Method New(S:StreamType, ThrowOnInvalid:Bool=True)
		If (ThrowOnInvalid) Then
			If (S = Null) Then
				Throw New InvalidWrapperStream(Self, S)
			Endif
		Endif

		Self.InternalStream = S
	End

	' Destructor(s):
	Method Close:Void()
		InternalStream.Close()

		Return
	End

	' Methods (Public):
	Method Read:Int(Buffer:DataBuffer, Offset:Int, Count:Int)
		Return InternalStream.Read(Buffer, Offset, Count)
	End

	Method Write:Int(Buffer:DataBuffer, Offset:Int, Count:Int)
		Return InternalStream.Write(Buffer, Offset, Count)
	End

	Method ReadAll:Void(Buffer:DataBuffer, Offset:Int, Count:Int)
		InternalStream.ReadAll(Buffer, Offset, Count)

		Return
	End

	Method ReadAll:DataBuffer()
		Return InternalStream.ReadAll()
	End

	Method WriteAll:Void(Buffer:DataBuffer, Offset:Int, Count:Int)
		InternalStream.WriteAll(Buffer, Offset, Count)

		Return
	End

	Method ReadString:String(Count:Int, Encoding:String="utf8")
		Return InternalStream.ReadString(Count, Encoding)
	End

	Method ReadString:String(Encoding:String="utf8")
		Return InternalStream.ReadString(Encoding)
	End

	Method ReadLine:String()
		Return InternalStream.ReadLine()
	End

	Method ReadByte:Int()
		Return InternalStream.ReadByte()
	End

	Method ReadShort:Int()
		Return InternalStream.ReadShort()
	End

	Method ReadInt:Int()
		Return InternalStream.ReadInt()
	End

	Method ReadFloat:Float()
		Return InternalStream.ReadFloat()
	End

	Method WriteByte:Void(Value:Int)
		InternalStream.WriteByte(Value)

		Return
	End

	Method WriteShort:Void(Value:Int)
		InternalStream.WriteShort(Value)

		Return
	End

	Method WriteInt:Void(Value:Int)
		InternalStream.WriteInt(Value)

		Return
	End

	Method WriteFloat:Void(Value:Float)
		InternalStream.WriteFloat(Value)

		Return
	End

	Method WriteString:Void(Value:String, Encoding:String="utf8")
		InternalStream.WriteString(Value, Encoding)

		Return
	End

	Method WriteLine:Void(Str:String)
		InternalStream.WriteLine(Str)

		Return
	End

	Method Seek:Int(Position:Int)
		Return InternalStream.Seek(Position)
	End

	Method Skip:Void(Count:Int)
		InternalStream.Skip(Count)

		Return
	End

	' Methods (Protected):
	Protected

	Method InternalReadAll:Void(Buffer:DataBuffer, Offset:Int, Count:Int)
		' Call the super-class's implementation.
		Super.ReadAll(Buffer, Offset, Count)

		Return
	End

	Method InternalReadAll:DataBuffer()
		' Call the super-class's implementation.
		Return Super.ReadAll()
	End

	Method InternalWriteAll:Void(Buffer:DataBuffer, Offset:Int, Count:Int)
		' Call the super-class's implementation.
		Super.WriteAll(Buffer, Offset, Count)

		Return
	End

	Public

	' Properties:
	Method Eof:Int() Property
		Return InternalStream.Eof
	End

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

	Method Position:Int() Property
		Return InternalStream.Position
	End

	Method Stream:StreamType() Property
		Return Self.InternalStream
	End

	' Fields (Public):
	' Nothing so far.

	' Fields (Protected):
	Protected

	Field InternalStream:StreamType

	Public
End

' Exceptions:
Class InvalidWrapperStream Extends StreamError
	' Constructor(s):
	Method New(Instance:Stream, WrappedStream:Stream=Null)
		Super.New(Instance)

		Self.WrappedStream = WrappedStream
	End

	' Fields (Protected):
	Protected

	Field WrappedStream:Stream

	Public
End

#Rem
	THIS MODULE IS CURRENTLY EXPERIMENTAL; USE AT YOUR OWN RISK.
#End

Strict

Public

' Imports (Public):
Import brl.stream

' Imports (Private):
Private

Import brl.databuffer

Public

' Classes:
Class WrapperStream<StreamType> Extends Stream
	' Constructor(s):
	Method New(S:StreamType)
		Self.InternalStream = S
	End

	' Destructor(s):
	Method Close:Void()
		InternalStream.Close()

		Return
	End

	' Methods (Public):
	Method Read:Int(Buffer:DataBuffer, Offset:Int, Count:Int)
		Return InternalStream.Read(Buffer, Offset, Count)
	End

	Method Write:Int(Buffer:DataBuffer, Offset:Int, Count:Int)
		Return InternalStream.Write(Buffer, Offset, Count)
	End

	Method ReadAll:Void(Buffer:DataBuffer, Offset:Int, Count:Int)
		InternalStream.ReadAll(Buffer, Offset, Count)

		Return
	End

	Method ReadAll:DataBuffer()
		Return InternalStream.ReadAll()
	End

	Method WriteAll:Void(Buffer:DataBuffer, Offset:Int, Count:Int)
		InternalStream.WriteAll(Buffer, Offset, Count)

		Return
	End

	Method ReadString:String(Count:Int, Encoding:String="utf8")
		Return InternalStream.ReadString(Count, Encoding)
	End

	Method ReadString:String(Encoding:String="utf8")
		Return InternalStream.ReadString(Encoding)
	End

	Method ReadLine:String()
		Return InternalStream.ReadLine()
	End

	Method ReadByte:Int()
		Return InternalStream.ReadByte()
	End

	Method ReadShort:Int()
		Return InternalStream.ReadShort()
	End

	Method ReadInt:Int()
		Return InternalStream.ReadInt()
	End

	Method ReadFloat:Float()
		Return InternalStream.ReadFloat()
	End

	Method WriteByte:Void(Value:Int)
		InternalStream.WriteByte(Value)

		Return
	End

	Method WriteShort:Void(Value:Int)
		InternalStream.WriteShort(Value)

		Return
	End

	Method WriteInt:Void(Value:Int)
		InternalStream.WriteInt(Value)

		Return
	End

	Method WriteFloat:Void(Value:Float)
		InternalStream.WriteFloat(Value)

		Return
	End

	Method WriteString:Void(Value:String, Encoding:String="utf8")
		InternalStream.WriteString(Value, Encoding)

		Return
	End

	Method WriteLine:Void(Str:String)
		InternalStream.WriteLine(Str)

		Return
	End

	Method Seek:Int(Position:Int)
		Return InternalStream.Seek(Position)
	End

	Method Skip:Void(Count:Int)
		InternalStream.Skip(Count)

		Return
	End

	' Methods (Protected):
	Protected

	Method InternalReadAll:Void(Buffer:DataBuffer, Offset:Int, Count:Int)
		' Call the super-class's implementation.
		Super.ReadAll(Buffer, Offset, Count)

		Return
	End

	Method InternalReadAll:DataBuffer()
		' Call the super-class's implementation.
		Return Super.ReadAll()
	End

	Method InternalWriteAll:Void(Buffer:DataBuffer, Offset:Int, Count:Int)
		' Call the super-class's implementation.
		Super.WriteAll(Buffer, Offset, Count)

		Return
	End

	Public

	' Properties:
	Method Eof:Int() Property
		Return InternalStream.Eof
	End

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

	Method Position:Int() Property
		Return InternalStream.Position
	End

	Method Stream:StreamType() Property
		Return Self.InternalStream
	End

	' Fields (Public):
	' Nothing so far.

	' Fields (Protected):
	Protected

	Field InternalStream:StreamType

	Public
End


Added FlxGroup final test

Added FlxGroup final test

'This is a not module
Strict

Import unittest

Import flxbasic
Import flxpoint
Import flxrect
Import flxobject
Import flxgroup

'#Region FlxPoint tests bundle

Class FlxPointUnitTestBase Implements IUnitTest Abstract

	Field x:Float = 10, y:Float = 100
	Field p1:FlxPoint, p2:FlxPoint

	Method New()
		p1 = New FlxPoint(x, y)
		p2 = New FlxPoint()
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

private
	Method _AssertPoint:Bool()
		Return (UnitTest.AssertEqualsF(x, p1.x) And UnitTest.AssertEqualsF(y, p1.y))
	End Method

	Method _AssertPoints:Bool()
		Return (UnitTest.AssertEqualsF(p2.x, p1.x) And UnitTest.AssertEqualsF(p2.y, p1.y))
	End Method

End Class

Class FlxPointNewUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		Return _AssertPoint()
	End Method

	Method GetName:String()
		Return "FlxPoint.New"
	End Method

End Class

Class FlxPointMakeUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p1 = FlxPoint.Make(x, y)
		Return _AssertPoint()
	End Method

	Method GetName:String()
		Return "FlxPoint.Make"
	End Method

End Class

Class FlxPointCopyToUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p1.CopyTo(p2)
		Return _AssertPoints()
	End Method

	Method GetName:String()
		Return "FlxPoint.CopyTo"
	End Method

End Class

Class FlxPointCopyFromUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p2.CopyFrom(p1)
		Return _AssertPoints()
	End Method

	Method GetName:String()
		Return "FlxPoint.CopyFrom"
	End Method

End Class

'#End Region

'#Region FlxRect tests bundle

Class FlxRectUnitTestBase Implements IUnitTest Abstract

	Field x:Float = 10, y:Float = 100
	Field width:Float = 110, height:Float = 1000
	Field r1:FlxRect, r2:FlxRect

	Method New()
		r1 = New FlxRect(x, y, width, height)
		r2 = New FlxRect()
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

Private
	Method _AssertRect:Bool()
		Return (UnitTest.AssertEqualsF(x, r1.x) And UnitTest.AssertEqualsF(y, r1.y) And
			UnitTest.AssertEqualsF(width, r1.width) And UnitTest.AssertEqualsF(height, r1.height))
	End Method

	Method _AssertRects:Bool()
		Return (UnitTest.AssertEqualsF(r2.x, r1.x) And UnitTest.AssertEqualsF(r2.y, r1.y) And
			UnitTest.AssertEqualsF(r2.width, r1.width) And UnitTest.AssertEqualsF(r2.height, r1.height))
	End Method

End Class

Class FlxRectNewUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return _AssertRect()
	End Method

	Method GetName:String()
		Return "FlxRect.New"
	End Method

End Class

Class FlxRectMakeUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r1 = FlxRect.Make(x, y, width, height)
		Return _AssertRect()
	End Method

	Method GetName:String()
		Return "FlxRect.Make"
	End Method

End Class

Class FlxRectLeftUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(x, r1.Left)
	End Method

	Method GetName:String()
		Return "FlxRect.Left"
	End Method

End Class

Class FlxRectRightUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(x + width, r1.Right)
	End Method

	Method GetName:String()
		Return "FlxRect.Right"
	End Method

End Class

Class FlxRectTopUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(y, r1.Top)
	End Method

	Method GetName:String()
		Return "FlxRect.Top"
	End Method

End Class

Class FlxRectBottomUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(y + height, r1.Bottom)
	End Method

	Method GetName:String()
		Return "FlxRect.Bottom"
	End Method

End Class

Class FlxRectCopyToUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r1.CopyTo(r2)
		Return _AssertRects()
	End Method

	Method GetName:String()
		Return "FlxRect.CopyTo"
	End Method

End Class

Class FlxRectCopyFromUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r2.CopyFrom(r1)
		Return _AssertRects()
	End Method

	Method GetName:String()
		Return "FlxRect.CopyFrom"
	End Method

End Class

'#End Region

'#Region FlxGroup tests bundle

Class FlxGroupUnitTestBase Implements IUnitTest Abstract

	Field countObjects:Int = 10
	Field objects:FlxBasic[]
	Field group:FlxGroup

	Method New()
		objects = new FlxBasic[countObjects]

		For Local i:Int = 0 To countObjects - 1
			objects[i] = New FlxBasic()
			objects[i].ID = i
		Next
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

End Class

Class FlxGroupAddUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group.Members
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.Length)) Return False

		Local maxSize:Int = 5
		group = New FlxGroup(maxSize)
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn group.Members
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		Return UnitTest.AssertEqualsI(i, maxSize)
	End Method

	Method GetName:String()
		Return "FlxGroup.Add"
	End Method

End Class

Class FlxGroupRemoveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		For Local basic:FlxBasic = EachIn objects
			If (Not UnitTest.AssertNotNull(group.Remove(basic))) Return False
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.Length)) Return False

		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		For Local basic:FlxBasic = EachIn objects
			If (Not UnitTest.AssertNotNull(group.Remove(basic, True))) Return False
		Next

		Return UnitTest.AssertEqualsI(0, group.Length)
	End Method

	Method GetName:String()
		Return "FlxGroup.Remove"
	End Method

End Class

Class FlxGroupAddRemoveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic)
			i+=1
		Next

		Local newBasic:FlxBasic = new FlxBasic()
		newBasic.ID = 10
		group.Add(newBasic)

		If (Not UnitTest.AssertEqualsI(group.Members.Get(5).ID, newBasic.ID)) Return False

		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic, True)
			i+=1
		Next

		group.Add(newBasic)
		If (Not UnitTest.AssertEqualsI(group.Members.Get(8).ID, newBasic.ID)) Return False

		group = New FlxGroup(6)

		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic)
			i+=1
		Next

		group.Add(newBasic)
		If (Not UnitTest.AssertEqualsI(group.Members.Get(5).ID, newBasic.ID)) Return False

		group = New FlxGroup(6)

		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic, True)
			i+=1
		Next

		group.Add(newBasic)
		Return (UnitTest.AssertEqualsI(group.Members.Get(5).ID, newBasic.ID))
	End Method

	Method GetName:String()
		Return "FlxGroup.Add/Remove"
	End Method

End Class

Class FlxGroupMaxSizeUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.MaxSize = 15

		If (Not UnitTest.AssertEqualsI(objects.Length, group.Length)) Return False

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group.Members
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		group.MaxSize = 6
		If (Not UnitTest.AssertEqualsI(group.MaxSize, group.Length)) Return False
		i = 0
		For Local basic:FlxBasic = EachIn group.Members
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.MaxSize"
	End Method

End Class

Class FlxGroupReplaceUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Replace(objects[0], objects[countObjects - 1])
		Return UnitTest.AssertEqualsI(countObjects - 1, group.Members.Get(0).ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.Replace"
	End Method

End Class

Class FlxGroupGetFirstAvailableUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		Local i:Int = 0
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
			If (i > 4 And i < 7) Then basic.Kill()
			i+=1
		Next

		Local basic:FlxBasic = group.GetFirstAvailable(FlxBasic.CREATOR)

		If (UnitTest.AssertNotNull(basic) And UnitTest.AssertEqualsI(5, basic.ID)) Then
			Local object:FlxObject = FlxObject(group.Add(new FlxObject()))
			object.ID = 10

			object = FlxObject(group.Add(new FlxObject()))
			object.ID = 11
			object.Kill()

			object = FlxObject(group.GetFirstAvailable(FlxObject.CREATOR))
			Return (UnitTest.AssertNotNull(object) And UnitTest.AssertEqualsI(11, object.ID))
		End If

		Return False
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstAvailable"
	End Method

End Class

Class FlxGroupFinalUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()

		group.Update()
		group.Draw()
		group.DrawDebug()
		group.ToString()

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup final"
	End Method

End Class

'#End Region

Class FlixelUnitTest Extends UnitTestApp

	Method Setup:Void()
		'#Region add FlxPoint tests bundle

		AddTest(New FlxPointNewUnitTest())
		AddTest(New FlxPointMakeUnitTest())
		AddTest(New FlxPointCopyToUnitTest())
		AddTest(New FlxPointCopyFromUnitTest())

		'#End Region

		'#Region add FlxRect tests bundle

		AddTest(New FlxRectNewUnitTest())
		AddTest(New FlxRectMakeUnitTest())
		AddTest(New FlxRectLeftUnitTest())
		AddTest(New FlxRectRightUnitTest())
		AddTest(New FlxRectTopUnitTest())
		AddTest(New FlxRectBottomUnitTest())
		AddTest(New FlxRectCopyToUnitTest())
		AddTest(New FlxRectCopyFromUnitTest())

		'#End Region

		'#Region add FlxGroup tests bundle

		AddTest(New FlxGroupAddUnitTest())
		AddTest(New FlxGroupRemoveUnitTest())
		AddTest(New FlxGroupAddRemoveUnitTest())
		AddTest(New FlxGroupMaxSizeUnitTest())
		AddTest(New FlxGroupReplaceUnitTest())
		AddTest(New FlxGroupGetFirstAvailableUnitTest())
		AddTest(New FlxGroupFinalUnitTest())

		'#End Region

	End Method

	Method GetName:String()
		Return "Flixel library"
	End Method

End Class

'This is a not module
Strict

Import unittest

Import flxbasic
Import flxpoint
Import flxrect
Import flxobject
Import flxgroup

'#Region FlxPoint tests bundle

Class FlxPointUnitTestBase Implements IUnitTest Abstract

	Field x:Float = 10, y:Float = 100
	Field p1:FlxPoint, p2:FlxPoint

	Method New()
		p1 = New FlxPoint(x, y)
		p2 = New FlxPoint()
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

private
	Method _AssertPoint:Bool()
		Return (UnitTest.AssertEqualsF(x, p1.x) And UnitTest.AssertEqualsF(y, p1.y))
	End Method

	Method _AssertPoints:Bool()
		Return (UnitTest.AssertEqualsF(p2.x, p1.x) And UnitTest.AssertEqualsF(p2.y, p1.y))
	End Method

End Class

Class FlxPointNewUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		Return _AssertPoint()
	End Method

	Method GetName:String()
		Return "FlxPoint.New"
	End Method

End Class

Class FlxPointMakeUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p1 = FlxPoint.Make(x, y)
		Return _AssertPoint()
	End Method

	Method GetName:String()
		Return "FlxPoint.Make"
	End Method

End Class

Class FlxPointCopyToUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p1.CopyTo(p2)
		Return _AssertPoints()
	End Method

	Method GetName:String()
		Return "FlxPoint.CopyTo"
	End Method

End Class

Class FlxPointCopyFromUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p2.CopyFrom(p1)
		Return _AssertPoints()
	End Method

	Method GetName:String()
		Return "FlxPoint.CopyFrom"
	End Method

End Class

'#End Region

'#Region FlxRect tests bundle

Class FlxRectUnitTestBase Implements IUnitTest Abstract

	Field x:Float = 10, y:Float = 100
	Field width:Float = 110, height:Float = 1000
	Field r1:FlxRect, r2:FlxRect

	Method New()
		r1 = New FlxRect(x, y, width, height)
		r2 = New FlxRect()
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

Private
	Method _AssertRect:Bool()
		Return (UnitTest.AssertEqualsF(x, r1.x) And UnitTest.AssertEqualsF(y, r1.y) And
			UnitTest.AssertEqualsF(width, r1.width) And UnitTest.AssertEqualsF(height, r1.height))
	End Method

	Method _AssertRects:Bool()
		Return (UnitTest.AssertEqualsF(r2.x, r1.x) And UnitTest.AssertEqualsF(r2.y, r1.y) And
			UnitTest.AssertEqualsF(r2.width, r1.width) And UnitTest.AssertEqualsF(r2.height, r1.height))
	End Method

End Class

Class FlxRectNewUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return _AssertRect()
	End Method

	Method GetName:String()
		Return "FlxRect.New"
	End Method

End Class

Class FlxRectMakeUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r1 = FlxRect.Make(x, y, width, height)
		Return _AssertRect()
	End Method

	Method GetName:String()
		Return "FlxRect.Make"
	End Method

End Class

Class FlxRectLeftUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(x, r1.Left)
	End Method

	Method GetName:String()
		Return "FlxRect.Left"
	End Method

End Class

Class FlxRectRightUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(x + width, r1.Right)
	End Method

	Method GetName:String()
		Return "FlxRect.Right"
	End Method

End Class

Class FlxRectTopUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(y, r1.Top)
	End Method

	Method GetName:String()
		Return "FlxRect.Top"
	End Method

End Class

Class FlxRectBottomUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(y + height, r1.Bottom)
	End Method

	Method GetName:String()
		Return "FlxRect.Bottom"
	End Method

End Class

Class FlxRectCopyToUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r1.CopyTo(r2)
		Return _AssertRects()
	End Method

	Method GetName:String()
		Return "FlxRect.CopyTo"
	End Method

End Class

Class FlxRectCopyFromUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r2.CopyFrom(r1)
		Return _AssertRects()
	End Method

	Method GetName:String()
		Return "FlxRect.CopyFrom"
	End Method

End Class

'#End Region

'#Region FlxGroup tests bundle

Class FlxGroupUnitTestBase Implements IUnitTest Abstract

	Field countObjects:Int = 10
	Field objects:FlxBasic[]
	Field group:FlxGroup

	Method New()
		objects = new FlxBasic[countObjects]

		For Local i:Int = 0 To countObjects - 1
			objects[i] = New FlxBasic()
			objects[i].ID = i
		Next
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

End Class

Class FlxGroupAddUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group.Members
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.Length)) Return False

		Local maxSize:Int = 5
		group = New FlxGroup(maxSize)
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn group.Members
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		Return UnitTest.AssertEqualsI(i, maxSize)
	End Method

	Method GetName:String()
		Return "FlxGroup.Add"
	End Method

End Class

Class FlxGroupRemoveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		For Local basic:FlxBasic = EachIn objects
			If (Not UnitTest.AssertNotNull(group.Remove(basic))) Return False
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.Length)) Return False

		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		For Local basic:FlxBasic = EachIn objects
			If (Not UnitTest.AssertNotNull(group.Remove(basic, True))) Return False
		Next

		Return UnitTest.AssertEqualsI(0, group.Length)
	End Method

	Method GetName:String()
		Return "FlxGroup.Remove"
	End Method

End Class

Class FlxGroupAddRemoveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic)
			i+=1
		Next

		Local newBasic:FlxBasic = new FlxBasic()
		newBasic.ID = 10
		group.Add(newBasic)

		If (Not UnitTest.AssertEqualsI(group.Members.Get(5).ID, newBasic.ID)) Return False

		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic, True)
			i+=1
		Next

		group.Add(newBasic)
		If (Not UnitTest.AssertEqualsI(group.Members.Get(8).ID, newBasic.ID)) Return False

		group = New FlxGroup(6)

		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic)
			i+=1
		Next

		group.Add(newBasic)
		If (Not UnitTest.AssertEqualsI(group.Members.Get(5).ID, newBasic.ID)) Return False

		group = New FlxGroup(6)

		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic, True)
			i+=1
		Next

		group.Add(newBasic)
		Return (UnitTest.AssertEqualsI(group.Members.Get(5).ID, newBasic.ID))
	End Method

	Method GetName:String()
		Return "FlxGroup.Add/Remove"
	End Method

End Class

Class FlxGroupMaxSizeUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.MaxSize = 15

		If (Not UnitTest.AssertEqualsI(objects.Length, group.Length)) Return False

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group.Members
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		group.MaxSize = 6
		If (Not UnitTest.AssertEqualsI(group.MaxSize, group.Length)) Return False
		i = 0
		For Local basic:FlxBasic = EachIn group.Members
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.MaxSize"
	End Method

End Class

Class FlxGroupReplaceUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Replace(objects[0], objects[countObjects - 1])
		Return UnitTest.AssertEqualsI(countObjects - 1, group.Members.Get(0).ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.Replace"
	End Method

End Class

Class FlxGroupGetFirstAvailableUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		Local i:Int = 0
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
			If (i > 4 And i < 7) Then basic.Kill()
			i+=1
		Next

		Local basic:FlxBasic = group.GetFirstAvailable(FlxBasic.CREATOR)

		If (UnitTest.AssertNotNull(basic) And UnitTest.AssertEqualsI(5, basic.ID)) Then
			Local object:FlxObject = FlxObject(group.Add(new FlxObject()))
			object.ID = 10

			object = FlxObject(group.Add(new FlxObject()))
			object.ID = 11
			object.Kill()

			object = FlxObject(group.GetFirstAvailable(FlxObject.CREATOR))
			Return (UnitTest.AssertNotNull(object) And UnitTest.AssertEqualsI(11, object.ID))
		End If

		Return False
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstAvailable"
	End Method

End Class

'#End Region

Class FlixelUnitTest Extends UnitTestApp

	Method Setup:Void()
		'#Region add FlxPoint tests bundle

		AddTest(New FlxPointNewUnitTest())
		AddTest(New FlxPointMakeUnitTest())
		AddTest(New FlxPointCopyToUnitTest())
		AddTest(New FlxPointCopyFromUnitTest())

		'#End Region

		'#Region add FlxRect tests bundle

		AddTest(New FlxRectNewUnitTest())
		AddTest(New FlxRectMakeUnitTest())
		AddTest(New FlxRectLeftUnitTest())
		AddTest(New FlxRectRightUnitTest())
		AddTest(New FlxRectTopUnitTest())
		AddTest(New FlxRectBottomUnitTest())
		AddTest(New FlxRectCopyToUnitTest())
		AddTest(New FlxRectCopyFromUnitTest())

		'#End Region

		'#Region add FlxGroup tests bundle

		AddTest(New FlxGroupAddUnitTest())
		AddTest(New FlxGroupRemoveUnitTest())
		AddTest(New FlxGroupAddRemoveUnitTest())
		AddTest(New FlxGroupMaxSizeUnitTest())
		AddTest(New FlxGroupReplaceUnitTest())
		AddTest(New FlxGroupGetFirstAvailableUnitTest())

		'#End Region

	End Method

	Method GetName:String()
		Return "Flixel library"
	End Method

End Class


Add public marker to utils.vector2d

Add public marker to utils.vector2d

Strict

Public

Class Vector2D
    Field x:Float
    Field y:Float

    Method New(x:Float=0, y:Float=0)
        Self.x = x
        Self.y = y
    End

    Method IsZero:Bool()
        Return (x = 0 And y = 0)
    End

    Method Length:Float()
        Return Sqrt(x * x + y * y)
    End

    Method DotProduct:Float(v2:Vector2D)
        Return (x * v2.x) + (y * v2.y)
    End

    Method CrossProduct:Float(v2:Vector2D)
        Return (x * v2.y) - (y * v2.x)
    End

    Method Distance:Float(v2:Vector2D)
        Return Sqrt((v2.x - x)) + Sqrt((v2.y - y))
    End

    Method Equal:Bool(v2:Vector2D)
        Return (x = v2.x And y = v2.y)
    End

    Method Copy:Vector2D()
        Return New Vector2D(x, y)
    End

    Method Normalize:Vector2D()
        Local length:Float = Length()
        If length = 0 Then Return Self

        x /= length
        y /= length

        Return Self
    End

    Method Rotate:Vector2D(angle:Float)
        Local tmpX:Float = (x * Cos(angle)) - (y * Sin(angle))
        Local tmpY:Float = (y * Cos(angle)) - (x * Sin(angle))

        x = tmpX
        y = tmpY

        Return Self
    End

    Method Revert:Vector2D()
        x *= -1
        y *= -1

        Return Self
    End

    Method Add:Vector2D(v2:Vector2D)
        x += v2.x
        y += v2.y
        Return Self
    End

    Method Add:Vector2D(factor:Float)
        x += factor
        y += factor
        Return Self
    End

    Method Sub:Vector2D(v2:Vector2D)
        x -= v2.x
        y -= v2.y
        Return Self
    End

    Method Sub:Vector2D(factor:Float)
        x -= factor
        y -= factor
        Return Self
    End

    Method Mul:Vector2D(v2:Vector2D)
        x *= v2.x
        y *= v2.y
        Return Self
    End

    Method Mul:Vector2D(factor:Float)
        x *= factor
        y *= factor
        Return Self
    End

    Method Div:Vector2D(v2:Vector2D)
        x /= v2.x
        y /= v2.y
        Return Self
    End

    Method Div:Vector2D(factor:Float)
        y /= factor
        x /= factor
        Return Self
    End

    Method ToString:String()
        Return "(" + x + ", " + y + ")"
    End
End

Strict

Class Vector2D
    Field x:Float
    Field y:Float

    Method New(x:Float=0, y:Float=0)
        Self.x = x
        Self.y = y
    End

    Method IsZero:Bool()
        Return (x = 0 And y = 0)
    End

    Method Length:Float()
        Return Sqrt(x * x + y * y)
    End

    Method DotProduct:Float(v2:Vector2D)
        Return (x * v2.x) + (y * v2.y)
    End

    Method CrossProduct:Float(v2:Vector2D)
        Return (x * v2.y) - (y * v2.x)
    End

    Method Distance:Float(v2:Vector2D)
        Return Sqrt((v2.x - x)) + Sqrt((v2.y - y))
    End

    Method Equal:Bool(v2:Vector2D)
        Return (x = v2.x And y = v2.y)
    End

    Method Copy:Vector2D()
        Return New Vector2D(x, y)
    End

    Method Normalize:Vector2D()
        Local length:Float = Length()
        If length = 0 Then Return Self

        x /= length
        y /= length

        Return Self
    End

    Method Rotate:Vector2D(angle:Float)
        Local tmpX:Float = (x * Cos(angle)) - (y * Sin(angle))
        Local tmpY:Float = (y * Cos(angle)) - (x * Sin(angle))

        x = tmpX
        y = tmpY

        Return Self
    End

    Method Revert:Vector2D()
        x *= -1
        y *= -1

        Return Self
    End

    Method Add:Vector2D(v2:Vector2D)
        x += v2.x
        y += v2.y
        Return Self
    End

    Method Add:Vector2D(factor:Float)
        x += factor
        y += factor
        Return Self
    End

    Method Sub:Vector2D(v2:Vector2D)
        x -= v2.x
        y -= v2.y
        Return Self
    End

    Method Sub:Vector2D(factor:Float)
        x -= factor
        y -= factor
        Return Self
    End

    Method Mul:Vector2D(v2:Vector2D)
        x *= v2.x
        y *= v2.y
        Return Self
    End

    Method Mul:Vector2D(factor:Float)
        x *= factor
        y *= factor
        Return Self
    End

    Method Div:Vector2D(v2:Vector2D)
        x /= v2.x
        y /= v2.y
        Return Self
    End

    Method Div:Vector2D(factor:Float)
        y /= factor
        x /= factor
        Return Self
    End

    Method ToString:String()
        Return "(" + x + ", " + y + ")"
    End
End


Fixed AssertRange functions.

Fixed AssertRange functions.

Strict

Const ASSERT_MESSAGE$ = "Assertion failed!"

#Rem
	Assertion functions.
	Call the corresponding Assert function with the check that you expect to pass.  If it fails, the
	error message will be thrown.
#End

Function Assert:Void(val?, msg$=ASSERT_MESSAGE)
	If Not val Then AssertError(msg)
End

Function AssertNull:Void(val:Object, msg$=ASSERT_MESSAGE)
	If val <> Null Then AssertError(msg)
End

Function AssertNotNull:Void(val:Object, msg$=ASSERT_MESSAGE)
	If val = Null Then AssertError(msg)
End

Function AssertEqualsInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val <> expected Then AssertError(msg + " " + val + "<>"+expected)
End

Function AssertEqualsFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val <> expected Then AssertError(msg + " " + val + "<>"+expected)
End

Function AssertEqualsString:Void(val$, expected$, msg$=ASSERT_MESSAGE)
	If val <> expected Then AssertError(msg + " " + val + "<>"+expected)
End

Function AssertEqualsIgnoreCase:Void(val$, expected$, msg$=ASSERT_MESSAGE)
	' TODO: optimise this (does it create new objects?)
	If val.ToLower() <> expected.ToLower() Then AssertError(msg + " " + val + "<>"+expected)
End

Function AssertNotEqualInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val = expected Then AssertError(msg + " " + val + "="+expected)
End

Function AssertNotEqualFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val = expected Then AssertError(msg + " " + val + "="+expected)
End

Function AssertNotEqualString:Void(val$, expected$, msg$=ASSERT_MESSAGE)
	If val = expected Then AssertError(msg + " " + val + "="+expected)
End

Function AssertNotEqualIgnoreCase:Void(val$, expected$, msg$=ASSERT_MESSAGE)
	' TODO:
End

Function AssertLessThanInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val >= expected Then AssertError(msg + " " + val + ">="+expected)
End

Function AssertLessThanFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val >= expected Then AssertError(msg + " " + val + ">="+expected)
End

Function AssertGreaterThanInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val <= expected Then AssertError(msg + " " + val + "<="+expected)
End

Function AssertGreaterThanFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val <= expected Then AssertError(msg + " " + val + "<="+expected)
End

Function AssertLessThanOrEqualInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val > expected Then AssertError(msg + " " + val + ">"+expected)
End

Function AssertLessThanOrEqualFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val > expected Then AssertError(msg + " " + val + ">"+expected)
End

Function AssertGreaterThanOrEqualInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val < expected Then AssertError(msg + " " + val + "<"+expected)
End

Function AssertGreaterThanOrEqualFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val < expected Then AssertError(msg + " " + val + "<"+expected)
End

Function AssertRangeInt:Void(val%, minbound%, maxbound%, msg$=ASSERT_MESSAGE)
	If val < minbound Or val >= maxbound Then AssertError(msg + " " + val + " is not " + minbound + "<=val<" + maxbound)
End

Function AssertRangeFloat:Void(val#, minbound#, maxbound#, msg$=ASSERT_MESSAGE)
	If val < minbound Or val >= maxbound Then AssertError(msg + " " + val + " is not " + minbound + "<=val<" + maxbound)
End

Function AssertRangeInclusiveInt:Void(val%, minbound%, maxbound%, msg$=ASSERT_MESSAGE)
	If val < minbound Or val > maxbound Then AssertError(msg + " " + val + " is not " + minbound + "<=val<=" + maxbound)
End

Function AssertRangeInclusiveFloat:Void(val#, minbound#, maxbound#, msg$=ASSERT_MESSAGE)
	If val < minbound Or val > maxbound Then AssertError(msg + " " + val + " is not " + minbound + "<=val<=" + maxbound)
End

Function AssertError:Void(msg:String)
	Print(msg)
	Error(msg)
End

Strict

Const ASSERT_MESSAGE$ = "Assertion failed!"

#Rem
	Assertion functions.
	Call the corresponding Assert function with the check that you expect to pass.  If it fails, the
	error message will be thrown.
#End

Function Assert:Void(val?, msg$=ASSERT_MESSAGE)
	If Not val Then AssertError(msg)
End

Function AssertNull:Void(val:Object, msg$=ASSERT_MESSAGE)
	If val <> Null Then AssertError(msg)
End

Function AssertNotNull:Void(val:Object, msg$=ASSERT_MESSAGE)
	If val = Null Then AssertError(msg)
End

Function AssertEqualsInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val <> expected Then AssertError(msg + " " + val + "<>"+expected)
End

Function AssertEqualsFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val <> expected Then AssertError(msg + " " + val + "<>"+expected)
End

Function AssertEqualsString:Void(val$, expected$, msg$=ASSERT_MESSAGE)
	If val <> expected Then AssertError(msg + " " + val + "<>"+expected)
End

Function AssertEqualsIgnoreCase:Void(val$, expected$, msg$=ASSERT_MESSAGE)
	' TODO: optimise this (does it create new objects?)
	If val.ToLower() <> expected.ToLower() Then AssertError(msg + " " + val + "<>"+expected)
End

Function AssertNotEqualInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val = expected Then AssertError(msg + " " + val + "="+expected)
End

Function AssertNotEqualFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val = expected Then AssertError(msg + " " + val + "="+expected)
End

Function AssertNotEqualString:Void(val$, expected$, msg$=ASSERT_MESSAGE)
	If val = expected Then AssertError(msg + " " + val + "="+expected)
End

Function AssertNotEqualIgnoreCase:Void(val$, expected$, msg$=ASSERT_MESSAGE)
	' TODO:
End

Function AssertLessThanInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val >= expected Then AssertError(msg + " " + val + ">="+expected)
End

Function AssertLessThanFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val >= expected Then AssertError(msg + " " + val + ">="+expected)
End

Function AssertGreaterThanInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val <= expected Then AssertError(msg + " " + val + "<="+expected)
End

Function AssertGreaterThanFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val <= expected Then AssertError(msg + " " + val + "<="+expected)
End

Function AssertLessThanOrEqualInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val > expected Then AssertError(msg + " " + val + ">"+expected)
End

Function AssertLessThanOrEqualFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val > expected Then AssertError(msg + " " + val + ">"+expected)
End

Function AssertGreaterThanOrEqualInt:Void(val%, expected%, msg$=ASSERT_MESSAGE)
	If val < expected Then AssertError(msg + " " + val + "<"+expected)
End

Function AssertGreaterThanOrEqualFloat:Void(val#, expected#, msg$=ASSERT_MESSAGE)
	If val < expected Then AssertError(msg + " " + val + "<"+expected)
End

Function AssertRangeInt:Void(val%, minbound%, maxbound%, msg$=ASSERT_MESSAGE)
	If val < minbound Or val >= maxbound Then AssertError(msg + " " + val + " is not " + minbound + "<=val<" + size)
End

Function AssertRangeFloat:Void(val#, minbound#, maxbound#, msg$=ASSERT_MESSAGE)
	If val < minbound Or val >= maxbound Then AssertError(msg + " " + val + " is not " + minbound + "<=val<" + size)
End

Function AssertRangeInclusiveInt:Void(val%, minbound%, maxbound%, msg$=ASSERT_MESSAGE)
	If val < minbound Or val > maxbound Then AssertError(msg + " " + val + " is not " + minbound + "<=val<=" + size)
End

Function AssertRangeInclusiveFloat:Void(val#, minbound#, maxbound#, msg$=ASSERT_MESSAGE)
	If val < minbound Or val > maxbound Then AssertError(msg + " " + val + " is not " + minbound + "<=val<=" + size)
End

Function AssertError:Void(msg:String)
	Print(msg)
	Error(msg)
End


Srand seed setup fixed

Srand seed setup fixed

Strict

Class FlxU

	Function Abs:Float(value:Float)
		Return monkey.math.Abs(value)
	End Function

	Function Floor:Float(value:Float)
		Return monkey.math.Floor(value)
	End Function

	Function Ceil:Float(value:Float)
		Return monkey.math.Ceil(value)
	End Function

	Function Round:Float(value:Float)
		If (value > 0) Then
			Return Int(value + .5)
		Else
			Return Int(value - .5)
		End If
	End Function

	Function Min:Float(number1:Float, number2:Float)
		Return monkey.math.Min(number1, number2)
	End Function

	Function Max:Float(number1:Float, number2:Float)
		Return monkey.math.Max(number1, number2)
	End Function

	Function Bound:Float(value:Float, min:Float, max:Float)
		Return Clamp(value, min, max)
	End Function

	Function Srand:Float(seed:Float)
		Seed = Int(seed * 10000)
		Return Rnd()
	End Function

	Function Shuffle:Object[](objects:Object[], howManyTimes:Int)
		'TODO
	End Function

End Class

Strict

Class FlxU

	Function Abs:Float(value:Float)
		Return monkey.math.Abs(value)
	End Function

	Function Floor:Float(value:Float)
		Return monkey.math.Floor(value)
	End Function

	Function Ceil:Float(value:Float)
		Return monkey.math.Ceil(value)
	End Function

	Function Round:Float(value:Float)
		If (value > 0) Then
			Return Int(value + .5)
		Else
			Return Int(value - .5)
		End If
	End Function

	Function Min:Float(number1:Float, number2:Float)
		Return monkey.math.Min(number1, number2)
	End Function

	Function Max:Float(number1:Float, number2:Float)
		Return monkey.math.Max(number1, number2)
	End Function

	Function Bound:Float(value:Float, min:Float, max:Float)
		Return Clamp(value, min, max)
	End Function

	Function Srand:Float(seed:Float)
		Seed = Int(seed * 1000)
		Return Rnd()
	End Function

	Function Shuffle:Object[](objects:Object[], howManyTimes:Int)
		'TODO
	End Function

End Class