/* * Copyright (c) 2006-2014, openmetaverse.org * 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.org 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.Threading; using System.Collections.Generic; #if VISUAL_STUDIO using ReaderWriterLockImpl = System.Threading.ReaderWriterLockSlim; #else using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim; #endif namespace OpenMetaverse { public class DoubleDictionary { Dictionary Dictionary1; Dictionary Dictionary2; ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl(); public DoubleDictionary() { Dictionary1 = new Dictionary(); Dictionary2 = new Dictionary(); } public DoubleDictionary(int capacity) { Dictionary1 = new Dictionary(capacity); Dictionary2 = new Dictionary(capacity); } public void Add(TKey1 key1, TKey2 key2, TValue value) { rwLock.EnterWriteLock(); try { if (Dictionary1.ContainsKey(key1)) { if (!Dictionary2.ContainsKey(key2)) throw new ArgumentException("key1 exists in the dictionary but not key2"); } else if (Dictionary2.ContainsKey(key2)) { if (!Dictionary1.ContainsKey(key1)) throw new ArgumentException("key2 exists in the dictionary but not key1"); } Dictionary1[key1] = value; Dictionary2[key2] = value; } finally { rwLock.ExitWriteLock(); } } public bool Remove(TKey1 key1, TKey2 key2) { bool success; rwLock.EnterWriteLock(); try { Dictionary1.Remove(key1); success = Dictionary2.Remove(key2); } finally { rwLock.ExitWriteLock(); } return success; } public bool Remove(TKey1 key1) { bool found = false; rwLock.EnterWriteLock(); try { // This is an O(n) operation! TValue value; if (Dictionary1.TryGetValue(key1, out value)) { foreach (KeyValuePair kvp in Dictionary2) { if (kvp.Value.Equals(value)) { Dictionary1.Remove(key1); Dictionary2.Remove(kvp.Key); found = true; break; } } } } finally { rwLock.ExitWriteLock(); } return found; } public bool Remove(TKey2 key2) { bool found = false; rwLock.EnterWriteLock(); try { // This is an O(n) operation! TValue value; if (Dictionary2.TryGetValue(key2, out value)) { foreach (KeyValuePair kvp in Dictionary1) { if (kvp.Value.Equals(value)) { Dictionary2.Remove(key2); Dictionary1.Remove(kvp.Key); found = true; break; } } } } finally { rwLock.ExitWriteLock(); } return found; } public void Clear() { rwLock.EnterWriteLock(); try { Dictionary1.Clear(); Dictionary2.Clear(); } finally { rwLock.ExitWriteLock(); } } public int Count { get { return Dictionary1.Count; } } public bool ContainsKey(TKey1 key) { return Dictionary1.ContainsKey(key); } public bool ContainsKey(TKey2 key) { return Dictionary2.ContainsKey(key); } public bool TryGetValue(TKey1 key, out TValue value) { bool success; rwLock.EnterReadLock(); try { success = Dictionary1.TryGetValue(key, out value); } finally { rwLock.ExitReadLock(); } return success; } public bool TryGetValue(TKey2 key, out TValue value) { bool success; rwLock.EnterReadLock(); try { success = Dictionary2.TryGetValue(key, out value); } finally { rwLock.ExitReadLock(); } return success; } public void ForEach(Action action) { rwLock.EnterReadLock(); try { foreach (TValue value in Dictionary1.Values) action(value); } finally { rwLock.ExitReadLock(); } } public void ForEach(Action> action) { rwLock.EnterReadLock(); try { foreach (KeyValuePair entry in Dictionary1) action(entry); } finally { rwLock.ExitReadLock(); } } public void ForEach(Action> action) { rwLock.EnterReadLock(); try { foreach (KeyValuePair entry in Dictionary2) action(entry); } finally { rwLock.ExitReadLock(); } } public TValue FindValue(Predicate predicate) { rwLock.EnterReadLock(); try { foreach (TValue value in Dictionary1.Values) { if (predicate(value)) return value; } } finally { rwLock.ExitReadLock(); } return default(TValue); } public IList FindAll(Predicate predicate) { IList list = new List(); rwLock.EnterReadLock(); try { foreach (TValue value in Dictionary1.Values) { if (predicate(value)) list.Add(value); } } finally { rwLock.ExitReadLock(); } return list; } public int RemoveAll(Predicate predicate) { IList list = new List(); rwLock.EnterUpgradeableReadLock(); try { foreach (KeyValuePair kvp in Dictionary1) { if (predicate(kvp.Value)) list.Add(kvp.Key); } IList list2 = new List(list.Count); foreach (KeyValuePair kvp in Dictionary2) { if (predicate(kvp.Value)) list2.Add(kvp.Key); } rwLock.EnterWriteLock(); try { for (int i = 0; i < list.Count; i++) Dictionary1.Remove(list[i]); for (int i = 0; i < list2.Count; i++) Dictionary2.Remove(list2[i]); } finally { rwLock.ExitWriteLock(); } } finally { rwLock.ExitUpgradeableReadLock(); } return list.Count; } } }