5 // Alexander Chebaturkin (chebaturkin@gmail.com)
7 // Copyright (C) 2011 Alexander Chebaturkin
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
33 namespace Mono.CodeContracts.Static.DataStructures {
34 class ImmutableMap<K, V> : IImmutableMap<K, V>
35 where K : IEquatable<K> {
36 public static readonly ImmutableMap<K, V> Empty = new ImmutableMap<K, V> (ImmutableIntMap<Sequence<Pair<K, V>>>.Empty, 0, null);
38 private readonly int count;
39 private readonly IImmutableIntMap<Sequence<Pair<K, V>>> immutable_int_map;
40 private readonly Sequence<K> keys;
42 private ImmutableMap (IImmutableIntMap<Sequence<Pair<K, V>>> map, int count, Sequence<K> keys)
46 this.immutable_int_map = map;
49 #region Implementation of IImmutableMap<K,V>
55 return TryGetValue (key, out value) ? value : default(V);
59 public bool TryGetValue (K key, out V value)
61 for (Sequence<Pair<K, V>> list = this.immutable_int_map[key.GetHashCode ()]; list != null; list = list.Tail)
65 return true.With (list.Head.Value, out value);
67 return false.Without (out value);
72 get { return this.keys.Head; }
75 public IEnumerable<K> Keys
77 get { return this.keys.AsEnumerable (); }
82 get { return this.immutable_int_map.Count; }
85 public IImmutableMap<K, V> EmptyMap
90 public IImmutableMap<K, V> Add (K key, V value)
92 int hashCode = key.GetHashCode ();
93 Sequence<Pair<K, V>> cur = this.immutable_int_map [hashCode];
94 Sequence<Pair<K, V>> newList = Remove (cur, key).Cons (new Pair<K, V> (key, value));
95 int diff = newList.Length () - cur.Length ();
96 Sequence<K> newKeys = diff == 0 ? this.keys : this.keys.Cons (key);
98 return new ImmutableMap<K, V> (this.immutable_int_map.Add (hashCode, newList), this.count + diff, newKeys);
101 public IImmutableMap<K, V> Remove (K key)
103 int hashCode = key.GetHashCode ();
104 Sequence<Pair<K, V>> from = this.immutable_int_map [hashCode];
107 Sequence<Pair<K, V>> newList = Remove (from, key);
111 Sequence<K> newKeys = RemoveKey (key, this.keys);
113 return new ImmutableMap<K, V> (this.immutable_int_map.Remove (hashCode), this.count - 1, newKeys);
114 return new ImmutableMap<K, V> (this.immutable_int_map.Add (hashCode, newList), this.count - 1, newKeys);
117 public bool ContainsKey (K key)
119 return this.immutable_int_map [key.GetHashCode ()].AsEnumerable ().Any (pair => key.Equals (pair.Key));
122 public void Visit (Func<K, V, VisitStatus> func)
124 this.immutable_int_map.Visit (list => {
125 foreach (var pair in list.AsEnumerable ())
126 func (pair.Key, pair.Value);
130 private Sequence<Pair<K, V>> Remove (Sequence<Pair<K, V>> from, K key)
134 if (key.Equals (from.Head.Key))
136 Sequence<Pair<K, V>> tail = Remove (from.Tail, key);
137 return tail == from.Tail ? from : tail.Cons (from.Head);
140 private static Sequence<K> RemoveKey (K key, Sequence<K> keys)
143 throw new InvalidOperationException ();
145 if (key.Equals (keys.Head))
148 return RemoveKey (key, keys.Tail).Cons (keys.Head);
152 public IImmutableMapFactory<K, V> Factory ()
154 return new MapFactory ();
157 private class MapFactory : IImmutableMapFactory<K, V>
159 public IImmutableMap<K, V> Empty { get { return ImmutableMap<K,V>.Empty;}}