/* * Copyright (c) 2003-2008 The University of Wroclaw. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the University may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using System.Diagnostics; using Nemerle.Assertions; using System.Runtime.Serialization; using SC = System.Collections; using SCG = System.Collections.Generic; namespace Nemerle.Collections { /** * This is a subtype of Generic.Dictionary, which provides some additional * functional-style methods to its base type. */ [System.Serializable] [System.Runtime.InteropServices.ComVisible(false)] [DebuggerDisplay("Count = {Count}: {ToString()}")] [DebuggerNonUserCode] public class Hashtable [TKey, TValue] : SCG.Dictionary [TKey, TValue] // , IDictionary [TKey,TValue] { /* -- PUBLIC CONSTRUCTORS ---------------------------------------------- */ /// Initializes a new instance of the class that is empty, has the default initial capacity, and uses the default equality comparer for the key type. public this () { } /// Initializes a new instance of the class that contains elements copied from the specified and uses the default equality comparer for the key type. /// The whose elements are copied to the new . /// dictionary contains one or more duplicate keys. /// dictionary is null. public this(dictionary : SCG.IDictionary[TKey, TValue]) { base (dictionary) } /// Initializes a new instance of the class that contains elements copied from the specified and uses the default equality comparer for the key type. /// The whose elements are copied to the new . public this (generator : SC.Generic.IEnumerable [TKey * TValue]) { base (); foreach ((key, val) in generator) Add (key, val) } /// Initializes a new instance of the Hashtable[,] class that is empty, has the default /// initial capacity, and uses the specified . /// The implementation to use when comparing keys, or null to use the default for the type of the key. public this(comparer : SCG.IEqualityComparer[TKey]) { base (comparer) } /// Initializes a new instance of the class that is empty, has the specified initial capacity, and uses the default equality comparer for the key type. /// The initial number of elements that the can contain. /// capacity is less than 0. public this (capacity : int) { base (capacity); } /// Initializes a new instance of the class that contains elements copied from the specified and uses the specified . /// The whose elements are copied to the new . /// The implementation to use when comparing keys, or null to use the default for the type of the key. /// dictionary contains one or more duplicate keys. /// dictionary is null. public this(dictionary : SCG.IDictionary[TKey, TValue], comparer : SCG.IEqualityComparer[TKey]) { base (dictionary, comparer) } /// Initializes a new instance of the class that is empty, has the specified initial capacity, and uses the specified . /// The initial number of elements that the can contain. /// The implementation to use when comparing keys, or null to use the default for the type of the key. /// capacity is less than 0. public this(capacity : int, comparer : SCG.IEqualityComparer[TKey]) { base (capacity, comparer) } /* -- SERIALIZATION CONSTRUCTOR ---------------------------------------------- */ /// Initializes a new instance of the class with serialized data. /// A structure containing the source and destination of the serialized stream associated with the . /// A object containing the information required to serialize the . protected this (info : SerializationInfo, context : StreamingContext) { base(info, context); } /* -- PUBLIC METHODS --------------------------------------------------- */ /** * Returns an optional value associated with the specified key. */ public Get (key : TKey) : option [TValue] { mutable value; if (TryGetValue (key, out value)) Some (value) else None () } public TryGetValue (key : TKey) : TValue * bool { mutable value; if (TryGetValue (key, out value)) (value, true) else (value, false) } /** * Returns value associated with the specified key or default value (null for * referece type and result of parameterless constractor for value type). */ public GetValueOrDefault (key : TKey) : TValue { mutable value; ignore (TryGetValue (key, out value)); value } /** * Returns value associated with the specified key or defaultValue. */ public GetValueOrDefault (key : TKey, defaultValue : TValue) : TValue { mutable value; if (TryGetValue (key, out value)) value else defaultValue } /** * Returns value associated with the specified key or result of call getDefaultValue(). * The getDefaultValue() called only if key not exists in collection. */ public GetValueOrGetDefault (key : TKey, getDefaultValue : void -> TValue) : TValue { mutable value; if (TryGetValue (key, out value)) value else getDefaultValue() } /** * Returns value associated with the specified key or new value. * The new value obtain by call getNewValue(). The new value add * to collection before return to caller. * The getNewValue() called only if key not exists in collection. * Example: * def map = Hashtable(); * Console.WriteLine(map.GetValue("1", () => 1)); // Write "1" * Console.WriteLine(map.GetValue("1", () => 2)); // Write "1" * Console.WriteLine(map["1"]); // Write "1" */ public GetValue (key : TKey, getNewValue : void -> TValue) : TValue { mutable value; if (TryGetValue (key, out value)) value else { value = getNewValue(); Add(key, value); value } } /** * This is different from add, which can fail if the key is * already in the underlying Framework hashtable. */ public Set (key : TKey, val : TValue) : void { this [key] = val; } /** * Clones this hashtable. */ public Clone () : Hashtable [TKey,TValue] { Hashtable (this) } /** * Returns `true' if the hashtable contains the specified key. * * NOTE: this is the same as ContainsKey. */ public Contains (key : TKey) : bool { ContainsKey (key) } /** * Folds a function over the key/value pairs. */ public Fold ['c] (s : 'c, f : (TKey * TValue * 'c) -> 'c) : 'c { mutable acc = s; foreach (x in this) acc = f (x.Key, x.Value, acc); acc } /** * Iterates a function over the key/value pairs in the hashtable. */ public Iter (f : TKey * TValue -> void) : void { foreach (x in this) f (x.Key, x.Value) } /** * Maps a given function defined of key-value pairs to the contents * of this hashtable. A new hashtable object is created, containing * the results of the application. */ public Map ['c, 'd] (f : TKey * TValue -> 'c * 'd) : Hashtable ['c,'d] { def ht = Hashtable (Count); foreach (x in this) { def (k, v) = f (x.Key, x.Value); ht.Add (k, v) } ht } /** * Removes elements for which predicate is false */ public Filter (f : TKey * TValue -> bool) : Hashtable [TKey, TValue] { def ht = Hashtable (); foreach (x in this) when (f (x.Key, x.Value)) ht.Add (x.Key, x.Value); ht } public new Remove (key : TKey) : void { _ = base.Remove (key) } /** * Returns a collection of the key/value pairs from this hashtable */ [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public KeyValuePairs : array [TKey * TValue] { get { def result = array(Count); mutable i = 0; foreach (kv in this) { result[i] = (kv.Key, kv.Value); i++; } result } } internal static better_to_string (x : object) : string { match (x) { | str is string => "\"" + str + "\"" | ch is char => "'" + ch.ToString () + "'" | null => "" | _ => x.ToString () } } public override ToString () : string { def sb = System.Text.StringBuilder ("{"); foreach (x in this) { _ = sb.Append (better_to_string (x.Key)); _ = sb.Append (": "); _ = sb.Append (better_to_string (x.Value)); _ = sb.Append (", "); } // cut the last ', ' if it exists when (sb.Length > 1) sb.Length = sb.Length - 2; _ = sb.Append ('}'); sb.ToString () } } /* end of class Hashtable (TKey,TValue) */ } /* end of namespace */