Code archives/Miscellaneous/keefpersistence

This code has been declared by its author to be Public Domain code.

Download source code

keefpersistence by slenkar2010
This is the same as bruceys persistence module except:
this persistence library simply doesnt store zeroes or nulls for a much smaller file size and faster loading time.
Strict
Module keef.keefpersistence
Import bah.libxml
Import brl.map
Import brl.reflection




Global object_Map:TMap







	
Function save_obj(i:Object, filename$)
object_map=New Tmap
Global doc:TxmlDoc = TxmlDoc.newdoc("1.0")

Local root:TxmlNode = TxmlNode.newnode("root")
doc.setrootelement(root)
Local thisnode:TxmlNode=root.addchild("object")
serialize_obj(thisnode,i )
doc.saveFile(filename)
EndFunction
	  
Function serialize_obj(node:TxmlNode, i:Object)

Local tid:TTypeId = TTypeId.ForObject(i)
'Print "saving " + tid.Name()
Local thename:String=tid.name()
node.setattribute("type",thename)
Local objRef:String = GetObjRef(i)
			node.setAttribute("ref", objRef)
			object_Map.Insert(objRef, objRef)

If thename="TList"
node.setAttribute("type", theName)
Local listy:TList=TList(i)
For Local ob:Object=EachIn listy
Local tid2:TTypeId = TTypeId.ForObject(ob)
Local thisnode:TxmlNode = node.addchild("listelement")
thisnode.setattribute("type",tid2.name())
serialize_obj(thisnode,ob)
Next
Return
EndIf

If theName.endswith("[]")
				'Local thisnode:TxmlNode = node.addchild("array")
				Local size:Int
				
				size = tid.ArrayLength(i)
				
				node.setAttribute("type", theName)
				node.setAttribute("size", size)

				If size > 0 Then
				saveArray(i, size, node, tid)
				Else
				node.setattribute("value","null")
				End If
EndIf

If thename = "TMap"
					' special case for TMaps
				' They have a Global "nil" object which needs to be referenced properly.
				' We add a specific reference to nil, which we'll use to re-reference when we de-serialize.

				Local ref:String = GetObjRef(New TMap._root)
				If Not object_Map.ValueForKey(ref) Then
					'Local node:TxmlNode = parent.addChild("TMap_nil")
					node.setAttribute("nil", ref)
					object_Map.Insert(ref, ref)
				End If
			
EndIf

For Local f:TField = EachIn tid.EnumFields()
										 ' Print "field name: " + f.Name()
										  
					If f.MetaData("nopersist") Then
						Continue
					End If
				
					Local fieldType:TTypeId = f.TypeId()
					
					Local fieldNode:TxmlNode 
						
					Select fieldType
						Case ByteTypeId
						If f.getint(i)=Null Or f.getint(i)=0
						Continue
						EndIf
						
							fieldnode= node.addChild("field")
							fieldNode.setattribute("value", f.GetInt(i))
						Case ShortTypeId
						If f.getint(i)=Null Or f.getint(i)=0
						Continue
						EndIf
						fieldNode.setattribute("value", f.GetInt(i))
					
						Case IntTypeId
						If f.getint(i)=Null Or f.getint(i)=0
						Continue
						EndIf
						fieldnode= node.addChild("field")
						fieldNode.setattribute("value", f.GetInt(i))
					
						Case LongTypeId
						If f.getlong(i)=Null Or f.getlong(i)=0
						Continue
						EndIf
						fieldnode= node.addChild("field")
						fieldNode.setattribute("value", f.GetLong(i))
						
						Case FloatTypeId
						
						If f.getfloat(i)=Null Or f.getfloat(i)=0
						Continue
						EndIf
						fieldnode= node.addChild("field")
						fieldNode.setattribute("value", f.GetFloat(i))
					
						Case DoubleTypeId
						If f.getdouble(i)=Null Or f.getdouble(i)=0
						Continue
						EndIf
						fieldnode= node.addChild("field")
						fieldNode.setattribute("value", f.GetDouble(i))
					
						Case StringTypeId
						If f.getstring(i)=Null Or f.getstring(i)="0" Or f.getstring(i)=""
						Continue
						EndIf
						fieldnode= node.addChild("field")
							Local s:String = f.GetString(i)
							If s Then
								fieldNode.setattribute("value", s)
							End If
						Default
							If fieldtype.name().EndsWith("[]")
					
			'	Local thisnode:TxmlNode = node.addchild("array")
				Local size:Int
				
				size=fieldType.ArrayLength(f.Get(i))

				If size > 0
				fieldnode= node.addChild("field")
				Fieldnode.setAttribute("size", size)
				fieldnode.setattribute("type",fieldtype.name())
				'saveArray(f, size, fieldnode, fieldType)
				saveArray(f.get(i), size, fieldnode, fieldType)
				End If
							Else
							'Print ("get object from field")
								Local fieldObject:Object = f.Get(i)
							Local fieldRef:String = GetObjRef(fieldObject)
							
								If fieldObject <> Null
								fieldNode = node.addChild("field")
								fieldnode.setattribute("type",fieldtype.name())
								If Not object_Map.Contains(fieldref) Then
									serialize_obj(fieldNode, fieldObject)
									Else
									fieldNode.setAttribute("ref", fieldref)
									End If
								Else
								Continue
								End If
							End If
					End Select
						fieldNode.setAttribute("name", f.Name())
						fieldnode.setAttribute("type",fieldtype.name())
						
					
				Next

