2004-05-06 19:14:30 +02:00
|
|
|
#ifndef ADTS_H__
|
|
|
|
#define ADTS_H__
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
#include "lib.h"
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
#include <cassert>
|
|
|
|
|
2004-06-04 14:41:53 +02:00
|
|
|
#include <list>
|
|
|
|
#include <map>
|
2004-05-06 19:14:30 +02:00
|
|
|
|
|
|
|
|
2004-06-11 04:14:18 +02:00
|
|
|
struct BIT_BUF
|
2004-05-06 19:14:30 +02:00
|
|
|
{
|
|
|
|
ulong buf;
|
|
|
|
ulong cur; /* bit to be appended (toggled by add()) */
|
|
|
|
ulong len; /* |buf| [bits] */
|
|
|
|
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
buf = 0;
|
|
|
|
cur = 0;
|
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* toggle current bit if desired, and add to buffer (new bit is LSB) */
|
|
|
|
void add(ulong toggle)
|
|
|
|
{
|
|
|
|
cur ^= toggle;
|
|
|
|
buf <<= 1;
|
|
|
|
buf |= cur;
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* extract LS n bits */
|
|
|
|
uint extract(ulong n)
|
|
|
|
{
|
|
|
|
ulong i = buf & ((1ul << n) - 1);
|
|
|
|
buf >>= n;
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
2004-06-11 04:14:18 +02:00
|
|
|
};
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
|
2004-06-14 15:27:33 +02:00
|
|
|
template<class T, size_t n> struct RingBuf
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
|
|
|
size_t size_; // # of entries in buffer
|
|
|
|
size_t pos; // index of oldest data
|
|
|
|
T data[n];
|
|
|
|
|
|
|
|
RingBuf() { clear(); }
|
|
|
|
void clear() { size_ = 0; pos = 0; }
|
|
|
|
size_t size() { return size_; }
|
|
|
|
|
2004-06-14 15:27:33 +02:00
|
|
|
const T& operator[](int ofs) const
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2004-06-14 15:27:33 +02:00
|
|
|
size_t idx = (size_t)(pos + ofs);
|
|
|
|
return data[idx % n];
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void push_back(const T& item)
|
|
|
|
{
|
|
|
|
if(size_ < n)
|
|
|
|
size_++;
|
|
|
|
|
|
|
|
data[pos] = item;
|
|
|
|
pos = (pos + 1) % n;
|
|
|
|
}
|
|
|
|
|
|
|
|
class const_iterator
|
|
|
|
{
|
|
|
|
public:
|
2004-05-06 19:14:30 +02:00
|
|
|
const_iterator() : data(0), pos(0)
|
|
|
|
{}
|
|
|
|
const_iterator(const T* _data, size_t _pos) : data(_data), pos(_pos)
|
|
|
|
{}
|
2004-03-03 00:56:51 +01:00
|
|
|
const T& operator[](int idx) const
|
2004-05-06 19:14:30 +02:00
|
|
|
{ return data[(pos+idx) % n]; }
|
2004-03-03 00:56:51 +01:00
|
|
|
const T& operator*() const
|
2004-06-27 03:42:17 +02:00
|
|
|
{ return data[pos % n]; }
|
2004-03-03 00:56:51 +01:00
|
|
|
const T* operator->() const
|
2004-05-06 19:14:30 +02:00
|
|
|
{ return &**this; }
|
2004-03-03 00:56:51 +01:00
|
|
|
const_iterator& operator++() // pre
|
2004-06-27 03:42:17 +02:00
|
|
|
{ ++pos; return (*this); }
|
2004-03-03 00:56:51 +01:00
|
|
|
const_iterator operator++(int) // post
|
2004-05-06 19:14:30 +02:00
|
|
|
{ const_iterator tmp = *this; ++*this; return tmp; }
|
2004-03-03 00:56:51 +01:00
|
|
|
bool operator==(const const_iterator& rhs) const
|
2004-06-27 03:42:17 +02:00
|
|
|
{ return data == rhs.data && pos == rhs.pos; }
|
2004-03-03 00:56:51 +01:00
|
|
|
bool operator!=(const const_iterator& rhs) const
|
2004-05-06 19:14:30 +02:00
|
|
|
{ return !(*this == rhs); }
|
2004-03-03 00:56:51 +01:00
|
|
|
protected:
|
|
|
|
const T* data;
|
|
|
|
size_t pos;
|
2004-06-27 03:42:17 +02:00
|
|
|
// not mod-N so that begin != end when buffer is full.
|
2004-03-03 00:56:51 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const_iterator begin() const
|
2004-06-27 03:42:17 +02:00
|
|
|
{
|
|
|
|
return const_iterator(data, (size_ < n)? 0 : pos);
|
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
const_iterator end() const
|
2004-06-27 03:42:17 +02:00
|
|
|
{
|
|
|
|
return const_iterator(data, (size_ < n)? size_ : pos+n);
|
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// cache
|
|
|
|
//
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
|
|
|
|
// owns a pool of resources (Entry-s), associated with a 64 bit id.
|
|
|
|
// typical use: add all available resources to the cache via grow();
|
|
|
|
// assign() ids to the resources, and update the resource data if necessary;
|
|
|
|
// retrieve() the resource, given id.
|
|
|
|
template<class Entry> class Cache
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
|
|
|
public:
|
2004-05-06 19:14:30 +02:00
|
|
|
// 'give' Entry to the cache.
|
|
|
|
int grow(Entry& e)
|
|
|
|
{
|
|
|
|
// add to front of LRU list, but not index
|
|
|
|
// (since we don't have an id yet)
|
2004-06-21 18:29:47 +02:00
|
|
|
lru_list.push_front(Line(e));
|
2004-05-06 19:14:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
// find the least-recently used line; associate id with it,
|
|
|
|
// and return its Entry. fails (returns 0) if id is already
|
|
|
|
// associated, or all lines are locked.
|
|
|
|
Entry* assign(u64 id)
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2004-05-06 19:14:30 +02:00
|
|
|
if(find_line(id))
|
|
|
|
{
|
2004-05-08 03:11:51 +02:00
|
|
|
debug_warn("assign: id already in cache!");
|
2004-05-06 19:14:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// scan in least->most used order for first non-locked entry
|
|
|
|
List_iterator l = lru_list.end();
|
|
|
|
while(l != lru_list.begin())
|
|
|
|
{
|
|
|
|
--l;
|
|
|
|
if(l->refs == 0)
|
|
|
|
goto have_line;
|
|
|
|
}
|
|
|
|
|
|
|
|
// all are locked and cannot be displaced.
|
|
|
|
// caller should grow() enough lines so that this never happens.
|
2004-05-08 03:11:51 +02:00
|
|
|
debug_warn("assign: all lines locked - grow() more lines");
|
2004-03-03 00:56:51 +01:00
|
|
|
return 0;
|
2004-05-06 19:14:30 +02:00
|
|
|
|
|
|
|
have_line:
|
|
|
|
|
|
|
|
// update mapping (index)
|
|
|
|
idx.erase(id);
|
|
|
|
idx[id] = l;
|
|
|
|
|
|
|
|
l->id = id;
|
|
|
|
return &l->ent;
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
|
|
|
|
// find line identified by id; return its entry or 0 if not in cache.
|
|
|
|
Entry* retrieve(u64 id)
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2004-05-06 19:14:30 +02:00
|
|
|
// invalid: id 0 denotes not-yet-associated lines
|
|
|
|
if(id == 0)
|
|
|
|
{
|
2004-05-08 03:11:51 +02:00
|
|
|
debug_warn("retrieve: id 0 not allowed");
|
2004-05-06 19:14:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
Line* l = find_line(id);
|
|
|
|
return l? &l->ent : 0;
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
|
|
|
|
// add/release a reference to a line, to protect it against
|
|
|
|
// displacement via associate(). we verify refs >= 0.
|
|
|
|
int lock(u64 id, bool locked)
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2004-05-06 19:14:30 +02:00
|
|
|
Line* l = find_line(id);
|
2004-03-03 00:56:51 +01:00
|
|
|
if(!l)
|
|
|
|
return -1;
|
2004-05-06 19:14:30 +02:00
|
|
|
|
|
|
|
if(locked)
|
|
|
|
l->refs++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(l->refs > 0);
|
|
|
|
l->refs--;
|
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
private:
|
|
|
|
// implementation:
|
|
|
|
// cache lines are stored in a list, most recently used in front.
|
2004-05-06 19:14:30 +02:00
|
|
|
// a map finds the list entry containing a given id in log-time.
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
struct Line
|
|
|
|
{
|
2004-05-06 19:14:30 +02:00
|
|
|
u64 id;
|
|
|
|
Entry ent;
|
|
|
|
int refs; // protect from displacement if > 0
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2004-06-21 18:29:47 +02:00
|
|
|
Line(Entry& _ent)
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2004-06-21 18:29:47 +02:00
|
|
|
id = 0;
|
2004-05-06 19:14:30 +02:00
|
|
|
ent = _ent;
|
|
|
|
refs = 0;
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::list<Line> List;
|
2004-05-06 19:14:30 +02:00
|
|
|
typedef typename List::iterator List_iterator;
|
2004-03-03 00:56:51 +01:00
|
|
|
List lru_list;
|
|
|
|
|
|
|
|
typedef std::map<u64, List_iterator> Map;
|
|
|
|
Map idx;
|
|
|
|
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
// return the line identified by id, or 0 if not in cache.
|
|
|
|
// mark it as the most recently used line.
|
|
|
|
Line* find_line(u64 id)
|
|
|
|
{
|
|
|
|
Map::const_iterator i = idx.find(id);
|
|
|
|
// not found
|
|
|
|
if(i == idx.end())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// index points us to list entry
|
|
|
|
List_iterator l = i->second;
|
|
|
|
|
|
|
|
// mark l as the most recently used line.
|
|
|
|
lru_list.splice(lru_list.begin(), lru_list, l);
|
|
|
|
idx[l->id] = l;
|
|
|
|
|
|
|
|
return &*l;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// from VFS, not currently needed
|
|
|
|
|
|
|
|
/*
|
|
|
|
template<class T> class StringMap
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
T* add(const char* fn, T& t)
|
|
|
|
{
|
|
|
|
const FnHash fn_hash = fnv_hash(fn);
|
|
|
|
|
|
|
|
t.name = fn;
|
|
|
|
|
|
|
|
std::pair<FnHash, T> item = std::make_pair(fn_hash, t);
|
|
|
|
std::pair<MapIt, bool> res;
|
|
|
|
res = map.insert(item);
|
|
|
|
|
|
|
|
if(!res.second)
|
|
|
|
{
|
2004-05-08 03:11:51 +02:00
|
|
|
debug_warn("add: already in container");
|
2004-05-06 19:14:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return address of user data (T) inserted into container.
|
|
|
|
return &((res.first)->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
T* find(const char* fn)
|
|
|
|
{
|
|
|
|
const FnHash fn_hash = fnv_hash(fn);
|
|
|
|
MapIt it = map.find(fn_hash);
|
|
|
|
// O(log(size))
|
|
|
|
if(it == map.end())
|
|
|
|
return 0;
|
|
|
|
return &it->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() const
|
|
|
|
{
|
|
|
|
return map.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
map.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
typedef std::map<FnHash, T> Map;
|
|
|
|
typedef typename Map::iterator MapIt;
|
|
|
|
Map map;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
class iterator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
iterator()
|
|
|
|
{}
|
|
|
|
iterator(typename StringMap<T>::MapIt _it)
|
|
|
|
{ it = _it; }
|
|
|
|
T& operator*() const
|
|
|
|
{ return it->second; }
|
|
|
|
T* operator->() const
|
|
|
|
{ return &**this; }
|
|
|
|
iterator& operator++() // pre
|
|
|
|
{ ++it; return (*this); }
|
|
|
|
bool operator==(const iterator& rhs) const
|
|
|
|
{ return it == rhs.it; }
|
|
|
|
bool operator!=(const iterator& rhs) const
|
|
|
|
{ return !(*this == rhs); }
|
|
|
|
protected:
|
|
|
|
typename StringMap<T>::MapIt it;
|
|
|
|
};
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
iterator begin()
|
|
|
|
{ return iterator(map.begin()); }
|
|
|
|
|
|
|
|
iterator end()
|
|
|
|
{ return iterator(map.end()); }
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class Key, class Data> class PriMap
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
int add(Key key, uint pri, Data& data)
|
|
|
|
{
|
|
|
|
Item item = std::make_pair(pri, data);
|
|
|
|
MapEntry ent = std::make_pair(key, item);
|
|
|
|
std::pair<MapIt, bool> ret;
|
|
|
|
ret = map.insert(ent);
|
|
|
|
// already in map
|
|
|
|
if(!ret.second)
|
|
|
|
{
|
|
|
|
MapIt it = ret.first;
|
|
|
|
Item item = it->second;
|
|
|
|
const uint old_pri = item.first;
|
|
|
|
Data& old_data = item.second;
|
|
|
|
|
|
|
|
// new data is of higher priority; replace older data
|
|
|
|
if(old_pri <= pri)
|
|
|
|
{
|
|
|
|
old_data = data;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// new data is of lower priority; don't add
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Data* find(Key key)
|
|
|
|
{
|
|
|
|
MapIt it = map.find(key);
|
|
|
|
if(it == map.end())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return &it->second.second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
map.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
typedef std::pair<uint, Data> Item;
|
|
|
|
typedef std::pair<Key, Item> MapEntry;
|
|
|
|
typedef std::map<Key, Item> Map;
|
|
|
|
typedef typename Map::iterator MapIt;
|
|
|
|
Map map;
|
2004-03-03 00:56:51 +01:00
|
|
|
};
|
2004-05-06 19:14:30 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif // #ifndef ADTS_H__
|