Merge: add NativeArray::length
authorJean Privat <jean@pryen.org>
Fri, 18 Apr 2014 17:36:53 +0000 (13:36 -0400)
committerJean Privat <jean@pryen.org>
Fri, 18 Apr 2014 17:37:05 +0000 (13:37 -0400)
Add and implement native methods `NativeArray::length` and `NativeArray::to_a`

The length could be available but was not for historial reasons.
`to_a` is trivial once `length` is defined.

A future series will add `NativeArray::new` and depreciate the ugly `calloc_array`.

Note: because of a bug in nitg, the compiler in `c_src` seems to return 0 on `length` instead of aborting.

Pull-Request: #405
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>

lib/standard/collection/array.nit
src/global_compiler.nit
src/naive_interpreter.nit
src/separate_compiler.nit
src/separate_erasure_compiler.nit
tests/sav/test_native_array.res [new file with mode: 0644]
tests/test_native_array.nit [new file with mode: 0644]

index d40a220..6ae145d 100644 (file)
@@ -650,8 +650,14 @@ interface ArrayCapable[E]
        protected fun calloc_array(size: Int): NativeArray[E] is intern
 end
 
-# Native C array (void ...).
+# Native Nit array
+# Access are unchecked and it has a fixed size
+# Not for public use: may become private.
 universal NativeArray[E]
+       # The length of the array
+       fun length: Int is intern
+       # Use `self` to initialize a standard Nit Array.
+       fun to_a: Array[E] do return new Array[E].with_native(self, length)
        fun [](index: Int): E is intern
        fun []=(index: Int, item: E) is intern
        fun copy_to(dest: NativeArray[E], length: Int) is intern
index ce8fde1..8eb0bdf 100644 (file)
@@ -165,6 +165,7 @@ class GlobalCompiler
 
                if mtype.mclass.name == "NativeArray" then
                        # NativeArrays are just a instance header followed by an array of values
+                       v.add_decl("int length;")
                        v.add_decl("{mtype.arguments.first.ctype} values[1];")
                end
 
@@ -212,6 +213,7 @@ class GlobalCompiler
                if is_native_array then
                        var mtype_elt = mtype.arguments.first
                        v.add("{res} = nit_alloc(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));")
+                       v.add("((struct {mtype.c_name}*){res})->length = length;")
                else
                        v.add("{res} = nit_alloc(sizeof(struct {mtype.c_name}));")
                end
@@ -318,6 +320,9 @@ class GlobalCompilerVisitor
                else if pname == "[]=" then
                        self.add("{recv}[{arguments[1]}]={arguments[2]};")
                        return
+               else if pname == "length" then
+                       self.ret(self.new_expr("((struct {arguments[0].mcasttype.c_name}*){arguments[0]})->length", ret_type.as(not null)))
+                       return
                else if pname == "copy_to" then
                        var recv1 = "((struct {arguments[1].mcasttype.c_name}*){arguments[1]})->values"
                        self.add("memcpy({recv1},{recv},{arguments[2]}*sizeof({elttype.ctype}));")
index a423c53..b84399f 100644 (file)
@@ -796,6 +796,8 @@ redef class AInternMethPropdef
                        else if pname == "[]=" then
                                recvval[args[1].to_i] = args[2]
                                return null
+                       else if pname == "length" then
+                               return v.int_instance(recvval.length)
                        else if pname == "copy_to" then
                                recvval.copy(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
                                return null
index 4b1c5cc..4c2f322 100644 (file)
@@ -806,7 +806,8 @@ class SeparateCompiler
                        self.header.add_decl("struct instance_{c_instance_name} \{")
                        self.header.add_decl("const struct type *type;")
                        self.header.add_decl("const struct class *class;")
-                       # NativeArrays are just a instance header followed by an array of values
+                       # NativeArrays are just a instance header followed by a length and an array of values
+                       self.header.add_decl("int length;")
                        self.header.add_decl("val* values[0];")
                        self.header.add_decl("\};")
 
@@ -814,15 +815,16 @@ class SeparateCompiler
                        self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(int length, const struct type* type);")
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("{mtype.ctype} NEW_{c_name}(int length, const struct type* type) \{")
-                       var res = v.new_named_var(mtype, "self")
-                       res.is_exact = true
+                       var res = v.get_name("self")
+                       v.add_decl("struct instance_{c_instance_name} *{res};")
                        var mtype_elt = mtype.arguments.first
                        v.add("{res} = nit_alloc(sizeof(struct instance_{c_instance_name}) + length*sizeof({mtype_elt.ctype}));")
                        v.add("{res}->type = type;")
                        hardening_live_type(v, "type")
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
-                       v.add("return {res};")
+                       v.add("{res}->length = length;")
+                       v.add("return (val*){res};")
                        v.add("\}")
                        return
                end
@@ -1696,6 +1698,9 @@ class SeparateCompilerVisitor
                else if pname == "[]=" then
                        self.add("{recv}[{arguments[1]}]={arguments[2]};")
                        return
+               else if pname == "length" then
+                       self.ret(self.new_expr("((struct instance_{nclass.c_instance_name}*){arguments[0]})->length", ret_type.as(not null)))
+                       return
                else if pname == "copy_to" then
                        var recv1 = "((struct instance_{nclass.c_instance_name}*){arguments[1]})->values"
                        self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
index d7d88e1..1a0fcaa 100644 (file)
@@ -306,6 +306,7 @@ class SeparateErasureCompiler
                        #Build instance struct
                        self.header.add_decl("struct instance_{c_name} \{")
                        self.header.add_decl("const struct class *class;")
+                       self.header.add_decl("int length;")
                        self.header.add_decl("val* values[];")
                        self.header.add_decl("\};")
 
@@ -313,13 +314,14 @@ class SeparateErasureCompiler
                        self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(int length);")
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("{mtype.ctype} NEW_{c_name}(int length) \{")
-                       var res = v.new_named_var(mtype, "self")
-                       res.is_exact = true
+                       var res = v.get_name("self")
+                       v.add_decl("struct instance_{c_name} *{res};")
                        var mtype_elt = mtype.arguments.first
                        v.add("{res} = nit_alloc(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
-                       v.add("return {res};")
+                       v.add("{res}->length = length;")
+                       v.add("return (val*){res};")
                        v.add("\}")
                        return
                end
diff --git a/tests/sav/test_native_array.res b/tests/sav/test_native_array.res
new file mode 100644 (file)
index 0000000..2da52ea
--- /dev/null
@@ -0,0 +1,7 @@
+3
+10
+20
+30
+10
+20
+30
diff --git a/tests/test_native_array.nit b/tests/test_native_array.nit
new file mode 100644 (file)
index 0000000..aac7a83
--- /dev/null
@@ -0,0 +1,30 @@
+# 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.
+
+class Toto
+       super ArrayCapable[Int]
+
+       fun toto
+       do
+               var a = calloc_array(3)
+               a[0] = 10
+               a[1] = 20
+               a[2] = 30
+               a.length.output
+               a.to_a.output
+               (new Array[Int].with_native(a, 3)).output
+       end
+end
+
+(new Toto).toto