This code has been declared by its author to be Public Domain code.
Download source code | Number Class Cluster by N | 2009 |
| |
|
This is probably going to win me the Most Useless Code award, but being able to have a list or map of numbers can be handy at times, however infrequently those times seem to come up.
Anyway, this is based off the same sort of idea for NSNumber, only the implementation is far simpler (if you've ever seen the source for GNUstep, you'd probably understand).
The TNumber subclasses are hidden to completely ensure you're not going to modify the _value field of the object, since the object is supposed to be considered immutable. |
SuperStrict
Public
Const DOUBLE_DELTA! = 4.94065645841247e-324!
Const FLOAT_DELTA# = 1.4e-45#
' Used mainly for comparing types
Const TYPE_INVALID:Int = -1
Const TYPE_BOOL:Int = 0
Const TYPE_BYTE:Int = 1
Const TYPE_SHORT:Int = 2
Const TYPE_INT:Int = 3
Const TYPE_LONG:Int = 4
Const TYPE_FLOAT:Int = 5
Const TYPE_DOUBLE:Int = 6
Type TNumber Abstract
Function ForDouble:TNumber(v!)
Type TDouble Extends TNumber
Field _value:Double
Method InitWithDouble:TDouble(v!)
_value = v
Return Self
End Method
Method DoubleValue!()
Return _value
End Method
Method FloatValue#()
Return Float(_value)
End Method
Method ByteValue@()
Return Byte(_value)
End Method
Method ShortValue@@()
Return Short(_value)
End Method
Method IntValue%()
Return Int(_value)
End Method
Method LongValue:Long()
Return Long(_value)
End Method
Method BoolValue:Int()
Return Int(_value)>0
End Method
Method GetType:Int()
Return TYPE_DOUBLE
End Method
Method ToString:String()
Return String(_value)
End Method
End Type
Return New TDouble.InitWithDouble(v)
End Function
Function ForFloat:TNumber(v#)
Type TFloat Extends TNumber
Field _value:Float
Method InitWithFloat:TFloat(v#)
_value = v
Return Self
End Method
Method DoubleValue!()
Return Double(_value)
End Method
Method FloatValue#()
Return Float(_value)
End Method
Method ByteValue@()
Return Byte(_value)
End Method
Method ShortValue@@()
Return Short(_value)
End Method
Method IntValue%()
Return Int(_value)
End Method
Method LongValue:Long()
Return Long(_value)
End Method
Method BoolValue:Int()
Return Int(_value)>0
End Method
Method GetType:Int()
Return TYPE_FLOAT
End Method
Method ToString:String()
Return String(_value)
End Method
End Type
Return New TFloat.InitWithFloat(v)
End Function
Function ForByte:TNumber(v@)
Type TByte Extends TNumber
Field _value:Byte
Method InitWithByte:TByte(v:Byte)
_value = v
Return Self
End Method
Method DoubleValue!()
Return Double(_value)
End Method
Method FloatValue#()
Return Float(_value)
End Method
Method ByteValue@()
Return _value
End Method
Method ShortValue@@()
Return Short(_value)
End Method
Method IntValue%()
Return Int(_value)
End Method
Method LongValue:Long()
Return Long(_value)
End Method
Method BoolValue:Int()
Return _value>0
End Method
Method GetType:Int()
Return TYPE_BYTE
End Method
Method ToString:String()
Return String(_value)
End Method
End Type
Return New TByte.InitWithByte(v)
End Function
Function ForShort:TNumber(v@@)
Type TShort Extends TNumber
Field _value:Short
Method InitWithShort:TShort(v:Short)
_value = v
Return Self
End Method
Method DoubleValue!()
Return Double(_value)
End Method
Method FloatValue#()
Return Float(_value)
End Method
Method ByteValue@()
Return Byte(_value)
End Method
Method ShortValue@@()
Return _value
End Method
Method IntValue%()
Return Int(_value)
End Method
Method LongValue:Long()
Return Long(_value)
End Method
Method BoolValue:Int()
Return _value>0
End Method
Method GetType:Int()
Return TYPE_SHORT
End Method
Method ToString:String()
Return String(_value)
End Method
End Type
Return New TShort.InitWithShort(v)
End Function
Function ForInt:TNumber(v%)
Type TInt Extends TNumber
Field _value:Int
Method InitWithInt:TInt(v:Int)
_value = v
Return Self
End Method
Method DoubleValue!()
Return Double(_value)
End Method
Method FloatValue#()
Return Float(_value)
End Method
Method ByteValue@()
Return Byte(_value)
End Method
Method ShortValue@@()
Return Short(_value)
End Method
Method IntValue%()
Return _value
End Method
Method LongValue:Long()
Return Long(_value)
End Method
Method BoolValue:Int()
Return _value>0
End Method
Method GetType:Int()
Return TYPE_INT
End Method
Method ToString:String()
Return String(_value)
End Method
End Type
Return New TInt.InitWithInt(v)
End Function
Function ForLong:TNumber(v:Long)
Type TLong Extends TNumber
Field _value:Long
Method InitWithLong:TLong(v:Long)
_value = v
Return Self
End Method
Method DoubleValue!()
Return Double(_value)
End Method
Method FloatValue#()
Return Float(_value)
End Method
Method ByteValue@()
Return Byte(_value)
End Method
Method ShortValue@@()
Return Short(_value)
End Method
Method IntValue%()
Return Int(_value)
End Method
Method LongValue:Long()
Return _value
End Method
Method BoolValue:Int()
Return _value>0
End Method
Method GetType:Int()
Return TYPE_LONG
End Method
Method ToString:String()
Return String(_value)
End Method
End Type
Return New TLong.InitWithLong(v)
End Function
Function ForBool:TNumber(b:Int)
Type TBool Extends TNumber
Field _value:Int
Method InitWithBool:TBool(v:Int)
_value = v>0
Return Self
End Method
Method DoubleValue!()
Return Double(_value)
End Method
Method FloatValue#()
Return Float(_value)
End Method
Method ByteValue@()
Return Byte(_value)
End Method
Method ShortValue@@()
Return Short(_value)
End Method
Method IntValue%()
Return _value
End Method
Method LongValue:Long()
Return Long(_value)
End Method
Method BoolValue:Int()
Return _value
End Method
Method ToString:String()
Return String(_value)
End Method
Method GetType:Int()
Return TYPE_BOOL
End Method
End Type
Return New TBool.InitWithBool(b)
End Function
Method DoubleValue!() Abstract
Method FloatValue#() Abstract
Method ByteValue@() Abstract
Method ShortValue@@() Abstract
Method IntValue%() Abstract
Method LongValue:Long() Abstract
Method BoolValue:Int() Abstract
Method ToString:String() Abstract
Method GetType:Int() Abstract
Method Compare:Int(other:Object)
Local n:TNumber = TNumber(other)
If n Then
Local _type:Int, t2:Int
_type = GetType()
t2 = GetType()
If _type = TYPE_INVALID Or t2 = TYPE_INVALID Then
Throw "Attempt to compare invalid number"
EndIf
If t2 > _type Then
_type = t2
EndIf
Select _type
Case TYPE_BOOL
Local b1%, b2%
b1 = n.BoolValue()
b2 = n.BoolValue()
If b1 = b2 Then
Return 0
ElseIf b1 Then
Return 1
EndIf
Return -1
Case TYPE_DOUBLE
Local d! = DoubleValue()-n.DoubleValue()
If d < -DOUBLE_DELTA Then
Return -1
ElseIf d > DOUBLE_DELTA then
Return 1
EndIf
Return 0
Case TYPE_FLOAT
Local f! = FloatValue()-n.FloatValue()
If f < -FLOAT_DELTA Then
Return -1
ElseIf f > FLOAT_DELTA then
Return 1
EndIf
Return 0
Case TYPE_LONG
Local l1:Long, l2:Long
l1 = LongValue()
l2 = n.LongValue()
If l1 = l2 Then
Return 0
ElseIf l1 < l2 Then
Return -1
EndIf
Return 1
Default ' int and under
Local i1%, i2%
i1 = IntValue()
i2 = n.IntValue()
If i1 = i2 Then
Return 0
ElseIf i1 < i2 Then
Return -1
EndIf
Return 1
End Select
EndIf
Return Super.Compare(other)
End Method
End Type |
Comments |
Interesting use of DOUBLE_DELTA and FLOAT_DELTA in the compare method, I wouldn't've thought of that.
I prefer to have modified list/map types which take numbers directly, and mark seems happy enough to cast to strings, but horses for courses I suppose.
|
|
Suppose I should mention that I just added a sort of bug fix, since previously bools would only be equal if both were true. Why I thought this was correct when I wrote it is beyond me, but that's fixed.
|
|
Something looks wrong here:
Local _type:Int, t2:Int
_type = GetType()
t2 = GetType()
Am I missing something: why is TNumber not Abstract?
|
|
It's not abstract so that you can, for whatever reason you would want to, do New TNumber.InitWithDouble(x).
Thinking about it now though, I'll probably just remove those...
|
|
I usually use bytes for my bools :)
|
Code Archives Forum