FreeBASIC syntax challenge games

For other topics related to the FreeBASIC project or its community.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: FreeBASIC syntax challenge games

Postby Tourist Trap » Jan 04, 2020 15:55

fxm wrote:In addition to be always unsafe, your code (that I does not understand) does not even output the right response on my PC:

Code: Select all

DESTR_UDT      1703480       4598484
true
OBJECT         4598468       4598512
true
integer        4598496       4598544
true
    (with Win32 and gas)

I'm on 64 and GCC. It's very surprising that it doesn't work for you.
I think I'll need a new clue, or maybe I'll wait and think a little more before trying maybe to add a constructor.
fxm
Posts: 10052
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBASIC syntax challenge games

Postby fxm » Jan 04, 2020 16:12

Similar bad response with Win64 and gcc:

Code: Select all

DESTR_UDT      4294967295    140705281448064
true
OBJECT         30962698417537070           12948059386478665
true
integer        140705281448064             4227200
true
fxm
Posts: 10052
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBASIC syntax challenge games

Postby fxm » Jan 04, 2020 16:13

Tourist Trap wrote:I think I'll need a new clue, or maybe I'll wait and think a little more before trying maybe to add a constructor.

Not a constructor.
fxm
Posts: 10052
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBASIC syntax challenge games

Postby fxm » Jan 04, 2020 16:20

Added a third clue to the enigma #25 of post viewtopic.php?p=267129#p267129.
(a fourth is still in reserve)
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: FreeBASIC syntax challenge games

Postby Tourist Trap » Jan 04, 2020 17:58

fxm wrote:Added a third clue to the enigma #25 of post viewtopic.php?p=267129#p267129.
(a fourth is still in reserve)

Hi,
I'm seriously discovering this feature. Totally missed it, and still probably have to learn. So here is my try with the last clue of the operator delete[]. (strings have destructors?):

Code: Select all

type DESTR_UDT
   declare destructor()
   as integer  dii
end type
destructor DESTR_UDT()
   this.dii = -111
end destructor

