source-engine/utils/tfstats/timeindexedlist.h

346 lines
8.2 KiB
C
Raw Permalink Normal View History

2020-04-22 16:56:21 +00:00
//========= 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 <list>
#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 T>
class CTimeIndexedList
{
public:
static time_t PENDING;
typedef struct{T data;time_t start; time_t end;} listtype;
typedef std::list<listtype>::iterator iterator;
typedef std::map<T,time_t>::iterator accumulatorIterator;
typedef std::map<T,time_t> accumulator;
typedef std::list<listtype> 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 <class T>
time_t CTimeIndexedList<T>::PENDING=-1;
template <class T>
CTimeIndexedList<T>::CTimeIndexedList()
{
endTime=0;
}
//------------------------------------------------------------------------------------------------------
// Function: CTimeIndexedList<T>::accumulate
// Purpose:
// Output: CTimeIndexedList<T>::accumulator
//------------------------------------------------------------------------------------------------------
template<class T>
CTimeIndexedList<T>::accumulator CTimeIndexedList<T>::accumulate()
{
CTimeIndexedList<T>::accumulator accum; //maps from a value of T, to the time that value was played
/*
//iterate through for debugging purposes
{
CTimeIndexedList<T>::iterator it=theList.begin();
for (it;it!=theList.end();++it)
{
CTimeIndexedList<T>::listtype lt=*it;
}
}
*/
CTimeIndexedList<T>::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<T>::add
// Purpose:
// Input: a -
// b -
//------------------------------------------------------------------------------------------------------
template<class T>
void CTimeIndexedList<T>::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<T>::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 <class T>
T CTimeIndexedList<T>::atTime(time_t tm,T errorvalue)
{
CTimeIndexedList<T>::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 <class T>
T CTimeIndexedList<T>::favourite(T errorvalue)
{
if (theList.empty())
return errorvalue;
CTimeIndexedList<T>::accumulator accum=accumulate();
//now scan that intermediate map, and determine the element with the longest duration
CTimeIndexedList<T>::accumulatorIterator accumiter=accum.begin();
time_t maxtime=0;
CTimeIndexedList<T>::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 <class T>
bool CTimeIndexedList<T>::contains(const T& t)
{
CTimeIndexedList<T>::iterator it=theList.begin();
for (it=theList.begin();it!=theList.end();++it)
{
if (it->data==t)
return true;
}
return false;
}
template <class T>
time_t CTimeIndexedList<T>::howLong(const T& t)
{
if (theList.begin()==theList.end())
return 0;
CTimeIndexedList<T>::accumulator accum=accumulate(); //maps from a value of T, to the time that value was played
return accum[t];
}
template <class T>
CTimeIndexedList<T>::iterator CTimeIndexedList<T>::begin()
{
return theList.begin();
}
template <class T>
CTimeIndexedList<T>::iterator CTimeIndexedList<T>::end()
{
return theList.end();
}
template <class T>
int CTimeIndexedList<T>::size()
{
return theList.size();
}
template <class T>
int CTimeIndexedList<T>::numDifferent()
{
if (theList.begin()==theList.end())
return 0;
//maps from a value of T, to the time that value was played
CTimeIndexedList<T>::accumulator accum=accumulate();
return accum.size();
}
template<class T>
void CTimeIndexedList<T>::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<T>::iterator last=theList.end();
last--;
if (last->end==PENDING)
last->end=t;
}
}
template<class T>
void CTimeIndexedList<T>::remove(T b)
{
CTimeIndexedList<T>::iterator it=theList.begin();
while(it!=theList.end())
{
if (it->data==b)
it=theList.erase(it);
else
++it;
}
}
template <class T>
bool CTimeIndexedList<T>::anythingAtTime(time_t tm)
{
/*
//iterate through for debugging purposes
{
CTimeIndexedList<T>::iterator it=theList.begin();
for (it;it!=theList.end();++it)
{
CTimeIndexedList<T>::listtype lt=*it;
}
}
*/
CTimeIndexedList<T>::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