Merge: contrib/header_static: a cog in the toolchains to generate Objcwrapper
authorJean Privat <jean@pryen.org>
Thu, 28 May 2015 00:18:39 +0000 (20:18 -0400)
committerJean Privat <jean@pryen.org>
Thu, 28 May 2015 00:18:39 +0000 (20:18 -0400)
### Filters preprocessed C-like header files to remove static code and keep their signatures.

This tool is used in the process of parsing header files to extract
information on the declared services (the functions and structures).
This information is then used to generate bindings for Nit code
to access these services.

The C header sometimes contains static code. It deletes static code of
headers, but keep their signatures. This tool is an extension of
header_keeper. It searches the keyword static to identify
the static code, and ignore the code into their brackets. The result is
printed to sdtout.

~~~sh
cat Pre-Processed/CGGeometry.h | header_static Pre-Processed/CGGeometry.h > Pre-Processed/static_header.h
~~~

This module can also be used as a library.
The main service is the method `header_static`

Pull-Request: #1396
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>

lib/json/serialization.nit
lib/serialization/caching.nit [new file with mode: 0644]
lib/serialization/engine_tools.nit
lib/serialization/serialization.nit
tests/sav/nitserial_args1.res

index 61c6f61..4b7cb15 100644 (file)
 # ~~~
 module serialization
 
-import ::serialization
+import ::serialization::caching
 private import ::serialization::engine_tools
 private import static
 
 # Serializer of Nit objects to Json string.
 class JsonSerializer
-       super Serializer
+       super CachingSerializer
 
        # Target writing stream
        var stream: Writer
@@ -143,9 +143,9 @@ class JsonSerializer
 
        redef fun serialize_reference(object)
        do
-               if not plain_json and refs_map.has_key(object) then
+               if not plain_json and cache.has_object(object) then
                        # if already serialized, add local reference
-                       var id = ref_id_for(object)
+                       var id = cache.id_for(object)
                        stream.write "\{\"__kind\": \"ref\", \"__id\": "
                        stream.write id.to_s
                        stream.write "\}"
@@ -154,26 +154,11 @@ class JsonSerializer
                        serialize object
                end
        end
-
-       # Map of references to already serialized objects.
-       private var refs_map = new StrictHashMap[Serializable,Int]
-
-       # Get the internal serialized reference for this `object`.
-       private fun ref_id_for(object: Serializable): Int
-       do
-               if refs_map.has_key(object) then
-                       return refs_map[object]
-               else
-                       var id = refs_map.length
-                       refs_map[object] = id
-                       return id
-               end
-       end
 end
 
 # Deserializer from a Json string.
 class JsonDeserializer
-       super Deserializer
+       super CachingDeserializer
 
        # Json text to deserialize from.
        private var text: Text
@@ -184,9 +169,6 @@ class JsonDeserializer
        # Depth-first path in the serialized object tree.
        private var path = new Array[JsonObject]
 
-       # Map of references to already deserialized objects.
-       private var id_to_object = new StrictHashMap[Int, Object]
-
        # Last encountered object reference id.
        #
        # See `id_to_object`.
@@ -215,7 +197,7 @@ class JsonDeserializer
        do
                var id = just_opened_id
                if id == null then return # Register `new_object` only once
-               id_to_object[id] = new_object
+               cache[id] = new_object
        end
 
        # Convert from simple Json object to Nit object
@@ -231,8 +213,8 @@ class JsonDeserializer
                                var id = object["__id"]
                                assert id isa Int
 
-                               assert id_to_object.has_key(id)
-                               return id_to_object[id]
+                               assert cache.has_id(id)
+                               return cache.object_for(id)
                        end
 
                        # obj?
@@ -245,7 +227,7 @@ class JsonDeserializer
                                var class_name = object["__class"]
                                assert class_name isa String
 
-                               assert not id_to_object.has_key(id) else print "Error: Object with id '{id}' of {class_name} is deserialized twice."
+                               assert not cache.has_id(id) else print "Error: Object with id '{id}' of {class_name} is deserialized twice."
 
                                # advance on path
                                path.push object
