module gedo.system.cache;



import std.cstream;



class Cache(T, uint N)
{
private:
	struct Container
	{
		uint date;
		uint size;
		T    instance;
	}


	Container[string] _container;
	uint              _date = 0;
	uint              _size = 0;


	void releaseOld()
	{
		if(_container.length == 0)
		{
			throw new Error("cache full!");
		}

		auto oldate = uint.max;

		foreach(c; _container)
		{
			if(c.date < oldate)
			{
				oldate = c.date;
			}
		}

		string oldkey;
		foreach(k, v; _container)
		{
			if(v.date == oldate)
			{
				if(k in _container)
				{
					_size -= v.size;
					oldkey = k;
				}
				else
				{
					dout.writefln("gedo.system.cache: invalid key(%s)", k);
				}
				break;
			}
		}

		if(oldkey.length > 0)
		{
			_container.remove(oldkey);
		}
		else
		{
			_container = null;
			_date = _size = 0;
		}
	}


public:
	T get(string name, T delegate(out uint size) dg)
	{
		if(auto p = name in _container)
		{
			p.date = _date++;
			return p.instance;
		}
		else
		{
			while(_size > N)
			{
				releaseOld();
			}

			Container c;

			c.instance = dg(c.size);

			c.date = _date++;

			_container[name] = c;

			_size += c.size;

			return c.instance;
		}
	}


	void clear()
	{
		_container = null;
	}
}
