summaryrefslogtreecommitdiff
path: root/cache.h
blob: 1fd08113e8e960771a58f3bf28670483c9bacc17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * $Id: cache.h,v 1.4 2004/06/16 18:46:50 lordjaxom Exp $
 */

#ifndef VDR_TEXT2SKIN_CACHE_HPP
#define VDR_TEXT2SKIN_CACHE_HPP

#include "common.h"
#include <vdr/tools.h>

// template class generic cache

template<class K,class D>
class cText2SkinCache {
private:
	struct Item {
		K      _key;
		D      _data;
		time_t _lastUsed;

		Item  *_next;
		Item  *_prev;

		Item() { _next = _prev = NULL; }
	};

	typedef map <K,Item*> DataMap;

	DataMap _items;
	int     _maxItems;
	Item   *_first;
	Item   *_last;
	
	void Unlink(Item *item);
	void Update(Item *item);
	void Delete(Item *item);
	void Delete(K &key, D &data);

public:
	cText2SkinCache(int maxItems);
	~cText2SkinCache();

	void Flush(void);
	bool Contains(const K &key);
	D &operator[](const K &key);
};

template<class K,class D>
inline void cText2SkinCache<K,D>::Unlink(Item *item) {
	if (item == _first) {
		_first = item->_next;
		if (_first)
			_first->_prev = NULL;
		else
			_last = NULL;
	} else if (item == _last) {
		_last = item->_prev;
		_last->_next = NULL;
	} else {
		item->_prev->_next = item->_next;
		item->_next->_prev = item->_prev;
	}
}

template<class K,class D>
inline void cText2SkinCache<K,D>::Delete(Item *item) {
	Delete(item->_key, item->_data);
	delete item;
}

template<class K,class D>
inline void cText2SkinCache<K,D>::Update(Item *item) {
	item->_lastUsed = time_ms();
	if (item->_next != NULL || item->_prev != NULL)
		Unlink(item);

	item->_next = NULL;
	item->_prev = _last;
	if (_last)
		_last->_next = item;
	_last = item;
	if (!_first)
		_first = item;

	while ((int)_items.size() > _maxItems) {
		Item *aged = _first;
		_items.erase(aged->_key);
		Unlink(aged);
		Delete(aged);
	}
}

template<class K,class D>
inline bool cText2SkinCache<K,D>::Contains(const K &key) {
	return (_items.find(key) != _items.end());
}

template<class K,class D>
cText2SkinCache<K,D>::cText2SkinCache(int maxItems) {
	_maxItems = maxItems;
	_first = _last = NULL;
}

template<class K,class D>
cText2SkinCache<K,D>::~cText2SkinCache() {
	Flush();
}

template<class K,class D>
void cText2SkinCache<K,D>::Delete(K &key, D &Data) {
	abort();
}

template<class K,class D>
void cText2SkinCache<K,D>::Flush(void) {
	Item *cur = _first;
	while (cur) {
		Item *tmp = cur->_next;
		_items.erase(cur->_key);
		Unlink(cur);
		Delete(cur);
		cur = tmp;
	}
}

template<class K,class D>
D &cText2SkinCache<K,D>::operator[](const K &key) {
	Item *item;
	if (Contains(key)) {
		item = _items[key];
	} else {
		item = new Item;
		item->_key = key;
		_items[key] = item;
	}
	Update(item);
	return item->_data;
}

#endif // VDR_TEXT2SKIN_CACHE_HPP