@@ -291,7 +273,7 @@ end
 redef class Serializable
        private fun serialize_to_json(v: JsonSerializer)
        do
-               var id = v.ref_id_for(self)
+               var id = v.cache.new_id_for(self)
                v.stream.write "\{"
                if not v.plain_json then
                        v.stream.write "\"__kind\": \"obj\", \"__id\": "
@@ -376,7 +358,7 @@ redef class SimpleCollection[E]
        do
                # Register as pseudo object
                if not v.plain_json then
-                       var id = v.ref_id_for(self)
+                       var id = v.cache.new_id_for(self)
                        v.stream.write """{"__kind": "obj", "__id": """
                        v.stream.write id.to_s
                        v.stream.write """, "__class": """"
@@ -395,6 +377,7 @@ redef class SimpleCollection[E]
 
        redef init from_deserializer(v: Deserializer)
        do
+               super
                if v isa JsonDeserializer then
                        v.notify_of_creation self
                        init
@@ -425,7 +408,7 @@ redef class Map[K, V]
        redef fun serialize_to_json(v)
        do
                # Register as pseudo object
-               var id = v.ref_id_for(self)
+               var id = v.cache.new_id_for(self)
 
                if v.plain_json then
                        v.stream.write "\{"
@@ -466,10 +449,11 @@ redef class Map[K, V]
        # Instantiate a new `Array` from its serialized representation.
        redef init from_deserializer(v: Deserializer)
        do
-               init
+               super
 
                if v isa JsonDeserializer then
                        v.notify_of_creation self
+                       init
 
                        var length = v.deserialize_attribute("__length").as(Int)
                        var keys = v.path.last["__keys"].as(SequenceRead[nullable Object])
diff --git a/lib/serialization/caching.nit b/lib/serialization/caching.nit
new file mode 100644 (file)
index 0000000..186c96c
--- /dev/null
@@ -0,0 +1,118 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services for caching serialization engines
+module caching
+
+import serialization
+private import engine_tools
+
+# A `Serializer` with a `cache`
+abstract class CachingSerializer
+       super Serializer
+
+       # Cache of known objects
+       var cache = new SerializerCache is lazy, writable
+
+       # Link the cache of `self` with `deserializer`
+       #
+       # This allows reference objects by id when they are known by the other side
+       # of the stream.
+       #
+       # Use `cache` if it is a `DuplexCache`, otherwise create a new one.
+       fun link(deserializer: CachingDeserializer)
+       do
+               var mem = self.cache
+               if not mem isa DuplexCache then mem = new DuplexCache
+
+               self.cache = mem
+               deserializer.cache = mem
+       end
+end
+
+# A `Deserializer` with a `cache`
+abstract class CachingDeserializer
+       super Deserializer
+
+       # Cache of known objects
+       var cache = new DeserializerCache is lazy, writable
+end
+
+# Cache of sent objects
+#
+# Used by `Serializer` to avoid duplicating objects, by serializing them once,
+# then using a reference.
+class SerializerCache
+       # Map of already serialized objects to the reference id
+       private var sent: Map[Serializable, Int] = new StrictHashMap[Serializable, Int]
+
+       # Is `object` known?
+       fun has_object(object: Serializable): Bool do return sent.keys.has(object)
+
+       # Get the id for `object`
+       #
+       # Require: `has_object(object)`
+       fun id_for(object: Serializable): Int
+       do
+               assert sent.keys.has(object)
+               return sent[object]
+       end
+
+       # Get a new id for `object` and store it
+       #
+       # Require: `not has_object(object)`
+       fun new_id_for(object: Serializable): Int
+       do
+               var id = sent.length
+               sent[object] = id
+               return id
+       end
+end
+
+# Cache of received objects sorted by there reference id
+#
+# Used by `Deserializer` to find already deserialized objects by their reference.
+class DeserializerCache
+       # Map of references to already deserialized objects.
+       private var received: Map[Int, Object] = new StrictHashMap[Int, Object]
+
+       # Is there an object associated to `id`?
+       fun has_id(id: Int): Bool do return received.keys.has(id)
+
+       # Get the object associated to `id`
+       fun object_for(id: Int): nullable Object do return received[id]
+
+       # Associate `object` to `id`
+       fun []=(id: Int, object: Object) do received[id] = object
+end
+
+# A shared cache for serialization and deserialization
+class DuplexCache
+       super SerializerCache
+       super DeserializerCache
+
+       redef fun new_id_for(object)
+       do
+               var id = super
+               received[id] = object
+               return id
+       end
+
+       redef fun []=(id, object)
+       do
+               super
+               assert object isa Serializable
+               sent[object] = id
+       end
+end
index 1e0ee0b..33d36b4 100644 (file)
 module engine_tools
 
 import serialization
