Binary Serializer and Reflection system
Posted: Thu Nov 22, 2018 8:52 pm
I'm creating a Binary Serializer for an in memory DB project
the db engine is lmdb from the openldap project which is also used in sqlite3 for it's in memory function.
The end result will be something like this
lmdb_Set(*data,structure,key.s)
lmdb_Get(*data,structure,key.s)
It utilizes the structure layout tables which are used internally for copystructure.
This provides enough information to get at the non serial objects within a structure
and the rest of the data can be inferred from the size, offsets and current position.
Adding runtime reflection would make it a lot easier but I don't see how to do that
without writing a compiler tool. Any thoughts on how to do it without a compiler tool
would be really welcome.
It's going to take a while to do and I'm still working through enumerating
and resolving lists and maps.
In the mean time here's a routine to examine the structure layout table.
not much use of itself and I'm still undecided if there's any point of putting the info in a list
Wilbert if you read this, is there a fix for the GetStructAdr(structAdr,struct) macro for osx ?
the db engine is lmdb from the openldap project which is also used in sqlite3 for it's in memory function.
The end result will be something like this
lmdb_Set(*data,structure,key.s)
lmdb_Get(*data,structure,key.s)
It utilizes the structure layout tables which are used internally for copystructure.
This provides enough information to get at the non serial objects within a structure
and the rest of the data can be inferred from the size, offsets and current position.
Adding runtime reflection would make it a lot easier but I don't see how to do that
without writing a compiler tool. Any thoughts on how to do it without a compiler tool
would be really welcome.
It's going to take a while to do and I'm still working through enumerating
and resolving lists and maps.
In the mean time here's a routine to examine the structure layout table.
not much use of itself and I'm still undecided if there's any point of putting the info in a list
Wilbert if you read this, is there a fix for the GetStructAdr(structAdr,struct) macro for osx ?
Code: Select all
Structure PB_ListHeader
*next.PB_ListHeader
*Previous.PB_ListHeader
EndStructure
Structure PB_ListPosition
*next.PB_ListPosition;
*Element.PB_ListHeader;
EndStructure
Structure PB_List
*First.PB_ListHeader;
*Last.PB_ListHeader;
*Current.PB_ListHeader; // Don't move it, as it is used internally by the compiler
*CurrentVariable.PB_ListHeader; **
NbElements.i;
Index.i;
*StructureMap;
*Allocator;
*PositionStack.PB_ListPosition;
*Object.PB_ListObject;
ElementSize.i; // moved here for better alignment on X64
ElementType.l;
IsIndexInvalid.b;
IsDynamic.b;
IsDynamicObject.b;
EndStructure
Structure PB_ListObject
*list.PB_List;
*CurrentElement.PB_ListElement;
EndStructure
Structure PB_ListElement
Header.PB_ListHeader;
StructureUnion
Long.i;
*String;
EndStructureUnion;
EndStructure
Import ""
PB_FirstElement(*List.PB_List)
PB_ListSize(*list.PB_List);
PB_NextElement(*List.PB_List)
EndImport
;
#ST_End = -1
#ST_StaticArray= -2
#ST_Structure = -3
#ST_Array = -4
#ST_List = -5
#ST_Map = -6
#ST_MultiArray = -7
#ST_String = 0
Structure StructInfo
TypeStr.s ;Array List Map String
Type.l ;Array list map
TypeSize.l ;Size of type
Offset.l ;offset in structure
SLAdr.i ;address of structure layout
NumElements.l ;Number of elements
NumDimentions.l ;number of dimentions
SpanDimentions.l ; Array(2,3) 2*3
StuctType.l ;type of contained structure
EndStructure
Structure structItr
index.i[0]
EndStructure
Global NewList StInfo.StructInfo()
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
Macro eax : rax : EndMacro
CompilerEndIf
Macro GetStructAdr(structAdr,struct)
!if defined s_#struct
!lea eax,[s_#struct]
!else
!xor eax,eax
!end if
EnableASM
mov structAdr,eax
DisableASM
EndMacro
#PB_FixedString = 10
Procedure.s GetTypeName(type)
Select type
Case #PB_Byte
ProcedureReturn "Byte"
Case #PB_Word
ProcedureReturn "Word"
Case #PB_Long
ProcedureReturn "Long"
Case #PB_Structure
ProcedureReturn "Structure"
Case #PB_String
ProcedureReturn "String"
Case #PB_Float
ProcedureReturn "Float"
Case #PB_FixedString
ProcedureReturn "FixedString"
Case #PB_Character
ProcedureReturn "Character"
Case #PB_Double
ProcedureReturn "Double"
Case #PB_Quad
ProcedureReturn "Quad"
Case #PB_Integer
ProcedureReturn "Integer"
Case #PB_Ascii
ProcedureReturn "Ascii"
Case #PB_Unicode
ProcedureReturn "Unicode"
EndSelect
EndProcedure
Procedure StructureInfo(structadr)
Protected a,*itr.structItr
*itr = structadr
If *itr
Repeat
x = *itr\index[a]
Select x
Case #ST_StaticArray
AddElement(StInfo())
stinfo()\TypeStr = "StaticArray"
stinfo()\Type = #ST_StaticArray
stinfo()\NumElements = *itr\index[a+1]
stinfo()\Offset = *itr\index[a+2]
stinfo()\StuctType = *itr\index[a+3]
stinfo()\SLAdr = *itr\index[a+4]
Debug "Static Array: Offset =" + stinfo()\offset + " StructType=" + GetTypeName(stinfo()\StuctType) + " ArraySize =" + stinfo()\NumElements + " Stucture Adr=" + stinfo()\SLAdr
a+4
If stinfo()\SLAdr <> 0
StructureInfo(stinfo()\SLAdr)
EndIf
Case #ST_Structure
AddElement(StInfo())
stinfo()\TypeStr = "Structure"
stinfo()\Type = #ST_Structure
stinfo()\Offset = *itr\index[a+1]
stinfo()\TypeSize = *itr\index[a+2]
stinfo()\SLAdr = *itr\index[a+3]
Debug "Structure: Offset =" + StInfo()\Offset + " Typesize =" + StInfo()\TypeSize + " stucture adr=" + stinfo()\SLAdr
a+3
If stinfo()\SLAdr <> 0
StructureInfo(stinfo()\SLAdr)
EndIf
Case #ST_Array
AddElement(StInfo())
StInfo()\TypeStr = "Array"
stinfo()\Type = #ST_Array
stInfo()\Offset = *itr\index[a+1]
StInfo()\TypeSize = *itr\index[a+2]
stInfo()\NumElements = *itr\index[a+3]
StInfo()\StuctType = *itr\index[a+4]
StInfo()\SLAdr = *itr\index[a+5]
Debug "Array: offset =" + stinfo()\offset + " typesize =" + stinfo()\TypeSize + " ArraySize =" + stinfo()\NumElements + " struct type=" + GetTypeName(StInfo()\StuctType)
a+5
If stinfo()\SLAdr <> 0
StructureInfo(stinfo()\SLAdr)
EndIf
Case #ST_List
AddElement(stInfo())
StInfo()\TypeStr = "List"
stinfo()\Type = #ST_List
stinfo()\Offset = *itr\index[a+1]
stinfo()\TypeSize = *itr\index[a+2]
StInfo()\SLAdr = *itr\index[a+3]
stInfo()\StuctType = *itr\index[a+4]
Debug "List: offset =" + stinfo()\offset + " typesize =" + stinfo()\TypeSize + " structure adr =" + stinfo()\SLAdr + " type =" + GetTypeName(stinfo()\StuctType)
a+4
If stinfo()\SLAdr <> 0
StructureInfo(stinfo()\SLAdr)
EndIf
Case #ST_Map
AddElement(stinfo())
StInfo()\TypeStr = "Map"
StInfo()\Type = #ST_Map
StInfo()\offset = *itr\index[a+1]
stinfo()\TypeSize = *itr\index[a+2]
stinfo()\StuctType = *itr\index[a+3]
StInfo()\SLAdr = *itr\index[a+4]
stinfo()\NumElements = *itr\index[a+5]
Debug "Map: offset =" + stinfo()\Offset + " typesize =" + stinfo()\TypeSize + " type =" + GetTypeName(stinfo()\StuctType) + " structure adr =" + stinfo()\SLAdr + " mapsize =" + stinfo()\NumElements
a+5
If stinfo()\SLAdr <> 0
StructureInfo(stinfo()\SLAdr)
EndIf
Case #ST_MultiArray
AddElement(StInfo())
StInfo()\TypeStr = "Multi Array"
stinfo()\Type = #ST_MultiArray
stinfo()\offset = *itr\index[a+1]
stinfo()\NumDimentions = *itr\index[a+2]
Stinfo()\TypeSize = *itr\index[a+3]
stinfo()\StuctType = *itr\index[a+4]
stinfo()\SLAdr = *itr\index[a+5]
Debug "Multi Array: offset =" + stinfo()\offset + " dimentions = " + stinfo()\NumDimentions + " typesize =" + stinfo()\TypeSize + " Type =" + GetTypeName(stinfo()\StuctType)
a+5
stinfo()\SpanDimentions = 1
For b= 1 To StInfo()\NumDimentions
stinfo()\SpanDimentions * *itr\index[a+b]
dims$ + Str(*itr\index[a+b]) + ","
Next
Debug "dimentions(" + dims$ +")"
a+stinfo()\NumDimentions
If stinfo()\SLAdr <> 0
StructureInfo(stinfo()\SLAdr)
EndIf
Default
If x >= 0
AddElement(StInfo())
StInfo()\TypeStr = "String"
stinfo()\Type = #ST_String
stinfo()\Offset = x
Debug "string: offset =" + x
EndIf
EndSelect
a+1
Until x = #ST_End
ProcedureReturn 1
EndIf
EndProcedure
Structure noObject
a.i
b.i
EndStructure
Structure RecordStructure
ID.l
Name.s
Age.l
List country.s()
Email.s
no.noObject
EndStructure
Structure foo
a.b
w.w
l.s[11]
i.i
s.s
Map mp.l(4096)
List ls.RecordStructure()
Array ar.f(10)
q.q
Array ard.q(12,10,5)
EndStructure
Structure serial
a.i
foo.foo
b.s
EndStructure
Define serial.serial
Define noobject.noobject
Global a.i
GetStructAdr(a,serial)
Debug StructureInfo(a)
Debug "+++++++++++++++++++"
ForEach StInfo()
Debug stInfo()\TypeStr
Debug stInfo()\Offset
Debug stinfo()\TypeSize
Next
Debug "+++++++++++++++++++"
ClearList(StInfo())
GetStructAdr(a,noObject)
Debug StructureInfo(a)
Debug "+++++++++++++++++++"