# assert [1..1[.is_empty == true
fun is_empty: Bool do return length == 0
+ # Alias for `not is_empty`.
+ #
+ # Some people prefer to have conditions grammatically easier to read.
+ #
+ # assert [1,2,3].not_empty == true
+ # assert [1..1[.not_empty == false
+ fun not_empty: Bool do return not self.is_empty
+
# Number of items in the collection.
#
# assert [10,20,30].length == 3
# assert [1,2,3].has(9) == false
# assert [1..5[.has(2) == true
# assert [1..5[.has(9) == false
- fun has(item: E): Bool
+ fun has(item: nullable Object): Bool
do
for i in self do if i == item then return true
return false
# assert [3..3[.has_only(1) == true # empty collection
#
# ENSURE `is_empty implies result == true`
- fun has_only(item: E): Bool
+ fun has_only(item: nullable Object): Bool
do
for i in self do if i != item then return false
return true
# Comparisons are done with ==
#
# assert [10,20,10].count(10) == 2
- fun count(item: E): Int
+ fun count(item: nullable Object): Int
do
var nb = 0
for i in self do if i == item then nb += 1
#
# 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_all(other: Collection[E]): Bool
+ fun has_all(other: Collection[nullable Object]): Bool
do
for x in other do if not has(x) then return false
return true
#
# Note that the default implementation is general and correct for any lawful Collections.
# It is memory-efficient but relies on `count` so may be CPU-inefficient for some kind of collections.
- fun has_exactly(other: Collection[E]): Bool
+ fun has_exactly(other: Collection[nullable Object]): Bool
do
if length != other.length then return false
for e in self do if self.count(e) != other.count(e) then return false
end
end
-# Instances of the Iterator class generates a series of elements, one at a time.
-# They are mainly used with collections.
+# Iterators generate a series of elements, one at a time.
+#
+# They are mainly used with collections and obtained from `Collection::iterator`.
interface Iterator[E]
# The current item.
# Require `is_ok`.
# Require `is_ok`.
fun next is abstract
+ # Jump to the next item `step` times.
+ #
+ # ~~~
+ # var i = [11, 22, 33, 44].iterator
+ # assert i.item == 11
+ # i.next_by 2
+ # assert i.item == 33
+ # ~~~
+ #
+ # `next_by` should be used instead of looping on `next` because is takes care
+ # of stopping if the end of iteration is reached prematurely whereas a loop of
+ # `next` will abort because of the precondition on `is_ok`.
+ #
+ # ~~~
+ # i.next_by 100
+ # assert not i.is_ok
+ # ~~~
+ #
+ # If `step` is negative, this method aborts.
+ # But specific subclasses can change this and do something more meaningful instead.
+ #
+ # Require `is_ok`
+ fun next_by(step: Int)
+ do
+ assert step >= 0
+ while is_ok and step > 0 do
+ next
+ step -= 1
+ end
+ end
+
# Is there a current item ?
fun is_ok: Bool is abstract
#
# Do nothing by default.
fun finish do end
+
+ # A decorator around `self` that advance self a given number of steps instead of one.
+ #
+ # ~~~
+ # var i = [11, 22, 33, 44, 55].iterator
+ # var i2 = i.to_step(2)
+ #
+ # assert i2.item == 11
+ # i2.next
+ # assert i2.item == 33
+ #
+ # assert i.item == 33
+ # ~~~
+ fun to_step(step: Int): Iterator[E] do return new StepIterator[E](self, step)
+end
+
+# A basic helper class to specialize specific Iterator decorators
+abstract class IteratorDecorator[E]
+ super Iterator[E]
+
+ # The underling iterator
+ protected var real: Iterator[E]
+
+ redef fun is_ok do return real.is_ok
+ redef fun item do return real.item
+ redef fun finish do real.finish
+ redef fun next do real.next
+ redef fun next_by(step) do real.next_by(step)
+end
+
+# A decorator that advance a given number of steps
+private class StepIterator[E]
+ super IteratorDecorator[E]
+ var step: Int
+
+ redef fun next do real.next_by(step)
+ redef fun next_by(step) do real.next_by(step * self.step)
end
# A collection that contains only one item.
#
# Used to pass arguments by reference.
#
-# Also used when one want to give asingle element when a full
+# Also used when one want to give a single element when a full
# collection is expected
class Container[E]
super Collection[E]
redef fun next do is_ok = false
- redef var is_ok: Bool = true
+ redef var is_ok = true
var container: Container[E]
end
# ENSURE `is_empty`
fun clear is abstract
- # Remove an occucence of `item`
+ # Remove an occurrence of `item`
#
# var a = [1,2,3,1,2,3]
# a.remove 2
# assert a == [1,3,1,2,3]
- fun remove(item: E) is abstract
+ fun remove(item: nullable Object) is abstract
- # Remove all occurences of `item`
+ # Remove all occurrences of `item`
#
# var a = [1,2,3,1,2,3]
# a.remove_all 2
# assert a == [1,3,1,3]
- fun remove_all(item: E) do while has(item) do remove(item)
+ fun remove_all(item: nullable Object) do while has(item) do remove(item)
end
# Items can be added to these collections.
# Equality is defined on set and means that each set contains the same elements
redef fun ==(other)
do
- if not other isa Set[Object] then return false
+ if not other isa Set[nullable Object] then return false
if other.length != length then return false
return has_all(other)
end
#
# If the key is not in the map, `provide_default_value` is called (that aborts by default)
# See `get_or_null` and `get_or_default` for safe variations.
- fun [](key: K): V is abstract
+ fun [](key: nullable Object): V is abstract
# Get the item at `key` or null if `key` is not in the map.
#
# assert x.get_or_null("five") == null
#
# Note: use `has_key` and `[]` if you need the distinction between a key associated with null, and no key.
- fun get_or_null(key: K): nullable V
+ fun get_or_null(key: nullable Object): nullable V
do
if has_key(key) then return self[key]
return null
# assert x.get_or_default("four", 40) == 4
# assert x.get_or_default("five", 50) == 50
#
- fun get_or_default(key: K, default: V): V
+ fun get_or_default(key: nullable Object, default: V): V
do
if has_key(key) then return self[key]
return default
# assert x.has_key("five") == false
#
# By default it is a synonymous to `keys.has` but could be redefined with a direct implementation.
- fun has_key(key: K): Bool do return self.keys.has(key)
+ fun has_key(key: nullable Object): Bool do return self.keys.has(key)
# Get a new iterator on the map.
fun iterator: MapIterator[K, V] is abstract
#
# 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
+ protected fun provide_default_value(key: nullable Object): V do abort
# Does `self` and `other` have the same keys associated with the same values?
#
end
return true
end
+
+ # A hashcode based on the hashcode of the keys and the values.
+ #
+ # ~~~
+ # var a = new HashMap[String, Int]
+ # var b = new ArrayMap[Object, Numeric]
+ # a["one"] = 1
+ # b["one"] = 1
+ # assert a.hash == b.hash
+ # ~~~
+ redef fun hash
+ do
+ var res = length
+ for k, v in self do
+ if k != null then res += k.hash * 7
+ if v != null then res += v.hash * 11
+ end
+ return res
+ end
end
# Maps are associative collections: `key` -> `item`.
# var a = [10,20,30,10,20,30]
# assert a.index_of(20) == 1
# assert a.index_of(40) == -1
- fun index_of(item: E): Int do return index_of_from(item, 0)
+ fun index_of(item: nullable Object): Int do return index_of_from(item, 0)
# The index of the last occurrence of `item`.
# Return -1 if `item` is not found.
# var a = [10,20,30,10,20,30]
# assert a.last_index_of(20) == 4
# assert a.last_index_of(40) == -1
- fun last_index_of(item: E): Int do return last_index_of_from(item, length-1)
+ fun last_index_of(item: nullable Object): Int do return last_index_of_from(item, length-1)
# The index of the first occurrence of `item`, starting from pos.
# Return -1 if `item` is not found.
# assert a.index_of_from(20, 3) == 4
# assert a.index_of_from(20, 4) == 4
# assert a.index_of_from(20, 5) == -1
- fun index_of_from(item: E, pos: Int): Int
+ fun index_of_from(item: nullable Object, pos: Int): Int
do
var p = 0
var i = iterator
# 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: E, pos: Int): Int
+ fun last_index_of_from(item: nullable Object, pos: Int): Int
do
var res = -1
var p = 0
# Return the couple of the corresponding key
# Return null if the key is no associated element
- protected fun couple_at(key: K): nullable Couple[K, V] is abstract
+ protected fun couple_at(key: nullable Object): nullable Couple[K, V] is abstract
# Return a new iteralot on all couples
# Used to provide `iterator` and others
private class CoupleMapIterator[K, V]
super MapIterator[K, V]
redef fun item do return _iter.item.second
-
+
#redef fun item=(e) do _iter.item.second = e
redef fun key do return _iter.item.first