EndFunction



	  
Function saveArray(arrayObject:Object, size:Int, node:TxmlNode, typeId:TTypeId)
									   
		Local elementType:TTypeId = typeId.ElementType()
		
		Select elementType
			Case ByteTypeId, ShortTypeId, IntTypeId, LongTypeId, FloatTypeId, DoubleTypeId

				Local content:String = ""
				
				For Local i:Int = 0 Until size
				
				Local aObj:Object = typeId.GetArrayElement(arrayObject, i)
				'Print String(aobj)
				content=String(aobj)
				Local content2:Int=content.toint()
				If Not content2=0
				Local thisnode:TxmlNode=node.addchild("arrayelement")
				thisnode.addattribute("pos",String(i))
				thisnode.addattribute("value",String(aobj))
				EndIf
				Next
		
			Default

				Local content:String = ""
				
			
				
			
				
					Select elementType
						Case StringTypeId
						For Local i:Int = 0 Until size
							Local aObj:Object = typeId.GetArrayElement(arrayObject, i)
					
						content = String(aobj)
						If Not content = "0"
						Local thisnode:TxmlNode = node.addchild("arrayelement")
						thisnode.addattribute("pos", String(i))
						thisnode.addattribute("value", content)
						EndIf
						Next
						
						Default
							For Local i:Int = 0 Until size
							Local aObj:Object = typeId.GetArrayElement(arrayObject, i)
							If aobj<>Null
							Local thisnode:TxmlNode = node.addchild("arrayelement")
							thisnode.addattribute("pos", String(i))
							thisnode.addattribute("type", typeId.elementType().Name())
							'If  typeId.elementType().Name().endswith("[]")
							'Local thisnode2:TxmlNode=TxmlNode(thisnode.getfirstchild())
							'serialize_obj(thisNode2, aObj)
							
							'Else
							serialize_obj(thisNode, aObj)
							'EndIf
							
							EndIf
							Next
					End Select
			
		End Select
		
	

EndFunction






Function load_object:Object(filename$)
object_map=New tmap
				' Print "loading object " + filename
	Local doc:TxmlDoc = TxmlDoc.parseFile(filename)
Local obby:Object

		If doc
		'Print "doc is not null"
			Local root:TxmlNode = doc.GetRootElement()
			For Local thisnode:TxmlNode=EachIn root.getchildren()
			obby:Object = DeSerializeObject("", thisnode,doc)
			doc.Free()
			doc = Null
			Next
		Else
		'Print "doc is null"
		End If
		Local arr:Int[] = Int[] obby
		For Local x:Int = 0 To arr.length - 1
		'Print arr[x]
		Next
Return obby
EndFunction

		
Function DeSerializeObject:Object(text:String, node:TxmlNode = Null,doc:TxmlDoc)
'If node.getattribute("type")="map_square"
'DebugLog "deserializing map square"
'EndIf
'DebugLog "argh fuck "+node.getname()
Local obj:Object 
'Local nodelist:TList = node.getchildren()
	Local ref:String = Node.getAttribute("ref")
										If ref 
										Local objRef:Object = object_Map.ValueForKey(ref)
											If objRef
											
												Return objref
											EndIf
											EndIf

Local objType:TTypeId = TTypeId.ForName(node.getattribute("type"))

If node.getattribute("type").endswith("[]")
'If node.getattribute("type")="map_square[]"
'DebugLog "creating array in deserialize object "+node.getattribute("type")
'EndIf
obj = Create_array(node, doc)
'If node.getattribute("type")="map_square[]"
'If obj=Null
'DebugLog "returning null array"
'Else
'DebugLog "returning full array"
'EndIf
'EndIf

Else

If node.getattribute("type")="TList"
'Print "deserializing list:"
Local listy:TList= New TList
obj=Object(listy)
object_Map.Insert(node.getAttribute("ref"), obj)

Local listy2:TList=node.getchildren()

If listy2<>Null
For Local c:TxmlNode=EachIn listy2

If c.getattribute("type")="String"
listy.addlast(c.getattribute("value"))
Else
listy.addlast(deSerializeObject("", c,doc))
EndIf

Next
EndIf
Return obj

EndIf 
				
	If node.getattribute("type") = "TMap" 

					' special case for TMaps
					' They have a Global "nil" object which needs to be referenced properly.
			
					Local attr:String = node.getAttribute("nil")
					If attr Then
						object_Map.Insert(attr, New TMap._root)
					End If
				End If

