From: Jean Privat Date: Thu, 28 May 2015 00:18:39 +0000 (-0400) Subject: Merge: contrib/header_static: a cog in the toolchains to generate Objcwrapper X-Git-Tag: v0.7.5~22 X-Git-Url: http://nitlanguage.org?hp=0767ae366c01dd1ac27dbda7776d9c6c44b76a0a Merge: contrib/header_static: a cog in the toolchains to generate Objcwrapper ### 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 Reviewed-by: Alexis Laferrière Reviewed-by: Jean Privat Reviewed-by: Lucas Bajolet --- diff --git a/lib/json/serialization.nit b/lib/json/serialization.nit index 61c6f61..4b7cb15 100644 --- a/lib/json/serialization.nit +++ b/lib/json/serialization.nit @@ -57,13 +57,13 @@ # ~~~ 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 index 0000000..186c96c --- /dev/null +++ b/lib/serialization/caching.nit @@ -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 diff --git a/lib/serialization/engine_tools.nit b/lib/serialization/engine_tools.nit index 1e0ee0b..33d36b4 100644 --- a/lib/serialization/engine_tools.nit +++ b/lib/serialization/engine_tools.nit @@ -16,59 +16,31 @@ 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 diff --git a/lib/serialization/serialization.nit b/lib/serialization/serialization.nit index 3ba9968..8977baa 100644 --- a/lib/serialization/serialization.nit +++ b/lib/serialization/serialization.nit @@ -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 diff --git a/tests/sav/nitserial_args1.res b/tests/sav/nitserial_args1.res index 7a38c28..b69dc33 100644 --- a/tests/sav/nitserial_args1.res +++ b/tests/sav/nitserial_args1.res @@ -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