X-Git-Url: http://nitlanguage.org diff --git a/lib/core/collection/abstract_collection.nit b/lib/core/collection/abstract_collection.nit index 6b07149..9e2179b 100644 --- a/lib/core/collection/abstract_collection.nit +++ b/lib/core/collection/abstract_collection.nit @@ -149,6 +149,12 @@ interface Collection[E] # It is memory-efficient but relies on `has` so may be CPU-inefficient for some kind of collections. fun has_all(other: Collection[nullable Object]): Bool do + if is_same_instance(other) then return true + var ol = other.length + var l = length + if ol == 0 then return true + if l == 0 then return false + if ol == 1 then return has(other.first) for x in other do if not has(x) then return false return true end @@ -177,6 +183,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. @@ -286,6 +307,45 @@ private class StepIterator[E] redef fun next_by(step) do real.next_by(step * self.step) end +# An iterator that lazyly cache the current item. +# +# This class can be used as an helper to build simple iterator with a single and simplier `next_item` method. +# The only constraint is that `next_item` returns null on the last item, so `null` cannot be a valid element. +abstract class CachedIterator[E: Object] + super Iterator[E] + + # Get the next item if any. + # Returns null if there is no next item. + fun next_item: nullable E is abstract + + # The last item effectively read. + # `null` if on start, after a next of if no more items are available. + protected var cache: nullable E = null + + # The current item, if any. + # If not, the cache is effectively filled (with `next_item`). + # Return `null` iff there is no more elements. + protected fun current_item: nullable E + do + var cache = self.cache + if cache != null then return cache + cache = next_item + self.cache = cache + return cache + end + + redef fun item do return current_item.as(not null) + + redef fun is_ok do return current_item != null + + redef fun next do + # If needed, fill the cache (an consume the current element) + current_item + # Empty the cache (so the next element will be read) + cache = null + end +end + # A collection that contains only one item. # # Used to pass arguments by reference. @@ -364,7 +424,7 @@ end interface SimpleCollection[E] super RemovableCollection[E] - # Add an item in a collection. + # Add `item` to this collection. # # var a = [1,2] # a.add 3 @@ -375,6 +435,7 @@ interface SimpleCollection[E] fun add(item: E) is abstract # Add each item of `coll`. + # # var a = [1,2] # a.add_all([3..5]) # assert a.has(4) == true @@ -394,6 +455,7 @@ end # assert s.has(b) == true interface Set[E] super SimpleCollection[E] + super Cloneable redef fun has_only(item) do @@ -435,7 +497,9 @@ interface Set[E] var res = 23 + length # Note: the order of the elements must not change the hash value. # So, unlike usual hash functions, the accumulator is not combined with itself. - for e in self do res += e.hash + for e in self do + if e != null then res += e.hash + end return res end @@ -456,6 +520,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 @@ -662,19 +728,17 @@ interface Map[K, V] # Add each (key,value) of `map` into `self`. # If a same key exists in `map` and `self`, then the value in self is discarded. # - # It is the analogous of `SimpleCollection::add_all` - # # var x = new HashMap[String, Int] # x["four"] = 4 # x["five"] = 5 # var y = new HashMap[String, Int] # y["four"] = 40 # y["nine"] = 90 - # x.recover_with y + # x.add_all y # assert x["four"] == 40 # assert x["five"] == 5 # assert x["nine"] == 90 - fun recover_with(map: MapRead[K, V]) + fun add_all(map: MapRead[K, V]) do var i = map.iterator while i.is_ok do @@ -683,6 +747,9 @@ interface Map[K, V] end end + # Alias for `add_all` + fun recover_with(map: MapRead[K, V]) is deprecated do add_all(map) + # Remove all items # # var x = new HashMap[String, Int] @@ -794,6 +861,74 @@ 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 + + # Try to get an element, return `null` if the `index` is invalid. + # + # ~~~ + # var a = [10,20,30] + # assert a.get_or_null(1) == 20 + # assert a.get_or_null(3) == null + # assert a.get_or_null(-1) == null + # assert a.get_or_null(-10) == null + # ~~~ + fun get_or_null(index: Int): nullable E + do + if index >= 0 and index < length then return self[index] + return null + end + + # Try to get an element, return `default` if the `index` is invalid. + # + # ~~~ + # var a = [10,20,30] + # assert a.get_or_default(1, -1) == 20 + # assert a.get_or_default(3, -1) == -1 + # assert a.get_or_default(-1, -1) == -1 + # assert a.get_or_default(-10, -1) == -1 + # ~~~ + fun get_or_default(index: Int, default: E): E + do + if index >= 0 and index < length then return self[index] + return default + end + # Get the last item. # Is equivalent with `self[length-1]`. # @@ -1044,6 +1179,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] @@ -1082,6 +1235,30 @@ interface Sequence[E] # # REQUIRE `index >= 0 and index < length` fun remove_at(index: Int) is abstract + + # Rotates the elements of self once to the left + # + # ~~~nit + # var a = [12, 23, 34, 45] + # a.rotate_left + # assert a == [23, 34, 45, 12] + # ~~~ + fun rotate_left do + var fst = shift + push fst + end + + # Rotates the elements of self once to the right + # + # ~~~nit + # var a = [12, 23, 34, 45] + # a.rotate_right + # assert a == [45, 12, 23, 34] + # ~~~ + fun rotate_right do + var lst = pop + unshift lst + end end # Iterators on indexed collections.