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
/*
*/
#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