lib/array: suppress a warning to be compatible with the bootstrap
[nit.git] / lib / standard / collection / array.nit
index 23b21c4..3cc0b57 100644 (file)
 
 # This module introduces the standard array structure.
 # It also implements two other abstract collections : ArrayMap and ArraySet
-package array
+module array is
+       no_warning "useless-type-test" # to avoid warning with nitc while compiling with c_src
+end
 
 import abstract_collection
 
-# One dimention array of objects.
-class AbstractArrayRead[E]
-special IndexedCollectionRead[E]
-       # The current length
-       redef readable var _length: Int = 0
+# One dimension array of objects.
+abstract class AbstractArrayRead[E]
+       super SequenceRead[E]
+
+       redef var length = 0
 
        redef fun is_empty do return _length == 0
 
@@ -47,8 +49,6 @@ special IndexedCollectionRead[E]
                return true
        end
 
-       redef fun has_key(index) do return index >= 0 and index < length
-
        redef fun count(item)
        do
                var res = 0
@@ -63,9 +63,9 @@ special IndexedCollectionRead[E]
 
        redef fun index_of(item) do return index_of_from(item, 0)
 
-       fun last_index_of(item: E): Int do return last_index_of_from(item, length-1)
+       redef fun last_index_of(item: E): Int do return last_index_of_from(item, length-1)
 
-       fun index_of_from(item: E, pos: Int): Int
+       redef fun index_of_from(item: E, pos: Int): Int
        do
                var i = pos
                var len = length
@@ -78,7 +78,7 @@ special IndexedCollectionRead[E]
                return -1
        end
 
-       fun last_index_of_from(item: E, pos: Int): Int
+       redef fun last_index_of_from(item: E, pos: Int): Int
        do
                var i = pos
                while i >= 0 do
@@ -91,6 +91,9 @@ special IndexedCollectionRead[E]
                return -1
        end
 
+       # Return a new array that is the reverse of `self`
+       #
+       #     assert [1,2,3].reversed      ==  [3, 2, 1]
        fun reversed: Array[E]
        do
                var cmp = _length
@@ -102,7 +105,13 @@ special IndexedCollectionRead[E]
                return result
        end
 
