[bmx] Program settings with reflection by JoshK [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:43

Previous topic - Next topic

BlitzBot

Title : Program settings with reflection
Author : JoshK
Posted : 1+ years ago

Description : This code will handle settings loading and saving automatically, with a nice interface for accessing the values in your program.

You can add fields to the TSettings type, or create an extended type with your fields.

The following types are supported:
float
double
int
string
int array
float array
double array

I didn't bother with string arrays, but it will probably work.

Here is what the saved settings file looks like:
greeting="Hello"
color=255,128,64


Code :
Code (blitzmax) Select
SuperStrict

Import brl.reflection
Import brl.stream

Type TSettings

Field greeting:String="Hello"
Field color:Int[]=[255,128,64]

Method Save:Int(url:Object)
Local typeid:TTypeId
Local f:TField
Local stream:TStream
Local o:Object
Local otypeid:TTypeId
Local etypeid:TTypeId
Local n:Int
Local element:Object
Local value:String

stream=WriteStream(url)
If Not stream Return False

typeid=TTypeId.ForObject(Self)

For f=EachIn typeid.enumfields()

Select f._typeid

Case IntTypeId
stream.WriteLine f.name()+"="+f.GetInt(Self)

Case FloatTypeId,DoubleTypeId
stream.WriteLine f.name()+"="+f.GetFloat(Self)

Case StringTypeId
stream.WriteLine f.name()+"=~q"+f.getstring(Self)+"~q"

Default
If f._typeid.Extendstype(ArrayTypeId)
o=f.Get(Self)
otypeid=TTypeId.ForObject(o)
value=""
For n=0 To otypeid.ArrayLength(o)-1
element=otypeid.GetArrayElement(o,n)
If n>0 value:+","
value:+String(element)
Next
stream.WriteLine f.name()+"="+value
EndIf
EndSelect

Next
stream.close()

Return True
EndMethod

Method Load:Int(url:Object)
Local map:TMap=New TMap
Local p:Int
Local key:String
Local value:String
Local typeid:TTypeId
Local stream:TStream
Local s:String
Local f:TField
Local fieldid:TTypeId
Local o:Object
Local otypeid:TTypeId
Local sarr:String[]
Local n:Int

stream=ReadStream(url)
If Not stream Return False

'Load pairs into map
While Not stream.Eof()
s=stream.ReadLine()
p=s.Find("=")
If p>-1
key=s[..p]
value=s[p+1..]
map.insert key,value
EndIf
Wend
stream.close()

typeid=TTypeId.ForObject(Self)
For f=EachIn typeid.enumfields()
key=f.name()
If map.contains(key)
value=String(map.valueforkey(key))

Select f._typeId

Case StringTypeId
value=value[1..]
value=value[..value.length-1]
f.setstring(Self,value)

Case FloatTypeId
f.setstring(Self,Float(value))

Case DoubleTypeId
f.setstring(Self,Double(value))

Case IntTypeId
f.setstring(Self,Int(value))

Default
If f._typeid.Extendstype(ArrayTypeId)
o=f.Get(Self)
otypeid=TTypeId.ForObject(o)
sarr=value.split(",")
sarr=sarr[..otypeid.ArrayLength(o)]
For n=0 To otypeid.ArrayLength(o)-1
otypeid.SetArrayElement(o,n,sarr[n])
Next
EndIf

EndSelect
EndIf
Next

Return True
EndMethod

EndType

Local settings:TSettings=New TSettings
settings.Save("settings.cfg")
settings.color=[0,0,0]
settings.Load("settings.cfg")
Print settings.greeting
Print settings.color[0]+", "+settings.color[1]+", "+settings.color[2]
End


Comments :


JoshK(Posted 1+ years ago)

 And this version will handle string arrays with quotes:
SuperStrict

Import brl.reflection
Import brl.stream

Type TSettings

Method Save:Int(url:Object)
Local typeid:TTypeId
Local f:TField
Local stream:TStream
Local o:Object
Local otypeid:TTypeId
Local etypeid:TTypeId
Local n:Int
Local element:Object
Local value:String

stream=WriteStream(url)
If Not stream Return False

typeid=TTypeId.ForObject(Self)

For f=EachIn typeid.enumfields()

Select f._typeid

Case IntTypeId
stream.WriteLine f.name()+"="+f.GetInt(Self)

Case FloatTypeId,DoubleTypeId
stream.WriteLine f.name()+"="+f.GetFloat(Self)

Case StringTypeId
stream.WriteLine f.name()+"=~q"+f.getstring(Self)+"~q"

Default
If f._typeid.Extendstype(ArrayTypeId)
o=f.Get(Self)
otypeid=TTypeId.ForObject(o)
value=""
For n=0 To otypeid.ArrayLength(o)-1
element=otypeid.GetArrayElement(o,n)
etypeid=otypeid.ElementType()
If n>0 value:+","
Select etypeid
Case StringTypeId
value:+"~q"+String(element)+"~q"
Default
value:+String(element)
EndSelect
Next
stream.WriteLine f.name()+"="+value
EndIf
EndSelect

Next
stream.close()

Return True
EndMethod

Method Load:Int(url:Object)
Local map:TMap=New TMap
Local p:Int
Local key:String
Local value:String
Local typeid:TTypeId
Local stream:TStream
Local s:String
Local f:TField
Local fieldid:TTypeId
Local o:Object
Local otypeid:TTypeId
Local etypeid:TTypeId
Local sarr:String[]
Local n:Int

stream=ReadStream(url)
If Not stream Return False

'Load pairs into map
While Not stream.Eof()
s=stream.ReadLine()
p=s.Find("=")
If p>-1
key=s[..p]
value=s[p+1..]
map.insert key,value
EndIf
Wend
stream.close()

typeid=TTypeId.ForObject(Self)
For f=EachIn typeid.enumfields()
key=f.name()
If map.contains(key)
value=String(map.valueforkey(key))

Select f._typeId

Case StringTypeId
value=value[1..]
value=value[..value.length-1]
f.setstring(Self,value)

Case FloatTypeId
f.setstring(Self,Float(value))

Case DoubleTypeId
f.setstring(Self,Double(value))

Case IntTypeId
f.setstring(Self,Int(value))

Default
If f._typeid.Extendstype(ArrayTypeId)
o=f.Get(Self)
otypeid=TTypeId.ForObject(o)
sarr=value.split(",")
sarr=sarr[..otypeid.ArrayLength(o)]
etypeid=otypeid.ElementType()
For n=0 To otypeid.ArrayLength(o)-1
If etypeid=StringTypeId
sarr[n]=sarr[n][1..]
sarr[n]=sarr[n][..sarr[n].length-1]
EndIf
otypeid.SetArrayElement(o,n,sarr[n])
Next
EndIf

EndSelect
EndIf
Next

Return True
EndMethod

EndType



JoshK(Posted 1+ years ago)

 This version has a Copy() method that will work on extended types, without adding a new method:SuperStrict

Import brl.reflection
Import brl.stream

Type TSettings

Method Save:Int(url:Object)
Local typeid:TTypeId
Local f:TField
Local stream:TStream
Local o:Object
Local otypeid:TTypeId
Local etypeid:TTypeId
Local n:Int
Local element:Object
Local value:String

stream=WriteStream(url)
If Not stream Return False

typeid=TTypeId.ForObject(Self)

For f=EachIn typeid.enumfields()

Select f._typeid

Case IntTypeId
stream.WriteLine f.name()+"="+f.GetInt(Self)

Case FloatTypeId,DoubleTypeId
stream.WriteLine f.name()+"="+f.GetFloat(Self)

Case StringTypeId
stream.WriteLine f.name()+"=~q"+f.getstring(Self)+"~q"

Default
If f._typeid.Extendstype(ArrayTypeId)
o=f.Get(Self)
otypeid=TTypeId.ForObject(o)
value=""
For n=0 To otypeid.ArrayLength(o)-1
element=otypeid.GetArrayElement(o,n)
etypeid=otypeid.ElementType()
If n>0 value:+","
Select etypeid
Case StringTypeId
value:+"~q"+String(element)+"~q"
Default
value:+String(element)
EndSelect
Next
stream.WriteLine f.name()+"="+value
EndIf
EndSelect

Next
stream.close()

Return True
EndMethod

Method Copy:TSettings()
Local settings:TSettings
Local bank:TBank=CreateBank()
Local stream:TStream=CreateBankStream(bank)
Local typeid:TTypeId=TTypeId.ForObject(Self)

Save(stream)
stream=CreateBankStream(bank)

settings=TSettings(typeid.NewObject())
settings.Load(stream)

Return settings
EndMethod

Method Load:Int(url:Object)
Local map:TMap=New TMap
Local p:Int
Local key:String
Local value:String
Local typeid:TTypeId
Local stream:TStream
Local s:String
Local f:TField
Local fieldid:TTypeId
Local o:Object
Local otypeid:TTypeId
Local etypeid:TTypeId
Local sarr:String[]
Local n:Int

stream=ReadStream(url)
If Not stream Return False

'Load pairs into map
While Not stream.Eof()
s=stream.ReadLine()
p=s.Find("=")
If p>-1
key=s[..p]
value=s[p+1..]
map.insert key,value
EndIf
Wend
stream.close()

typeid=TTypeId.ForObject(Self)
For f=EachIn typeid.enumfields()
key=f.name()
If map.contains(key)
value=String(map.valueforkey(key))

Select f._typeId

Case StringTypeId
value=value[1..]
value=value[..value.length-1]
f.setstring(Self,value)

Case FloatTypeId
f.setstring(Self,Float(value))

Case DoubleTypeId
f.setstring(Self,Double(value))

Case IntTypeId
f.setstring(Self,Int(value))

Default
If f._typeid.Extendstype(ArrayTypeId)
o=f.Get(Self)
otypeid=TTypeId.ForObject(o)
sarr=value.split(",")
sarr=sarr[..otypeid.ArrayLength(o)]
etypeid=otypeid.ElementType()
For n=0 To otypeid.ArrayLength(o)-1
If etypeid=StringTypeId
sarr[n]=sarr[n][1..]
sarr[n]=sarr[n][..sarr[n].length-1]
EndIf
otypeid.SetArrayElement(o,n,sarr[n])
Next
EndIf

EndSelect
EndIf
Next

Return True
EndMethod

EndType