namespace Cobra.Core use System.Collections #use System.Collections.Generic use System.Collections.ObjectModel interface ISet inherits System.Collections.Generic.ISet, ICollection, IEnumerable, ISet ## Collection type operations def addRange(items as IEnumerable) def clone as ISet ## Set operations def intersection(s as ISet) as ISet def union(s as ISet) as ISet def difference(s as ISet) as ISet def symmetricDifference(s as ISet) as ISet def toList as List class Set inherits HashSet implements ISet, ICollection, IEnumerable, ISet """ A Set holds a hashed, unordered collections of items. Membership testing and set operations (intersection, union, etc.) are faster than with lists, but order is not preserved. Set implements ICollection, so it has the usual collection operations such as `add`, `count` and `contains`. It also has set specific operations including `union`, `intersection` and `isSubsetOf`. As with other collections, to create a copy of a set, create a new one passing the original to the initializer: s = Set(s) This one is now based on .NET 4.0 System.Collections.Generic.HashSet augmented to support same API as the original Cobra implemented version running on .NET 2.0. TODO: [-] List style items [ ] Can the methods use .getType instead of hardcoding Set? Then subclasses would get created for example .intersection [ ] could use an indexer: s[key]. Does it return bool or T? like NSSet? [ ] Test without args: s = Set(s) (test in C# too) [ ] yielded versions of Set operators? [ ] unit test CobraCore.toTechString() results [ ] ReadOnlySet? [ ] Move some method implementations up to ISet extension """ ## Initialization cue init base.init # Just for backward compatibility cue init(capacity as int) base.init cue init(items as IEnumerable) # CC: ensure for item in items assert .contains(item) or, # CC: ensure for item in items get .contains(item) base.init(items) cue init(comparer as IEqualityComparer) base.init(comparer) cue init(items as IEnumerable?, comparer as IEqualityComparer?) base.init(items, comparer) # also for backwards compatibility cue init(capacity as int, items as IEnumerable?, comparer as IEqualityComparer?) base.init(items, comparer) ## Object def equals(other as Object?) as bool is override # TODO: could this be more efficient? if other inherits Set if .count <> other.count return false for item in this if not other.contains(item) return false for item in other if not .contains(item) return false return true else if other inherits ISet # TODO: cleanup the following if .countOfISet <> other.countOfISet return false for item in this if not other.contains(item) return false for item2 in other if not item2 inherits T return false if not .contains(item2 to T) return false return true else return false def getHashCode as int code = base.getHashCode for item in this code ^= item.getHashCode return code # ISet get countOfISet as int return base.count def contains(item as Object) as bool implements ISet return if(sharp'item is T', base.contains(item to T), false) ## Set operations def intersection(s as ISet) as ISet """ Returns a new set containing only the elements that are in this set and `s`. (AND) See also: .intersectionWith which modifies the set in place """ #r = Set() #for item in this # if s.contains(item) # r.add(item) #return r # to-do: which is faster, the above or this: r = Set(this) r.intersectWith(s) return r def union(s as ISet) as ISet """ Returns a new set containing the elements of that are in this set or `s`. (OR) See also: .unionWith which modifies the set in place """ r = Set(this) r.unionWith(s) return r def difference(s as ISet) as ISet """ Returns a new set with elements in this set that are not in `s`. """ r = Set() for item in this if not s.contains(item) r.add(item) return r def symmetricDifference(s as ISet) as ISet """ Returns a new set with elements in either s or t but not both. (XOR) base.symmetricExceptWith modifies this set. """ r = Set(this) r.symmetricExceptWith(s) return r #r = Set() #for item in this # if not s.contains(item) # r.add(item) #for item in s # if not .contains(item) # r.add(item) #return r ## List-inspired Members def addRange(items as ISet) # ensure all (for item in items get .contains(item)) for item in items .add(item) def addRange(items as IEnumerable) for item in items .add(item) def asReadOnly as ReadOnlyCollection return ReadOnlyCollection(.toList) # TODO #def convertAll(converter as Converter) as Set # newSet = Set() # for item in this # newSet.add(converter(item)) # return newSet def exists(predicate as Predicate) as bool for item in this if predicate(item) return true return false # TODO: find # TODO: findAll # TODO: forEach (or for) # TODO: removeAll # TODO: trueForAll ## Other def clone as ISet # CC: as same """ Returns a new set with the contents of this set. Does not clone the contents themselves. This is sometimes known as a "shallow copy". """ ensure result is not this result.count == .count result.typeOf is .typeOf body return .memberwiseClone to ISet def toList as List return List(this) interface ISet inherits System.Collections.IEnumerable """ This interface is to facilitate Set.equals when the generic types are different (which does not necessarily restrict the two sets from having the same contents). Use ISet instead. """ get countOfISet as int def contains(item as Object) as bool class TestSet test s = Set() assert s.count == 0 s1 = Set() assert s1.count == 0 assert s is not s1 assert s == s1 assert s.getHashCode <> s1.getHashCode s = Set() assert s.count == 0 t = Set() to ISet assert t.count == 0 assert s is not t assert s == t s.add(1) assert s.contains(1) assert not s.contains(2) assert s <> t assert t.isSubsetOf(s) assert s.isSupersetOf(t) t.add(1) assert s == t s.clear t.clear assert s.count == 0 s.add(1) t = s.clone assert t is not s assert t.count == s.count assert 1 in t and 2 not in t s.clear t.clear u = s.union(t) assert t is not u assert s.count == 0 assert t.count == 0 assert u.count == 0 s = Set() s.add(1) assert s.contains(1) assert not s.contains(2) # remove s.remove(1) assert s.count == 0 assert not s.contains(1) # double add s.add(1) s.add(1) assert s.count == 1 assert s.contains(1) # make lists and sets from each other s = Set([1, 2]) assert s.contains(1) and s.contains(2) and s.count == 2 list = List(s) assert list == [1, 2] or list == [2, 1] # repeated element s = Set([1, 1]) assert s.contains(1) and not s.contains(2) and s.count == 1 s.add(1) assert s.contains(1) and not s.contains(2) and s.count == 1 # set operations r = Set([1, 2]).intersection(Set([2, 3])) assert r.toList == [2] r = Set([1, 2]).union(Set([2, 3])) list = r.toList list.sort assert list == [1, 2, 3] r = Set([1, 2]).difference(Set([2, 3])) assert r.toList == [1] r = Set([1, 2]).symmetricDifference(Set([2, 3])) assert r.toList == [1, 3] or r.toList == [3, 1] p = Set([1,2,3,4]).exists(do(i as int)) return i % 2 == 0 assert p p = Set([1,2,3,4]).exists(do(i as int)) return i >5 assert not p