-       protected fun copy_to(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
+       # Copy a portion of `self` to an other array.
+       #
+       #     var a = [1, 2, 3, 4]
+       #     var b = [10, 20, 30, 40, 50]
+       #     a.copy_to(1, 2, b, 2)
+       #     assert b      ==  [10, 20, 2, 3, 50]
+       fun copy_to(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
        do
                # TODO native one
                var i = len
@@ -123,27 +132,31 @@ special IndexedCollectionRead[E]
                end
        end
 
-       redef fun iterator: ArrayIterator[E] do return new ArrayIterator[E](self)
-
-       # Two arrays are equals if they have the same items in the same order.
-       redef fun ==(o)
-       do
-               if not o isa AbstractArray[E] or o is null then return false
-               var l = length
-               if o.length != l then return false
-               var i = 0
-               while i < l do
-                       if self[i] != o[i] then return false
-                       i += 1
-               end
-               return true
+       redef fun iterator: ArrayIterator[E] do
+               var res = _free_iterator
+               if res == null then return new ArrayIterator[E](self)
+               res._index = 0
+               _free_iterator = null
+               return res
        end
+
+       # An old iterator, free to reuse.
+       # Once an iterator is `finish`, it become reusable.
+       # Since some arrays are iterated a lot, this avoid most of the
+       # continuous allocation/garbage-collection of the needed iterators.
+       private var free_iterator: nullable ArrayIterator[E] = null
+
+       redef fun reverse_iterator do return new ArrayReverseIterator[E](self)
 end
 
-# Resizeable one dimention array of objects.
-class AbstractArray[E]
-special AbstractArrayRead[E]
-special IndexedCollection[E]
+# Resizable one dimension array of objects.
+abstract class AbstractArray[E]
+       super AbstractArrayRead[E]
+       super Sequence[E]
+
+       # Force the capacity to be at least `cap`.
+       # The capacity of the array is an internal information.
+       # However, this method can be used to prepare a large amount of add
        fun enlarge(cap: Int) is abstract
 
        redef fun push(item) do add(item)
@@ -173,20 +186,33 @@ special IndexedCollection[E]
        redef fun unshift(item)
        do
                var i = length - 1
-               while i > 0 do
+               while i >= 0 do
                        self[i+1] = self[i]
                        i -= 1
                end
                self[0] = item
        end
 
-       fun insert(item: E, pos: Int)
+       redef fun insert(item: E, pos: Int)
        do
                enlarge(length + 1)
                copy_to(pos, length-pos, self, pos + 1)
                self[pos] = item
        end
 
+       redef fun insert_all(coll, pos)
+       do
+               var l = coll.length
+               if l == 0 then return
+               enlarge(length + l)
+               _length += l
+               copy_to(pos, length-pos-l, self, pos + l)
+               for c in coll do
+                       self[pos] = c
+                       pos += 1
+               end
+       end
+
        redef fun add(item) do self[length] = item
 
        redef fun clear do _length = 0
@@ -214,20 +240,35 @@ special IndexedCollection[E]
                        _length = l - 1
                end
        end
+
+       # Invert two elements in the array
+       #
+       #     var a = [10, 20, 30, 40]
+       #     a.swap_at(1, 3)
+       #     assert a      ==  [10, 40, 30, 20]
+       fun swap_at(a: Int,b: Int)
+       do
+           var e = self[a]
+           self[a] = self[b]
+           self[b] = e
+       end
 end
 
-# Resizeable one dimention array of objects.
+# Resizable one dimension array of objects.
 #
 # Arrays have a literal representation.
-#     a = [12, 32, 8]
-# is equivalent with:
-#     a = new Array[Int]
-#     a.push(12)
-#     a.push(32)
-#     a.push(8)
+#
+#     var a = [12, 32, 8]
+#     # is equivalent with:
+#     var b = new Array[Int]
+#     b.push(12)
+#     b.push(32)
+#     b.push(8)
+#     assert a == b
 class Array[E]
-special AbstractArray[E]
-special ArrayCapable[E]
+       super AbstractArray[E]
+       super Cloneable
+
        redef fun [](index)
        do
                assert index: index >= 0 and index < _length
@@ -256,12 +297,38 @@ special ArrayCapable[E]
                _items[l] = item
        end
 
+       # Slight optimization for arrays
+       redef fun add_all(items)
+       do
+               var l = _length
+               var nl = l + items.length
+               if _capacity < nl then
+                       enlarge nl
+               end
+
+               if items isa Array[E] then
+                       var k = 0
+                       while l < nl do
+                               _items[l] = items._items[k]
+                               l += 1
+                               k += 1
+                       end
+               else
+                       for item in items do
+                               _items[l] = item
+                               l += 1
+                       end
+               end
+
+               _length = nl
+       end
+
        redef fun enlarge(cap)
        do
                var c = _capacity
                if cap <= c then return
                while c <= cap do c = c * 2 + 2
-               var a = calloc_array(c)
+               var a = new NativeArray[E](c)
                if _capacity > 0 then _items.copy_to(a, _length)
                _items = a
                _capacity = c
@@ -274,7 +341,13 @@ special ArrayCapable[E]
                _length = 0
        end
 
-       # Create an array with some `items'.
+       # Create an array from a collection.
+       init from(items: Collection[E]) do
+               with_capacity(items.length)
+               self.add_all(items)
+       end
+
+       # Create an array with some `objects`.
        init with_items(objects: E...)
        do
                _items = objects._items
@@ -286,16 +359,16 @@ special ArrayCapable[E]
        init with_capacity(cap: Int)
        do
                assert positive: cap >= 0
-               _items = calloc_array(cap)
+               _items = new NativeArray[E](cap)
                _capacity = cap
                _length = 0
        end
 
-       # Create an array of `count' elements
+       # Create an array of `count` elements
        init filled_with(value: E, count: Int)
        do
                assert positive: count >= 0
-               _items = calloc_array(count)
+               _items = new NativeArray[E](count)
                _capacity = count
                _length = count
                var i = 0
@@ -315,19 +388,99 @@ special ArrayCapable[E]
        end
 
        # The internal storage.
-       var _items: nullable NativeArray[E] = null
+       private var items: nullable NativeArray[E] = null
 
-       # Do not use this method
-       # FIXME: Remove it once modules can intrude non local modules
-       fun intern_items: NativeArray[E] do return _items.as(not null)
+       # The size of `_items`.
+       private var capacity: Int = 0
 
-       # The size of `_items'.
-       var _capacity: Int = 0
+       redef fun ==(o)
+       do
+               if not o isa Array[nullable Object] then return super
+               # Efficient implementation
+               var l = length
+               if l != o.length then return false
+               var i = 0
+               var it = _items
+               var oit = o._items
+               while i < l do
+                       if it[i] != oit[i] then return false
+                       i += 1
+               end
+               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.
+       #
+       #     var a1 = [1,2,3]
+       #     var a2 = [4,5,6]
+       #     var a3 = a1 + a2
+       #     assert a3 == [1,2,3,4,5,6]
+       #
+       # Because a new array is always created, future modification on `self` and `other`
+       # does not impact the previously computed result.
+       #
+       #     a1.add(30)
+       #     a2.add(60)
+       #     assert a3      == [1,2,3,4,5,6] # unchanged
+       #     assert a1 + a2 == [1,2,3,30,4,5,6,60]
+       fun +(other: Array[E]): Array[E]
+       do
+               var res = new Array[E].with_capacity(length + other.length)
+               res.append(self)
+               res.append(other)
+               return res
+       end
+
+       # Repetition of arrays.
+       #
+       # returns a new array built by concatenating `self` `repeat` times.
+       #
+       #     var a = [1,2,3]
+       #     assert (a * 0).is_empty
+       #     assert a * 1  ==  [1,2,3]
+       #     assert a * 2  ==  [1,2,3,1,2,3]
+       #     assert (a * 10).length  ==  30
+       fun *(repeat: Int): Array[E]
+       do
+               assert repeat >= 0
+               var res = new Array[E].with_capacity(length * repeat)
+               while repeat > 0 do
+                       res.add_all(self)
+                       repeat -= 1
+               end
+               return res
+       end
 end
 
-# An `Iterator' on `AbstractArray'
-class ArrayIterator[E]
-special IndexedIterator[E]
+# An `Iterator` on `AbstractArray`
+private class ArrayIterator[E]
+       super IndexedIterator[E]
+
        redef fun item do return _array[_index]
 
        # redef fun item=(e) do _array[_index] = e
@@ -336,23 +489,35 @@ special IndexedIterator[E]
 
        redef fun next do _index += 1
 
-       init(a: AbstractArrayRead[E])
+       redef var index = 0
+
+       var array: AbstractArrayRead[E]
+
+       redef fun finish do _array._free_iterator = self
+end
+
+private class ArrayReverseIterator[E]
+       super ArrayIterator[E]
+
+       redef fun is_ok do return _index >= 0
+
+       redef fun next do _index -= 1
+
+       init
        do
-               _array = a
-               _index = 0
+               _index = _array.length - 1
        end
-
-       redef readable var _index: Int = 0
-       var _array: AbstractArrayRead[E]
 end
 
 # Others collections ##########################################################
 
 # A set implemented with an Array.
 class ArraySet[E]
-special Set[E]
+       super Set[E]
+       super Cloneable
+
        # The stored elements.
-       var _array: Array[E]
+       private var array: Array[E] is noinit
 
        redef fun has(e) do return _array.has(e)
 
@@ -380,7 +545,7 @@ special Set[E]
 
        redef fun iterator do return new ArraySetIterator[E](_array.iterator)
 
-       # Assume the capacitydd is at least `cap'.
+       # Assume the capacity is at least `cap`.
        fun enlarge(cap: Int) do _array.enlarge(cap)
 
        private fun remove_at(i: Int)
@@ -394,11 +559,44 @@ special Set[E]
 
        # Create an empty set with a given capacity.
        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.
-class ArraySetIterator[E]
-special Iterator[E]
+private class ArraySetIterator[E]
+       super Iterator[E]
 
        redef fun is_ok do return _iter.is_ok
 
@@ -406,15 +604,14 @@ special Iterator[E]
 
        redef fun item: E do return _iter.item
 
-       init(iter: ArrayIterator[E]) do _iter = iter
-
-       var _iter: ArrayIterator[E]
+       var iter: ArrayIterator[E]
 end
 
 
 # Associative arrays implemented with an array of (key, value) pairs.
 class ArrayMap[K, E]
-special CoupleMap[K, E]
+       super CoupleMap[K, E]
+       super Cloneable
 
        # O(n)
        redef fun [](key)
@@ -423,7 +620,7 @@ special CoupleMap[K, E]
                if i >= 0 then
                        return _items[i].second
                else
-                       abort
+                       return provide_default_value(key)
                end
        end
 
@@ -438,72 +635,19 @@ special CoupleMap[K, E]
                end
        end
 
-       # O(n)
-       redef fun has_key(key) do return index(key) >= 0
-
-       # O(n)
-       redef fun has(item)
-       do
-               for i in _items do if i.second == item then return true
-               return false
-       end
-
-       # O(n)
-       redef fun has_only(item)
-       do
-               for i in _items do if i.second != item then return false
-               return true
-       end
+       redef var keys: RemovableCollection[K] = new ArrayMapKeys[K, E](self) is lazy
+       redef var values: RemovableCollection[E] = new ArrayMapValues[K, E](self) is lazy
 
        # O(1)
        redef fun length do return _items.length
 
-       redef fun first do return _items.first.first
-
-       # O(n)
-       redef fun count(item)
-       do
-               var nb = 0
-               for i in _items do if i.second == item then nb += 1
-               return nb
-       end
-
-       redef fun iterator: CoupleMapIterator[K, E] do return new CoupleMapIterator[K, E](_items.iterator)
+       redef fun couple_iterator do return _items.iterator
 
        redef fun is_empty do return _items.is_empty
 
-       redef fun remove(item)
-       do
-               var i = _items.length - 1
-               while i >= 0 do
-                       if _items[i].second == item then
-                               remove_at_index(i)
-                               return
-                       end
-                       i -= 1
-               end
-       end
-
-       redef fun remove_all(item: E)
-       do
-               var i = _items.length - 1
-               while i >= 0 do
-                       if _items[i].second == item then
-                               remove_at_index(i)
-                       end
-                       i -= 1
-               end
-       end
-
-       redef fun remove_at(key)
-       do
-               var i = index(key)
-               if i >= 0 then remove_at_index(i)
-       end
-
        redef fun clear do _items.clear
 
-       # Assume the capacity to be at least `cap'.
+       # Assume the capacity to be at least `cap`.
        fun enlarge(cap: Int) do _items.enlarge(cap)
 
        redef fun couple_at(key)
@@ -517,7 +661,7 @@ special CoupleMap[K, E]
        end
 
        # Internal storage.
-       var _items: Array[Couple[K,E]]
+       private var items = new Array[Couple[K,E]]
 
        # fast remove the ith element of the array
        private fun remove_at_index(i: Int)
@@ -527,9 +671,9 @@ special CoupleMap[K, E]
        end
 
        # The last positive result given by a index(1) call
-       var _last_index: Int = 0
+       private var last_index: Int = 0
 
-       # Where is the `key' in `_item'?
+       # Where is the `key` in `_item`?
        # return -1 if not found
        private fun index(key: K): Int
        do
@@ -547,17 +691,186 @@ special CoupleMap[K, E]
                return -1
        end
 
-       # A new empty map.
-       init
+       # 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]
+       super RemovableCollection[K]
+       # The original map
+       var map: ArrayMap[K, E]
+       redef fun count(k) do if self.has(k) then return 1 else return 0
+       redef fun first do return self.map._items.first.first
+       redef fun has(k) do return self.map.index(k) >= 0
+       redef fun has_only(k) do return (self.has(k) and self.length == 1) or self.is_empty
+       redef fun is_empty do return self.map.is_empty
+       redef fun length do return self.map.length
+       redef fun iterator do return new MapKeysIterator[K, E](self.map.iterator)
+       redef fun clear do self.map.clear
+       redef fun remove(key)
+       do
+               var i = self.map.index(key)
+               if i >= 0 then self.map.remove_at_index(i)
+       end
+       redef fun remove_all(key) do self.remove(key)
+end
+
+private class ArrayMapValues[K, E]
+       super RemovableCollection[E]
+       # The original map
+       var map: ArrayMap[K, E]
+       redef fun first do return self.map._items.first.second
+       redef fun is_empty do return self.map.is_empty
+       redef fun length do return self.map.length
+       redef fun iterator do return new MapValuesIterator[K, E](self.map.iterator)
+
+       # O(n)
+       redef fun has(item)
+       do
+               for i in self.map._items do if i.second == item then return true
+               return false
+       end
+
+       # O(n)
+       redef fun has_only(item)
+       do
+               for i in self.map._items do if i.second != item then return false
+               return true
+       end
+
+       # O(n)
+       redef fun count(item)
+       do
+               var nb = 0
+               for i in self.map._items do if i.second == item then nb += 1
+               return nb
+       end
+
+       redef fun clear do self.map.clear
+
+       redef fun remove(item)
+       do
+               var map = self.map
+               var i = map._items.length - 1
+               while i >= 0 do
+                       if map._items[i].second == item then
+                               map.remove_at_index(i)
+                               return
+                       end
+                       i -= 1
+               end
+       end
+
+       redef fun remove_all(item)
        do
-               _items = new Array[Couple[K,E]]
+               var map = self.map
+               var i = map._items.length - 1
+               while i >= 0 do
+                       if map._items[i].second == item then
+                               map.remove_at_index(i)
+                       end
+                       i -= 1
+               end
+       end
+end
+
+# Comparable array for comparable elements.
+#
+# For two arrays, if one is a prefix, then it is lower.
+#
+# ~~~
+# var a12 = new ArrayCmp[nullable Int].with_items(1,2)
+# var a123 = new ArrayCmp[nullable Int].with_items(1,2,3)
+# assert a12 < a123
+# ~~~
+#
+# Otherwise, the first element just after the longest
+# common prefix gives the order between the two arrays.
+#
+# ~~~
+# var a124 = new ArrayCmp[nullable Int].with_items(1,2,4)
+# var a13 = new ArrayCmp[nullable Int].with_items(1,3)
+# assert a12  < a123
+# assert a123 < a13
+# ~~~
+#
+# Obviously, two equal arrays are equal.
+#
+# ~~~
+# var b12 = new ArrayCmp[nullable Int].with_items(1,2)
+# assert (a12 <=> b12) == 0
+# ~~~
+#
+# `null` is considered lower than any other elements.
+# But is still greater than no element.
+#
+# ~~~
+# var a12n = new ArrayCmp[nullable Int].with_items(1,2,null)
+# assert a12n < a123
+# assert a12  < a12n
+# ~~~
+class ArrayCmp[E: nullable Comparable]
+       super Array[E]
+       super Comparable
+       redef type OTHER: ArrayCmp[E] is fixed
+
+       redef fun <(o) do return (self <=> o) < 0
+
+       redef fun <=>(o)
+       do
+               var it = _items
+               var oit = o._items
+               var i = 0
+               var l = length
+               var ol = o.length
+               var len
+               if l < ol then len = l else len = ol
+               while i < len do
+                       var a = it[i]
+                       var b = oit[i]
+                       if a != null then
+                               if b == null then return 1
+                               var d = a <=> b.as(Comparable)
+                               if d != 0 then return d
+                       else
+                               if b != null then return -1
+                       end
+                       i += 1
+               end
+               return l <=> ol
        end
 end
 
 # Others tools ################################################################
 
 redef class Iterator[E]
-       # Interate on `self' and build an array
+       # Interate on `self` and build an array
        fun to_a: Array[E]
        do
                var res = new Array[E]
@@ -573,22 +886,32 @@ redef class Collection[E]
        # Build a new array from a collection
        fun to_a: Array[E]
        do
-               return iterator.to_a
+               var res = new Array[E].with_capacity(length)
+               res.add_all(self)
+               return res
        end
 end
 
 # Native classes ##############################################################
 
-# Subclasses of this class can create native arrays
-interface ArrayCapable[E]
-       # Get a new array of `size' elements.
-       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]
+       # Creates a new NativeArray of capacity `length`
+       new(length: Int) is intern
+       # 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)
+
+       # Get item at `index`.
        fun [](index: Int): E is intern
+
+       # Set `item` at `index`.
        fun []=(index: Int, item: E) is intern
+
+       # Copy `length` items to `dest`.
        fun copy_to(dest: NativeArray[E], length: Int) is intern
        #fun =(o: NativeArray[E]): Bool is intern
        #fun !=(o: NativeArray[E]): Bool is intern