// Copyright (c) 2020 Sergey Ivonchik // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE // OR OTHER DEALINGS IN THE SOFTWARE. using System.Collections; using System.Collections.Generic; using System.Linq; namespace Httx.Caches.Collections { /// /// Works as equivalent of LinkedHashMap from JDK if accessOrder = true. /// public class LinkedDictionary : IDictionary { private readonly Dictionary>> impl; private readonly LinkedList> policy; public LinkedDictionary() { impl = new Dictionary>>(); policy = new LinkedList>(); } public void Add(TKey key, TValue value) { var pair = new KeyValuePair(key, value); var node = new LinkedListNode>(pair); policy.AddLast(node); impl.Add(key, node); } public bool Remove(TKey key) { impl.TryGetValue(key, out var node); if (null == node) { return false; } policy.Remove(node); return impl.Remove(key); } public bool TryGetValue(TKey key, out TValue value) { impl.TryGetValue(key, out var node); if (null != node) { policy.Remove(node); policy.AddLast(node); value = node.Value.Value; return true; } value = default; return false; } public TValue this[TKey key] { get { TryGetValue(key, out var value); if (null == value) { throw new KeyNotFoundException(); } return value; } set => Add(key, value); } public void Clear() { impl.Clear(); policy.Clear(); } public void CopyTo(KeyValuePair[] array, int arrayIndex) => policy.CopyTo(array, arrayIndex); public bool Contains(KeyValuePair p) => policy.Contains(p); public bool ContainsKey(TKey key) => impl.ContainsKey(key); public void Add(KeyValuePair p) => Add(p.Key, p.Value); public bool Remove(KeyValuePair p) => Remove(p.Key); public int Count => policy.Count; public bool IsReadOnly => false; public IEnumerator> GetEnumerator() => policy.GetEnumerator(); public ICollection Keys => policy.Select(p => p.Key).ToList(); public ICollection Values => policy.Select(p => p.Value).ToList(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } }