using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Developpez.Dotnet.Collections
{
///
/// Dictionnaire qui maintient ses éléments dans l'ordre où ils ont été ajoutés
///
/// Type de la clé
/// Type de la valeur
public class OrderedDictionary : IDictionary
{
private readonly object _syncLock = new object();
private readonly Dictionary>> _nodes;
private readonly LinkedList> _entries;
///
/// Initialise une nouvelle instance vide de OrderedDictionary, qui utilise
/// le comparateur spécifié pour tester l'égalité des clés.
///
/// Comparateur utilisé pour tester l'égalité des clés
public OrderedDictionary(IEqualityComparer comparer)
{
_nodes = new Dictionary>>(comparer);
_entries = new LinkedList>();
}
///
/// Initialise une nouvelle instance vide de OrderedDictionary
///
public OrderedDictionary()
: this (default(IEqualityComparer))
{
}
///
/// Initialise une nouvelle instance de OrderedDictionary qui contient les
/// éléments du dictionnaire spécifié et utilise le comparateur spécifié
/// pour tester l'égalité des clés.
///
/// Dictionnaire à partir duquel copier les éléments
/// Comparateur utilisé pour tester l'égalité des clés
public OrderedDictionary(IDictionary dictionary, IEqualityComparer comparer)
: this(comparer)
{
foreach (var kvp in dictionary)
{
this.Add(kvp.Key, kvp.Value);
}
}
///
/// Initialise une nouvelle instance de OrderedDictionary qui contient les
/// éléments du dictionnaire spécifié.
///
/// Dictionnaire à partir duquel copier les éléments
public OrderedDictionary(IDictionary dictionary)
: this(dictionary, null)
{
}
#region Implementation of IEnumerable
///
/// Retourne un énumérateur qui parcourt le dictionnaire
///
/// Un énumerateur pour parcourir le dictionnaire
public IEnumerator> GetEnumerator()
{
return _entries.GetEnumerator();
}
///
/// Retourne un énumérateur qui parcourt le dictionnaire
///
/// Un énumerateur pour parcourir le dictionnaire
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region Implementation of ICollection>
///
/// Ajoute la paire clé/valeur spécifiée au dictionnaire
///
/// Paire clé/valeur à ajouter
public void Add(KeyValuePair item)
{
Add(item.Key, item.Value);
}
///
/// Supprime toutes les clés et les valeurs du dictionnaire.
///
public void Clear()
{
lock (_syncLock)
{
_entries.Clear();
_nodes.Clear();
}
}
///
/// Détermine si le dictionnaire contient la paire clé/valeur spécifiée.
///
/// Paire clé/valeur recherchée
/// true si le dictionnaire contient la paire clé/valeur, false sinon
public bool Contains(KeyValuePair item)
{
lock (_syncLock)
{
TValue value;
if (TryGetValue(item.Key, out value))
return EqualityComparer.Default.Equals(item.Value, value);
return false;
}
}
///
/// Copie les éléments du dictionnaire dans un tableau, à partir de la position spécifiée
///
/// Tableau de destination
/// Index du tableau où commencer la copie
public void CopyTo(KeyValuePair[] array, int arrayIndex)
{
lock (_syncLock)
{
this.CopyTo(array, arrayIndex);
}
}
///
/// Supprime du dictionnaire la paire clé/valeur spécifiée.
///
/// Paire clé/valeur
/// true si la recherche et la suppression de l'élément réussissent ; sinon, false.
public bool Remove(KeyValuePair item)
{
lock (_syncLock)
{
LinkedListNode> node;
if (_nodes.TryGetValue(item.Key, out node))
{
if (EqualityComparer.Default.Equals(item.Value, node.Value.Value))
return Remove(item.Key);
}
return false;
}
}
///
/// Obtient le nombre de paires clé/valeur contenues dans le dictionnaire.
///
public int Count
{
get { return _nodes.Count; }
}
///
/// Obtient une valeur indiquant si le dictionnaire est en lecture seule.
///
public bool IsReadOnly
{
get { return false; }
}
#endregion
#region Implementation of IDictionary
///
/// Détermine si le dictionnaire contient la clé spécifiée.
///
/// Clé à rechercher
/// true si le dictionnaire contient un élément correspondant à la clé spécifiée ; sinon, false.
/// Cette méthode est proche d'une opération en O(1).
public bool ContainsKey(TKey key)
{
return _nodes.ContainsKey(key);
}
///
/// Ajoute la clé et la valeur spécifiées au dictionnaire.
///
/// Clé de l'élément à ajouter.
/// Valeur de l'élément à ajouter. La valeur peut être null pour les types référence.
/// Cette méthode est proche d'une opération en O(1) si la capacité interne est suffisante.
/// Si la capacité doit être augmentée, cette méthode devient une opération en O(n).
public void Add(TKey key, TValue value)
{
lock (_syncLock)
{
var entry = new KeyValuePair(key, value);
var node = new LinkedListNode>(entry);
_nodes.Add(key, node);
_entries.AddLast(node);
}
}
///
/// Supprime du dictionnaire la valeur ayant la clé spécifiée.
///
/// Clé de l'élément à supprimer.
/// true si la recherche et la suppression de l'élément réussissent ; sinon, false.
/// Cette méthode est proche d'une opération en O(1).
public bool Remove(TKey key)
{
lock (_syncLock)
{
LinkedListNode> node;
if (_nodes.TryGetValue(key, out node))
{
_nodes.Remove(key);
_entries.Remove(node);
return true;
}
return false;
}
}
///
/// Obtient la valeur associée à la clé spécifiée.
///
/// Clé de la valeur à obtenir.
/// Paramètre de sortie auquel est affecté la valeur trouvée
/// true si le dictionnaire contient un élément correspondant à la clé spécifiée ; sinon, false.
/// Cette méthode est proche d'une opération en O(1).
public bool TryGetValue(TKey key, out TValue value)
{
LinkedListNode> node;
if (_nodes.TryGetValue(key, out node))
{
value = node.Value.Value;
return true;
}
value = default(TValue);
return false;
}
///
/// Obtient ou définit la valeur associée à la clé spécifiée.
///
/// Clé de l'élément à obtenir ou à définir
/// Valeur associée à la clé spécifiée. Si la clé spécifiée est introuvable, une opération Get retourne KeyNotFoundException et une opération Set crée un nouvel élément avec la clé spécifiée.
/// Obtenir la valeur de cette propriété est proche d'une opération en O(1). Définir la valeur
/// de cette propriété est proche d'une opération en O(1) si la capacité interne est suffisante
/// ou que la clé est déjà présente dans le dictionnaire. Si la clé n'est pas déjà présente et que
/// la capacité doit être augmentée, définir la valeur devient une opération en O(n).
public TValue this[TKey key]
{
get
{
lock (_syncLock)
{
TValue value;
if (TryGetValue(key, out value))
return value;
throw new KeyNotFoundException();
}
}
set
{
lock (_syncLock)
{
LinkedListNode> node;
if (_nodes.TryGetValue(key, out node))
{
node.Value = new KeyValuePair(key, value);
}
else
{
Add(key, value);
}
}
}
}
///
/// Obtient une collection contenant les clés du dictionnaire.
///
/// Les clés sont renvoyées dans l'ordre où elles ont été ajoutées.
public ICollection Keys
{
get
{
lock (_syncLock)
{
var keys = _entries.Select(e => e.Key);
return keys.ToList().AsReadOnly();
}
}
}
///
/// Obtient une collection contenant les valeurs du dictionnaire.
///
/// Les valeurs sont renvoyées dans l'ordre où elles ont été ajoutées.
public ICollection Values
{
get
{
lock (_syncLock)
{
var values = _entries.Select(e => e.Value);
return values.ToList().AsReadOnly();
}
}
}
#endregion
}
}