Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Static.Lattices / EnvironmentDomain.cs
1 // 
2 // EnvironmentDomain.cs
3 // 
4 // Authors:
5 //      Alexander Chebaturkin (chebaturkin@gmail.com)
6 // 
7 // Copyright (C) 2011 Alexander Chebaturkin
8 // 
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:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //  
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.
27 //
28
29 using System;
30 using System.Collections.Generic;
31 using System.IO;
32 using System.Linq;
33
34 using Mono.CodeContracts.Static.DataStructures;
35
36 namespace Mono.CodeContracts.Static.Lattices {
37         class EnvironmentDomain<K, V> : IAbstractDomain<EnvironmentDomain<K, V>>
38                 where V : IAbstractDomain<V>
39                 where K : IEquatable<K> {
40                 readonly IImmutableMapFactory<K, V> factory;
41                 readonly IImmutableMap<K, V> map;
42
43                 EnvironmentDomain (IImmutableMapFactory<K, V> factory)
44                         : this (factory, factory.Empty)
45                 {
46                 }
47
48                 EnvironmentDomain (IImmutableMap<K, V> map)
49                         : this (map.Factory (), map)
50                 {
51                 }
52
53                 EnvironmentDomain (IImmutableMapFactory<K, V> factory, IImmutableMap<K, V> map)
54                 {
55                         this.factory = factory;
56                         this.map = map;
57                 }
58
59                 public V this [K key] { get { return map == null ? default(V) : map[key]; } }
60
61                 public IEnumerable<K> Keys { get { return map.Keys; } }
62
63                 #region IAbstractDomain<EnvironmentDomain<K,V>> Members
64
65                 public EnvironmentDomain<K, V> Top { get { return new EnvironmentDomain<K, V> (factory.Empty); } }
66
67                 public EnvironmentDomain<K, V> Bottom { get { return new EnvironmentDomain<K, V> (factory, null); } }
68
69                 public bool IsTop { get { return map != null && map.Count == 0; } }
70
71                 public bool IsBottom { get { return map == null; } }
72
73                 public EnvironmentDomain<K, V> Join (EnvironmentDomain<K, V> that)
74                 {
75                         return JoinOrWiden (that, (a, b) => a.Join (b));
76                 }
77
78                 public EnvironmentDomain<K, V> Widen (EnvironmentDomain<K, V> that)
79                 {
80                         return JoinOrWiden (that, (a, b) => a.Widen (b));
81                 }
82
83                 EnvironmentDomain<K, V> JoinOrWiden (EnvironmentDomain<K, V> that, Func<V, V, V> op)
84                 {
85                         if (ReferenceEquals (map, that.map) || IsBottom)
86                                 return that;
87                         if (that.IsBottom)
88                                 return this;
89
90                         IImmutableMap<K, V> min;
91                         IImmutableMap<K, V> max;
92                         GetMinAndMaxByCount (map, that.map, out min, out max);
93
94                         var result = min; // intersection of keys
95                         foreach (var key in min.Keys) {
96                                 V thatValue;
97                                 if (max.TryGetValue (key, out thatValue)) {
98                                         var join = op (min[key], thatValue);
99                                         if (join.IsBottom)
100                                                 return Bottom;
101
102                                         result = join.IsTop ? result.Remove (key) : result.Add (key, join);
103                                 }
104                                 else
105                                         result = result.Remove (key);
106                         }
107
108                         return new EnvironmentDomain<K, V> (result);
109                 }
110
111                 public EnvironmentDomain<K, V> Join (EnvironmentDomain<K, V> that, bool widening, out bool weaker)
112                 {
113                         //todo: remove it
114
115                         weaker = false;
116                         if (map == that.map || IsTop)
117                                 return this;
118                         if (that.IsTop) {
119                                 weaker = !IsTop;
120                                 return that;
121                         }
122                         if (IsBottom) {
123                                 weaker = !that.IsBottom;
124                                 return that;
125                         }
126                         if (that.IsBottom)
127                                 return this;
128
129                         IImmutableMap<K, V> min;
130                         IImmutableMap<K, V> max;
131                         GetMinAndMaxByCount (map, that.map, out min, out max);
132
133                         var intersect = min;
134                         foreach (var key in min.Keys) {
135                                 if (!max.ContainsKey (key))
136                                         intersect = intersect.Remove (key);
137                                 else {
138                                         bool keyWeaker;
139                                         var join = min[key].Join (max[key], widening, out keyWeaker);
140                                         if (keyWeaker) {
141                                                 weaker = true;
142                                                 intersect = join.IsTop ? intersect.Remove (key) : intersect.Add (key, join);
143                                         }
144                                 }
145                         }
146
147                         weaker |= intersect.Count < map.Count;
148                         return new EnvironmentDomain<K, V> (intersect);
149                 }
150
151                 public EnvironmentDomain<K, V> Meet (EnvironmentDomain<K, V> that)
152                 {
153                         if (ReferenceEquals (map, that.map))
154                                 return this;
155                         if (IsTop)
156                                 return that;
157                         if (that.IsTop || IsBottom)
158                                 return this;
159                         if (that.IsBottom)
160                                 return that;
161
162                         IImmutableMap<K, V> min;
163                         IImmutableMap<K, V> max;
164                         GetMinAndMaxByCount (map, that.map, out min, out max);
165
166                         var union = max;
167                         foreach (var key in min.Keys) {
168                                 if (!max.ContainsKey (key))
169                                         union = union.Add (key, min[key]);
170                                 else {
171                                         var meet = min[key].Meet (max[key]);
172                                         union = union.Add (key, meet);
173                                 }
174                         }
175
176                         return new EnvironmentDomain<K, V> (union);
177                 }
178
179                 public bool LessEqual (EnvironmentDomain<K, V> that)
180                 {
181                         bool result;
182                         if (this.TryTrivialLessEqual (that, out result))
183                                 return result;
184
185                         if (map.Count < that.map.Count)
186                                 return false;
187
188                         return that.map.Keys.All (key => map.ContainsKey (key) && map[key].LessEqual (that.map[key]));
189                 }
190
191                 public EnvironmentDomain<K, V> ImmutableVersion ()
192                 {
193                         return this;
194                 }
195
196                 public EnvironmentDomain<K, V> Clone ()
197                 {
198                         return this;
199                 }
200
201                 public void Dump (TextWriter tw)
202                 {
203                         if (IsTop)
204                                 tw.WriteLine ("Top");
205                         else if (IsBottom)
206                                 tw.WriteLine (this.BottomSymbolIfAny ());
207                         else {
208                                 map.Visit ((k, v) => {
209                                         tw.WriteLine ("{0} -> {1}", k, v);
210                                         return VisitStatus.ContinueVisit;
211                                 });
212                         }
213                 }
214
215                 #endregion
216
217                 public static EnvironmentDomain<K, V> TopValue (Func<K, int> keyConverter)
218                 {
219                         if (keyConverter == null)
220                                 throw new ArgumentNullException ("keyConverter");
221
222                         return new EnvironmentDomain<K, V> (ImmutableIntKeyMap<K, V>.Empty (keyConverter));
223                 }
224
225                 public static EnvironmentDomain<K, V> TopValue ()
226                 {
227                         return new EnvironmentDomain<K, V> (ImmutableMap<K, V>.Empty);
228                 }
229
230                 public static EnvironmentDomain<K, V> BottomValue (Func<K, int> keyConverter)
231                 {
232                         if (keyConverter == null)
233                                 throw new ArgumentNullException ("keyConverter");
234
235                         return new EnvironmentDomain<K, V> (ImmutableIntKeyMap<K, V>.Empty (keyConverter).Factory (), null);
236                 }
237
238                 public static EnvironmentDomain<K, V> BottomValue ()
239                 {
240                         return new EnvironmentDomain<K, V> (ImmutableMap<K, V>.Empty.Factory (), null);
241                 }
242
243                 public EnvironmentDomain<K, V> With (K key, V value)
244                 {
245                         if (value.IsTop)
246                                 return Without (key);
247
248                         return new EnvironmentDomain<K, V> (map.Add (key, value));
249                 }
250
251                 public EnvironmentDomain<K, V> RefineWith (K key, V value)
252                 {
253                         V old;
254                         if (map.TryGetValue (key, out old))
255                                 value = value.Meet (old);
256
257                         return With (key, value);
258                 }
259
260                 public EnvironmentDomain<K, V> Without (K key)
261                 {
262                         return new EnvironmentDomain<K, V> (map.Remove (key));
263                 }
264
265                 public bool Contains (K key)
266                 {
267                         return map != null && map.ContainsKey (key);
268                 }
269
270                 public bool TryGetValue (K key, out V value)
271                 {
272                         if (map == null)
273                                 return false.Without (out value);
274
275                         return map.TryGetValue (key, out value);
276                 }
277
278                 public EnvironmentDomain<K, V> Empty ()
279                 {
280                         return new EnvironmentDomain<K, V> (factory.Empty);
281                 }
282
283                 static bool GetMinAndMaxByCount
284                         (IImmutableMap<K, V> a, IImmutableMap<K, V> b,
285                          out IImmutableMap<K, V> min, out IImmutableMap<K, V> max)
286                 {
287                         if (a.Count < b.Count) {
288                                 min = a;
289                                 max = b;
290                                 return true;
291                         }
292                         max = a;
293                         min = b;
294                         return false;
295                 }
296                 }
297 }