Mixed datatype

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
MrSwiss
Posts: 3657
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Mixed datatype

Postby MrSwiss » Jun 16, 2020 16:48

Yep, but more likely a ZString Ptr ... (since, String handles that 'behind the scenes').
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Mixed datatype

Postby srvaldez » Jun 16, 2020 17:48

perhaps it's a good Idea to post the corrected version here for others
corrections are thanks to fxm

mixed.bi

Code: Select all

''
''    Mixed datatype definition
''
''    by Aleksandar Ruzicic
''

#Ifndef __MIXED_TYPE__
#Define __MIXED_TYPE__

   #Macro MixedDeclareOperators(_TYPE_)
      Declare Operator Cast As _TYPE_
      Declare Operator Let(value As _TYPE_)
      Declare Operator +=(value As _TYPE_)
      Declare Operator -=(value As _TYPE_)
      Declare Operator *=(value As _TYPE_)
      Declare Operator /=(value As _TYPE_)
      Declare Operator \=(value As _TYPE_)
      Declare Operator ^=(value As _TYPE_)
      Declare Operator Mod=(value As _TYPE_)
      Declare Operator Shl=(value As _TYPE_)
      Declare Operator Shr=(value As _TYPE_)
      Declare Operator And=(value As _TYPE_)
      Declare Operator Or=(value As _TYPE_)
      Declare Operator Xor=(value As _TYPE_)
      Declare Operator Imp=(value As _TYPE_)
      Declare Operator Eqv=(value As _TYPE_)
   #EndMacro

   #Macro MixedImplementAssignmentOperators(_TYPE_)
      Operator Mixed.+=(value As _TYPE_)
         This = Cast(_TYPE_, This) + value
      End Operator
      Operator Mixed.-=(value As _TYPE_)
         This = Cast(_TYPE_, This) - value
      End Operator
      Operator Mixed.*=(value As _TYPE_)
         This = Cast(_TYPE_, This) * value
      End Operator
      Operator Mixed./=(value As _TYPE_)
         This = Cast(_TYPE_, This) / value
      End Operator
      Operator Mixed.\=(value As _TYPE_)
         This = Cast(_TYPE_, This) \ value
      End Operator
      Operator Mixed.^=(value As _TYPE_)
         This = Cast(_TYPE_, This) ^ value
      End Operator
      Operator Mixed.Mod=(value As _TYPE_)
         This = Cast(_TYPE_, This) Mod value
      End Operator
      Operator Mixed.Shl=(value As _TYPE_)
         This = Cast(_TYPE_, This) Shl value
      End Operator
      Operator Mixed.Shr=(value As _TYPE_)
         This = Cast(_TYPE_, This) Shr value
      End Operator
      Operator Mixed.And=(value As _TYPE_)
         This = Cast(_TYPE_, This) And value
      End Operator
      Operator Mixed.Or=(value As _TYPE_)
         This = Cast(_TYPE_, This) Or value
      End Operator
      Operator Mixed.Xor=(value As _TYPE_)
         This = Cast(_TYPE_, This) Xor value
      End Operator
      Operator Mixed.Imp=(value As _TYPE_)
         This = Cast(_TYPE_, This) Imp value
      End Operator
      Operator Mixed.Eqv=(value As _TYPE_)
         This = Cast(_TYPE_, This) Eqv value
      End Operator
   #EndMacro

   #Macro MixedImplementBinaryOperator(_OP_)
   Operator _OP_(ByRef lhs As Mixed, ByRef rhs As Mixed) As Mixed
      If lhs.TypeId < fbInteger Or rhs.TypeId < fbInteger Then
         Return CDbl(lhs) _OP_ CDbl(rhs)
      Else
         Return CInt(lhs) _OP_ CInt(rhs)
      EndIf
   End Operator
   #EndMacro


   Enum MixedType
      fbEmpty
      fbString
      fbDouble
      fbSingle
      fbLongInt
      fbLong
      fbInteger
      fbShort
      fbByte
      fbAnyPointer
   End Enum

   Type Mixed

      Public:

         Declare Destructor

         Declare Property TypeId As MixedType

         Declare Operator Cast As String
         Declare Operator Let(value As String)
         Declare Operator +=(value As String)
         Declare Operator &=(value As String)

         MixedDeclareOperators(Double)
         MixedDeclareOperators(Single)
         MixedDeclareOperators(LongInt)
         MixedDeclareOperators(Long)
         MixedDeclareOperators(Integer)
         MixedDeclareOperators(Short)
         MixedDeclareOperators(Byte)

         Declare Operator Cast As Any Pointer
         Declare Operator Let(value As Any Pointer)

      Private:

         StoredType   As MixedType   = fbEmpty
         StoredData   As Any Pointer   = 0

   End Type

   Destructor Mixed
      If This.StoredType <> fbEmpty And this.StoredType <> fbAnyPointer Then
         If This.StoredType = fbString Then
            *Cast(String Pointer, This.StoredData) = ""
         EndIf
         DeAllocate This.StoredData
      EndIf
   End Destructor

   Property Mixed.TypeId As MixedType
      Return This.StoredType
   End Property

   Operator Mixed.Cast As String
      Select Case This.StoredType
         Case fbEmpty: Return ""
         Case fbString: Return *Cast(String Pointer, This.StoredData)
         Case fbDouble: Return Str(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return Str(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return Str(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return Str(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return Str(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return Str(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return Str(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(String Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As String)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         If This.StoredType = fbString Then
            *Cast(String Pointer, This.StoredData) = ""
         EndIf
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbString
      This.StoredData = Callocate(SizeOf(String))
      *Cast(String Pointer, This.StoredData) = value
   End Operator
   Operator Mixed.+=(value As String)
      This = Cast(String, This) & value
   End Operator
   Operator Mixed.&=(value As String)
      This = Cast(String, This) & value
   End Operator

   Operator Mixed.Cast As Double
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CDbl(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return *Cast(Double Pointer, This.StoredData)
         Case fbSingle: Return CDbl(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CDbl(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CDbl(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CDbl(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CDbl(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CDbl(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Double Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Double)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbDouble
      This.StoredData = Allocate(SizeOf(Double))
      *Cast(Double Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Double)

   Operator Mixed.Cast As Single
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CSng(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CSng(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return *Cast(Single Pointer, This.StoredData)
         Case fbLongInt: Return CSng(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CSng(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CSng(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CSng(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CSng(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Single Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Single)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbSingle
      This.StoredData = Allocate(SizeOf(Single))
      *Cast(Single Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Single)

   Operator Mixed.Cast As LongInt
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CLngInt(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CLngInt(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CLngInt(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return *Cast(LongInt Pointer, This.StoredData)
         Case fbLong: Return CLngInt(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CLngInt(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CLngInt(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CLngInt(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(LongInt Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As LongInt)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbLongInt
      This.StoredData = Allocate(SizeOf(LongInt))
      *Cast(LongInt Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(LongInt)

   Operator Mixed.Cast As Long
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CLng(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CLng(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CLng(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CLng(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return *Cast(Long Pointer, This.StoredData)
         Case fbInteger: Return CLng(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CLng(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CLng(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Long Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Long)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbLong
      This.StoredData = Allocate(SizeOf(Long))
      *Cast(Long Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Long)

   Operator Mixed.Cast As Integer
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CInt(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CInt(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CInt(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CInt(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CInt(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return *Cast(Integer Pointer, This.StoredData)
         Case fbShort: Return CInt(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CInt(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Integer Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Integer)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbInteger
      This.StoredData = Allocate(SizeOf(Integer))
      *Cast(Integer Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Integer)

   Operator Mixed.Cast As Short
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CShort(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CShort(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CShort(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CShort(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CShort(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CShort(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return *Cast(Short Pointer, This.StoredData)
         Case fbByte: Return CShort(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Short Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Short)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbShort
      This.StoredData = Allocate(SizeOf(Short))
      *Cast(Short Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Short)

   Operator Mixed.Cast As Byte
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CByte(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CByte(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CByte(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CByte(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CByte(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CByte(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CByte(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return *Cast(Byte Pointer, This.StoredData)
         Case fbAnyPointer: Return *Cast(Byte Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Byte)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbByte
      This.StoredData = Allocate(SizeOf(Byte))
      *Cast(Byte Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Byte)

   Operator Mixed.Cast As Any Pointer
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return Cast(String Pointer, This.StoredData)
         Case fbDouble: Return Cast(Double Pointer, This.StoredData)
         Case fbSingle: Return Cast(Single Pointer, This.StoredData)
         Case fbLongInt: Return Cast(LongInt Pointer, This.StoredData)
         Case fbLong: Return Cast(Long Pointer, This.StoredData)
         Case fbInteger: Return Cast(Integer Pointer, This.StoredData)
         Case fbShort: Return Cast(Short Pointer, This.StoredData)
         Case fbByte: Return Cast(Byte Pointer, This.StoredData)
         Case fbAnyPointer: Return This.StoredData
      End Select
   End Operator
   Operator Mixed.Let(Value As Any Pointer)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbAnyPointer
      This.StoredData = Allocate(SizeOf(Any Pointer))
      This.StoredData = value
   End Operator

   Operator -(ByRef rhs As Mixed) As Mixed
      Select Case rhs.TypeId
         Case fbEmpty:    Return 0
         Case Else:       Return -Cast(Double, rhs)
      End Select
   End Operator

   Operator &(ByRef lhs As Mixed, ByRef rhs As Mixed) As Mixed
      Return Str(lhs) & Str(rhs)
   End Operator

   MixedImplementBinaryOperator(+)
   MixedImplementBinaryOperator(-)
   MixedImplementBinaryOperator(*)
   MixedImplementBinaryOperator(/)
   MixedImplementBinaryOperator(\)
   MixedImplementBinaryOperator(Mod)
   MixedImplementBinaryOperator(Shl)
   MixedImplementBinaryOperator(Shr)
   MixedImplementBinaryOperator(And)
   MixedImplementBinaryOperator(Or)
   MixedImplementBinaryOperator(Xor)
   MixedImplementBinaryOperator(Imp)
   MixedImplementBinaryOperator(Eqv)
   MixedImplementBinaryOperator(^)
   MixedImplementBinaryOperator(=)
   MixedImplementBinaryOperator(<>)
   MixedImplementBinaryOperator(<)
   MixedImplementBinaryOperator(>)
   MixedImplementBinaryOperator(<=)
   MixedImplementBinaryOperator(>=)

#EndIf

Mixed_test.bas

Code: Select all

#include "mixed.bi"

Dim m As Mixed
Dim As string Mixed_types(9) = {"fbEmpty", "fbString", "fbDouble",_
                  "fbSingle", "fbLongInt", "fbLong", _
                  "fbInteger", "fbShort", "fbByte", _
                  "fbAnyPointer"}
m = 123   ' Integer

Print "m = "; m, Mixed_types(m.TypeId)

m /= 5!    ' Single

Print "m = "; m, Mixed_types(m.TypeId)

m = 3.141592653589793

Print "m = "; m, Mixed_types(m.TypeId)

m = "bla bla"  ' String

Print "m = "; m, Mixed_types(m.TypeId)

m = m + 5 ' Integer

Print "m = "; m, Mixed_types(m.TypeId)

Print

Print "Press RETURN to quit"

Sleep
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Mixed datatype

Postby srvaldez » Jun 16, 2020 20:04

unfortunately the mixed type is problematic, the following code will probably crash or give bad result

Code: Select all

#include "mixed.bi"

Dim As string Mixed_types(9) = {"fbEmpty", "fbString", "fbDouble",_
                  "fbSingle", "fbLongInt", "fbLong", _
                  "fbInteger", "fbShort", "fbByte", _
                  "fbAnyPointer"}
redim shared stack(10) as Mixed
dim shared as integer stack_pointer=0, stack_ubound=10

sub push(byval n as Mixed)
   stack(stack_pointer)=n
   if stack_pointer=stack_ubound then
      stack_ubound+=10
      redim preserve stack(stack_ubound)
   end if
   stack_pointer+=1
end sub

function pop() as Mixed
   if stack_pointer=0 then
      print "stack is empty"
      return 9
   end if
   stack_pointer-=1
   return stack(stack_pointer)
end function

dim as double i
dim n as Mixed

for i=0 to 15
   n=i
   push(n)
next

for i=0 to 15
   n=pop()
   print i,n, Mixed_types(n.TypeId)
next
n=pop()

Print "Press RETURN to quit"

Sleep
fxm
Posts: 10046
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Mixed datatype

Postby fxm » Jun 16, 2020 21:01

You can not pass and return a Mixed instance by value (in push and pop procedures) because the copy-constructor(byref as Mixed) is not defined in the Mixed Type.
A simpler workaround (without defining this member procedure) would be to pass and return a Mixed instance by reference only:

Code: Select all

sub push(byref n as Mixed)
   stack(stack_pointer)=n
   if stack_pointer=stack_ubound then
      stack_ubound+=10
      redim preserve stack(stack_ubound)
   end if
   stack_pointer+=1
end sub

function pop() byref as Mixed
   if stack_pointer=0 then
      print "stack is empty"
      static as Mixed m
      m = 9
      return m
   end if
   stack_pointer-=1
   return stack(stack_pointer)
end function

Code: Select all

 0            15            fbDouble
 1            15            fbDouble
 2            15            fbDouble
 3            15            fbDouble
 4            15            fbDouble
 5            15            fbDouble
 6            15            fbDouble
 7            15            fbDouble
 8            15            fbDouble
 9            15            fbDouble
 10           15            fbDouble
 11           15            fbDouble
 12           15            fbDouble
 13           15            fbDouble
 14           15            fbDouble
 15           15            fbDouble
stack is empty
Press RETURN to quit
The program runs but the result is wrong (because stack(stack_pointer)=n and n=pop() call the Let-operator).

Otherwise (as difficult exercise), define these two member procedures in mixed.bi !
Last edited by fxm on Jun 17, 2020 9:40, edited 4 times in total.
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Mixed datatype

Postby srvaldez » Jun 16, 2020 21:13

I see, I will study the Mixed code a bit, thanks.
dodicat
Posts: 6761
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Mixed datatype

Postby dodicat » Jun 16, 2020 21:26

My way of solving the problems caused new/delete allocate/deallocate (as I have posted several times) is to use a static memory stack(array), in each
mixed.let in this code.
This way allocated memory is contiguous in memory, and destroyed normally at the program end, as any array is annihilated.
Instead of deallocating throughout the code where it is written,I just set to zero, but this move isn't even necessary.
I have set an upper bound of 500 mixed elements, at the top, which can be changed of course.

Code: Select all


''
''    Mixed datatype definition
''
''    by Aleksandar Ruzicic
''
#define lim 500

#Ifndef __MIXED_TYPE__
#Define __MIXED_TYPE__

   #Macro MixedDeclareOperators(_TYPE_)
      Declare Operator Cast As _TYPE_
      Declare Operator Let(value As _TYPE_)
      Declare Operator +=(value As _TYPE_)
      Declare Operator -=(value As _TYPE_)
      Declare Operator *=(value As _TYPE_)
      Declare Operator /=(value As _TYPE_)
      Declare Operator \=(value As _TYPE_)
      Declare Operator ^=(value As _TYPE_)
      Declare Operator Mod=(value As _TYPE_)
      Declare Operator Shl=(value As _TYPE_)
      Declare Operator Shr=(value As _TYPE_)
      Declare Operator And=(value As _TYPE_)
      Declare Operator Or=(value As _TYPE_)
      Declare Operator Xor=(value As _TYPE_)
      Declare Operator Imp=(value As _TYPE_)
      Declare Operator Eqv=(value As _TYPE_)
   #EndMacro

   #Macro MixedImplementAssignmentOperators(_TYPE_)
      Operator Mixed.+=(value As _TYPE_)
         This = Cast(_TYPE_, This) + value
      End Operator
      Operator Mixed.-=(value As _TYPE_)
         This = Cast(_TYPE_, This) - value
      End Operator
      Operator Mixed.*=(value As _TYPE_)
         This = Cast(_TYPE_, This) * value
      End Operator
      Operator Mixed./=(value As _TYPE_)
         This = Cast(_TYPE_, This) / value
      End Operator
      Operator Mixed.\=(value As _TYPE_)
         This = Cast(_TYPE_, This) \ value
      End Operator
      Operator Mixed.^=(value As _TYPE_)
         This = Cast(_TYPE_, This) ^ value
      End Operator
      Operator Mixed.Mod=(value As _TYPE_)
         This = Cast(_TYPE_, This) Mod value
      End Operator
      Operator Mixed.Shl=(value As _TYPE_)
         This = Cast(_TYPE_, This) Shl value
      End Operator
      Operator Mixed.Shr=(value As _TYPE_)
         This = Cast(_TYPE_, This) Shr value
      End Operator
      Operator Mixed.And=(value As _TYPE_)
         This = Cast(_TYPE_, This) And value
      End Operator
      Operator Mixed.Or=(value As _TYPE_)
         This = Cast(_TYPE_, This) Or value
      End Operator
      Operator Mixed.Xor=(value As _TYPE_)
         This = Cast(_TYPE_, This) Xor value
      End Operator
      Operator Mixed.Imp=(value As _TYPE_)
         This = Cast(_TYPE_, This) Imp value
      End Operator
      Operator Mixed.Eqv=(value As _TYPE_)
         This = Cast(_TYPE_, This) Eqv value
      End Operator
   #EndMacro

   #Macro MixedImplementBinaryOperator(_OP_)
   Operator _OP_(ByRef lhs As Mixed, ByRef rhs As Mixed) As Mixed
      If lhs.TypeId < fbInteger Or rhs.TypeId < fbInteger Then
         Return CDbl(lhs) _OP_ CDbl(rhs)
      Else
         Return CInt(lhs) _OP_ CInt(rhs)
      EndIf
   End Operator
   #EndMacro


   Enum MixedType
      fbEmpty
      fbString
      fbDouble
      fbSingle
      fbLongInt
      fbLong
      fbInteger
      fbShort
      fbByte
      fbAnyPointer
   End Enum

   Type Mixed

      Public:

         Declare Destructor

         Declare Property TypeId As MixedType

         Declare Operator Cast As String
         Declare Operator Let(value As String)
         Declare Operator +=(value As String)
         Declare Operator &=(value As String)

         MixedDeclareOperators(Double)
         MixedDeclareOperators(Single)
         MixedDeclareOperators(LongInt)
         MixedDeclareOperators(Long)
         MixedDeclareOperators(Integer)
         MixedDeclareOperators(Short)
         MixedDeclareOperators(Byte)

         Declare Operator Cast As Any Pointer
         Declare Operator Let(value As Any Pointer)
         
      Private:

         StoredType   As MixedType   = fbEmpty
         StoredData   As Any Pointer   = 0

   End Type
 

   Destructor Mixed
      If This.StoredType <> fbEmpty And this.StoredType <> fbAnyPointer Then
         This.StoredData=0
      EndIf
   End Destructor

   Property Mixed.TypeId As MixedType
      Return This.StoredType
   End Property

   Operator Mixed.Cast As String
      Select Case This.StoredType
         Case fbEmpty: Return ""
         Case fbString: Return *Cast(String Pointer, This.StoredData)
         Case fbDouble: Return Str(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return Str(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return Str(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return Str(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return Str(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return Str(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return Str(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(String Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As String)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         'DeAllocate This.StoredData
      EndIf
      static as string mem(lim)
      static as long counter
      counter+=1
      if counter>lim then counter=1
      This.StoredType = fbString
      This.StoredData = @mem(counter)
      *Cast(String Pointer, This.StoredData) = value
   End Operator
   Operator Mixed.+=(value As String)
      This = Cast(String, This) & value
   End Operator
   Operator Mixed.&=(value As String)
      This = Cast(String, This) & value
   End Operator

   Operator Mixed.Cast As Double
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CDbl(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return *Cast(Double Pointer, This.StoredData)
         Case fbSingle: Return CDbl(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CDbl(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CDbl(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CDbl(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CDbl(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CDbl(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Double Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Double)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
          This.StoredData=0
      EndIf
      static as double mem(lim)
      static as long counter
      counter+=1
      if counter>lim then counter=1
      This.StoredData = @mem(counter)
      This.StoredType = fbDouble
     
      *Cast(Double Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Double)

   Operator Mixed.Cast As Single
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CSng(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CSng(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return *Cast(Single Pointer, This.StoredData)
         Case fbLongInt: Return CSng(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CSng(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CSng(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CSng(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CSng(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Single Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Single)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         This.StoredData=0
      EndIf
       static as single mem(lim)
      static as long counter
      counter+=1
      if counter>lim then counter=1
      This.StoredData = @mem(counter)
      This.StoredType = fbSingle
     
      *Cast(Single Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Single)

   Operator Mixed.Cast As LongInt
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CLngInt(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CLngInt(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CLngInt(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return *Cast(LongInt Pointer, This.StoredData)
         Case fbLong: Return CLngInt(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CLngInt(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CLngInt(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CLngInt(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(LongInt Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As LongInt)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
          This.StoredData=0
      EndIf
       static as ulongint mem(lim)
      static as long counter
      counter+=1
      if counter>lim then counter=1
      This.StoredData = @mem(counter)
      This.StoredType = fbLongInt
     ' This.StoredData = Allocate(SizeOf(LongInt))
      *Cast(LongInt Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(LongInt)

   Operator Mixed.Cast As Long
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CLng(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CLng(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CLng(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CLng(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return *Cast(Long Pointer, This.StoredData)
         Case fbInteger: Return CLng(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CLng(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CLng(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Long Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Long)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
          This.StoredData=0
      EndIf
       static as long mem(lim)
      static as long counter
      counter+=1
      if counter>lim then counter=1
      This.StoredData = @mem(counter)
      This.StoredType = fbLong
      'This.StoredData = Allocate(SizeOf(Long))
      *Cast(Long Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Long)

   Operator Mixed.Cast As Integer
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CInt(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CInt(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CInt(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CInt(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CInt(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return *Cast(Integer Pointer, This.StoredData)
         Case fbShort: Return CInt(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CInt(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Integer Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Integer)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
          This.StoredData=0
      EndIf
       static as integer mem(lim)
      static as long counter
      counter+=1
      if counter>lim then counter=1
      This.StoredData = @mem(counter)
      This.StoredType = fbInteger
      'This.StoredData = Allocate(SizeOf(Integer))
      *Cast(Integer Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Integer)

   Operator Mixed.Cast As Short
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CShort(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CShort(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CShort(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CShort(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CShort(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CShort(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return *Cast(Short Pointer, This.StoredData)
         Case fbByte: Return CShort(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Short Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Short)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         This.StoredData=0
      EndIf
       static as short mem(lim)
      static as long counter
      counter+=1
      if counter>lim then counter=1
      This.StoredData = @mem(counter)
      This.StoredType = fbShort
      'This.StoredData = Allocate(SizeOf(Short))
      *Cast(Short Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Short)

   Operator Mixed.Cast As Byte
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CByte(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CByte(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CByte(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CByte(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CByte(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CByte(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CByte(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return *Cast(Byte Pointer, This.StoredData)
         Case fbAnyPointer: Return *Cast(Byte Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Byte)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         This.StoredData=0
      EndIf
       static as byte mem(lim)
      static as long counter
      counter+=1
      if counter>lim then counter=1
      This.StoredData = @mem(counter)
      This.StoredType = fbByte
      'This.StoredData = Allocate(SizeOf(Byte))
      *Cast(Byte Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Byte)

   Operator Mixed.Cast As Any Pointer
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return Cast(String Pointer, This.StoredData)
         Case fbDouble: Return Cast(Double Pointer, This.StoredData)
         Case fbSingle: Return Cast(Single Pointer, This.StoredData)
         Case fbLongInt: Return Cast(LongInt Pointer, This.StoredData)
         Case fbLong: Return Cast(Long Pointer, This.StoredData)
         Case fbInteger: Return Cast(Integer Pointer, This.StoredData)
         Case fbShort: Return Cast(Short Pointer, This.StoredData)
         Case fbByte: Return Cast(Byte Pointer, This.StoredData)
         Case fbAnyPointer: Return This.StoredData
      End Select
   End Operator
   Operator Mixed.Let(Value As Any Pointer)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
          This.StoredData=0
      EndIf
       static as any ptr mem(lim)
      static as long counter
      counter+=1
      if counter>lim then counter=1
      This.StoredData = @mem(counter)
      This.StoredType = fbAnyPointer
      'This.StoredData = Allocate(SizeOf(Any Pointer))
      This.StoredData = value
   End Operator

   Operator -(ByRef rhs As Mixed) As Mixed
      Select Case rhs.TypeId
         Case fbEmpty:    Return 0
         Case Else:       Return -Cast(Double, rhs)
      End Select
   End Operator

   Operator &(ByRef lhs As Mixed, ByRef rhs As Mixed) As Mixed
      Return Str(lhs) & Str(rhs)
   End Operator

   MixedImplementBinaryOperator(+)
   MixedImplementBinaryOperator(-)
   MixedImplementBinaryOperator(*)
   MixedImplementBinaryOperator(/)
   MixedImplementBinaryOperator(\)
   MixedImplementBinaryOperator(Mod)
   MixedImplementBinaryOperator(Shl)
   MixedImplementBinaryOperator(Shr)
   MixedImplementBinaryOperator(And)
   MixedImplementBinaryOperator(Or)
   MixedImplementBinaryOperator(Xor)
   MixedImplementBinaryOperator(Imp)
   MixedImplementBinaryOperator(Eqv)
   MixedImplementBinaryOperator(^)
   MixedImplementBinaryOperator(=)
   MixedImplementBinaryOperator(<>)
   MixedImplementBinaryOperator(<)
   MixedImplementBinaryOperator(>)
   MixedImplementBinaryOperator(<=)
   MixedImplementBinaryOperator(>=)

#EndIf




Dim m As Mixed

m = 123   ' Integer

Print "m = "; m

m /= 5    ' Single

Print "m = "; m

m = "bla bla"  ' String

Print "m = "; m

m = m + 5 ' Integer

Print "m = "; m


Dim As string Mixed_types(9) = {"fbEmpty", "fbString", "fbDouble",_
                  "fbSingle", "fbLongInt", "fbLong", _
                  "fbInteger", "fbShort", "fbByte", _
                  "fbAnyPointer"}
redim shared stack(10) as Mixed
dim shared as integer stack_pointer=0, stack_ubound=10

sub push(byval n as Mixed)
   stack(stack_pointer)=n
   if stack_pointer=stack_ubound then
      stack_ubound+=10
      redim preserve stack(stack_ubound)
   end if
   stack_pointer+=1
end sub

function pop() as Mixed
   if stack_pointer=0 then
      print "stack is empty"
      return 9
   end if
   stack_pointer-=1
   return stack(stack_pointer)
end function

dim as double i
dim n as Mixed



for i=0 to 15
    select case i
    case 1,2:n=cint(i)
    case 3,4:n=clng(i)
    case 5,6:n=clngint(i)
    case 7,8:n=cdbl(i)
    case 9,10:n=csng(i)
    case 11,12:n=cshort(i)
    case 13,14:n=cbyte(i)
    case 0,15:n=str(i)
   end select
   push(n)
next

for i=0 to 15
   n=pop()
   print i,n, Mixed_types(n.TypeId)
next
n=pop()

Print "Press RETURN to quit"

Sleep

 

Tested win 32/64 and gas64
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Mixed datatype

Postby srvaldez » Jun 16, 2020 21:59

nicely done dodicat, thanks
I like the concept of Mixed type, but it's implementation is too complex for my limited intellect.
fxm
Posts: 10046
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Mixed datatype

Postby fxm » Jun 16, 2020 22:34

New version of mixed.bi working with your last code:

Code: Select all

''
''    Mixed datatype definition
''
''    by Aleksandar Ruzicic
''

#Ifndef __MIXED_TYPE__
#Define __MIXED_TYPE__

   #Macro MixedDeclareOperators(_TYPE_)
      Declare Operator Cast As _TYPE_
      Declare Operator Let(value As _TYPE_)
      Declare Operator +=(value As _TYPE_)
      Declare Operator -=(value As _TYPE_)
      Declare Operator *=(value As _TYPE_)
      Declare Operator /=(value As _TYPE_)
      Declare Operator \=(value As _TYPE_)
      Declare Operator ^=(value As _TYPE_)
      Declare Operator Mod=(value As _TYPE_)
      Declare Operator Shl=(value As _TYPE_)
      Declare Operator Shr=(value As _TYPE_)
      Declare Operator And=(value As _TYPE_)
      Declare Operator Or=(value As _TYPE_)
      Declare Operator Xor=(value As _TYPE_)
      Declare Operator Imp=(value As _TYPE_)
      Declare Operator Eqv=(value As _TYPE_)
   #EndMacro

   #Macro MixedImplementAssignmentOperators(_TYPE_)
      Operator Mixed.+=(value As _TYPE_)
         This = Cast(_TYPE_, This) + value
      End Operator
      Operator Mixed.-=(value As _TYPE_)
         This = Cast(_TYPE_, This) - value
      End Operator
      Operator Mixed.*=(value As _TYPE_)
         This = Cast(_TYPE_, This) * value
      End Operator
      Operator Mixed./=(value As _TYPE_)
         This = Cast(_TYPE_, This) / value
      End Operator
      Operator Mixed.\=(value As _TYPE_)
         This = Cast(_TYPE_, This) \ value
      End Operator
      Operator Mixed.^=(value As _TYPE_)
         This = Cast(_TYPE_, This) ^ value
      End Operator
      Operator Mixed.Mod=(value As _TYPE_)
         This = Cast(_TYPE_, This) Mod value
      End Operator
      Operator Mixed.Shl=(value As _TYPE_)
         This = Cast(_TYPE_, This) Shl value
      End Operator
      Operator Mixed.Shr=(value As _TYPE_)
         This = Cast(_TYPE_, This) Shr value
      End Operator
      Operator Mixed.And=(value As _TYPE_)
         This = Cast(_TYPE_, This) And value
      End Operator
      Operator Mixed.Or=(value As _TYPE_)
         This = Cast(_TYPE_, This) Or value
      End Operator
      Operator Mixed.Xor=(value As _TYPE_)
         This = Cast(_TYPE_, This) Xor value
      End Operator
      Operator Mixed.Imp=(value As _TYPE_)
         This = Cast(_TYPE_, This) Imp value
      End Operator
      Operator Mixed.Eqv=(value As _TYPE_)
         This = Cast(_TYPE_, This) Eqv value
      End Operator
   #EndMacro

   #Macro MixedImplementBinaryOperator(_OP_)
   Operator _OP_(ByRef lhs As Mixed, ByRef rhs As Mixed) As Mixed
      If lhs.TypeId < fbInteger Or rhs.TypeId < fbInteger Then
         Return CDbl(lhs) _OP_ CDbl(rhs)
      Else
         Return CInt(lhs) _OP_ CInt(rhs)
      EndIf
   End Operator
   #EndMacro


   Enum MixedType
      fbEmpty
      fbString
      fbDouble
      fbSingle
      fbLongInt
      fbLong
      fbInteger
      fbShort
      fbByte
      fbAnyPointer
   End Enum

   Type Mixed

      Public:

         Declare Constructor

         Declare Constructor(ByRef m As Mixed)

         Declare Operator Let(ByRef m As Mixed)
   
         Declare Destructor

         Declare Property TypeId As MixedType

         Declare Operator Cast As String
         Declare Operator Let(value As String)
         Declare Operator +=(value As String)
         Declare Operator &=(value As String)

         MixedDeclareOperators(Double)
         MixedDeclareOperators(Single)
         MixedDeclareOperators(LongInt)
         MixedDeclareOperators(Long)
         MixedDeclareOperators(Integer)
         MixedDeclareOperators(Short)
         MixedDeclareOperators(Byte)

         Declare Operator Cast As Any Pointer
         Declare Operator Let(value As Any Pointer)

      Private:

         StoredType   As MixedType   = fbEmpty
         StoredData   As Any Pointer   = 0

   End Type

   Constructor Mixed
   End Constructor

   Constructor Mixed(ByRef m As Mixed)
       This = m
   End Constructor

   Operator Mixed.Let(ByRef m As Mixed)
      Select Case m.StoredType
         Case fbEmpty:
         Case fbString: This = *Cast(String Pointer, m.StoredData)
         Case fbDouble: This = *Cast(Double Pointer, m.StoredData)
         Case fbSingle: This = *Cast(Single Pointer, m.StoredData)
         Case fbLongInt: This = *Cast(LongInt Pointer, m.StoredData)
         Case fbLong: This = *Cast(Long Pointer, m.StoredData)
         Case fbInteger: This = *Cast(Integer Pointer, m.StoredData)
         Case fbShort: This = *Cast(Short Pointer, m.StoredData)
         Case fbByte: This = *Cast(Byte Pointer, m.StoredData)
         Case fbAnyPointer: This = *Cast(Single Pointer, m.StoredData)
      End Select
   End Operator

   Destructor Mixed
      If This.StoredType <> fbEmpty And this.StoredType <> fbAnyPointer Then
         If This.StoredType = fbString Then
            *Cast(String Pointer, This.StoredData) = ""
         EndIf
         DeAllocate This.StoredData
      EndIf
   End Destructor

   Property Mixed.TypeId As MixedType
      Return This.StoredType
   End Property

   Operator Mixed.Cast As String
      Select Case This.StoredType
         Case fbEmpty: Return ""
         Case fbString: Return *Cast(String Pointer, This.StoredData)
         Case fbDouble: Return Str(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return Str(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return Str(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return Str(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return Str(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return Str(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return Str(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(String Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As String)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         If This.StoredType = fbString Then
            *Cast(String Pointer, This.StoredData) = ""
         EndIf
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbString
      This.StoredData = CAllocate(SizeOf(String))
      *Cast(String Pointer, This.StoredData) = value
   End Operator
   Operator Mixed.+=(value As String)
      This = Cast(String, This) & value
   End Operator
   Operator Mixed.&=(value As String)
      This = Cast(String, This) & value
   End Operator

   Operator Mixed.Cast As Double
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CDbl(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return *Cast(Double Pointer, This.StoredData)
         Case fbSingle: Return CDbl(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CDbl(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CDbl(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CDbl(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CDbl(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CDbl(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Double Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Double)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbDouble
      This.StoredData = Allocate(SizeOf(Double))
      *Cast(Double Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Double)

   Operator Mixed.Cast As Single
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CSng(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CSng(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return *Cast(Single Pointer, This.StoredData)
         Case fbLongInt: Return CSng(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CSng(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CSng(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CSng(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CSng(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Single Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Single)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbSingle
      This.StoredData = Allocate(SizeOf(Single))
      *Cast(Single Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Single)

   Operator Mixed.Cast As LongInt
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CLngInt(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CLngInt(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CLngInt(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return *Cast(LongInt Pointer, This.StoredData)
         Case fbLong: Return CLngInt(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CLngInt(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CLngInt(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CLngInt(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(LongInt Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As LongInt)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbLongInt
      This.StoredData = Allocate(SizeOf(LongInt))
      *Cast(LongInt Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(LongInt)

   Operator Mixed.Cast As Long
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CLng(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CLng(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CLng(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CLng(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return *Cast(Long Pointer, This.StoredData)
         Case fbInteger: Return CLng(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CLng(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CLng(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Long Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Long)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbLong
      This.StoredData = Allocate(SizeOf(Long))
      *Cast(Long Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Long)

   Operator Mixed.Cast As Integer
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CInt(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CInt(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CInt(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CInt(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CInt(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return *Cast(Integer Pointer, This.StoredData)
         Case fbShort: Return CInt(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CInt(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Integer Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Integer)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbInteger
      This.StoredData = Allocate(SizeOf(Integer))
      *Cast(Integer Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Integer)

   Operator Mixed.Cast As Short
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CShort(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CShort(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CShort(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CShort(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CShort(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CShort(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return *Cast(Short Pointer, This.StoredData)
         Case fbByte: Return CShort(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Short Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Short)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbShort
      This.StoredData = Allocate(SizeOf(Short))
      *Cast(Short Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Short)

   Operator Mixed.Cast As Byte
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CByte(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CByte(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CByte(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CByte(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CByte(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CByte(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CByte(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return *Cast(Byte Pointer, This.StoredData)
         Case fbAnyPointer: Return *Cast(Byte Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Byte)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbByte
      This.StoredData = Allocate(SizeOf(Byte))
      *Cast(Byte Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Byte)

   Operator Mixed.Cast As Any Pointer
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return Cast(String Pointer, This.StoredData)
         Case fbDouble: Return Cast(Double Pointer, This.StoredData)
         Case fbSingle: Return Cast(Single Pointer, This.StoredData)
         Case fbLongInt: Return Cast(LongInt Pointer, This.StoredData)
         Case fbLong: Return Cast(Long Pointer, This.StoredData)
         Case fbInteger: Return Cast(Integer Pointer, This.StoredData)
         Case fbShort: Return Cast(Short Pointer, This.StoredData)
         Case fbByte: Return Cast(Byte Pointer, This.StoredData)
         Case fbAnyPointer: Return This.StoredData
      End Select
   End Operator
   Operator Mixed.Let(Value As Any Pointer)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbAnyPointer
      This.StoredData = Allocate(SizeOf(Any Pointer))
      This.StoredData = value
   End Operator

   Operator -(ByRef rhs As Mixed) As Mixed
      Select Case rhs.TypeId
         Case fbEmpty:    Return 0
         Case Else:       Return -Cast(Double, rhs)
      End Select
   End Operator

   Operator &(ByRef lhs As Mixed, ByRef rhs As Mixed) As Mixed
      Return Str(lhs) & Str(rhs)
   End Operator

   MixedImplementBinaryOperator(+)
   MixedImplementBinaryOperator(-)
   MixedImplementBinaryOperator(*)
   MixedImplementBinaryOperator(/)
   MixedImplementBinaryOperator(\)
   MixedImplementBinaryOperator(Mod)
   MixedImplementBinaryOperator(Shl)
   MixedImplementBinaryOperator(Shr)
   MixedImplementBinaryOperator(And)
   MixedImplementBinaryOperator(Or)
   MixedImplementBinaryOperator(Xor)
   MixedImplementBinaryOperator(Imp)
   MixedImplementBinaryOperator(Eqv)
   MixedImplementBinaryOperator(^)
   MixedImplementBinaryOperator(=)
   MixedImplementBinaryOperator(<>)
   MixedImplementBinaryOperator(<)
   MixedImplementBinaryOperator(>)
   MixedImplementBinaryOperator(<=)
   MixedImplementBinaryOperator(>=)

#EndIf

Code: Select all

#include "mixed.bi"

Dim As string Mixed_types(9) = {"fbEmpty", "fbString", "fbDouble",_
                  "fbSingle", "fbLongInt", "fbLong", _
                  "fbInteger", "fbShort", "fbByte", _
                  "fbAnyPointer"}
redim shared stack(10) as Mixed
dim shared as integer stack_pointer=0, stack_ubound=10

sub push(byval n as Mixed)
   stack(stack_pointer)=n
   if stack_pointer=stack_ubound then
      stack_ubound+=10
      redim preserve stack(stack_ubound)
   end if
   stack_pointer+=1
end sub

function pop() as Mixed
   if stack_pointer=0 then
      print "stack is empty"
      return 9
   end if
   stack_pointer-=1
   return stack(stack_pointer)
end function

dim as double i
dim n as Mixed

for i=0 to 15
   n=i
   push(n)
next

for i=0 to 15
   n=pop()
   print i,n, Mixed_types(n.TypeId)
next
n=pop()

Print "Press RETURN to quit"

Sleep

Code: Select all

 0            15            fbDouble
 1            14            fbDouble
 2            13            fbDouble
 3            12            fbDouble
 4            11            fbDouble
 5            10            fbDouble
 6            9             fbDouble
 7            8             fbDouble
 8            7             fbDouble
 9            6             fbDouble
 10           5             fbDouble
 11           4             fbDouble
 12           3             fbDouble
 13           2             fbDouble
 14           1             fbDouble
 15           0             fbDouble
stack is empty
Press RETURN to quit
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Mixed datatype

Postby srvaldez » Jun 16, 2020 22:57

thank you fxm, this is definitely a must study :-)
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Mixed datatype

Postby srvaldez » Jun 16, 2020 23:35

@fxm
this code is more complex than I have dealt with before, from what I have seen, a constructor basically has the body of a let but it may also need memory allocation/initialization
I am groping in the dark here, would a mixed integer constructor have the same body as that of the let operator or does it need extra memory management?
so I made a copy of the Operator Mixed.Let(Value As Integer) and made a constructor out of it, what do think?

Code: Select all

   Constructor Mixed(Value As Integer)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbInteger
      This.StoredData = Allocate(SizeOf(Integer))
      *Cast(Integer Pointer, This.StoredData) = value
   End Constructor

it seems to work, I can do: Print Mixed(i) where i is an integer
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Mixed datatype

Postby srvaldez » Jun 17, 2020 2:12

ok, as it stand the Mixed type has problems being promoted from integer to double in a binary operation involving itself, for example
it was the integer constructor that I had added that was causing the problem

Code: Select all

dim n as mixed
dim x as double
n=16
x=1.23
n=n*x

the type of n is fbInteger and the result is not what I would expect
n*=x will have the desired result, however n=n*x should also promote n to fbDouble with the correct result
so I un-privated the members StoredType and StoredData
now I can add operators

Code: Select all

   Operator * (byref lhs as Mixed, byval rhs As Double) as Mixed
   dim as Mixed res
   res = lhs
      If res.StoredType <> fbEmpty And res.StoredType <> fbAnyPointer Then
         DeAllocate res.StoredData
      EndIf
      res.StoredType = fbDouble
      res.StoredData = Allocate(SizeOf(Double))
      *Cast(Double Pointer, res.StoredData) = cdbl(lhs) * rhs
      return res
   End Operator

more than likely it's not 100% correct but it works, I am concerned that this may brake the integrity of the Mixed type
@fxm
what do you think?
complete code follows

Code: Select all

''
''    Mixed datatype definition
''
''    by Aleksandar Ruzicic
''

#Ifndef __MIXED_TYPE__
#Define __MIXED_TYPE__

   #Macro MixedDeclareOperators(_TYPE_)
      Declare Operator Cast As _TYPE_
      Declare Operator Let(value As _TYPE_)
      Declare Operator +=(value As _TYPE_)
      Declare Operator -=(value As _TYPE_)
      Declare Operator *=(value As _TYPE_)
      Declare Operator /=(value As _TYPE_)
      Declare Operator \=(value As _TYPE_)
      Declare Operator ^=(value As _TYPE_)
      Declare Operator Mod=(value As _TYPE_)
      Declare Operator Shl=(value As _TYPE_)
      Declare Operator Shr=(value As _TYPE_)
      Declare Operator And=(value As _TYPE_)
      Declare Operator Or=(value As _TYPE_)
      Declare Operator Xor=(value As _TYPE_)
      Declare Operator Imp=(value As _TYPE_)
      Declare Operator Eqv=(value As _TYPE_)
   #EndMacro

   #Macro MixedImplementAssignmentOperators(_TYPE_)
      Operator Mixed.+=(value As _TYPE_)
         This = Cast(_TYPE_, This) + value
      End Operator
      Operator Mixed.-=(value As _TYPE_)
         This = Cast(_TYPE_, This) - value
      End Operator
      Operator Mixed.*=(value As _TYPE_)
         This = Cast(_TYPE_, This) * value
      End Operator
      Operator Mixed./=(value As _TYPE_)
         This = Cast(_TYPE_, This) / value
      End Operator
      Operator Mixed.\=(value As _TYPE_)
         This = Cast(_TYPE_, This) \ value
      End Operator
      Operator Mixed.^=(value As _TYPE_)
         This = Cast(_TYPE_, This) ^ value
      End Operator
      Operator Mixed.Mod=(value As _TYPE_)
         This = Cast(_TYPE_, This) Mod value
      End Operator
      Operator Mixed.Shl=(value As _TYPE_)
         This = Cast(_TYPE_, This) Shl value
      End Operator
      Operator Mixed.Shr=(value As _TYPE_)
         This = Cast(_TYPE_, This) Shr value
      End Operator
      Operator Mixed.And=(value As _TYPE_)
         This = Cast(_TYPE_, This) And value
      End Operator
      Operator Mixed.Or=(value As _TYPE_)
         This = Cast(_TYPE_, This) Or value
      End Operator
      Operator Mixed.Xor=(value As _TYPE_)
         This = Cast(_TYPE_, This) Xor value
      End Operator
      Operator Mixed.Imp=(value As _TYPE_)
         This = Cast(_TYPE_, This) Imp value
      End Operator
      Operator Mixed.Eqv=(value As _TYPE_)
         This = Cast(_TYPE_, This) Eqv value
      End Operator
   #EndMacro

   #Macro MixedImplementBinaryOperator(_OP_)
   Operator _OP_(ByRef lhs As Mixed, ByRef rhs As Mixed) As Mixed
      If lhs.TypeId < fbInteger Or rhs.TypeId < fbInteger Then
         Return CDbl(lhs) _OP_ CDbl(rhs)
      Else
         Return CInt(lhs) _OP_ CInt(rhs)
      EndIf
   End Operator
   #EndMacro


   Enum MixedType
      fbEmpty
      fbString
      fbDouble
      fbSingle
      fbLongInt
      fbLong
      fbInteger
      fbShort
      fbByte
      fbAnyPointer
   End Enum

   Type Mixed

      Public:

         Declare Constructor

         Declare Constructor(ByRef m As Mixed)
'v         
declare Constructor (Value As Integer)
'^
         Declare Operator Let(ByRef m As Mixed)
   
         Declare Destructor

         Declare Property TypeId As MixedType

         Declare Operator Cast As String
         Declare Operator Let(value As String)
         Declare Operator +=(value As String)
         Declare Operator &=(value As String)

         MixedDeclareOperators(Double)
         MixedDeclareOperators(Single)
         MixedDeclareOperators(LongInt)
         MixedDeclareOperators(Long)
         MixedDeclareOperators(Integer)
         MixedDeclareOperators(Short)
         MixedDeclareOperators(Byte)

         Declare Operator Cast As Any Pointer
         Declare Operator Let(value As Any Pointer)

      'Private:

         StoredType   As MixedType   = fbEmpty
         StoredData   As Any Pointer   = 0

   End Type

   Constructor Mixed
   End Constructor

   Constructor Mixed(ByRef m As Mixed)
       This = m
   End Constructor
'v
Constructor Mixed(Value As Integer)
  If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
    DeAllocate This.StoredData
  EndIf
  This.StoredType = fbInteger
  This.StoredData = Allocate(SizeOf(Integer))
  *Cast(Integer Pointer, This.StoredData) = value
End Constructor
'MixedImplementAssignmentOperators(Integer)
'^
   Operator Mixed.Let(ByRef m As Mixed)
      Select Case m.StoredType
         Case fbEmpty:
         Case fbString: This = *Cast(String Pointer, m.StoredData)
         Case fbDouble: This = *Cast(Double Pointer, m.StoredData)
         Case fbSingle: This = *Cast(Single Pointer, m.StoredData)
         Case fbLongInt: This = *Cast(LongInt Pointer, m.StoredData)
         Case fbLong: This = *Cast(Long Pointer, m.StoredData)
         Case fbInteger: This = *Cast(Integer Pointer, m.StoredData)
         Case fbShort: This = *Cast(Short Pointer, m.StoredData)
         Case fbByte: This = *Cast(Byte Pointer, m.StoredData)
         Case fbAnyPointer: This = *Cast(Single Pointer, m.StoredData)
      End Select
   End Operator

   Destructor Mixed
      If This.StoredType <> fbEmpty And this.StoredType <> fbAnyPointer Then
         If This.StoredType = fbString Then
            *Cast(String Pointer, This.StoredData) = ""
         EndIf
         DeAllocate This.StoredData
      EndIf
   End Destructor

   Property Mixed.TypeId As MixedType
      Return This.StoredType
   End Property

   Operator Mixed.Cast As String
      Select Case This.StoredType
         Case fbEmpty: Return ""
         Case fbString: Return *Cast(String Pointer, This.StoredData)
         Case fbDouble: Return Str(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return Str(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return Str(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return Str(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return Str(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return Str(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return Str(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(String Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As String)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         If This.StoredType = fbString Then
            *Cast(String Pointer, This.StoredData) = ""
         EndIf
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbString
      This.StoredData = CAllocate(SizeOf(String))
      *Cast(String Pointer, This.StoredData) = value
   End Operator
   Operator Mixed.+=(value As String)
      This = Cast(String, This) & value
   End Operator
   Operator Mixed.&=(value As String)
      This = Cast(String, This) & value
   End Operator

   Operator Mixed.Cast As Double
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CDbl(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return *Cast(Double Pointer, This.StoredData)
         Case fbSingle: Return CDbl(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CDbl(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CDbl(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CDbl(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CDbl(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CDbl(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Double Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Double)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbDouble
      This.StoredData = Allocate(SizeOf(Double))
      *Cast(Double Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Double)

   Operator Mixed.Cast As Single
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CSng(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CSng(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return *Cast(Single Pointer, This.StoredData)
         Case fbLongInt: Return CSng(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CSng(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CSng(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CSng(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CSng(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Single Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Single)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbSingle
      This.StoredData = Allocate(SizeOf(Single))
      *Cast(Single Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Single)

   Operator Mixed.Cast As LongInt
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CLngInt(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CLngInt(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CLngInt(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return *Cast(LongInt Pointer, This.StoredData)
         Case fbLong: Return CLngInt(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CLngInt(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CLngInt(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CLngInt(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(LongInt Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As LongInt)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbLongInt
      This.StoredData = Allocate(SizeOf(LongInt))
      *Cast(LongInt Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(LongInt)

   Operator Mixed.Cast As Long
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CLng(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CLng(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CLng(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CLng(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return *Cast(Long Pointer, This.StoredData)
         Case fbInteger: Return CLng(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CLng(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CLng(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Long Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Long)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbLong
      This.StoredData = Allocate(SizeOf(Long))
      *Cast(Long Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Long)

   Operator Mixed.Cast As Integer
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CInt(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CInt(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CInt(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CInt(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CInt(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return *Cast(Integer Pointer, This.StoredData)
         Case fbShort: Return CInt(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return CInt(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Integer Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Integer)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbInteger
      This.StoredData = Allocate(SizeOf(Integer))
      *Cast(Integer Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Integer)

   Operator Mixed.Cast As Short
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CShort(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CShort(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CShort(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CShort(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CShort(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CShort(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return *Cast(Short Pointer, This.StoredData)
         Case fbByte: Return CShort(*Cast(Byte Pointer, This.StoredData))
         Case fbAnyPointer: Return *Cast(Short Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Short)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbShort
      This.StoredData = Allocate(SizeOf(Short))
      *Cast(Short Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Short)

   Operator Mixed.Cast As Byte
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return CByte(*Cast(String Pointer, This.StoredData))
         Case fbDouble: Return CByte(*Cast(Double Pointer, This.StoredData))
         Case fbSingle: Return CByte(*Cast(Single Pointer, This.StoredData))
         Case fbLongInt: Return CByte(*Cast(LongInt Pointer, This.StoredData))
         Case fbLong: Return CByte(*Cast(Long Pointer, This.StoredData))
         Case fbInteger: Return CByte(*Cast(Integer Pointer, This.StoredData))
         Case fbShort: Return CByte(*Cast(Short Pointer, This.StoredData))
         Case fbByte: Return *Cast(Byte Pointer, This.StoredData)
         Case fbAnyPointer: Return *Cast(Byte Pointer, This.StoredData)
      End Select
   End Operator
   Operator Mixed.Let(Value As Byte)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbByte
      This.StoredData = Allocate(SizeOf(Byte))
      *Cast(Byte Pointer, This.StoredData) = value
   End Operator
   MixedImplementAssignmentOperators(Byte)

   Operator Mixed.Cast As Any Pointer
      Select Case This.StoredType
         Case fbEmpty: Return 0
         Case fbString: Return Cast(String Pointer, This.StoredData)
         Case fbDouble: Return Cast(Double Pointer, This.StoredData)
         Case fbSingle: Return Cast(Single Pointer, This.StoredData)
         Case fbLongInt: Return Cast(LongInt Pointer, This.StoredData)
         Case fbLong: Return Cast(Long Pointer, This.StoredData)
         Case fbInteger: Return Cast(Integer Pointer, This.StoredData)
         Case fbShort: Return Cast(Short Pointer, This.StoredData)
         Case fbByte: Return Cast(Byte Pointer, This.StoredData)
         Case fbAnyPointer: Return This.StoredData
      End Select
   End Operator
   Operator Mixed.Let(Value As Any Pointer)
      If This.StoredType <> fbEmpty And This.StoredType <> fbAnyPointer Then
         DeAllocate This.StoredData
      EndIf
      This.StoredType = fbAnyPointer
      This.StoredData = Allocate(SizeOf(Any Pointer))
      This.StoredData = value
   End Operator

   Operator -(ByRef rhs As Mixed) As Mixed
      Select Case rhs.TypeId
         Case fbEmpty:    Return 0
         Case Else:       Return -Cast(Double, rhs)
      End Select
   End Operator

   Operator &(ByRef lhs As Mixed, ByRef rhs As Mixed) As Mixed
      Return Str(lhs) & Str(rhs)
   End Operator

   MixedImplementBinaryOperator(+)
   MixedImplementBinaryOperator(-)
   MixedImplementBinaryOperator(*)
   MixedImplementBinaryOperator(/)
   MixedImplementBinaryOperator(\)
   MixedImplementBinaryOperator(Mod)
   MixedImplementBinaryOperator(Shl)
   MixedImplementBinaryOperator(Shr)
   MixedImplementBinaryOperator(And)
   MixedImplementBinaryOperator(Or)
   MixedImplementBinaryOperator(Xor)
   MixedImplementBinaryOperator(Imp)
   MixedImplementBinaryOperator(Eqv)
   MixedImplementBinaryOperator(^)
   MixedImplementBinaryOperator(=)
   MixedImplementBinaryOperator(<>)
   MixedImplementBinaryOperator(<)
   MixedImplementBinaryOperator(>)
   MixedImplementBinaryOperator(<=)
   MixedImplementBinaryOperator(>=)
 
   Operator *(byref lhs as Mixed, byval rhs As Double) as Mixed
   dim as Mixed res
   res = lhs
      If res.StoredType <> fbEmpty And res.StoredType <> fbAnyPointer Then
         DeAllocate res.StoredData
      EndIf
      res.StoredType = fbDouble
      res.StoredData = Allocate(SizeOf(Double))
      *Cast(Double Pointer, res.StoredData) = cdbl(lhs) * rhs
      return res
   End Operator
   
#EndIf

Dim As string Mixed_types(9) = {"fbEmpty", "fbString", "fbDouble",_
                  "fbSingle", "fbLongInt", "fbLong", _
                  "fbInteger", "fbShort", "fbByte", _
                  "fbAnyPointer"}
                 
dim as Mixed n
dim as double x

n=16
print n, Mixed_types(n.TypeId)
x=1.23
n=n*x
print n, Mixed_types(n.TypeId)
Print "Press RETURN to quit"

Sleep
Last edited by srvaldez on Jun 17, 2020 10:12, edited 1 time in total.
fxm
Posts: 10046
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Mixed datatype

Postby fxm » Jun 17, 2020 5:19

A 'Let-operator(as udt2)' may be necessary in a complex udt1 Type if one want to use for example a udt1 instance assignment from a udt2 instance such as:
dim as udt2 u2
dim as udt1 u1
u1 = u2 '' <==

or else:
function test () as udt1
dim as udt2 u2
function = u2 '' <==
end function


A 'Constructor(as udt2)' may be necessary in a complex udt1 Type if one want to use for example a udt1 instance construction with a udt2 instance initializer such as:
dim as udt2 u2
dim as udt1 u1 = u2 '' <==

or else:
function test () as udt1
dim as udt2 u2
return u2 '' <==
end function

or else:
sub test (byval u1 as udt1)
end sub
dim as udt2 u2
test(u2) '' <==


In your specific example above, I don't see why a 'Constructor (Value As Integer)' would be needed.
Last edited by fxm on Jun 17, 2020 9:35, edited 6 times in total.
fxm
Posts: 10046
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Mixed datatype

Postby fxm » Jun 17, 2020 5:37

dodicat
Posts: 6761
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Mixed datatype

Postby dodicat » Jun 17, 2020 7:41

If you create a constructor for each datatype
VIZ
constructor mixed
end constructor

constructor mixed(i as integer)
this=i 'use let
end constructor

constructor mixed(i as double)
this=i 'use let
end constructor


. . .

it allows you to do things like

Code: Select all

 dim as mixed k(. . .)={csng(sqr(2)),sqr(2),"Hello",5,__function__,13ll,cubyte(asc("a"))}
for n as long=lbound(k) to ubound(k)
    print k(n);tab(30);Mixed_types(k(n).TypeId)
next n

Result:

Code: Select all

1.414214                     fbSingle
1.414213562373095            fbDouble
Hello                        fbString
5                            fbInteger
__FB_MAINPROC__              fbString
13                           fbLongInt
97                           fbByte

Press RETURN to quit

But the author's code is now 569 lines long.
I had to adjust srvaldez pop to return a byref value otherwise I got an ambiguous call error.
and sub push( n as Mixed) instead of byval n as Mixed.

The author probably wanted to concentrate on other aspects of the code, which I think is pretty comprehensive.
And from 2008 to now and running with little alteration is a testament to the freebasic language.
fxm
Posts: 10046
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Mixed datatype

Postby fxm » Jun 17, 2020 8:44

dodicat wrote:I had to adjust srvaldez pop to return a byref value otherwise I got an ambiguous call error.
and sub push( n as Mixed) instead of byval n as Mixed.

or define a 'Constructor Mixed (Byref As Mixed)'.
And an 'Operator Mixed.Let (Byref As Mixed)' because 'stack(stack_pointer)=n' and 'n=pop()' also call the Let-operator.

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 3 guests