/*
* 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 */