2017-07-10 21:29:48 -05:00
/ *
* Copyright ( c ) 2008 Solutions Design .
* Copyright ( c ) 2017 openmetaverse . co .
* All rights reserved .
*
* - Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* - Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
* - Neither the name of the openmetaverse . co nor the names
* of its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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 ;
using System.Collections.Generic ;
namespace LibreMetaverse
{
/// <summary>
/// Extension to the normal Dictionary. This class can store more than one value for every key. It keeps a HashSet for every Key value.
/// Calling Add with the same Key and multiple values will store each value under the same Key in the Dictionary. Obtaining the values
/// for a Key will return the HashSet with the Values of the Key.
/// </summary>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
2017-07-11 12:04:25 -05:00
public class MultiValueDictionary < TKey , TValue > : Dictionary < TKey , IList < TValue > >
2017-07-10 21:29:48 -05:00
{
/// <summary>
/// Adds the specified value under the specified key
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public void Add ( TKey key , TValue value )
{
if ( key = = null ) throw new ArgumentNullException ( nameof ( key ) ) ;
2017-07-11 12:12:06 -05:00
IList < TValue > container ;
if ( ! TryGetValue ( key , out container ) )
2017-07-10 21:29:48 -05:00
{
container = new List < TValue > ( ) ;
base . Add ( key , container ) ;
}
container . Add ( value ) ;
}
/// <summary>
/// Determines whether this dictionary contains the specified value for the specified key
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <returns>true if the value is stored for the specified key in this dictionary, false otherwise</returns>
public bool ContainsValue ( TKey key , TValue value )
{
if ( key = = null ) throw new ArgumentNullException ( nameof ( key ) ) ;
bool toReturn = false ;
2017-07-11 12:12:06 -05:00
IList < TValue > values ;
if ( TryGetValue ( key , out values ) )
2017-07-10 21:29:48 -05:00
{
toReturn = values . Contains ( value ) ;
}
return toReturn ;
}
/// <summary>
/// Removes the specified value for the specified key. It will leave the key in the dictionary.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public void Remove ( TKey key , TValue value )
{
if ( key = = null ) throw new ArgumentNullException ( nameof ( key ) ) ;
2017-07-11 12:12:06 -05:00
IList < TValue > container ;
if ( TryGetValue ( key , out container ) )
2017-07-10 21:29:48 -05:00
{
container . Remove ( value ) ;
if ( container . Count < = 0 )
{
2017-07-11 12:04:25 -05:00
Remove ( key ) ;
2017-07-10 21:29:48 -05:00
}
}
}
/// <summary>
/// Merges the specified multivaluedictionary into this instance.
/// </summary>
/// <param name="toMergeWith">To merge with.</param>
public void Merge ( MultiValueDictionary < TKey , TValue > toMergeWith )
{
if ( toMergeWith = = null )
{
return ;
}
2017-07-11 12:04:25 -05:00
foreach ( var pair in toMergeWith )
2017-07-10 21:29:48 -05:00
{
foreach ( TValue value in pair . Value )
{
2017-07-11 12:04:25 -05:00
Add ( pair . Key , value ) ;
2017-07-10 21:29:48 -05:00
}
}
}
/// <summary>
/// Gets the values for the key specified. This method is useful if you want to avoid an exception for key value retrieval and you can't use TryGetValue
/// (e.g. in lambdas)
/// </summary>
/// <param name="key">The key.</param>
/// <param name="returnEmptySet">if set to true and the key isn't found, an empty hashset is returned, otherwise, if the key isn't found, null is returned</param>
/// <returns>
/// This method will return null (or an empty set if returnEmptySet is true) if the key wasn't found, or
/// the values if key was found.
/// </returns>
2017-07-11 12:04:25 -05:00
public IList < TValue > GetValues ( TKey key , bool returnEmptySet )
2017-07-10 21:29:48 -05:00
{
2017-07-11 12:12:06 -05:00
IList < TValue > toReturn ;
if ( ! TryGetValue ( key , out toReturn ) & & returnEmptySet )
2017-07-10 21:29:48 -05:00
{
toReturn = new List < TValue > ( ) ;
}
return toReturn ;
}
}
}