# Note: the value is returned *as is*, implementations may want to store the value in the map before returning it
# @toimplement
protected fun provide_default_value(key: K): V do abort
+
+ # Does `self` and `other` have the same keys associated with the same values?
+ #
+ # ~~~
+ # var a = new HashMap[String, Int]
+ # var b = new ArrayMap[Object, Numeric]
+ # assert a == b
+ # a["one"] = 1
+ # assert a != b
+ # b["one"] = 1
+ # assert a == b
+ # b["one"] = 2
+ # assert a != b
+ # ~~~
+ redef fun ==(other)
+ do
+ if not other isa MapRead[nullable Object, nullable Object] then return false
+ if other.length != self.length then return false
+ for k, v in self do
+ if not other.has_key(k) then return false
+ if other[k] != v then return false
+ end
+ return true
+ end
end
# Maps are associative collections: `key` -> `item`.
# assert a == b
class Array[E]
super AbstractArray[E]
+ super Cloneable
redef fun [](index)
do
return true
end
+ # Shallow clone of `self`
+ #
+ # ~~~
+ # var a = [1,2,3]
+ # var b = a.clone
+ # assert a == b
+ # a.add 4
+ # assert a != b
+ # b.add 4
+ # assert a == b
+ # ~~~
+ #
+ # Note that the clone is shallow and elements are shared between `self` and the result.
+ #
+ # ~~~
+ # var aa = [a]
+ # var bb = aa.clone
+ # assert aa == bb
+ # aa.first.add 5
+ # assert aa == bb
+ # ~~~
+ redef fun clone do return to_a
+
# Concatenation of arrays.
#
# Returns a new array built by concatenating `self` and `other` together.
# A set implemented with an Array.
class ArraySet[E]
super Set[E]
+ super Cloneable
# The stored elements.
private var array: Array[E] is noinit
init with_capacity(i: Int) do _array = new Array[E].with_capacity(i)
redef fun new_set do return new ArraySet[E]
+
+ # Shallow clone of `self`
+ #
+ # ~~~
+ # var a = new ArraySet[Int]
+ # a.add 1
+ # a.add 2
+ # var b = a.clone
+ # assert a == b
+ # a.add 3
+ # assert a != b
+ # b.add 3
+ # assert a == b
+ # ~~~
+ #
+ # Note that the clone is shallow and keys and values are shared between `self` and the result.
+ #
+ # ~~~
+ # var aa = new ArraySet[Array[Int]]
+ # aa.add([1,2])
+ # var bb = aa.clone
+ # assert aa == bb
+ # aa.first.add 5
+ # assert aa == bb
+ # ~~~
+ redef fun clone
+ do
+ var res = new ArraySet[E]
+ res.add_all self
+ return res
+ end
end
# Iterators on sets implemented with arrays.
# Associative arrays implemented with an array of (key, value) pairs.
class ArrayMap[K, E]
super CoupleMap[K, E]
+ super Cloneable
# O(n)
redef fun [](key)
end
return -1
end
+
+ # Shallow clone of `self`
+ #
+ # ~~~
+ # var a = new ArrayMap[String,Int]
+ # a["one"] = 1
+ # a["two"] = 2
+ # var b = a.clone
+ # assert a == b
+ # a["zero"] = 0
+ # assert a != b
+ # ~~~
+ #
+ # Note that the clone is shallow and keys and values are shared between `self` and the result.
+ #
+ # ~~~
+ # var aa = new ArrayMap[String, Array[Int]]
+ # aa["two"] = [1,2]
+ # var bb = aa.clone
+ # assert aa == bb
+ # aa["two"].add 5
+ # assert aa == bb
+ # ~~~
+ redef fun clone
+ do
+ var res = new ArrayMap[K,E]
+ res.recover_with self
+ return res
+ end
end
private class ArrayMapKeys[K, E]
end
end
+# Something that can be cloned
+#
+# This interface introduces the `clone` method used to duplicate an instance
+# Its specific semantic is let to the subclasses.
+interface Cloneable
+ # Duplicate `self`
+ #
+ # The specific semantic of this method is let to the subclasses;
+ # Especially, if (and how) attributes are cloned (depth vs. shallow).
+ #
+ # As a rule of thumb, the principle of least astonishment should
+ # be used to guide the semantic.
+ #
+ # Note that as the returned clone depends on the semantic,
+ # the `==` method, if redefined, should ensure the equality
+ # between an object and its clone.
+ fun clone: SELF is abstract
+end
+
# A numeric value supporting mathematical operations
interface Numeric
super Comparable
redef fun compile_callsite(callsite, args)
do
var rta = compiler.runtime_type_analysis
- var mmethod = callsite.mproperty
# TODO: Inlining of new-style constructors with initializers
if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and callsite.mpropdef.initializers.is_empty then
var tgs = rta.live_targets(callsite)
if tgs.length == 1 then
- # DIRECT CALL
- var res0 = before_send(mmethod, args)
- var res = call(tgs.first, tgs.first.mclassdef.bound_mtype, args)
- if res0 != null then
- assert res != null
- self.assign(res0, res)
- res = res0
- end
- add("\}") # close the before_send
- return res
+ return direct_call(tgs.first, args)
end
end
+ # Shortcut intern methods as they are not usually redefinable
+ if callsite.mpropdef.is_intern and callsite.mproperty.name != "object_id" then
+ # `object_id` is the only redefined intern method, so it can not be directly called.
+ # TODO find a less ugly approach?
+ return direct_call(callsite.mpropdef, args)
+ end
return super
end
+
+ # Fully and directly call a mpropdef
+ #
+ # This method is used by `compile_callsite`
+ private fun direct_call(mpropdef: MMethodDef, args: Array[RuntimeVariable]): nullable RuntimeVariable
+ do
+ var res0 = before_send(mpropdef.mproperty, args)
+ var res = call(mpropdef, mpropdef.mclassdef.bound_mtype, args)
+ if res0 != null then
+ assert res != null
+ self.assign(res0, res)
+ res = res0
+ end
+ add("\}") # close the before_send
+ return res
+ end
redef fun send(mmethod, arguments)
do
if arguments.first.mcasttype.ctype != "val*" then
var nclass = self.get_class("NativeArray")
var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
if pname == "[]" then
- self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
+ # Because the objects are boxed, return the box to avoid unnecessary (or broken) unboxing/reboxing
+ var res = self.new_expr("{recv}[{arguments[1]}]", compiler.mainmodule.object_type)
+ res.mcasttype = ret_type.as(not null)
+ self.ret(res)
return
else if pname == "[]=" then
self.add("{recv}[{arguments[1]}]={arguments[2]};")
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:413)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:432)
11
21
31
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:413)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:432)
11
21
31
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:413)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:432)
11
21
31
]
Comparable -> Discrete [dir=back arrowtail=open style=dashed];
+Cloneable [
+ label = "{interface\nCloneable||+ clone(): SELF\l}"
+]
+Object -> Cloneable [dir=back arrowtail=open style=dashed];
+
Numeric [
label = "{interface\nNumeric||+ +(i: OTHER): OTHER\l+ -(i: OTHER): OTHER\l+ unary -(): OTHER\l+ *(i: OTHER): OTHER\l+ /(i: OTHER): OTHER\l+ to_i(): Int\l+ to_f(): Float\l+ is_zero(): Bool\l+ zero(): OTHER\l+ value_of(val: Numeric): OTHER\l}"
]
]
Comparable -> Discrete [dir=back arrowtail=open style=dashed];
+Cloneable [
+ label = "{interface\nCloneable||+ clone(): SELF\l}"
+]
+Object -> Cloneable [dir=back arrowtail=open style=dashed];
+
Numeric [
label = "{interface\nNumeric||+ +(i: OTHER): OTHER\l+ -(i: OTHER): OTHER\l+ unary -(): OTHER\l+ *(i: OTHER): OTHER\l+ /(i: OTHER): OTHER\l+ to_i(): Int\l+ to_f(): Float\l+ is_zero(): Bool\l+ zero(): OTHER\l+ value_of(val: Numeric): OTHER\l}"
]
-Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:808)
+Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:894)
NativeString
N
Nit