obj=objType.NewObject()
object_Map.Insert(node.getAttribute("ref"), obj)

Local listy:TList=node.getchildren()

	If listy <> Null Then
					For Local fieldNode:TxmlNode = EachIn listy
		If fieldNode.GetName() = "field"	
	Local fieldObj:TField = objType.FindField(fieldnode.getAttribute("name"))
							If fieldobj<>Null
							Local fieldType:String = fieldNode.getAttribute("type")
							Select fieldType
								Case "Byte", "Short", "Int"
									fieldObj.SetInt(obj, fieldNode.getattribute("value").toInt())
								'If node.getattribute("type")="map_square"
								'DebugLog fieldNode.getattribute("value")+" "+ fieldNode.getattribute("name")
								
								 
								'EndIf
								Case "Long"
									fieldObj.SetLong(obj, fieldNode.getattribute("value").toLong())
								Case "Float"
									fieldObj.SetFloat(obj, fieldNode.getattribute("value").toFloat())
								Case "Double"
									fieldObj.SetDouble(obj, fieldNode.getattribute("value").toDouble())
								Case "String"
									fieldObj.SetString(obj, fieldnode.getattribute("value"))
								Default
								
										Local ref:String = fieldNode.getAttribute("ref")
										If ref Then
											Local objRef:Object = object_Map.ValueForKey(ref)
											If objRef Then
											
												fieldObj.Set(obj, objRef)
											Else
											fieldObj.Set(obj, DeSerializeObject("", fieldNode,doc))
											End If
										Else
											fieldObj.Set(obj, DeSerializeObject("", fieldNode,doc))
										End If
										
								EndSelect
								EndIf
			EndIf
			Next
			EndIf					
	EndIf							
'If node.getattribute("type")="map_square"
'DebugLog "returning obj"
'EndIf
Return obj
	End Function

Function Create_array:Object(node:TxmlNode, doc:TxmlDoc)

'If node.getattribute("type")="map_square[]"
'DebugLog "Create array function"
'EndIf		 

Local objType:TTypeId = TTypeId.ForName(node.getAttribute("type"))
		
				Local size:Int = node.getAttribute("size").toInt()
				Local obj:Object = objType.NewArray(size)
				If node.getattribute("type")="map_square[]"
				If obj=Null
				DebugLog "array object is null"
				EndIf
				EndIf
				
				If obj<>Null
				
				'If node.getattribute("type")="map_square[]"
				'DebugLog "array object is not null:"
				'EndIf
				
				If size > 0 
				
				If node.getattribute("type")="map_square[]"
				DebugLog "array size is bigger than zero:"+size
				EndIf
				
					Local arrayElementType:TTypeId = objType.ElementType()
					'Print "array is: "+arrayelementtype.name()
					Select arrayElementType
						Case ByteTypeId, ShortTypeId, IntTypeId, LongTypeId, FloatTypeId, DoubleTypeId
						'Print"array element is int"
							Local arraylist:TList = node.getChildren()
							Local arraynode:TxmlNode
							If arraylist<>Null
							For arraynode = EachIn arraylist
							'Print arraynode.getAttribute("value")
							'Print arraynode.getAttribute("pos")
							
							If Int arraynode.getAttribute("value") <> 0
							objType.SetArrayElement(obj, Int arraynode.getAttribute("pos") , Object arraynode.getAttribute("value"))
								
							EndIf
							Next
							EndIf
						Default
							Local arrayList:TList = node.getChildren()
							
							If arrayList
								
								Local i:Int
								For Local arrayNode:TxmlNode = EachIn arrayList
		
									Select arrayElementType
										Case StringTypeId
										If arrayNode.Getattribute("value")<>""
											objType.SetArrayElement(obj, Int arraynode.getAttribute("pos"), arrayNode.Getattribute("value"))
										EndIf
										Default
										
									
											objType.SetArrayElement(obj, Int arraynode.getAttribute("pos"), DeSerializeObject("", arrayNode, doc))
									End Select
		
									i:+ 1
								Next
							EndIf
					End Select
				EndIf
				End If
						  Return obj
EndFunction

	Function GetObjRef:String(obj:Object)
		Return Base36(Int(Byte Ptr(obj)))
	End Function

	Function Base36:String( val:Int )
		Local buf:Short[6]
		For Local k:Int=5 To 0 Step -1
			Local n:Int=(val Mod 36) + 48
			If n > 57 n:+ 7
			buf[k]=n
			val = val / 36
		Next
		Return String.FromShorts( buf,6 )
	End Function

Comments

puki2010
Deleted.


puki2010
I love arrays.

EDIT:
Wait a minute, this is BlitzMax - my bad.

EDIT:
I edited my post and it created a new one - just in case anyone thinks I was spamming.

EDIT:
It must have been one of those double posts and when I edited it, it edited the second post.

Still, ignore me - pretend I am not here.


ShadowTurtle2010
you edited the second post...


Code Archives Forum