Archives for posts with tag: lists

While working on a package manager for CMake I came across the problem of finding a suitable format for my package descriptor files. First I thought about and tried using plain old CMake file that simply sets variables and can be included to access its contents.  It was very quick and easy to implement. Hierarchical data structures however where hard to implement and a none standard format makes it harder to exchange data with a webservice/other programs. So I opted for using JSON as my import/export format.  JSON is alot easier to parse than XML and is still ubiquitous in software developement so I cast aside XML (for now).

You can grab my implementation for reading and writing JSON with CMake  at  https://github.com/toeb/oo-cmake.git.  Its part of my object oriented CMake library and uses my implementation for CMake maps and references.

Note: Because CMake only understands strings the deserializer only accepts string , array or object values.  Also all keys and values have to be double quoted.

As always: feedback is most welcome if you feel like it you can tell me if you find it usefull, have ideas, or think that I have reinvented the wheel.

Here are some examples for serialization and deserialization:

Code Snippet
  1. # serialize empty value
  2. json_serialize(res “”)
  3. assert(NOT res)
  4. # serialze simple value
  5. json_serialize(res “hello!”)
  6. assert(res)
  7. assert(“\”hello!\”” STREQUAL ${res})
  8. #empty object
  9. element(uut MAP)
  10. element(END)
  11. json_serialize(res ${uut})
  12. assert(“{}” STREQUAL ${res})
  13. # empty list
  14. element(uut LIST)
  15. element(END)
  16. json_serialize(res ${uut})
  17. assert(“[]” STREQUAL ${res})
  18. # ref
  19. ref_new(uut)
  20. ref_set(${uut} “a b c”)
  21. json_serialize(res ${uut})
  22. assert(“\”a b c\”” STREQUAL ${res})
  23. # list with one element
  24. element(uut LIST)
  25. value(1)
  26. element(END)
  27. json_serialize(res ${uut})
  28. assert(“[\”1\”]” STREQUAL ${res})
  29. # list with multiple elements element
  30. element(uut LIST)
  31. value(1)
  32. value(2)
  33. element(END)
  34. json_serialize(res ${uut})
  35. assert(“[\”1\”,\”2\”]” STREQUAL ${res})
  36. # object with single value
  37. element(uut MAP)
  38. value(KEY k1 val1)
  39. element(END)
  40. json_serialize(res ${uut})
  41. assert(“{\”k1\”:\”val1\”}” STREQUAL ${res})
  42. # object with multiple value
  43. element(uut MAP)
  44. value(KEY k1 val1)
  45. value(KEY k2 val2)
  46. element(END)
  47. json_serialize(res ${uut})
  48. assert(“{\”k1\”:\”val1\”,\”k2\”:\”val2\”}” STREQUAL ${res})
  49. # list with single map
  50. element(uut LIST)
  51. element()
  52. value(KEY k1 1)
  53. element(END)
  54. element(END)
  55. json_serialize(res ${uut})
  56. assert(“[{\”k1\”:\”1\”}]” STREQUAL ${res})
  57. # list with differnt elements map
  58. element(uut LIST)
  59.     element(MAP)
  60.         value(KEY k1 1)
  61.         value(KEY k2 2)
  62.         value(KEY k3 3)
  63.     element(END)
  64.     element(LIST)
  65.         value(1)
  66.         value(2)
  67.     element(END)
  68.     value(a)
  69.     value(b)
  70. element(END)
  71. json_serialize(res ${uut})
  72. assert(“[{\”k1\”:\”1\”,\”k2\”:\”2\”,\”k3\”:\”3\”},[\”1\”,\”2\”],\”a\”,\”b\”]” STREQUAL ${res})
  73. # deserialize a empty value
  74. json_deserialize(res “”)
  75. assert(NOT res)
  76. # deserialize a empty object
  77. json_deserialize(res “{}”)
  78. assert(res)
  79. ref_isvalid(is_ref ${res} )
  80. assert(is_ref MESSAGE “expected res to be a ref”)
  81. # desirialize a empty array
  82. json_deserialize(res “[]”)
  83. assert(res)
  84. ref_isvalid(is_ref ${res})
  85. assert(is_ref MESSAGE “expected res to be a ref”)
  86. # deserialize a simple value
  87. json_deserialize(res “\”teststring\””)
  88. assert(${res} STREQUAL “teststring”)
  89. # deserialize a array with one value
  90. json_deserialize(res “[\”1\”]”)
  91. map_navigate(${res} val “[0]”)
  92. assert(${val} STREQUAL “1”)
  93. #deserialize a array with multiple values
  94. json_deserialize(res “[\”1\”, \”2\”]”)
  95. map_navigate(${res} val “[0]”)
  96. assert(${val} STREQUAL “1”)
  97. map_navigate(${res} val “[1]”)
  98. assert(${val} STREQUAL “2”)
  99. # deserialize a simple object with one value
  100. json_deserialize(res “{ \”key\” : \”value\”}”)
  101. map_navigate(${res} val “key”)
  102. assert(${val} STREQUAL “value”)
  103. # deserialize a simple object with multiple values
  104. json_deserialize(res “{ \”key\” : \”value\”, \”key2\” : \”val2\”}”)
  105. map_navigate(${res} val “key”)
  106. assert(${val} STREQUAL “value”)
  107. map_navigate(${res} val “key2”)
  108. assert(${val} STREQUAL “val2”)
  109. # deserialize a simple nested structure
  110. json_deserialize(res “{ \”key\” : {\”key3\”:\”myvalue\” }, \”key2\” : \”val2\”}”)
  111. map_navigate(${res} val “key2”)
  112. assert(${val} STREQUAL “val2”)
  113. map_navigate(${res} val “key.key3”)
  114. assert(${val} STREQUAL “myvalue”)
  115. # deserialize a nested structure containing both arrays and objects
  116. json_deserialize(res “{ \”key\” : [\”1\”, \”2\”], \”key2\” : \”val2\”}”)
  117. map_navigate(${res} val “key2”)
  118. assert(${val} STREQUAL “val2”)
  119. map_navigate(${res} val “key[0]”)
  120. assert(${val} STREQUAL “1”)
  121. map_navigate(${res} val “key[1]”)
  122. assert(${val} STREQUAL “2”)
  123. # deserialize a ‘deeply’ nested structure and get a value
  124. json_deserialize(res “{ \”key\” : [{\”k1\”:\”v1\”}, \”2\”], \”key2\” : \”val2\”}”)
  125. map_navigate(${res} val “key[0].k1”)
  126. assert(${val} STREQUAL “v1”)

