1 package frost.collections
2
3 ====================================================================================================
4 A `Set` which compares its entries using identity (`==`) instead of equality (`=`). Unlike
5 `HashSet`, which requires its entries to implement the `Key` interface, any type of object may be
6 used in an `IdentitiySet`. However, it is important that the type not be a subclass of `Value`, as
7 values do not have well-defined identities and `IdentitySet` will therefore not function properly
8 with value types.
9 ====================================================================================================
10 class IdentitySet<T> : Collection<T> {
11 @private
12 def contents := IdentityMap<T, T>()
13
14 ================================================================================================
15 Creates a new empty `IdentitySet`.
16 ================================================================================================
17 init() {
18 }
19
20 ================================================================================================
21 Creates a new set containing all of the elements from another collection, with duplicate entries
22 filtered out.
23 ================================================================================================
24 init(c:CollectionView<T>) {
25 addAll(c)
26 }
27
28 @override
29 method add(value:T) {
30 contents[value] := value
31 }
32
33 @override
34 method addAll(c:CollectionView<T>) {
35 for v in c {
36 add(v)
37 }
38 }
39
40 ================================================================================================
41 Removes an entry from the set, if present.
42 ================================================================================================
43 method remove(value:T) {
44 contents.remove(value)
45 }
46
47 @override
48 function get_count():Int {
49 return contents.count
50 }
51
52 @override
53 method clear() {
54 contents.clear()
55 }
56
57 @override
58 function get_iterator():Iterator<T> {
59 return contents.keys
60 }
61
62 ================================================================================================
63 Returns `true` if the value is present in the set.
64 ================================================================================================
65 function contains(value:T):Bit {
66 return contents.contains(value)
67 }
68
69 @override
70 method filterInPlace(test:(T)=>(Bit)) {
71 contents.filterInPlace((k, v) => test(k))
72 }
73
74 @override
75 method mapInPlace(f:(T)=>(T)) {
76 for (k, v) in contents.entries {
77 contents[k] := f(v)
78 }
79 }
80
81 @override
82 function get_toString():String {
83 def result := MutableString("[")
84 var separator := ""
85 for v in contents.keys {
86 result.append(separator)
87 -- FIXME cast shouldn't be necessary
88 if v->Object? !== null {
89 result.append(v)
90 }
91 else {
92 result.append("<null>")
93 }
94 separator := ", "
95 }
96 result.append("]")
97 return result.finish()
98 }
99 }
100