//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Interface AND implementation of CTimeIndexedList // // $Workfile: $ // $Date: $ // //------------------------------------------------------------------------------------------------------ // $Log: $ // // $NoKeywords: $ //=============================================================================// #ifndef TIMEINDEXEDLIST_H #define TIMEINDEXEDLIST_H #ifdef WIN32 #pragma once #endif #include #include "TFStatsApplication.h" #include "util.h" //------------------------------------------------------------------------------------------------------ // Purpose: CTimedIndexedList is a list of elements indexed by time_t's. // the elements of the list are meant to represent a state that endures over time // and when it is switched to another state, that is represented by an element in this // list with the value of the new state at index t, where t is the time that the switch // occured. // in TFStats, this is used for player names and player classes //------------------------------------------------------------------------------------------------------ template class CTimeIndexedList { public: static time_t PENDING; typedef struct{T data;time_t start; time_t end;} listtype; typedef std::list::iterator iterator; typedef std::map::iterator accumulatorIterator; typedef std::map accumulator; typedef std::list timelist; timelist theList; time_t endTime; bool anythingAtTime(time_t); T atTime(time_t,T errorvalue=T()); T favourite(T errorvalue=T()); CTimeIndexedList(); void add(time_t a,T b); bool contains(const T& t); accumulator accumulate(); time_t howLong(const T& t); iterator begin(); iterator end(); int size(); int numDifferent(); void cut(time_t t); void remove(T b); }; template time_t CTimeIndexedList::PENDING=-1; template CTimeIndexedList::CTimeIndexedList() { endTime=0; } //------------------------------------------------------------------------------------------------------ // Function: CTimeIndexedList::accumulate // Purpose: // Output: CTimeIndexedList::accumulator //------------------------------------------------------------------------------------------------------ template CTimeIndexedList::accumulator CTimeIndexedList::accumulate() { CTimeIndexedList::accumulator accum; //maps from a value of T, to the time that value was played /* //iterate through for debugging purposes { CTimeIndexedList::iterator it=theList.begin(); for (it;it!=theList.end();++it) { CTimeIndexedList::listtype lt=*it; } } */ CTimeIndexedList::iterator it=theList.begin(); for (it;it!=theList.end();++it) { time_t start=it->start; time_t end=it->end; T& bucket=it->data; if (end==PENDING) { end=endTime; if (end==0) { g_pApp->fatalError("Time flow error, make sure your log file\n"); } } accum[bucket]+=(end-start); } return accum; } //------------------------------------------------------------------------------------------------------ // Function: CTimeIndexedList::add // Purpose: // Input: a - // b - //------------------------------------------------------------------------------------------------------ template void CTimeIndexedList::add(time_t a,T b) { bool lastIsB=false; bool firstElement=false; listtype insertme; insertme.data=b; insertme.start=a; insertme.end=PENDING; if (!theList.empty()) { //find the last element and fix up its end-time (if it's pending) CTimeIndexedList::iterator last=theList.end(); last--; listtype lt=*last; if (last->end==PENDING && last->data!=b) last->end=insertme.start; } //add the new element! theList.push_back(insertme); if (a > endTime) endTime=a; } //------------------------------------------------------------------------------------------------------ // Function: CTimeIndexedList::atTime // Purpose: returns the element whose time index is the closest to and less than or // equal to the queried time // Input: tm - the time that is being queried // Output: T, the element //------------------------------------------------------------------------------------------------------ template T CTimeIndexedList::atTime(time_t tm,T errorvalue) { CTimeIndexedList::iterator it; if (theList.empty()) return errorvalue; //nothing exists here! if (tm < theList.begin()->start) return errorvalue; for (it=theList.begin();it!=theList.end();++it) { time_t mark=it->start; time_t markend=it->end; if (tm >= mark && tm < markend) return it->data; if (tm >= mark && markend == PENDING) return it->data; } return errorvalue; } //------------------------------------------------------------------------------------------------------ // Function: CTimeIndexedList::favourite // Purpose: returns the element that spans the most time // Output: T, the element //------------------------------------------------------------------------------------------------------ template T CTimeIndexedList::favourite(T errorvalue) { if (theList.empty()) return errorvalue; CTimeIndexedList::accumulator accum=accumulate(); //now scan that intermediate map, and determine the element with the longest duration CTimeIndexedList::accumulatorIterator accumiter=accum.begin(); time_t maxtime=0; CTimeIndexedList::accumulatorIterator fave=accumiter; T t= fave->first; for (accumiter;accumiter!=accum.end();++accumiter) { t= fave->first; time_t clicksPlayed=accumiter->second; if (clicksPlayed> maxtime) { maxtime=clicksPlayed; fave=accumiter; } } T ttt= fave->first; return ttt; } //------------------------------------------------------------------------------------------------------ // Function: CTimeIndexedList::contains // Purpose: returns true if the element is in the list // Input: t, the element value that we're querying // Output: Returns true if the element was in the list //------------------------------------------------------------------------------------------------------ template bool CTimeIndexedList::contains(const T& t) { CTimeIndexedList::iterator it=theList.begin(); for (it=theList.begin();it!=theList.end();++it) { if (it->data==t) return true; } return false; } template time_t CTimeIndexedList::howLong(const T& t) { if (theList.begin()==theList.end()) return 0; CTimeIndexedList::accumulator accum=accumulate(); //maps from a value of T, to the time that value was played return accum[t]; } template CTimeIndexedList::iterator CTimeIndexedList::begin() { return theList.begin(); } template CTimeIndexedList::iterator CTimeIndexedList::end() { return theList.end(); } template int CTimeIndexedList::size() { return theList.size(); } template int CTimeIndexedList::numDifferent() { if (theList.begin()==theList.end()) return 0; //maps from a value of T, to the time that value was played CTimeIndexedList::accumulator accum=accumulate(); return accum.size(); } template void CTimeIndexedList::cut(time_t t) { if (t > endTime) endTime=t; if (!theList.empty()) { //find the last element and fix up its end-time (if it's pending) CTimeIndexedList::iterator last=theList.end(); last--; if (last->end==PENDING) last->end=t; } } template void CTimeIndexedList::remove(T b) { CTimeIndexedList::iterator it=theList.begin(); while(it!=theList.end()) { if (it->data==b) it=theList.erase(it); else ++it; } } template bool CTimeIndexedList::anythingAtTime(time_t tm) { /* //iterate through for debugging purposes { CTimeIndexedList::iterator it=theList.begin(); for (it;it!=theList.end();++it) { CTimeIndexedList::listtype lt=*it; } } */ CTimeIndexedList::iterator it; if (theList.empty()) return false; //nothing exists here! if (tm < theList.begin()->start) return false; for (it=theList.begin();it!=theList.end();++it) { time_t mark=it->start; time_t markend=it->end; if (tm >= mark && tm < markend) return true; } return false; } #endif // TIMEINDEXEDLIST_H