Page 1 of 1

MruList

PostPosted: Fri Sep 02, 2011 3:07 am
by Charles
Here is a little MruList I whipped up. It has tests, but hasn't been tested much. Suggestions and fixes are welcome.
class MruList<of T> implements ICollection<of T>
"""
Store a "most recently used" list of items.
Calling .add puts the item at the front of the list.
Also, .add will not grow the list when it already contains a given item.
An MruList is enumerable, so you can use for loops on it, .toList, .numbered, .reversed, etc.

Because an MruList uses a dictionary internally for some caching, the item T should implement
both .equals and .getHashCode.

to-do: support a max capacity
"""

var _list = LinkedList<of T>()
var _dict = Dictionary<of T, LinkedListNode<of T>>()

def add(item as T)
if _list.count <= 4 # to-do: test what the real switchover should be
_list.remove(item)
else
lln as LinkedListNode<of T>?
if _dict.tryGetValue(item, out lln), _list.remove(lln)
_dict[item] = _list.addFirst(item) to !
assert _list.count == _dict.count

def clear
_list.clear
_dict.clear
assert _list.count == _dict.count

def contains(item as T) as bool
return _list.contains(item)

def copyTo(array as T[], arrayIndex as int)
_list.copyTo(array, arrayIndex)

get count as int
return _list.count

def getEnumerator as IEnumerator<of T>
return _list.getEnumerator

def getEnumerator as System.Collections.IEnumerator
implements System.Collections.IEnumerable
return .getEnumerator

get isReadOnly as bool
return false

def remove(item as T) as bool
_dict.remove(item)
r = _list.remove(item)
assert _list.count == _dict.count
return r

def set(items as IList<of T>)
"""
Set all the items in the MRU list.
There is no reversal of the items like if you called .add for each item.
Repeated items are forbidden and will cause an exception.
"""
.clear
for item in items, _dict[item] = _list.addLast(item) to !
if _dict.count <> _list.count, throw InvalidOperationException('repeated items in set list')


class TestMruList

test
ml = MruList<of String>()
assert ml.count == 0
ml.add('foo')
assert ml.count == 1
assert ml.contains('foo')
assert not ml.contains('bar')
assert ml.toList == ['foo']
ml.clear
assert ml.count == 0

ml = MruList<of String>()
ml.add('foo')
ml.add('bar')
assert ml.contains('foo')
assert ml.contains('bar')
assert ml.toList == ['bar', 'foo'] # note the mru order
ml.add('bar')
assert ml.toList == ['bar', 'foo']
ml.add('bar')
assert ml.toList == ['bar', 'foo']
ml.add('foo')
assert ml.toList == ['foo', 'bar']
ml.add('baz')
assert ml.toList == ['baz', 'foo', 'bar']

ml = MruList<of String>()
ml.set(['foo', 'bar', 'baz'])
assert ml.toList == ['foo', 'bar', 'baz']
ml.add('buzz')
assert ml.toList == ['buzz', 'foo', 'bar', 'baz']
ml.set(['foo', 'bar', 'baz'])
assert ml.toList == ['foo', 'bar', 'baz']

...Hmm that syntax highlighting doesn't look right.

Update 2011-09-05: Syntax highlighting fixed courtesy of Todd A.

Re: MruList

PostPosted: Mon Sep 05, 2011 6:33 pm
by torial
Can't say when (as I seem perpetually swamped) but when I get a chance, I'll see about adding this to Naja.

Re: MruList

PostPosted: Mon Sep 05, 2011 9:02 pm
by Charles
torial wrote:Can't say when (as I seem perpetually swamped) but when I get a chance, I'll see about adding this to Naja.

Sounds good.