/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
using System;
using System.Collections;
namespace Qpid.Collections
{
public class LinkedHashtable : IDictionary
{
///
/// Maps from key to LinkedDictionaryEntry
///
private Hashtable _indexedValues = new Hashtable();
private LinkedDictionaryEntry _head;
private LinkedDictionaryEntry _tail;
private class LinkedDictionaryEntry
{
public LinkedDictionaryEntry _previous;
public LinkedDictionaryEntry _next;
internal DictionaryEntry _entry;
public LinkedDictionaryEntry(object key, object value)
{
_entry = new DictionaryEntry(key, value);
}
}
public object this[object key]
{
get
{
LinkedDictionaryEntry entry = (LinkedDictionaryEntry)_indexedValues[key];
if (entry == null)
{
return null; // key not found
}
else
{
return entry._entry.Value;
}
}
set
{
LinkedDictionaryEntry entry = (LinkedDictionaryEntry)_indexedValues[key];
if (entry == null)
{
Add(key, value);
}
else
{
entry._entry.Value = value;
}
}
}
///
/// Collect keys in linked order.
///
public ICollection Keys
{
get
{
IList result = new ArrayList();
foreach (DictionaryEntry entry in this)
{
result.Add(entry.Key);
}
return result;
}
}
///
/// Collect values in linked order.
///
public ICollection Values
{
get
{
IList result = new ArrayList();
foreach (DictionaryEntry entry in this)
{
result.Add(entry.Value);
}
return result;
}
}
public bool IsReadOnly
{
get { return _indexedValues.IsReadOnly; }
}
public bool IsFixedSize
{
get { return _indexedValues.IsFixedSize; }
}
public bool Contains(object key)
{
return _indexedValues.Contains(key);
}
public void Add(object key, object value)
{
if (key == null) throw new ArgumentNullException("key");
if (Contains(key))
{
throw new ArgumentException("LinkedHashtable already contains key. key=" + key);
}
LinkedDictionaryEntry de = new LinkedDictionaryEntry(key, value);
if (_head == null)
{
_head = de;
_tail = de;
}
else
{
_tail._next = de;
de._previous = _tail;
_tail = de;
}
_indexedValues[key] = de;
}
public void Clear()
{
_indexedValues.Clear();
}
IDictionaryEnumerator IDictionary.GetEnumerator()
{
return new LHTEnumerator(this);
}
public void Remove(object key)
{
if (key == null) throw new ArgumentNullException("key");
LinkedDictionaryEntry de = (LinkedDictionaryEntry)_indexedValues[key];
if (de == null) return; // key not found.
LinkedDictionaryEntry prev = de._previous;
if (prev == null)
{
_head = de._next;
}
else
{
prev._next = de._next;
}
LinkedDictionaryEntry next = de._next;
if (next == null)
{
_tail = de;
}
else
{
next._previous = de._previous;
}
}
private LinkedDictionaryEntry Head
{
get
{
return _head;
}
}
private LinkedDictionaryEntry Tail
{
get
{
return _tail;
}
}
private class LHTEnumerator : IDictionaryEnumerator
{
private LinkedHashtable _container;
private LinkedDictionaryEntry _current;
///
/// Set once we have navigated off the end of the collection
///
private bool _needsReset = false;
public LHTEnumerator(LinkedHashtable container)
{
_container = container;
}
public object Current
{
get
{
if (_current == null)
{
throw new Exception("Iterator before first element");
}
else
{
return _current._entry;
}
}
}
public object Key
{
get { return _current._entry.Key; }
}
public object Value
{
get { return _current._entry.Value; }
}
public DictionaryEntry Entry
{
get
{
return _current._entry;
}
}
public bool MoveNext()
{
if (_needsReset)
{
return false;
}
else if (_current == null)
{
_current = _container.Head;
}
else
{
_current = _current._next;
}
_needsReset = (_current == null);
return !_needsReset;
}
public void Reset()
{
_current = null;
_needsReset = false;
}
}
public void MoveToHead(object key)
{
LinkedDictionaryEntry de = (LinkedDictionaryEntry)_indexedValues[key];
if (de == null)
{
throw new ArgumentException("Key " + key + " not found");
}
// if the head is the element then there is nothing to do
if (_head == de)
{
return;
}
de._previous._next = de._next;
if (de._next != null)
{
de._next._previous = de._previous;
}
else
{
_tail = de._previous;
}
de._next = _head;
_head = de;
de._previous = null;
}
public void CopyTo(Array array, int index)
{
_indexedValues.CopyTo(array, index);
}
public int Count
{
get { return _indexedValues.Count; }
}
public object SyncRoot
{
get { return _indexedValues.SyncRoot; }
}
public bool IsSynchronized
{
get { return _indexedValues.IsSynchronized; }
}
public IEnumerator GetEnumerator()
{
return new LHTEnumerator(this);
}
}
}