Merge pull request #2424 from alexrp/task-unobserved-exceptions
[mono.git] / mcs / class / System.Json / System.Json / JsonObject.cs
index 2cd6d0f6c5b88a64110fa1fb2b82ecad916432f3..91366a2243a766eac337d7bc7739dfa3df5035be 100644 (file)
@@ -1,7 +1,6 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
-using System.Linq;
 using System.Globalization;
 using System.IO;
 using System.Text;
@@ -9,71 +8,47 @@ using System.Text;
 using JsonPair = System.Collections.Generic.KeyValuePair<string, System.Json.JsonValue>;
 using JsonPairEnumerable = System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, System.Json.JsonValue>>;
 
-
 namespace System.Json
 {
-       public class JsonObject : JsonValue, IDictionary<string, JsonValue>, ICollection<KeyValuePair<string, JsonValue>>
+       public class JsonObject : JsonValue, IDictionary<string, JsonValue>, ICollection<JsonPair>
        {
-               int known_count = -1;
-               Dictionary<string, JsonValue> map;
-               JsonPairEnumerable source;
+               // Use SortedDictionary to make result of ToString() deterministic
+               SortedDictionary<string, JsonValue> map;
 
-               public JsonObject (params KeyValuePair<string, JsonValue> [] items)
-                       : this ((JsonPairEnumerable) items)
+               public JsonObject (params JsonPair [] items)
                {
+                       map = new SortedDictionary<string, JsonValue> (StringComparer.Ordinal);
+
+                       if (items != null)
+                               AddRange (items);
                }
 
                public JsonObject (JsonPairEnumerable items)
                {
                        if (items == null)
                                throw new ArgumentNullException ("items");
-                       this.source = items;
+
+                       map = new SortedDictionary<string, JsonValue> (StringComparer.Ordinal);
+                       AddRange (items);
                }
 
                public override int Count {
-                       get {
-                               if (known_count < 0) {
-                                       if (map != null)
-                                               known_count = map.Count;
-                                       else {
-                                               known_count = 0;
-                                               foreach (JsonPair p in source)
-                                                       known_count++;
-                                       }
-                               }
-                               return known_count;
-                       }
+                       get { return map.Count; }
                }
 
                public IEnumerator<JsonPair> GetEnumerator ()
                {
-                       return AsEnumerable ().GetEnumerator ();
+                       return map.GetEnumerator ();
                }
 
-               JsonPairEnumerable AsEnumerable ()
+               IEnumerator IEnumerable.GetEnumerator ()
                {
-                       return map ?? source;
-               }
-
-               public bool IsReadOnly {
-                       get { return false; }
-               }
-
-               bool ICollection<JsonPair>.IsReadOnly {
-                       get { return ((ICollection<JsonPair>) map).IsReadOnly; }
+                       return map.GetEnumerator ();
                }
 
                public override sealed JsonValue this [string key] {
-                       get {
-                               foreach (JsonPair pair in AsEnumerable ())
-                                       if (pair.Key == key)
-                                               return pair.Value;
-                               throw new KeyNotFoundException (String.Format ("key '{0}' was not found.", key));
-                       }
-                       set {
-                               PopulateMap ();
-                               map [key] = value;
-                       }
+                       get { return map [key]; }
+                       set { map [key] = value; }
                }
 
                public override JsonType JsonType {
@@ -81,26 +56,18 @@ namespace System.Json
                }
 
                public ICollection<string> Keys {
-                       get {
-                               PopulateMap ();
-                               return map.Keys;
-                       }
+                       get { return map.Keys; }
                }
 
                public ICollection<JsonValue> Values {
-                       get {
-                               PopulateMap ();
-                               return map.Values;
-                       }
+                       get { return map.Values; }
                }
 
                public void Add (string key, JsonValue value)
                {
                        if (key == null)
                                throw new ArgumentNullException ("key");
-                       if (value == null)
-                               throw new ArgumentNullException ("value");
-                       PopulateMap ();
+
                        map.Add (key, value);
                }
 
@@ -113,55 +80,54 @@ namespace System.Json
                {
                        if (items == null)
                                throw new ArgumentNullException ("items");
-                       source = source.Concat (items);
-                       map = null;
+
+                       foreach (var pair in items)
+                               map.Add (pair.Key, pair.Value);
                }
 
-               public void AddRange (JsonPair [] items)
+               public void AddRange (params JsonPair [] items)
                {
                        AddRange ((JsonPairEnumerable) items);
                }
 
-               static readonly JsonPair [] empty = new JsonPair [0];
-
                public void Clear ()
                {
-                       if (map != null)
-                               map.Clear ();
-                       else
-                               source = empty;
+                       map.Clear ();
                }
 
                bool ICollection<JsonPair>.Contains (JsonPair item)
                {
-                       return ContainsKey (item.Key);
+                       return (map as ICollection<JsonPair>).Contains (item);
+               }
+
+               bool ICollection<JsonPair>.Remove (JsonPair item)
+               {
+                       return (map as ICollection<JsonPair>).Remove (item);
                }
 
                public override bool ContainsKey (string key)
                {
                        if (key == null)
                                throw new ArgumentNullException ("key");
-                       foreach (JsonPair p in AsEnumerable ())
-                               if (p.Key == key)
-                                       return true;
-                       return false;
+
+                       return map.ContainsKey (key);
                }
 
                public void CopyTo (JsonPair [] array, int arrayIndex)
                {
-                       foreach (JsonPair p in AsEnumerable ())
-                               array [arrayIndex++] = p;
+                       (map as ICollection<JsonPair>).CopyTo (array, arrayIndex);
                }
 
                public bool Remove (string key)
                {
-                       PopulateMap ();
+                       if (key == null)
+                               throw new ArgumentNullException ("key");
+
                        return map.Remove (key);
                }
 
-               bool ICollection<JsonPair>.Remove (JsonPair item)
-               {
-                       return ((ICollection<JsonPair>) map).Remove (item);
+               bool ICollection<JsonPair>.IsReadOnly {
+                       get { return false; }
                }
 
                public override void Save (Stream stream)
@@ -169,36 +135,27 @@ namespace System.Json
                        if (stream == null)
                                throw new ArgumentNullException ("stream");
                        stream.WriteByte ((byte) '{');
-                       foreach (JsonPair pair in this) {
+                       foreach (JsonPair pair in map) {
                                stream.WriteByte ((byte) '"');
                                byte [] bytes = Encoding.UTF8.GetBytes (EscapeString (pair.Key));
                                stream.Write (bytes, 0, bytes.Length);
                                stream.WriteByte ((byte) '"');
                                stream.WriteByte ((byte) ',');
                                stream.WriteByte ((byte) ' ');
-                               pair.Value.Save (stream);
+                               if (pair.Value == null) {
+                                       stream.WriteByte ((byte) 'n');
+                                       stream.WriteByte ((byte) 'u');
+                                       stream.WriteByte ((byte) 'l');
+                                       stream.WriteByte ((byte) 'l');
+                               } else
+                                       pair.Value.Save (stream);
                        }
                        stream.WriteByte ((byte) '}');
                }
 
                public bool TryGetValue (string key, out JsonValue value)
                {
-                       foreach (JsonPair p in AsEnumerable ())
-                               if (p.Key == key) {
-                                       value = p.Value;
-                                       return true;
-                               }
-                       value = null;
-                       return false;
-               }
-
-               void PopulateMap ()
-               {
-                       if (map == null) {
-                               map = new Dictionary<string, JsonValue> ();
-                               foreach (JsonPair pair in source)
-                                       map.Add (pair.Key, pair.Value);
-                       }
+                       return map.TryGetValue (key, out value);
                }
        }
 }