lib/serialization: let refinements and subclasses access caches
[nit.git] / lib / serialization / caching.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Services for caching serialization engines
16 module caching
17
18 import serialization
19 private import engine_tools
20
21 # A `Serializer` with a `cache`
22 abstract class CachingSerializer
23 super Serializer
24
25 # Cache of known objects
26 var cache = new SerializerCache is lazy, writable
27
28 # Link the cache of `self` with `deserializer`
29 #
30 # This allows reference objects by id when they are known by the other side
31 # of the stream.
32 #
33 # Use `cache` if it is a `DuplexCache`, otherwise create a new one.
34 fun link(deserializer: CachingDeserializer)
35 do
36 var mem = self.cache
37 if not mem isa DuplexCache then mem = new DuplexCache
38
39 self.cache = mem
40 deserializer.cache = mem
41 end
42 end
43
44 # A `Deserializer` with a `cache`
45 abstract class CachingDeserializer
46 super Deserializer
47
48 # Cache of known objects
49 var cache = new DeserializerCache is lazy, writable
50 end
51
52 # Cache of sent objects
53 #
54 # Used by `Serializer` to avoid duplicating objects, by serializing them once,
55 # then using a reference.
56 class SerializerCache
57 # Map of already serialized objects to the reference id
58 protected var sent: Map[Serializable, Int] = new StrictHashMap[Serializable, Int]
59
60 # Is `object` known?
61 fun has_object(object: Serializable): Bool do return sent.keys.has(object)
62
63 # Get the id for `object`
64 #
65 # Require: `has_object(object)`
66 fun id_for(object: Serializable): Int
67 do
68 assert sent.keys.has(object)
69 return sent[object]
70 end
71
72 # Get a new id for `object` and store it
73 #
74 # Require: `not has_object(object)`
75 fun new_id_for(object: Serializable): Int
76 do
77 var id = next_available_id
78 sent[object] = id
79 return id
80 end
81
82 # Get a free id to associate to an object in the cache
83 protected fun next_available_id: Int do return sent.length
84 end
85
86 # Cache of received objects sorted by there reference id
87 #
88 # Used by `Deserializer` to find already deserialized objects by their reference.
89 class DeserializerCache
90 # Map of references to already deserialized objects.
91 protected var received: Map[Int, Object] = new StrictHashMap[Int, Object]
92
93 # Is there an object associated to `id`?
94 fun has_id(id: Int): Bool do return received.keys.has(id)
95
96 # Get the object associated to `id`
97 fun object_for(id: Int): nullable Object do return received[id]
98
99 # Associate `object` to `id`
100 fun []=(id: Int, object: Object) do received[id] = object
101 end
102
103 # A shared cache for serialization and deserialization
104 class DuplexCache
105 super SerializerCache
106 super DeserializerCache
107
108 redef fun new_id_for(object)
109 do
110 var id = super
111 received[id] = object
112 return id
113 end
114
115 redef fun []=(id, object)
116 do
117 super
118 assert object isa Serializable
119 sent[object] = id
120 end
121 end
122
123 # A shared cache where 2 clients serialize objects at the same types, prevents references collision
124 class AsyncCache
125 super DuplexCache
126
127 # Should this end use even numbers?
128 var use_even: Bool
129
130 private var last_id: Int is lazy do return if use_even then 0 else 1
131
132 redef fun next_available_id
133 do
134 last_id += 2
135 return last_id
136 end
137 end