# Advanced services for serialization engines
module engine_tools
-import serialization
+import serialization_core
+intrude import core::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]]]
+ super HashMap[K, V]
- redef var length = 0
+ redef fun index_at(k)
+ do
+ if k == null then return 0
- redef fun is_empty do return length == 0
+ var i = k.serialization_hash % _capacity
+ if i < 0 then i = - i
+ return i
+ end
- # private
- fun node_at(key: K): nullable Couple[K, V]
+ redef fun node_at_idx(i, 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
+ var c = _array[i]
+ while c != null do
+ var ck = c._key
+ assert ck != null
+ if ck.is_same_serialized(k) then
+ break
end
+ c = c._next_in_bucklet
end
-
- return null
+ return c
end
+end
+
+redef interface Object
+ # Is `self` the same as `other` in a serialization context?
+ #
+ # Used to determine if an object has already been serialized.
+ fun is_same_serialized(other: nullable Object): Bool do return is_same_instance(other)
- redef fun [](key)
+ # 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
+
+redef class String
+ redef fun serialization_hash do return hash
+ redef fun is_same_serialized(o) do return self == o
+end
+
+redef class Text
+
+ # Strip the `nullable` prefix from the type name `self`
+ #
+ # ~~~
+ # assert "String".strip_nullable == "String"
+ # assert "nullable Array[Int]".strip_nullable == "Array[Int]"
+ # assert "Map[Set[String], Set[Int]]".strip_nullable == "Map[Set[String], Set[Int]]"
+ # ~~~
+ fun strip_nullable: Text
do
- var node = node_at(key)
- assert node != null
- return node.second
+ var prefix = "nullable "
+ return if has_prefix(prefix) then substring_from(prefix.length) else self
end
- redef fun []=(key, value)
+ # Strip the `nullable` prefix and the params from the type name `self`
+ #
+ # ~~~
+ # assert "String".strip_nullable_and_params == "String"
+ # assert "nullable Array[Int]".strip_nullable_and_params == "Array"
+ # assert "Map[Set[String], Set[Int]]".strip_nullable_and_params == "Map"
+ # ~~~
+ fun strip_nullable_and_params: Text
do
- var node = node_at(key)
- if node != null then
- node.second = value
- return
- end
+ var class_name = strip_nullable
- 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
+ var bracket_index = class_name.index_of('[')
+ if bracket_index == -1 then return class_name
+ return class_name.substring(0, bracket_index)
end
-
- redef fun has_key(key) do return node_at(key) != null
end