#macro TypeHasDtor(T, R)
   ? #T,
   
   type UDT_##T
      declare operator delete[] ( buf as UDT_##T ptr )
      as T       tt##T
      static as integer bufvalue
   end type
   dim as integer UDT_##T.bufvalue = -1
   operator UDT_##T.delete[] ( buf as UDT_##T ptr )
      UDT_##T.bufvalue = buf
   end operator
   
   dim as UDT_##T ptr uu_##T = new UDT_##T[1]
   
   scope
      ? uu_##T
     
      delete[] uu_##T
     
      ? uu_##T
     
      R = (UDT_##T.bufvalue = uu_##T)
   end scope
   
#endMacro

dim shared as boolean          res
sub PrintRes()
   if not res then
      color 11, 5
   else
      color 6, 12
   end if
   ? not res
   color 7, 0
end sub

? "has destructor?.."
TypeHasDtor(DESTR_UDT, res)      : PrintRes()
TypeHasDtor(OBJECT, res)         : PrintRes()
TypeHasDtor(integer, res)        : PrintRes()
TypeHasDtor(double, res)         : PrintRes()
TypeHasDtor(string, res)         : PrintRes()
has destructor?..
DESTR_UDT 11933356
11933356
true
OBJECT 11933368
11933368
false
integer 11938544
11938544
false
double 11938560
11938560
false
string 11938580
11938580
true
fxm
Posts: 10052
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBASIC syntax challenge games

Postby fxm » Jan 04, 2020 18:38

Yes!

Just a small remark:
Don't forget to deallocate the memory in the overload operator DELETE []. It is its main aim, otherwise memory leak.
fxm
Posts: 10052
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBASIC syntax challenge games

Postby fxm » Jan 04, 2020 18:50

Added a forth clue and a note to the enigma #25 of post viewtopic.php?p=267129#p267129:
fxm wrote:Enigma #25, force 5 (successive clues could be given to lower the level of difficulty)
Macro to determine if any Type (including pre-defined types and user defined types) has a destructor (explicit or implicit).

Fill in the macro definition ('TypeHasDtor()') of the code below, which from a passed symbol name for a Type ('Typesymbol') assigns the value of a passed Boolean variable ('TypeHasDtorResult') as 'True' or 'False' depending of the existence of a destructor for the corresponding Type:

Code: Select all

#macro TypeHasDtor(TypeSymbol, TypeHasDtorResult)
    '' Determine if the Type has a destructor (implicit or explicit).
   
    '' TypeSymbol must be a symbol name referring to a Type (built-in or UDT).
    ''    (either the Type name itself if it's a symbol name, or an alias)
   
    '' TypeHasDtorResult must be a Boolean variable.
    ''    (or an integer numeric variable)
   
    '' ------------------------------------------------------------------------
    ' Insert here the definition code of the macro:
    ' .....
    ' .....
    ' .....
    ' TypeHasDtorResult = ...
    '' ------------------------------------------------------------------------
#endmacro


Dim As Boolean hasDtorResult

TypeHasDtor(Integer, hasDtorResult)
Print "The 'Integer' Type has a destructor (implicit or explicit): ", hasDtorResult

TypeHasDtor(String, hasDtorResult)
Print "The 'String' Type has a destructor (implicit or explicit): ", hasDtorResult

Type string10Type As String * 10  '' define an alias to get a symbol name
TypeHasDtor(string10Type, hasDtorResult)
Print "The 'String * 10' Type has a destructor (implicit or explicit): ", hasDtorResult

Type stringptrType As String Ptr  '' define an alias to get a symbol name
TypeHasDtor(stringptrType, hasDtorResult)
Print "The 'String Ptr' Type has a destructor (implicit or explicit): ", hasDtorResult

TypeHasDtor(Object, hasDtorResult)
Print "The 'Object' Type has a destructor (implicit or explicit): ", hasDtorResult

Type UDT1 Extends Object
End Type
TypeHasDtor(UDT1, hasDtorResult)
Print "The 'UDT1' User-Type has destructor (implicit or explicit): ", hasDtorResult

Type UDT2 Extends Object
    Declare Destructor ()
End Type
Destructor UDT2 ()
End Destructor
TypeHasDtor(UDT2, hasDtorResult)
Print "The 'UDT2' User-Type has destructor (implicit or explicit): ", hasDtorResult

Sleep
My full solution for defining this macro is a code of 16 simple lines (no concatenated instructions on the same line with ':').

Expected output for the above test case (but must work for any Type):

Code: Select all

The 'Integer' Type has a destructor (implicit or explicit):           false
The 'String' Type has a destructor (implicit or explicit):            true
The 'String * 10' Type has a destructor (implicit or explicit):       false
The 'String Ptr' Type has a destructor (implicit or explicit):        false
The 'Object' Type has a destructor (implicit or explicit):            false
The 'UDT1' User-Type has destructor (implicit or explicit):           false
The 'UDT2' User-Type has destructor (implicit or explicit):           true

[edit]
- First clue lowering Enigma #25 to force 4: When a Type has a destructor (explicit or implicit), NEW [] adds an Integer in front of the user instances block to store the number of allocated elements, so that DELETE [] can call the destructor on each element.
- Second clue lowering Enigma #25 to force 3: The macro principle is to apply the New [] operator on an UDT containing a single data member of the Type to test, and to safely check if an Integer (to store the number of instances to destroy) is added ahead the user instances block in the allocated memory. Consequently, the address of the user instances block is different from that of the global allocated memory.
- Third clue lowering Enigma #25 to force 2: To resolve this, the simpler is to define in the UDT an overload operator DELETE [] (a similar method could have been used by defining this time an overload operator NEW []).
- Forth (and last) clue lowering Enigma #25 to force 1: The address of the global memory that the overload operator NEW [] must deallocate is passed to it (under the hood) as a parameter. So, one just has to also store it to later can compare it to the known address of the user instances block (the overload operator being static has no access to the THIS reference).
    Note:
    - When one adds an overload operator NEW or NEW [], a parameter gives the number of byte to allocate, and the operator must return the allocated memory address.
    - When one adds an overload operator DELETE or DELETE [], a parameter gives the memory address to deallocate.

My solution using an overload operator DELETE []:

Code: Select all

#macro TypeHasDtor(TypeSymbol, TypeHasDtorResult)
    '' Determine if the Type has a destructor (implicit or explicit).
   
    '' TypeSymbol must be a symbol name referring to a Type (built-in or UDT).
    ''    (either the Type name itself if it's a symbol name, or an alias)
   
    '' TypeHasDtorResult must be a Boolean variable.
    ''    (or an integer numeric variable)
   
    '' ------------------------------------------------------------------------
    '
    ' Insert here the definition code of the macro:
        #ifndef TypeSymbol##UDT
            Type TypeSymbol##UDT
                Declare Operator Delete [] (Byval buf As Any Ptr)
                Dim As TypeSymbol variable
                Static As Any Ptr deallocationPointer
            End Type
           
            Dim As Any Ptr TypeSymbol##UDT.deallocationPointer
           
            Operator TypeSymbol##UDT.Delete [] (Byval buf As Any Ptr)
                TypeSymbol##UDT.deallocationPointer = buf
                Deallocate(buf)
            End Operator
           
            Dim As TypeSymbol##UDT Ptr TypeSymbol##UDT##p
        #endif
         
        TypeSymbol##UDT##p = New TypeSymbol##UDT[1]  '' 1 for example
        Delete [] TypeSymbol##UDT##p
        TypeHasDtorResult = TypeSymbol##UDT.deallocationPointer <> TypeSymbol##UDT##p
    '' ------------------------------------------------------------------------
#endmacro


Dim As Boolean hasDtorResult

TypeHasDtor(Integer, hasDtorResult)
Print "The 'Integer' Type has a destructor (implicit or explicit): ", hasDtorResult

TypeHasDtor(String, hasDtorResult)
Print "The 'String' Type has a destructor (implicit or explicit): ", hasDtorResult

Type string10Type As String * 10  '' define an alias to get a symbol name
TypeHasDtor(string10Type, hasDtorResult)
Print "The 'String * 10' Type has a destructor (implicit or explicit): ", hasDtorResult

Type stringptrType As String Ptr  '' define an alias to get a symbol name
TypeHasDtor(stringptrType, hasDtorResult)
Print "The 'String Ptr' Type has a destructor (implicit or explicit): ", hasDtorResult

TypeHasDtor(Object, hasDtorResult)
Print "The 'Object' Type has a destructor (implicit or explicit): ", hasDtorResult

Type UDT1 Extends Object
End Type
TypeHasDtor(UDT1, hasDtorResult)
Print "The 'UDT1' User-Type has destructor (implicit or explicit): ", hasDtorResult

Type UDT2 Extends Object
    Declare Destructor ()
End Type
Destructor UDT2 ()
End Destructor
TypeHasDtor(UDT2, hasDtorResult)
Print "The 'UDT2' User-Type has destructor (implicit or explicit): ", hasDtorResult

Sleep

My solution using an overload operator NEW []:

Code: Select all

#macro TypeHasDtor(TypeSymbol, TypeHasDtorResult)
    '' Determine if the Type has a destructor (implicit or explicit).
   
    '' TypeSymbol must be a symbol name referring to a Type (built-in or UDT).
    ''    (either the Type name itself if it's a symbol name, or an alias)
   
    '' TypeHasDtorResult must be a Boolean variable.
    ''    (or an integer numeric variable)
   
    '' ------------------------------------------------------------------------
    '
    ' Insert here the definition code of the macro:
        #ifndef TypeSymbol##UDT
            Type TypeSymbol##UDT
                Declare Operator New [] (Byval size As Uinteger) As Any Ptr
                Dim As TypeSymbol variable
                Static As Any Ptr allocationPointer
            End Type
           
            Dim As Any Ptr TypeSymbol##UDT.allocationPointer
           
            Operator TypeSymbol##UDT.New [] (Byval size As Uinteger) As Any Ptr
                TypeSymbol##UDT.allocationPointer = Allocate(size)
                Return TypeSymbol##UDT.allocationPointer
            End Operator
           
            Dim As TypeSymbol##UDT Ptr TypeSymbol##UDT##p
        #endif
         
        TypeSymbol##UDT##p = New TypeSymbol##UDT[1]  '' 1 for example
        Delete [] TypeSymbol##UDT##p
        TypeHasDtorResult = TypeSymbol##UDT.allocationPointer <> TypeSymbol##UDT##p
    '' ------------------------------------------------------------------------
#endmacro


Dim As Boolean hasDtorResult

TypeHasDtor(Integer, hasDtorResult)
Print "The 'Integer' Type has a destructor (implicit or explicit): ", hasDtorResult

TypeHasDtor(String, hasDtorResult)
Print "The 'String' Type has a destructor (implicit or explicit): ", hasDtorResult

Type string10Type As String * 10  '' define an alias to get a symbol name
TypeHasDtor(string10Type, hasDtorResult)
Print "The 'String * 10' Type has a destructor (implicit or explicit): ", hasDtorResult

Type stringptrType As String Ptr  '' define an alias to get a symbol name
TypeHasDtor(stringptrType, hasDtorResult)
Print "The 'String Ptr' Type has a destructor (implicit or explicit): ", hasDtorResult

TypeHasDtor(Object, hasDtorResult)
Print "The 'Object' Type has a destructor (implicit or explicit): ", hasDtorResult

Type UDT1 Extends Object
End Type
TypeHasDtor(UDT1, hasDtorResult)
Print "The 'UDT1' User-Type has destructor (implicit or explicit): ", hasDtorResult

Type UDT2 Extends Object
    Declare Destructor ()
End Type
Destructor UDT2 ()
End Destructor
TypeHasDtor(UDT2, hasDtorResult)
Print "The 'UDT2' User-Type has destructor (implicit or explicit): ", hasDtorResult

Sleep


Normally, the two operators New and Delete must be overloaded simultaneously to be 100% sure of the compatibility between memory allocation and memory release.
But in my two proposed solutions, only one operator is overloaded each time to most simply highlight the useful part of the code for this enigma.
Last edited by fxm on Jan 20, 2020 12:57, edited 2 times in total.
fxm
Posts: 10052
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBASIC syntax challenge games

Postby fxm » Jan 04, 2020 18:57

Tourist Trap wrote:strings have destructors?

Yes, the var-len string type uses a dynamic memory to store the character data of the string.
When a non-empty string goes out the scope, a destructor is mandatory to deallocate its associated dynamic memory.
fxm
Posts: 10052
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBASIC syntax challenge games

Postby fxm » Jan 04, 2020 19:05

Tourist Trap wrote:I'm seriously discovering this feature. Totally missed it, and still probably have to learn.

In the Programmer's Guide, I wrote a page to introduce all forms of NEW and DELETE:
Programmer's Guide / User Defined Types / New and Delete
Last edited by fxm on Jan 04, 2020 19:07, edited 1 time in total.
dodicat
Posts: 6763
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FreeBASIC syntax challenge games

Postby dodicat » Jan 04, 2020 19:07

A crude method.
create an integer pointer (new integer[1]) just before creating the instance pointer (new typesymbol[a random number]
Divide the difference in addresses by (sizeof(integer))
If there is an extra address space inserted by the compiler (for the new[] operator), then the resultant division will be an odd number.

Code: Select all



#macro TypeHasDtor(TypeSymbol, TypeHasDtorResult)
  randomize
    type udt##typesymbol
        as typesymbol  x
    end type
   
    dim as integer Num##typesymbol=2000+int(rnd*10000) 'arbitrary size
    dim  as integer ptr p0##typesymbol=new integer[1]                               'address 0
    dim  as udt##typesymbol ptr p1##typesymbol=new udt##typesymbol[Num##typesymbol] 'address 1
    dim as integer x##typesymbol= (cint(p1##typesymbol)-cint(p0##typesymbol))/sizeof(integer)
    'print x##typesymbol
    TypeHasDtorResult=iif(x##typesymbol and 1,true,false) 'if difference is odd then true
    delete[] p1##typesymbol
    delete[] p0##typesymbol
#endmacro

'


Dim As boolean hasDtorResult

TypeHasDtor(Integer, hasDtorResult)
Print "The 'Integer' Type has a destructor (implicit or explicit): ", hasDtorResult

TypeHasDtor(String, hasDtorResult)
Print "The 'String' Type has a destructor (implicit or explicit): ", hasDtorResult

Type string10Type As String * 10  '' define an alias to get a symbol name
TypeHasDtor(string10Type, hasDtorResult)
Print "The 'String * 10' Type has a destructor (implicit or explicit): ", hasDtorResult

Type stringptrType As String Ptr  '' define an alias to get a symbol name
TypeHasDtor(stringptrType, hasDtorResult)
Print "The 'String Ptr' Type has a destructor (implicit or explicit): ", hasDtorResult

TypeHasDtor(Object, hasDtorResult)
Print "The 'Object' Type has a destructor (implicit or explicit): ", hasDtorResult

Type UDT1 Extends Object
End Type
TypeHasDtor(UDT1, hasDtorResult)
Print "The 'UDT1' User-Type has destructor (implicit or explicit): ", hasDtorResult

Type UDT2 Extends Object
    Declare Destructor ()
End Type
Destructor UDT2 ()
End Destructor
TypeHasDtor(UDT2, hasDtorResult)
Print "The 'UDT2' User-Type has destructor (implicit or explicit): ", hasDtorResult
'====================================
sleep


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

Re: FreeBASIC syntax challenge games

Postby fxm » Jan 04, 2020 19:37

dodicat wrote:A crude method.
create an integer pointer (new integer[1]) just before creating the instance pointer (new typesymbol[a random number]
Divide the difference in addresses by (sizeof(integer))
If there is an extra address space inserted by the compiler (for the new[] operator), then the resultant division will be an odd number.

This assumes that the allocated memory blocks are always aligned (whatever the OS) with each other on a multiple of 2 integers (or 2 pointers).
Does it also work for the Linux OS?
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: FreeBASIC syntax challenge games

Postby Tourist Trap » Jan 04, 2020 19:43

dodicat wrote:A crude method.
create an integer pointer (new integer[1]) just before creating the instance pointer (new typesymbol[a random number]
Divide the difference in addresses by (sizeof(integer))
If there is an extra address space inserted by the compiler (for the new[] operator), then the resultant division will be an odd number.

Hi dodi,

as I understand it, you are assuming that the compiler will "pack" the variables without any blanck. And then so, if a blanck of an integer size is detected, that is the extra bit we are looking for. I'm not sure that this is true in general. It would be great however in the contrary. Right now, I believe that variables may well be put anywhere in any order in the memory, even if most of time it's well packed from what we can observe.

If I'm wrong here, I would be pleased to ear the speech of truth.
fxm wrote:In the Programmer's Guide, I wrote a page to introduce all forms of NEW and DELETE:
Programmer's Guide / User Defined Types / New and Delete

Really nice work! Your graphical description is killing.
dodicat
Posts: 6763
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FreeBASIC syntax challenge games

Postby dodicat » Jan 04, 2020 19:51

Hello from my Scientific Linux distro.
The code works OK in Linux.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: FreeBASIC syntax challenge games

Postby Tourist Trap » Jan 04, 2020 20:31

fxm wrote:I wrote about thirty articles in the Programmer's Guide

Hi fxm! I downloaded the last chm, I had them all now, and they render very well in this format as well. Thanks for all this good stuff.

But about the last challenge, following the insight from dodicat, what if we try a placement new[] pointing in the middle of an array? I tried that, when I delete[] at one index, things are messed up in all the array:

Code: Select all

type DESTR_UDT
   declare destructor()
   as integer  dii
end type
destructor DESTR_UDT()
   this.dii = -111
end destructor

type TESTOBJ as DESTR_UDT

redim as TESTOBJ arr(1 to 2)
clear arr(1), , 2*SizeOf(TESTOBJ)

'? sizeOf(TESTOBJ), sizeOf(byte)
for i as integer = 0 to 2*SizeOf(TESTOBJ)/sizeOf(byte) - 1
   ? "..";i , cast(byte ptr, @arr(1))[i]
next i
? "/////////////////////////////"
? cast(integer ptr, @arr(1))[0]
? cast(integer ptr, @arr(2))[0]

dim as TESTOBJ ptr dd = new (@arr(2)) TESTOBJ[1]

for i as integer = 0 to 2*SizeOf(TESTOBJ)/sizeOf(byte) - 1
   ? "..";i , cast(byte ptr, @arr(1))[i]
next i
? "/////////////////////////////"
? cast(integer ptr, @arr(1))[0]
? cast(integer ptr, @arr(2))[0]

? : ? "DELETE dd"
delete[] dd

for i as integer = 0 to 2*SizeOf(TESTOBJ)/sizeOf(byte) - 1
   ? "..";i , cast(byte ptr, @arr(1))[i]
next i
? "/////////////////////////////"
? cast(integer ptr, @arr(1))[0]
? cast(integer ptr, @arr(2))[0]

.. 0 0
.. 1 0
.. 2 0
.. 3 0
.. 4 0
.. 5 0
.. 6 0
.. 7 0
/////////////////////////////
0
0
.. 0 0
.. 1 0
.. 2 0
.. 3 0
.. 4 0
.. 5 0
.. 6 0
.. 7 0
/////////////////////////////
0
0

DELETE dd / array(2)
.. 0 -72
.. 1 22
.. 2 -100
.. 3 0
.. 4 -64
.. 5 0
.. 6 -100
.. 7 0
/////////////////////////////
10229432
10223808

Return to “Community Discussion”

Who is online

Users browsing this forum: No registered users and 11 guests