Get it at https://github.com/toeb/oo-cmake and tell me if you like it

For more complex build system features oo programming would be a major boon. So I took it upon myself to create a usable and tested oo-extension for cmake (in pure CMake) so I could continue developing and extending my plattform independent tooling support (cutil) .

It’s too bad that Kitware decided to use their own language (with very little high level language features) for their build system product because CMakes project generation capabilties are unparalleled .  I can understand that it seemed like a good idea at first ( the CMake scripting Language is platform independent and easier to use than make or bash or cmd also it was not intended to do complicated things). I however strongly believe that building a programm should be as easy as possible and therefore a high level language should have been used. CMake’s creators Bill Hoffman and Kenneth Martin have said that they would have done this differently if they had to do it again (http://www.aosabook.org/en/cmake.html)

Of course CMake does not offer language features for a very sleak usage but the with these functions you can use prototypical inheritance, maps, methods, objects, lists, properties, references, etc. which are at the basis of every oo language.

Even if you do not want to do inheritance in CMake you can use these functions for Maps (Dictionaries)

People familiar with JavaScript will be familiar with this approach to object orientation.

Here is a simple example

cmake_minimum_required(VERSION 2.8)
# include standalone version of oo-cmake
# when not using cutil this  includes the function files as well as
# the dependent functions
include("../oo-cmake.cmake")

message("creating a simple inheritance example")

#create animal object
obj_create(animal)

# set object method eat
# this method prints out which food the animal is eating
# existing functions can also be appliead via obj_bindcall(${ref} func arg1 arg2 arg3)
obj_set(
    ${animal}   #reference to animal object
    "eat"       #name of property
    RAW         # RAW indictates that the data is to be treated as a raw string not a list (hinders evaluation)
    "function(eat this)
      obj_get(\${this} food food) 
      message(\"I am eating \${food}\") 
     endfunction()"
)

# create mamal object
obj_create(mamal)
obj_setprototype(${mamal} ${animal})

#create bird object
obj_create(bird)                    #create instance
obj_setprototype(${bird} ${animal}) #set prototype animal
obj_set(${bird} food Birdfood)      #set bird's food property to "Birdfood"

#create dog object
obj_create(dog)                     #create instance
obj_setprototype(${dog} ${mamal})   #set prototype mamal
obj_set(${dog} food Dogfood)        #set dogs food property to "Dogfood"

#create cat object
obj_create(cat)                     #create instance
obj_setprototype(${cat} ${mamal})   #set prototype mamal
obj_set(${cat} food Catfood)        #set cat's food property to "Catfood"

# call eat function for different objects
obj_callmember(${bird} eat) 
obj_callmember(${dog} eat)
obj_callmember(${cat} eat)

#output should be
#I am eating Birdfood
#I am eating Dogfood
#I am eating Catfood

You can use the following commands

 
obj_create(out_ref [objectpath]) #returns a ref to a new object. this object is persistent and will exist until obj_delete is called, internally the object is represented by a folder
obj_delete(in_ref) # deletes a object (deletes the folder internally)
obj_find(refOrId) # searches for a named object or id
obj_get(ref value key) # gets a property ${value} = ref[key] the prototype chain is considered
obj_set(ref key value) # sets a property ref[key] = value
obj_getref(ref prop_ref key) # returns the reference to a property (a file)
obj_getownproperty(ref value key) # returns the value for property if the property belongs to ref 
obj_setownproperty(ref key value) # sets the own property ref[key] =value
obj_has(ref result key) # sets result to true if ref[key] exists
obj_hasownproperty(ref result key) # sets result to true if ref[key] exists and is owned by ref
obj_callmember(ref methodname args...) # calls a stored memberfunction (first argument passed is ref)
obj_bindcall(ref methodname args...) # calls a defined function setting first argument to ref
obj_setprototype(ref proto_ref) # sets the prototype for ref
obj_getprototype(ref proto_ref) # returns the prototyp for ref
obj_settype(ref type) # sets the type for ref
obj_gettype(ref type) # gets the type for ref
obj_getkeys(ref keys) # returns all defined properties for ref
obj_getownkeys(ref keys) # returns all defined properties that ref owns