With the runtime reflection it's then possible to create an in memory object dB that's transparent to users and facilitates persisting data to file transparently with minimal code.
An example windows x64 asm, use the macro to set a json runtime structure
Code: Select all
JsonRuntimeStruct(*mypt,mpoint,"mpoint") ;add Json runtime structure
AddDb("mypt","mpoint",*mypt) ;uses a map but would in practice use a trie
Code: Select all
Select *value\type
Case "PB_Integer"
index = AddJSONElement(obj)
keyval\value = PeekI(*value\value)
InsertJSONStructure(index, @keyval, keyval)
Case "PB_UTF8"
index = AddJSONElement(obj)
InsertJSONStructure(index, @keyval, keyval)
index = AddJSONElement(obj)
SetJSONString(index,PeekS(*value\value,-1,#PB_UTF8))
Default ;default type is a strucutre
If FindMapElement(JsonRuntime(),*value\type)
index = AddJSONElement(obj)
InsertJSONStructure(index, @keyval,keyval)
index = AddJSONElement(obj)
gJsonAdr = JsonRuntime()\JsonAdr
gJsonSz = JsonRuntime()\JsonSz
InsertJSONRuntimeStructure(index,*value\value) ;macro is specific to this proceddure
EndIf
EndSelect
simulates save and restore, Json Runtime structures are declared as UPPERCASE
Code: Select all
;JSonRuntimeStructure
;x64 asm windows
;Authour idle
;Provides a means to serialize a programs state to and from disk
Structure JsonRuntime
JsonAdr.i
JsonSz.i
StructlayoutAdr.i
EndStructure
#PB_integer$ = "PB_Integer"
#PB_UTF8$ = "PB_UTF8"
Global NewMap JsonRuntime.JsonRuntime()
Structure ara
a.a[0]
EndStructure
Procedure BMSearch(*pinput,inlen,*pat.ara,palen,pos=0)
;booyer moore search
Protected i,t,len,skip,*input, *pa.Ascii,*pb.Ascii
Structure ST
a.a[256]
EndStructure
Static skiptable.ST
inlen-pos
*input = *pinput+pos
len = inlen - palen
If pos = 0
For i = 0 To 255
Skiptable\a[i] = 255;
Next
t= palen-1
For i = 0 To t
skiptable\a[*pat\a[i]] = i
Next
EndIf
i=0
skip=0
While skip <= len
i = palen - 1;
*pa = (*input + skip + i)
*pb = *pat+i
While (*pb\a = *pa\a)
i-1
*pa - 1
*pb - 1
Wend
If i > 0
t = i - Skiptable\a[*pa\a]
If t > 1
skip + t
Else
skip + 1
EndIf
Else
ProcedureReturn skip + pos
EndIf
Wend
ProcedureReturn 0
EndProcedure
Global gJsonAdr,gJsonSz, gJsonSt,gJsonEt,gJsonlb,gJsonRet,gStructlayoutAdr
Macro InsertJSONRuntimeStructure(index,value)
CompilerIf #PB_Compiler_64Bit
!SUB rsp,8
!MOV rax, [v_gJsonAdr]
!PUSH rax
!PUSH qword [v_gJsonSz]
!MOV rbp,qword [rsp+PS2+40]
!PUSH qword [rbp+8]
!PUSH qword [rsp+120]
!POP rcx
!POP rdx
!POP r8
!POP r9
!SUB rsp,32
!CALL PB_InsertJSONStructure
!ADD rsp,40
CompilerElse
!PUSH [v_gJsonAdr]
!PUSH [v_gJsonSz]
!MOV ebp,dword [esp+PS2+16]
!PUSH dword [ebp+4]
!PUSH dword [esp+32]
!CALL _PB_InsertJSONStructure@16
CompilerEndIf
EndMacro
Macro ExtractJSONRuntimeStructure(ele,ptr)
CompilerIf #PB_Compiler_64Bit
!SUB rsp,8
!MOV rax, [v_gStructlayoutAdr]
!PUSH rax
!PUSH qword [v_gJsonSz]
!POP rcx
!POP rdx
!SUB rsp,32
!CALL PB_AllocateStructure
!ADD rsp,40
!MOV qword [p.p_ptr],rax
!SUB rsp,8
!MOV rax, [v_gJsonAdr]
!PUSH rax
!PUSH qword [v_gJsonSz]
!PUSH qword [p.a_keyval]
!PUSH qword [rsp+128]
!POP rcx
!POP rdx
!POP r8
!POP r9
!SUB rsp,32
!CALL PB_ExtractJSONStructure
!ADD rsp,40
CompilerElse
CompilerEndIf
EndMacro
Macro JsonRuntimeStruct(ptr,struct,key) ;generates the structure layout table
Global ptr.struct = AllocateStructure(struct)
js = CreateJSON(#PB_Any)
Ar = SetJSONArray(JSONValue(js))
index = AddJSONElement(Ar)
InsertJSONStructure(index,ptr,struct)
ExtractJSONStructure(index,ptr,struct)
FreeJSON(js)
gJsonSz = SizeOf(struct)
CompilerIf #PB_Compiler_64Bit
!lea rax, [_SYS_StaticStringEnd]
!lea rdx, [SYS_EndDataSection]
!mov [v_gJsonSt], rax ;_SYS_StaticStringEnd
!mov [v_gJsonEt], rdx ; SYS_EndDataSection
CompilerElse
!mov [v_gJsonSt], _SYS_StaticStringEnd
!mov [v_gJsonEt], SYS_EndDataSection
CompilerEndIf
*pat = Ascii(UCase(key))
gJsonlb = BMSearch(gJsonst,gJsonet-gJsonst,*pat,MemorySize(*pat))
gJsonAdr=gJsonst+gJsonlb
AddMapElement(JsonRuntime(),key)
JsonRuntime()\JsonAdr = gJsonAdr
JsonRuntime()\JsonSz = gJsonSz
JsonRuntime()\StructlayoutAdr = PeekI(gJsonAdr+MemorySize(*pat)+1)
FreeMemory(*pat)
EndMacro
;-test keypair store
Structure dbval
type.s
value.i
EndStructure
Structure keyval
key.s
type.s
value.i
EndStructure
Global NewMap DBitems.dbval() ;use a map as key pair store would actually use a trie in practice
Procedure CBSave(key.s,*value.dbval=0,*userdata=0)
Protected keyval.keyval,str.s
Static obj
If obj <> *userdata
obj = *userdata
EndIf
keyval\key = key
keyval\type = *value\type
If *value
Select *value\type
Case #PB_Integer$
index = AddJSONElement(obj)
keyval\value = PeekI(*value\value)
InsertJSONStructure(index, @keyval, keyval)
Case #PB_UTF8$
index = AddJSONElement(obj)
InsertJSONStructure(index, @keyval, keyval)
index = AddJSONElement(obj)
SetJSONString(index,PeekS(*value\value,-1,#PB_UTF8))
Default ;default type is a strucutre
If FindMapElement(JsonRuntime(),*value\type)
index = AddJSONElement(obj)
InsertJSONStructure(index, @keyval,keyval)
index = AddJSONElement(obj)
gJsonAdr = JsonRuntime()\JsonAdr
gJsonSz = JsonRuntime()\JsonSz
InsertJSONRuntimeStructure(index,*value\value) ;macro is specific to this proceddure
EndIf
EndSelect
EndIf
ProcedureReturn 1
EndProcedure
Procedure SetDB(key.s,type.s,*ptr)
AddMapElement(DBitems(),key)
DBitems()\type = type
DBitems()\value = *ptr
EndProcedure
Procedure GetDBValue(key.s)
ProcedureReturn DBitems(key)\value
EndProcedure
Procedure.s GetDBType(key.s)
ProcedureReturn DBitems(key)\type
EndProcedure
Procedure RestoreDB(file.s)
Protected key.s
Protected obj,json
Protected *ptr
Protected a, ele
Dim keyval.keyval(0)
json = LoadJSON(#PB_Any,file)
obj = JSONValue(json)
ExtractJSONArray(obj,keyval())
sz = ArraySize(keyval())
For a = 0 To sz
Select keyval(a)\type
Case #PB_Integer$
SetDB(keyval(a)\key,keyval(a)\type,keyval(a)\value)
Case #PB_UTF8$
key = keyval(a)\key
a+1
ele = GetJSONElement(obj,a)
*ptr = UTF8(GetJSONString(ele))
SetDB(keyval(a-1)\key,keyval(a)\type,*ptr)
Default
key = keyval(a)\key
If FindMapElement(JsonRuntime(),keyval(a)\type)
a+1
ele = GetJSONElement(obj,a)
gJsonAdr = JsonRuntime()\JsonAdr
gJsonSz = JsonRuntime()\JsonSz
gStructlayoutAdr = JsonRuntime()\StructlayoutAdr
ExtractJSONRuntimeStructure(ele,*ptr)
SetDB(key,keyval(a)\type,*ptr)
EndIf
EndSelect
Next
FreeJSON(json)
EndProcedure
Procedure SaveDB(file.s)
Protected res,json,ArrayValue,lock.s,path.s
json = CreateJSON(#PB_Any)
ArrayValue = SetJSONArray(JSONValue(json))
ForEach DBitems()
cbSave(MapKey(DBitems()),@DBitems(),ArrayValue)
Next
SaveJSON(json,file)
Debug ComposeJSON(json, #PB_JSON_PrettyPrint)
FreeJSON(json)
EndProcedure
Procedure FreeDB()
ForEach DBitems()
Select DBitems()\type
Case "PB_Integer"
Case "PB_UTF8"
FreeMemory(DBitems()\value)
Default
If DBitems()\type <> ""
FreeStructure(DBitems()\value)
EndIf
EndSelect
Next
ClearMap(DBitems())
EndProcedure
;-Test the JsonRuntimeStructures in the keypair store
Structure MPOINT ;db structues declare as UPPERCASE
x.i
y.i
EndStructure
Structure bar
Map mp.s()
x.f
y.f
EndStructure
Structure FOO ;db structues declare as UPPERCASE a nested sructure, only need to declare FOO
x.i
y.i
b.bar
List pt.mpoint()
EndStructure
Global *str = UTF8("Hello Runtime")
SetDB("mystr",#PB_UTF8$,*str)
Global int.i = 12345
SetDB("myint",#PB_Integer$,@int)
JsonRuntimeStruct(*mypt,mpoint,"mpoint") ;add to Json runtime structure allocates item on heap
SetDB("mypt","mpoint",*mypt) ;Set to the db
JsonRuntimeStruct(*myfoo,foo,"foo") ;add Json runtime structure
SetDB("myfoo","foo",*myfoo) ;set to the db
*mypt\x = 234 ;set values
*mypt\y = 567
*myfoo\x = 123 ;set its values
*myfoo\y = 234
AddElement(*myfoo\pt())
*myfoo\pt()\x = 678
*myfoo\pt()\y = 789
AddElement(*myfoo\pt())
*myfoo\pt()\x = 1678
*myfoo\pt()\y = 1789
AddMapElement(*myfoo\b\mp(),"hello")
*myfoo\b\mp() = "world"
*myfoo\b\x = #PI
*myfoo\b\y = 2*#PI
;-Serialize the runtime strucutres to disk
Global file.s = GetTemporaryDirectory() + "testdb.json"
SaveDB(file) ;save the serialzied json to file
Debug "saved DB"
Debug ""
FreeDB() ;free the DB clears the heap allocated items
;-Reload the the keypair store from disk
RestoreDB(file) ;reload the json to DB
Debug "Restored DB"
;-debug the restored items
*mypt = GetDBValue("mypt")
Debug "mypt\x = " + Str(*mypt\x)
Debug "mypt\y = " + Str(*mypt\y)
*myfoo = GetDBValue("myfoo") ;get an item
ForEach *myfoo\pt()
Debug "myfoo\pt()\x = " + Str(*myfoo\pt()\x)
Debug "myfoo\pt()\y = " + Str(*myfoo\pt()\y)
Next
;
Debug "myfoo\x =" + Str(*myfoo\x)
Debug "myfoo\y = " + Str(*myfoo\y)
Debug "myfoo\b\mp(hello) = " + *myfoo\b\mp("hello")
Debug "myfoo\b\x =" + Str(*myfoo\b\x)
Debug "*myfoo\b\y =" + Str(*myfoo\b\y)
*ptr = GetDBValue("mystr")
Debug "str =" + PeekS(*ptr,-1,#PB_UTF8)
int = GetDBValue("myint")
Debug "int=" + Str(int)
FreeDB()