/****************************************************************************
* tseries.h :
* header file for time series class.
*
* Change Log :
* July-28-1997 Initial version, Liujian Qian
*
* $Id: gtseries.h,v 1.9 1999/02/03 07:41:25 qian Exp $
***************************************************************************/
#ifndef _TIMESERIES_H_
#define _TIMESERIES_H_
#include "gadt.h"
#include "gadt_time.h"
class GEpisode;
/**
* @internal
*
* GEpisodePool
*
*
* THis class manages a pool of GEpisodes. This is meant to speed up
* the allocation/freeing of individual GEpisodes. The pool is
* extended with POOL_DELTA structures of GEpisodes each time.
* It is a globaly shared pool.
*/
class GEpisodePool
{
enum {POOL_DELTA = 400};
static int n_total;
static int n_free;
static GEpisode* pool;
public:
/**
*/
~GEpisodePool() {freeAll(); };
/**
* allocate an episode record from the pool
*/
static GEpisode* allocEpisode();
/**
* free an episode record and put it back to the pool
*/
static void freeEpisode(GEpisode* ep);
/**
* extend the capacity of the pool w/ 'incr' of new episodes
*/
static Result extendPool(int incr=POOL_DELTA);
/**
* free all episodes; vacate the pool
*/
static void freeAll();
static void printStats (){
cout<<"total episodes allocated: "
<<n_total<<", free episodes: "
<<n_free<<endl;
}
};
/**
* @short The unit of a time series.
*
* This class represents an episode (or an event) in a time series.
* GEpisode is the unit of time series. Each episode has a timestamp
* and an event descriptor which is not interpreted by this class.
*/
class GEpisode : public GTimestamp
{
char evt_desc[8];
GEpisode* prev; // for linking episodes
GEpisode* next;
friend class GEpisodePool;
friend class GTimeSeries;
public:
/**
*/
GEpisode () :prev(0),next(0) { memset(evt_desc, 0, 8); }
/**
*/
GEpisode (const GDate& d) : GTimestamp(d) { memset(evt_desc, 0, 8); }
/**
*/
GEpisode (int year):GTimestamp(year), prev(0),next(0) { memset(evt_desc, 0, 8); }
/**
*/
GEpisode (int year, int mon, int day, int hour=0, int min=0, int sec=0)
:GTimestamp(year, mon, day, hour, min, sec), prev(0), next(0)
{ memset(evt_desc, 0, 8); }
GEpisode(const GEpisode& a);
virtual ~GEpisode() {};
// GROUP: GEpisode specific methods.
/**
* return pointer to the next episode
*/
GEpisode* nextEpisode(void) const {return next; }
/**
* return previous episode (the one whose timestamp is smaller/earlier)
*/
GEpisode* prevEpisode(void) const {return prev; }
/**
* return the event descriptor; desc must be preallocated w/ >= 8 bytes.
*/
char* desc(void) {return evt_desc;}
/**
* set the event descriptor
*/
void setDesc (const char* desc) {
if(!desc) { msgWarn("invalid evt desc!"); }
else memcpy(evt_desc, desc, 8);
}
/**
* set the specific date
*/
void setDate (int year, int mon, int day, int hour=0, int min=0, int sec=0);
/**
* set the timestamp
*/
void setTimestamp(const GTimestamp& st) { GTimestamp::operator=(st); };
/**
*/
void * operator new(size_t){ return GEpisodePool::allocEpisode();}
/**
*/
void operator delete(void* ep, size_t){ GEpisodePool::freeEpisode( (GEpisode*)ep);}
friend ostream& operator<<(ostream& o, const GEpisode& e);
};
/**
* direction for scanning a time series
*/
enum TimeDir {FORWARD=0, BACKWARD=1};
/**
* @short GTimeSeries manages a time series.
A time series is simply a list of episodes of (TIMESTAMP, EVENT_DESC),
where the TIMESTAMP is the time an event of interest happened.
The event here is a rather broad concept, it can be virtualy
anything worthing recording. THe EVENT_DESC is a pointer (not the actual
entity) to a record of the associated event. One
use of the EVENT_DESC is to store an record ID of an externaly stored
event. But it is really an opaque data structure as far as time series
is concerned.
When the list of episodes are sorted (as they always are), the order
is that the older (earlier) the episode, the smaller the value.
The main methods for GTimeSeries includes: inserting/deleting,
iterating and generalizing the timestamps etc.
When iterating the series, first call firstEpisode() or lastEpisode(),
depending on which direction you want to scan the episodes, which
will return a pointer to the correct episode; then call that episode's
nextEpisode() or prevEpisode() correspondingly.
Note: the time series stores only the pointer to episodes! So if you
want to store two episodes, they must be physically different
objects (allocated using two new() opeations). If you just
allocate one episode, and try to add two episodes to the series
by assigning two different timestamp to the same episode object,
it won't work! The doubly-linked list will be messed up if you
add the same objects twice!
Also note that it uses the GTimestamp class extensively, but
GTimeSeries isn't an ADT per se., aka, it can't be stored in a
database.
*/
class GTimeSeries
{
public:
// GROUP:: ctor/dtor
/**
*/
GTimeSeries(TimeUnit u=_DAY): n_episodes(0), sorted(0),
first(0), t_unit(u), last_active(0) {};
GTimeSeries& operator= (const GTimeSeries& a);
/**
*/
~GTimeSeries();
/**
* set the unit time for the series
*/
void setTimeUnit(TimeUnit u) { t_unit=u;};
/**
* return the current time unit for the series
*/
TimeUnit timeUnit(void) const { return t_unit; }
/**
* add an episode into the series (in sorted order)
*/
Result addEpisode(GEpisode* r);
/**
* delete an episode from the series (and put back to the pool)
*/
Result delEpisode(GEpisode* r);
/**
* For every 'delta' time unit between 'from' (included) and 'to',
* generate an episode and add the episode to the series. The
* newly added episodes will be in sorted order.
*/
Result addRange(const GDate& from, const GDate& to, int delta=1);
/**
* same as above, except it accepts GTimestamps
*/
Result addRange(const GTimestamp& begin, const GTimestamp& end, int delta=1);
/**
* delete all the episodes and reset to the new time unit if different
*/
Result reset(TimeUnit u=_INVALID);
/**
* return number of episodes in the series
*/
int numEpisodes(void) const {return n_episodes; }
/**
* return the first episodes in the series
*/
GEpisode* firstEpisode(void) const {return first; }
/**
* return the last episode (most recent one)
*/
GEpisode* lastEpisode(void) {return first->prev;};
/**
* generalize the series to a larger unit (eg, hours -> days)
*/
Result generalize(TimeUnit new_unit);
/**
* return true if the series is empty
*/
bool isEmpty(void) { return n_episodes==0; }
friend ostream& operator<<(ostream& os, const GTimeSeries& t);
private:
Result deleteAllEpisodes(void);
friend class GTimeSeriesItr;
int n_episodes;
short sorted; //0: not sorted; 1: ascend; 2:descend
GEpisode* first; //first episode
TimeUnit t_unit; //hours, days, months, years...
GEpisode* last_active; //for speeding purpose (alwyas keep last
//active episode (the one last looked at,
//just inserted, et al)
};
/**
An iterator class for a time series object.
This is the iterator class for the GTimeSeries class. It steps through
individual episodes (either backwards or forwards).
*/
class GTimeSeriesItr
{
GTimeSeries* series;
GTimestamp starting;
GEpisode episode;
TimeDir dir; //backward or forward
int idx;
bool end;
GEpisode ep;
public:
GTimeSeriesItr();
GTimeSeriesItr(GTimeSeries* ser, TimeDir dir=FORWARD);
GTimeSeriesItr(GTimeSeries* ser, GTimestamp& begin, TimeDir _dir=FORWARD);
virtual ~GTimeSeriesItr() {}
// GROUP: common iterating methods
/**
* 'what' to iterate on
*/
virtual void reset(const GADT* what=0) ;
/**
* true if have more elements.
*/
virtual bool more() const ;
/**
* return next avialable episode
*/
GEpisode& next() ;
/**
* set the series to iterate on
*/
void seGTimeSeries(GTimeSeries* ser);
/**
* set the direction to iterate
*/
void setDirection(TimeDir direction);
/**
* return the current iterating direction
*/
TimeDir direction();
};
#endif
Documentation generated by lqian@lqian-sun on Wed Jul 14 09:36:10 EDT 1999