+intrude import standard::collection::hash_collection
 
-# Maps instances to a value, uses `is_same_instance`
-#
-# Warning: This class does not implement all the services from `Map`.
+# Maps instances to a value, uses `is_same_serialized` and `serialization_hash`.
 class StrictHashMap[K, V]
-       super Map[K, V]
-
-       # private
-       var map = new HashMap[K, Array[Couple[K, V]]]
-
-       redef var length = 0
-
-       redef fun is_empty do return length == 0
+       super HashMap[K, V]
 
-       # private
-       fun node_at(key: K): nullable Couple[K, V]
+       redef fun index_at(k)
        do
-               if not map.keys.has(key) then return null
-
-               var arr = map[key]
-               for couple in arr do
-                       if couple.first.is_same_serialized(key) then
-                               return couple
-                       end
-               end
+               if k == null then return 0
 
-               return null
+               var i = k.serialization_hash % _capacity
+               if i < 0 then i = - i
+               return i
        end
 
-       redef fun [](key)
+       redef fun node_at_idx(i, k)
        do
-               var node = node_at(key)
-               assert node != null
-               return node.second
-       end
-
-       redef fun []=(key, value)
-       do
-               var node = node_at(key)
-               if node != null then
-                       node.second = value
-                       return
+               var c = _array[i]
+               while c != null do
+                       var ck = c._key
+                       if ck.is_same_serialized(k) then
+                               break
+                       end
+                       c = c._next_in_bucklet
                end
-
-               var arr
-               if not map.keys.has(key) then
-                       arr = new Array[Couple[K, V]]
-                       map[key] = arr
-               else arr = map[key]
-
-               arr.add new Couple[K, V](key, value)
-               self.length += 1
+               return c
        end
-
-       redef fun has_key(key) do return node_at(key) != null
 end
index 3ba9968..8977baa 100644 (file)
@@ -146,6 +146,12 @@ redef interface Object
        #
        # Used to determine if an object has already been serialized.
        fun is_same_serialized(other: nullable Object): Bool do return is_same_instance(other)
+
+       # Hash value use for serialization
+       #
+       # Used in combination with `is_same_serialized`. If two objects are the same
+       # in a serialization context, they must have the same `serialization_hash`.
+       fun serialization_hash: Int do return object_id
 end
 
 # Instances of this class are not delayed and instead serialized immediately
index 7a38c28..b69dc33 100644 (file)
@@ -13,9 +13,6 @@ redef class Deserializer
                if name == "Array[nullable Object]" then return new Array[nullable Object].from_deserializer(self)
                if name == "Array[Serializable]" then return new Array[Serializable].from_deserializer(self)
                if name == "Array[String]" then return new Array[String].from_deserializer(self)
-               if name == "HashMap[Serializable, Array[Couple[Serializable, Int]]]" then return new HashMap[Serializable, Array[Couple[Serializable, Int]]].from_deserializer(self)
-               if name == "Array[Couple[Serializable, Int]]" then return new Array[Couple[Serializable, Int]].from_deserializer(self)
-               if name == "Couple[Serializable, Int]" then return new Couple[Serializable, Int].from_deserializer(self)
                return super
        end
 end