Page 1 of 1
Can I use "Dynamic numbering" in my code, if so, how?
Posted: Sun Oct 16, 2022 11:29 am
by pdwyer
I'd like to create a module (several actually) where a create() call can create an instance using #PB_Any and I return a handle/id
It sounds like it works similar to PB Object handles for managing images, files, connections etc.
Does anyone have any boilerplate code for how to do something like this? Obviously the back end handle creation and release would need to be managed etc.
I think over the years I've seen some code snippets of people doing this kind of thing but I can find them now.
Cheers
Re: Can I use "Dynamic numbering" in my code, if so, how?
Posted: Sun Oct 16, 2022 12:58 pm
by Caronte3D
Maybe you can use AllocateMemory (a simple byte) and use the returned *MemoryID like a "dinamic numbering"?
I think it's the way #PB_Any works.
Re: Can I use "Dynamic numbering" in my code, if so, how?
Posted: Sun Oct 16, 2022 1:05 pm
by Little John
pdwyer wrote: Sun Oct 16, 2022 11:29 am
I'd like to create a module (several actually) where a create() call can create an instance using #PB_Any and I return a handle/id
Erm ... sorry, I don't understand. Create an instance of what?
In case you mean an instance of the module: This is not possible. A module is just a way for providing a separate namespace in the source code. It's not a PB object.
Re: Can I use "Dynamic numbering" in my code, if so, how?
Posted: Sun Oct 16, 2022 1:23 pm
by pdwyer
Looking at the PB help file in the section called "PureBasic objects" I realise that these are some kind of library for statically linking to the final executable but I'd like to create a module that works in a similar way but have it in a PBI file or DLL rather than a statically linked lib.
When I say module, I don't necessarily mean pb module code. I may well use that for the isolation features but it doesn't contain any functionality specifically for what I want to do.
One of the thing I want to use this for is Neural Network code. I have this already but my current code only creates a single network. I'd like to create several networks and interact with them via a handle or ID and to run create, load, train, query functions etc. I have an analytics graph UI based on a canvas gadget with OLAP functions and events but I want to be able to create several windows each with it's own analytics graph control. There are several others too.
What I want is a standard way to approach this (and likely put it in a module or DLL but thats a separate thing, I can do that with the current code).
I'm pretty sure I saw code once years ago where someone had a function in a module that managed the handles with static variables and passed them back with an id when it received a #PB_Any. I'm sure there's lots of gotcha's with this so I thought since I couldn't find any code like that on the forum that I'd see if someone had been through this and could share some lessons learned and approaches
Re: Can I use "Dynamic numbering" in my code, if so, how?
Posted: Sun Oct 16, 2022 3:51 pm
by mk-soft
I took a look at PB's SDK. Object and Ticket. Unfortunately, I couldn't get it to work with a static ID. Therefore I created my own example with array and map.
Update
Code: Select all
;-TOP
DeclareModule MyTicket
Structure udtTicket
Value.i
EndStructure
Declare NewTicket(ID, Value = 0)
Declare GetTicket(ID)
Declare FreeTicket(ID)
EndDeclareModule
Module MyTicket
Global Dim *arrTicket.udtTicket(16)
Global NewMap *mapTicket.udtTicket()
Procedure NewTicket(ID, Value = 0)
Protected *Ticket.udtTicket
*Ticket = AllocateStructure(udtTicket)
If *Ticket
If id = #PB_Any
*mapTicket(Str(*Ticket)) = *Ticket
Else
If id >= 5000
CompilerWarning "Very big Ticket ID!"
EndIf
If id > ArraySize(*arrTicket())
ReDim *arrTicket(id + 16)
EndIf
If *arrTicket(id) <> 0
FreeStructure(*arrTicket(id))
EndIf
*arrTicket(id) = *Ticket
EndIf
*Ticket\Value = Value
EndIf
ProcedureReturn *Ticket
EndProcedure
Procedure GetTicket(ID)
If ID <= ArraySize(*arrTicket())
ProcedureReturn *arrTicket(id)
Else
If FindMapElement(*mapTicket(), Str(id))
ProcedureReturn *mapTicket()
EndIf
EndIf
ProcedureReturn 0
EndProcedure
Procedure FreeTicket(ID)
If ID <= ArraySize(*arrTicket())
If *arrTicket(ID)
FreeStructure(*arrTicket(id))
*arrTicket(id) = 0
EndIf
Else
If FindMapElement(*mapTicket(), Str(id))
DeleteMapElement(*mapTicket())
EndIf
EndIf
EndProcedure
EndModule
;-Test
UseModule MyTicket
*data1.udtTicket = NewTicket(0, 100)
*data2.udtTicket = NewTicket(1, 200)
*data3.udtTicket = NewTicket(#PB_Any, 300)
*data.udtTicket = GetTicket(1)
If *data
Debug *data\Value
EndIf
*data.udtTicket = GetTicket(*data3)
If *data
Debug *data\Value
EndIf
Re: Can I use "Dynamic numbering" in my code, if so, how?
Posted: Sun Oct 16, 2022 5:57 pm
by StarBootics
Hello everyone,
@mk-soft : You can't use CompilerWarning or CompilerError with regular If/EndIf statement. You will get the warning or error message no matter what the ID value is.
Code: Select all
ID = 0
If ID >= 5000
CompilerWarning "Very big ID!"
Else
Debug "ID OK"
EndIf
If ID > 5000
CompilerError "Very big ID!"
Else
Debug "ID OK"
EndIf
Best regards
StarBootics
Re: Can I use "Dynamic numbering" in my code, if so, how?
Posted: Mon Oct 17, 2022 2:48 pm
by pdwyer
Thanks MK-Soft, you have given me some ideas to build on
Re: Can I use "Dynamic numbering" in my code, if so, how?
Posted: Mon Oct 17, 2022 10:58 pm
by Olli
Macro id :
Code: Select all
Macro macId()
(MacroExpandedCount)
EndMacro
Debug macId()
Re: Can I use "Dynamic numbering" in my code, if so, how?
Posted: Wed Oct 19, 2022 2:20 pm
by StarBootics
Hello everyone,
The following code is an adaptation of mk-soft's original code.
Code: Select all
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; AUTOMATICALLY GENERATED CODE, DO NOT MODIFY
; UNLESS YOU REALLY, REALLY, REALLY MEAN IT !!
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Code generated by : Dev-Object - V2.0.0
; Project name : Tickets System
; File name : Tickets - OOP.pb
; File Version : 1.0.0
; Programmation : OK
; Programmed by : StarBootics
; Creation Date : 16-10-2022
; Last update : 19-10-2022
; Coded for PureBasic : V6.00 LTS
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming Notes
;
; 1. Based on mk-soft's original code.
;
; 2. Work with objects coded with Dev-Object and Allocated
; structures. It's possible to put different objects
; inside the same Tickets system. See the example.
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
DeclareModule Tickets
Interface Tickets
NewTicket.i(ID.i, *ObjectPtr, Tag.l = 0, *ObjectDestructor = #Null)
GetTicketObject.i(ID.i)
GetTicketTag.l(ID.i)
FreeTicket(ID.i)
Free()
EndInterface
Declare.i New(*ObjectDestructor = #Null)
EndDeclareModule
Module Tickets
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Structures declaration <<<<<
Structure Ticket
Tag.l
*ObjectPtr
*ObjectDestructor
EndStructure
Structure Private_Members
VirtualTable.i
*ObjectDestructor
Array *ArrayTickets.Ticket(16)
Map *MapTickets.Ticket()
EndStructure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Object Destructor prototype <<<<<
Prototype DestructorFunction(*ObjectPtr)
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The NewTicket operator <<<<<
Procedure.i NewTicket(*This.Private_Members, ID.i, *ObjectPtr, Tag.l = 0, *ObjectDestructorAddress = #Null)
*Ticket.Ticket = AllocateStructure(Ticket)
If *Ticket
If ID = #PB_Any
*This\MapTickets(Str(*Ticket)) = *Ticket
Else
If ID > ArraySize(*This\ArrayTickets())
ReDim *This\ArrayTickets(ID + 16)
EndIf
If *This\ArrayTickets(ID) <> #Null
If *This\ArrayTickets(ID)\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\ArrayTickets(ID)\ObjectDestructor
Destructor(*This\ArrayTickets(ID)\ObjectPtr)
ElseIf *This\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\ObjectDestructor
Destructor(*This\ArrayTickets(ID)\ObjectPtr)
Else
FreeStructure(*This\ArrayTickets(ID)\ObjectPtr)
EndIf
FreeStructure(*This\ArrayTickets(ID))
EndIf
*This\ArrayTickets(ID) = *Ticket
EndIf
*Ticket\Tag = Tag
*Ticket\ObjectPtr = *ObjectPtr
*Ticket\ObjectDestructor = *ObjectDestructorAddress
EndIf
ProcedureReturn *Ticket
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Observators <<<<<
Procedure.i GetTicketObject(*This.Private_Members, ID.i)
If ID <= ArraySize(*This\ArrayTickets())
ProcedureReturn *This\ArrayTickets(ID)\ObjectPtr
Else
If FindMapElement(*This\MapTickets(), Str(ID))
ProcedureReturn *This\MapTickets()\ObjectPtr
EndIf
EndIf
ProcedureReturn 0
EndProcedure
Procedure.l GetTicketTag(*This.Private_Members, ID.i)
If ID <= ArraySize(*This\ArrayTickets())
ProcedureReturn *This\ArrayTickets(ID)\Tag
Else
If FindMapElement(*This\MapTickets(), Str(ID))
ProcedureReturn *This\MapTickets()\Tag
EndIf
EndIf
ProcedureReturn -1
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The FreeTicket operator <<<<<
Procedure FreeTicket(*This.Private_Members, ID.i)
If ID <= ArraySize(*This\ArrayTickets())
If *This\ArrayTickets(ID) <> #Null
If *This\ArrayTickets(ID)\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\ArrayTickets(ID)\ObjectDestructor
Destructor(*This\ArrayTickets(ID)\ObjectPtr)
ElseIf *This\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\ObjectDestructor
Destructor(*This\ArrayTickets(ID)\ObjectPtr)
Else
FreeStructure(*This\ArrayTickets(ID)\ObjectPtr)
EndIf
FreeStructure(*This\ArrayTickets(ID))
*This\ArrayTickets(ID) = #Null
EndIf
Else
If FindMapElement(*This\MapTickets(), Str(ID))
If *This\MapTickets()\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\MapTickets()\ObjectDestructor
Destructor(*This\MapTickets()\ObjectPtr)
ElseIf *This\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\ObjectDestructor
Destructor(*This\MapTickets()\ObjectPtr)
Else
FreeStructure(*This\MapTickets()\ObjectPtr)
EndIf
DeleteMapElement(*This\MapTickets())
EndIf
EndIf
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Destructor <<<<<
Procedure Free(*This.Private_Members)
ArrayMax.l = ArraySize(*This\ArrayTickets())
For Index = 0 To ArrayMax
If *This\ArrayTickets(Index) <> #Null
If *This\ArrayTickets(Index)\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\ArrayTickets(Index)\ObjectDestructor
Destructor(*This\ArrayTickets(Index)\ObjectPtr)
ElseIf *This\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\ObjectDestructor
Destructor(*This\ArrayTickets(Index)\ObjectPtr)
Else
FreeStructure(*This\ArrayTickets(Index)\ObjectPtr)
EndIf
EndIf
Next
ForEach *This\MapTickets()
If *This\MapTickets() <> #Null
If *This\MapTickets()\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\MapTickets()\ObjectDestructor
Destructor(*This\MapTickets()\ObjectPtr)
ElseIf *This\ObjectDestructor <> #Null
Destructor.DestructorFunction = *This\ObjectDestructor
Destructor(*This\MapTickets()\ObjectPtr)
Else
FreeStructure(*This\MapTickets()\ObjectPtr)
EndIf
EndIf
Next
FreeStructure(*This)
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Constructor <<<<<
Procedure.i New(*ObjectDestructor = #Null)
*This.Private_Members = AllocateStructure(Private_Members)
*This\VirtualTable = ?START_METHODS
*This\ObjectDestructor = *ObjectDestructor
ProcedureReturn *This
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Virtual Table Entries <<<<<
DataSection
START_METHODS:
Data.i @NewTicket()
Data.i @GetTicketObject()
Data.i @GetTicketTag()
Data.i @FreeTicket()
Data.i @Free()
END_METHODS:
EndDataSection
EndModule
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Code generated in : 00.001 seconds (76000.00 lines/second) <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CompilerIf #PB_Compiler_IsMainFile
DeclareModule Cube
Interface Cube
GetSide.d()
SetSide(Side.d)
Free()
EndInterface
Declare Free(*This)
Declare.i New(Side.d = 0.0)
EndDeclareModule
Module Cube
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Structure declaration <<<<<
Structure Private_Members
VirtualTable.i
Side.d
EndStructure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The observators <<<<<
Procedure.d GetSide(*This.Private_Members)
ProcedureReturn *This\Side
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The mutators <<<<<
Procedure SetSide(*This.Private_Members, Side.d)
*This\Side = Side
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Destructor <<<<<
Procedure Free(*This.Private_Members)
Debug "Cube Destructor called !"
FreeStructure(*This)
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Constructor <<<<<
Procedure.i New(Side.d = 0.0)
*This.Private_Members = AllocateStructure(Private_Members)
*This\VirtualTable = ?START_METHODS
*This\Side = Side
ProcedureReturn *This
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Virtual Table Entries <<<<<
DataSection
START_METHODS:
Data.i @GetSide()
Data.i @SetSide()
Data.i @Free()
END_METHODS:
EndDataSection
EndModule
DeclareModule Sphere
Interface Sphere
GetRadius.d()
SetRadius(Radius.d)
Free()
EndInterface
Declare Free(*This)
Declare.i New(Radius.d = 0.0)
EndDeclareModule
Module Sphere
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Structure declaration <<<<<
Structure Private_Members
VirtualTable.i
Radius.d
EndStructure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The observators <<<<<
Procedure.d GetRadius(*This.Private_Members)
ProcedureReturn *This\Radius
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The mutators <<<<<
Procedure SetRadius(*This.Private_Members, Radius.d)
*This\Radius = Radius
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Destructor <<<<<
Procedure Free(*This.Private_Members)
Debug "Sphere Destructor called !"
FreeStructure(*This)
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Constructor <<<<<
Procedure.i New(Radius.d = 0.0)
*This.Private_Members = AllocateStructure(Private_Members)
*This\VirtualTable = ?START_METHODS
*This\Radius = Radius
ProcedureReturn *This
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Virtual Table Entries <<<<<
DataSection
START_METHODS:
Data.i @GetRadius()
Data.i @SetRadius()
Data.i @Free()
END_METHODS:
EndDataSection
EndModule
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CubeTickets.Tickets::Tickets = Tickets::New(Cube::@Free())
CubeTickets\NewTicket(00, Cube::New(5.25))
CubeTickets\NewTicket(01, Cube::New(4.50))
*CubeTicket00 = CubeTickets\NewTicket(#PB_Any, Cube::New(3.75))
Debug "Working with cube objects"
If CubeTickets\GetTicketTag(0) = 0
*CubeA.Cube::Cube = CubeTickets\GetTicketObject(0)
Debug *CubeA\GetSide()
EndIf
If CubeTickets\GetTicketTag(1) = 0
*CubeA.Cube::Cube = CubeTickets\GetTicketObject(1)
Debug *CubeA\GetSide()
EndIf
If CubeTickets\GetTicketTag(*CubeTicket00) = 0
*CubeA.Cube::Cube = CubeTickets\GetTicketObject(*CubeTicket00)
Debug *CubeA\GetSide()
EndIf
Debug ""
CubeTickets\Free()
Debug ""
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
SphereTickets.Tickets::Tickets = Tickets::New(Sphere::@Free())
SphereTickets\NewTicket(00, Sphere::New(5.25))
SphereTickets\NewTicket(01, Sphere::New(4.50))
*SphereTicket00 = SphereTickets\NewTicket(#PB_Any, Sphere::New(3.75))
Debug "Working with sphere objects"
If SphereTickets\GetTicketTag(0) = 0
*SphereA.Sphere::Sphere = SphereTickets\GetTicketObject(0)
Debug *SphereA\GetRadius()
EndIf
If SphereTickets\GetTicketTag(1) = 0
*SphereA.Sphere::Sphere = SphereTickets\GetTicketObject(1)
Debug *SphereA\GetRadius()
EndIf
If SphereTickets\GetTicketTag(*SphereTicket00) = 0
*SphereA.Sphere::Sphere = SphereTickets\GetTicketObject(*SphereTicket00)
Debug *SphereA\GetRadius()
EndIf
Debug ""
SphereTickets\Free()
Debug ""
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
FormsTickets.Tickets::Tickets = Tickets::New()
FormsTickets\NewTicket(00, Cube::New(5.25), 0, Cube::@Free())
FormsTickets\NewTicket(01, Sphere::New(5.25), 1, Sphere::@Free())
FormsTickets\NewTicket(02, Cube::New(4.50), 0, Cube::@Free())
FormsTickets\NewTicket(03, Sphere::New(4.50), 1, Sphere::@Free())
*FormsTickets00 = FormsTickets\NewTicket(#PB_Any, Cube::New(3.75), 0, Cube::@Free())
*FormsTickets01 = FormsTickets\NewTicket(#PB_Any, Sphere::New(3.75), 1, Sphere::@Free())
Debug "Working with cube and sphere objects"
For Index = 0 To 3
Select FormsTickets\GetTicketTag(Index)
Case 0
Debug "It's a Cube Object"
*CubeA.Cube::Cube = FormsTickets\GetTicketObject(Index)
Debug *CubeA\GetSide()
Case 1
Debug "It's a Sphere Object"
*SphereA.Sphere::Sphere = FormsTickets\GetTicketObject(Index)
Debug *SphereA\GetRadius()
EndSelect
Next
Debug ""
FormsTickets\Free()
Debug ""
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Structure Tetrahedron
Side.d
EndStructure
TetrahedronTickets.Tickets::Tickets = Tickets::New(#Null)
*TetrahedronA.Tetrahedron = AllocateStructure(Tetrahedron)
*TetrahedronA\Side = 5.75
TetrahedronTickets\NewTicket(00, *TetrahedronA, 0, #Null)
*TetrahedronA.Tetrahedron = AllocateStructure(Tetrahedron)
*TetrahedronA\Side = 6.50
TetrahedronTickets\NewTicket(01, *TetrahedronA, 0, #Null)
Debug "Working with Tetrahedron structures"
For Index = 0 To 1
*TetrahedronB.Tetrahedron = TetrahedronTickets\GetTicketObject(Index)
Debug *TetrahedronB\Side
Next
Debug ""
TetrahedronTickets\Free()
CompilerEndIf
; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Have fun with this code.
Best regards
StarBootics
Re: Can I use "Dynamic numbering" in my code, if so, how?
Posted: Sat Oct 22, 2022 5:09 am
by pdwyer
Wow,
I'm going to need some time to study this.
I'm curious about your code auto-gen thingy too