QUB_Freezer.h.html mathcode2html   
 Source file:   QUB_Freezer.h
 Converted:   Mon Mar 16 2015 at 09:48:41
 This documentation file will not reflect any later changes in the source file.

$$\phantom{******** If you see this on the webpage then the browser could not locate *********}$$
$$\phantom{******** jsMath/easy/load.js or the variable root is set wrong in this file *********}$$
$$\newcommand{\vector}[1]{\left[\begin{array}{c} #1 \end{array}\right]}$$ $$\newenvironment{matrix}{\left[\begin{array}{cccccccccc}} {\end{array}\right]}$$ $$\newcommand{\A}{{\cal A}}$$ $$\newcommand{\W}{{\cal W}}$$

/* Copyright 2002-2014 Research Foundation State University of New York   */

/* This file is part of QUB Express.                                      */

/* QUB Express is free software; you can redistribute it and/or modify    */
/* it under the terms of the GNU General Public License as published by   */
/* the Free Software Foundation, either version 3 of the License, or      */
/* (at your option) any later version.                                    */

/* QUB Express is distributed in the hope that it will be useful,         */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/* GNU General Public License for more details.                           */

/* You should have received a copy of the GNU General Public License,     */
/* named LICENSE.txt, in the QUB Express program directory.  If not, see  */
/* <http://www.gnu.org/licenses/>.                                        */

#ifndef QUB_FREEZER_H
#define QUB_FREEZER_H

/*
Up: Index
*/

#include <climits>
#include "QUB_Heap.h"

// you don't setup/clear a storage level unless the freezer says so or item is checked out


enum QUB_FreezerLevel {
	QUB_FS_0 = 0x1,
	QUB_FS_1 = 0x2,
	QUB_FS_2 = 0x4
};

#define QUB_FREEZER_INSIGNIFICANT 20
#define QUB_FREEZER_TIME2FREEZE 1.3


template<class T>
class QUB_FreezerInfo
{
public:

	T*  item;
	int size;
	int checkedOut;
	int storage;
	int seq;

	QUB_FreezerInfo( T *aitem )
		: item(aitem), size(aitem->size()), checkedOut(0), storage(aitem->getStorage())
	{}
	/*
	int getDeltaSize() // (update size)
	{
		int newsize = item->size();
		int delta = newsize - size;
		size = newsize;
		return delta;
	}
*/
	void checkOut() { ++checkedOut; }
	void checkIn() {
		--checkedOut;
		storage = item->getStorage();
		size = item->size();
	}

	bool hasStorage(int lvl) { return (0!=(storage & (0x1 << lvl))); }
	void setStorage(int lvl)
	{
		item->setupStorage(lvl);
		storage |= (1 << lvl);
	}
	void clearStorage(int lvl)
	{
		item->clearStorage(lvl);
		storage &= ~(1 << lvl);
	}
/*
	void updateStorage(int& added, int& removed)
	{
		added = removed = 0;
		int actualKept = item->getStorage();
		int actual = actualKept;

		int lvl, lvlb;
		for ( lvl=0, lvlb=0x1; actual; ++lvl, lvlb<<=1, actual>>=1 ) {
			bool actualSet = actual & 0x1;
			bool oldSet = (int) (storage & lvlb);
			if ( actualSet && ! oldSet )
				added |= lvlb;
			else if ( oldSet && ! actualSet )
				removed |= lvlb;
		}
		storage = actualKept;
	}
*/
};

template<class T>
class QUB_FreezerInfoRec
{
public:
	QUB_FreezerInfo<T> *info;
	QUB_FreezerInfoRec( QUB_FreezerInfo<T> *nfo )
		: info(nfo)
	{}
	
	bool operator< (const QUB_FreezerInfoRec<T>& other) const {
		return info->seq < other.info->seq;
	}
	bool operator== (const QUB_FreezerInfoRec<T>& other) const {
		return info == other.info;
	}
};


template<class T>
class QUB_FreezerSeries;


template<class T>
class QUB_Freezer
{
public:
	typedef QUB_FreezerInfo<T>    Info;
	typedef QUB_FreezerInfoRec<T> InfoRec;
	typedef QUB_Heap< InfoRec >   Ages;

	std::vector<int>  thresholds;
	std::vector<int>  levelSizes; // # at 0, # at 1, ...
	std::vector<Ages> ages;
	int               seq;

	void freezeAsNeeded()
	{
		for ( int lvl=0; lvl<int(thresholds.size()); ++lvl ) {
			if ( levelSizes[lvl] > thresholds[lvl] * QUB_FREEZER_TIME2FREEZE ) {
				while ( ages[lvl].size() ) {
					InfoRec info = ages[lvl].first();
					ages[lvl].pop();
					if ( ! info.info->hasStorage( lvl+1 ) ) {
						info.info->setStorage( lvl+1 );
						if ( lvl+1 < int(levelSizes.size()) ) {
							levelSizes[lvl+1] += info.info->size;
							ages[lvl+1].push( info );
						}
					}
					info.info->clearStorage(lvl);
					levelSizes[lvl] -= info.info->size;
				}
			}
		}
/*
		if ( ! thresholds.size() )
			return;

		int lvl;
		bool badEnough = false;
		for ( lvl=0; lvl<thresholds.size(); ++lvl ) {
			if ( levelSizes[lvl] > thresholds[lvl] * 1.2 ) {
				badEnough = true;
				break;
			}
		}
		if ( ! badEnough )
			return;

		Ages::iterator ai = ages.begin(); // ha ha going sequentially through a heap is not exactly correct, but maybe faster?
		lvl = 0;
		while ( true ) {
			if ( levelSizes[lvl] < thresholds[lvl] ) {
				++lvl;
				ai = ages.begin();
			}
			if ( lvl == thresholds.size() )
				break;
			if ( ai == ages.end() )
				break;

			if ( agesNeedsSort )
				ages.resort();

			if ( (! ai->info->checkedOut) && ai->info->hasStorage(lvl) && (ai->info->size > 10) ) {
				if ( ! ai->info->hasStorage(lvl+1) ) {
					ai->info->setStorage(lvl+1);
					levelSizes[lvl+1] += ai->info->size;
				}
				ai->info->clearStorage(lvl);
				levelSizes[lvl] -= ai->info->size;
			}
			++ai;
		}
*/
	}
		
	QUB_Freezer()
		: seq(INT_MAX)
	{}

	~QUB_Freezer()
	{
		/*
		for ( int i=0; i<ages.size(); ++i )
			if ( ages[i].size() )
				throw 1;
				*/
	}

	void setThreshold(int storageLevel, int count) // no more than count at or better than level
	{ // please call this before adding anything
		while ( int(thresholds.size()) <= storageLevel ) {
			thresholds.push_back( thresholds.size() ? thresholds[thresholds.size()-1] : 0 );
			levelSizes.push_back( 0 );
			ages.resize( ages.size() + 1 );
		}
		thresholds[ storageLevel ] = count;
	}

	void addInfo( Info *info )
	{
		info->seq = --seq;
		for ( int lvl=0; lvl<int(levelSizes.size()); ++lvl )
			if ( info->hasStorage(lvl) ) {
				levelSizes[lvl] += info->size;
				if ( info->size > QUB_FREEZER_INSIGNIFICANT )
					ages[lvl].push( InfoRec(info) );
			}
		freezeAsNeeded();
	}

	void remInfo( Info *info )
	{
		for ( int lvl=0; lvl<int(levelSizes.size()); ++lvl )
			if ( info->hasStorage(lvl) ) {
				levelSizes[lvl] -= info->size;
				if ( info->size > QUB_FREEZER_INSIGNIFICANT )
					ages[lvl].erase( InfoRec(info) );
			}
	}

	void checkOut( Info *info, int lvlBits )
	{
		if ( ! info->checkedOut )
			remInfo( info );
		info->checkOut();

		if ( ! (info->storage & lvlBits) ) {
		  int lvl, lvlb, nlevel = (int) levelSizes.size();
			for ( lvl=nlevel, lvlb=(0x1 << lvl); lvl>=0; --lvl, lvlb>>=1 ) {
				if ( lvlBits & lvlb ) {
					info->setStorage(lvl);
					break;
				}
			}
		}
	}

	void checkIn( Info *info, bool changed )
	{
		info->checkIn();

		if ( changed ) {
		  int lvl, minlevel, nlevel = (int) levelSizes.size();
			for ( minlevel = 0; minlevel < nlevel; ++minlevel ) {
				if ( info->hasStorage(minlevel) )
					break;
			}
			if ( minlevel < nlevel ) {
				info->clearStorage(nlevel);
				for ( lvl=nlevel-1; lvl>minlevel; --lvl ) {
					info->clearStorage(lvl);
				}
			}
		}

		if ( ! info->checkedOut )
			addInfo( info );
	}
};

template<class T>
class QUB_FreezerSeries
{
public:
	typedef QUB_FreezerInfo<T>    Info;
	typedef std::vector< Info* >       InfoList;

	QUB_Freezer<T> *freezer;
	InfoList        items;

	QUB_FreezerSeries( QUB_Freezer<T> *afreezer )
		: freezer( afreezer )
	{}

	~QUB_FreezerSeries()
	{
		truncate(0);
	}

	int size() { return (int) items.size(); }
	void truncate( int newsize )
	{
		while ( size() > newsize )
			erase( size() - 1 );
	}

	void insert( int ix, T* item )
	{
		Info *info = new Info( item );
		freezer->addInfo( info );
		if ( ix >= size() )
			items.push_back( info );
		else {
			typename InfoList::iterator ii = items.begin();
			for ( int i=0; i<ix; ++i )
				++ii;
			items.insert(ii, info);
		}
	}

	void erase( int ix )
	{
		//InfoList::iterator ii = items.begin();
		//for ( int i=0; i<ix; ++i )
		//	++ii;
		Info *info = items[ix];;
		items.erase( items.begin() + ix );
		freezer->remInfo( info );
		delete info->item;
		delete info;
	}

	T* checkOut( int ix, int lvlBits )
	{
		Info *info = items[ix];
		freezer->checkOut( info, lvlBits );
		return info->item;
	}

	void checkIn( int ix, bool changed )
	{
		Info *info = items[ix];
		freezer->checkIn( info, changed );
	}
};



/* int  T.size()
   void T.setupStorage(int lvl)
   void T.clearStorage(int lvl)
   bits T.getStorage()
*/

// storage levels (0 is the biggest most available, 1 is a little more frozen etc.)




#endif