lib/core: add Sequence::modulo to access with a Python-wrap semantic
[nit.git] / lib / core / collection / abstract_collection.nit
index aca4fdc..5f9af05 100644 (file)
@@ -177,6 +177,21 @@ interface Collection[E]
                for e in self do if self.count(e) != other.count(e) then return false
                return true
        end
+
+       # Does the collection contain at least one element of `other`?
+       #
+       #     assert [1,3,4,2].has_any([1..10])    == true
+       #     assert [1,3,4,2].has_any([5..10])    == false
+       #
+       # Note that the default implementation is general and correct for any lawful Collections.
+       # It is memory-efficient but relies on `has` so may be CPU-inefficient for some kind of collections.
+       fun has_any(other: Collection[nullable Object]): Bool
+       do
+               for o in other do
+                       if has(o) then return true
+               end
+               return false
+       end
 end
 
 # Iterators generate a series of elements, one at a time.
@@ -394,6 +409,7 @@ end
 #      assert s.has(b)      ==  true
 interface Set[E]
        super SimpleCollection[E]
+       super Cloneable
 
        redef fun has_only(item)
        do
@@ -456,6 +472,8 @@ interface Set[E]
                return nhs
        end
 
+       redef fun clone do return union(self)
+
        # Returns a new instance of `Set`.
        #
        # Depends on the subclass, mainly used for copy services
@@ -794,6 +812,44 @@ interface SequenceRead[E]
        # REQUIRE `index >= 0 and index < length`
        fun [](index: Int): E is abstract
 
+       # Return the index-th element but wrap
+       #
+       # Whereas `self[]` requires the index to exists, the `modulo` accessor automatically
+       # wraps overbound and underbouds indexes.
+       #
+       # ~~~
+       # var a = [10,20,30]
+       # assert a.modulo(1) == 20
+       # assert a.modulo(3) == 10
+       # assert a.modulo(-1) == 30
+       # assert a.modulo(-10) == 30
+       # ~~~
+       #
+       # REQUIRE `not_empty`
+       # ENSURE `result == self[modulo_index(index)]`
+       fun modulo(index: Int): E do return self[modulo_index(index)]
+
+       # Returns the real index for a modulo index.
+       #
+       # ~~~
+       # var a = [10,20,30]
+       # assert a.modulo_index(1) == 1
+       # assert a.modulo_index(3) == 0
+       # assert a.modulo_index(-1) == 2
+       # assert a.modulo_index(-10) == 2
+       # ~~~
+       #
+       # REQUIRE `not_empty`
+       fun modulo_index(index: Int): Int
+       do
+               var length = self.length
+               if index >= 0 then
+                       return index % length
+               else
+                       return length - (-1 - index) % length - 1
+               end
+       end
+
        # Get the last item.
        # Is equivalent with `self[length-1]`.
        #
@@ -853,18 +909,13 @@ interface SequenceRead[E]
        #     assert a.last_index_of_from(20, 2)   == 1
        #     assert a.last_index_of_from(20, 1)   == 1
        #     assert a.last_index_of_from(20, 0)   == -1
-       fun last_index_of_from(item: nullable Object, pos: Int): Int
-       do
-               var res = -1
-               var p = 0
-               var i = iterator
-               while i.is_ok do
-                       if p>pos then break
-                       if i.item == item then res = p
-                       i.next
-                       p += 1
+       fun last_index_of_from(item: nullable Object, pos: Int): Int do
+               var i = pos
+               while i >= 0 do
+                       if self[i] == item then return i
+                       i -= 1
                end
-               return res
+               return -1
        end
 
        # Two sequences are equals if they have the same items in the same order.
@@ -1049,6 +1100,24 @@ interface Sequence[E]
        # REQUIRE `index >= 0 and index <= length`
        fun []=(index: Int, item: E) is abstract
 
+       # Set the index-th element but wrap
+       #
+       # Whereas `self[]=` requires the index to exists, the `modulo` accessor automatically
+       # wraps overbound and underbouds indexes.
+       #
+       # ~~~
+       # var a = [10,20,30]
+       # a.modulo(1) = 200
+       # a.modulo(3) = 100
+       # a.modulo(-1) = 300
+       # a.modulo(-10) = 301
+       # assert a == [100, 200, 301]
+       # ~~~
+       #
+       # REQUIRE `not_empty`
+       # ENSURE `self[modulo_index(index)] == value`
+       fun modulo=(index: Int, value: E) do self[modulo_index(index)] = value
+
        # Insert an element at a given position, following elements are shifted.
        #
        #     var a = [10, 20, 30, 40]