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