Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
8.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Interface AND implementation of CTimeIndexedList
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. //
  8. //------------------------------------------------------------------------------------------------------
  9. // $Log: $
  10. //
  11. // $NoKeywords: $
  12. //=============================================================================//
  13. #ifndef TIMEINDEXEDLIST_H
  14. #define TIMEINDEXEDLIST_H
  15. #ifdef WIN32
  16. #pragma once
  17. #endif
  18. #include <list>
  19. #include "TFStatsApplication.h"
  20. #include "util.h"
  21. //------------------------------------------------------------------------------------------------------
  22. // Purpose: CTimedIndexedList is a list of elements indexed by time_t's.
  23. // the elements of the list are meant to represent a state that endures over time
  24. // and when it is switched to another state, that is represented by an element in this
  25. // list with the value of the new state at index t, where t is the time that the switch
  26. // occured.
  27. // in TFStats, this is used for player names and player classes
  28. //------------------------------------------------------------------------------------------------------
  29. template <class T>
  30. class CTimeIndexedList
  31. {
  32. public:
  33. static time_t PENDING;
  34. typedef struct{T data;time_t start; time_t end;} listtype;
  35. typedef std::list<listtype>::iterator iterator;
  36. typedef std::map<T,time_t>::iterator accumulatorIterator;
  37. typedef std::map<T,time_t> accumulator;
  38. typedef std::list<listtype> timelist;
  39. timelist theList;
  40. time_t endTime;
  41. bool anythingAtTime(time_t);
  42. T atTime(time_t,T errorvalue=T());
  43. T favourite(T errorvalue=T());
  44. CTimeIndexedList();
  45. void add(time_t a,T b);
  46. bool contains(const T& t);
  47. accumulator accumulate();
  48. time_t howLong(const T& t);
  49. iterator begin();
  50. iterator end();
  51. int size();
  52. int numDifferent();
  53. void cut(time_t t);
  54. void remove(T b);
  55. };
  56. template <class T>
  57. time_t CTimeIndexedList<T>::PENDING=-1;
  58. template <class T>
  59. CTimeIndexedList<T>::CTimeIndexedList()
  60. {
  61. endTime=0;
  62. }
  63. //------------------------------------------------------------------------------------------------------
  64. // Function: CTimeIndexedList<T>::accumulate
  65. // Purpose:
  66. // Output: CTimeIndexedList<T>::accumulator
  67. //------------------------------------------------------------------------------------------------------
  68. template<class T>
  69. CTimeIndexedList<T>::accumulator CTimeIndexedList<T>::accumulate()
  70. {
  71. CTimeIndexedList<T>::accumulator accum; //maps from a value of T, to the time that value was played
  72. /*
  73. //iterate through for debugging purposes
  74. {
  75. CTimeIndexedList<T>::iterator it=theList.begin();
  76. for (it;it!=theList.end();++it)
  77. {
  78. CTimeIndexedList<T>::listtype lt=*it;
  79. }
  80. }
  81. */
  82. CTimeIndexedList<T>::iterator it=theList.begin();
  83. for (it;it!=theList.end();++it)
  84. {
  85. time_t start=it->start;
  86. time_t end=it->end;
  87. T& bucket=it->data;
  88. if (end==PENDING)
  89. {
  90. end=endTime;
  91. if (end==0)
  92. {
  93. g_pApp->fatalError("Time flow error, make sure your log file\n");
  94. }
  95. }
  96. accum[bucket]+=(end-start);
  97. }
  98. return accum;
  99. }
  100. //------------------------------------------------------------------------------------------------------
  101. // Function: CTimeIndexedList<T>::add
  102. // Purpose:
  103. // Input: a -
  104. // b -
  105. //------------------------------------------------------------------------------------------------------
  106. template<class T>
  107. void CTimeIndexedList<T>::add(time_t a,T b)
  108. {
  109. bool lastIsB=false;
  110. bool firstElement=false;
  111. listtype insertme;
  112. insertme.data=b;
  113. insertme.start=a;
  114. insertme.end=PENDING;
  115. if (!theList.empty())
  116. {
  117. //find the last element and fix up its end-time (if it's pending)
  118. CTimeIndexedList<T>::iterator last=theList.end();
  119. last--;
  120. listtype lt=*last;
  121. if (last->end==PENDING && last->data!=b)
  122. last->end=insertme.start;
  123. }
  124. //add the new element!
  125. theList.push_back(insertme);
  126. if (a > endTime)
  127. endTime=a;
  128. }
  129. //------------------------------------------------------------------------------------------------------
  130. // Function: CTimeIndexedList::atTime
  131. // Purpose: returns the element whose time index is the closest to and less than or
  132. // equal to the queried time
  133. // Input: tm - the time that is being queried
  134. // Output: T, the element
  135. //------------------------------------------------------------------------------------------------------
  136. template <class T>
  137. T CTimeIndexedList<T>::atTime(time_t tm,T errorvalue)
  138. {
  139. CTimeIndexedList<T>::iterator it;
  140. if (theList.empty())
  141. return errorvalue;
  142. //nothing exists here!
  143. if (tm < theList.begin()->start)
  144. return errorvalue;
  145. for (it=theList.begin();it!=theList.end();++it)
  146. {
  147. time_t mark=it->start;
  148. time_t markend=it->end;
  149. if (tm >= mark && tm < markend)
  150. return it->data;
  151. if (tm >= mark && markend == PENDING)
  152. return it->data;
  153. }
  154. return errorvalue;
  155. }
  156. //------------------------------------------------------------------------------------------------------
  157. // Function: CTimeIndexedList::favourite
  158. // Purpose: returns the element that spans the most time
  159. // Output: T, the element
  160. //------------------------------------------------------------------------------------------------------
  161. template <class T>
  162. T CTimeIndexedList<T>::favourite(T errorvalue)
  163. {
  164. if (theList.empty())
  165. return errorvalue;
  166. CTimeIndexedList<T>::accumulator accum=accumulate();
  167. //now scan that intermediate map, and determine the element with the longest duration
  168. CTimeIndexedList<T>::accumulatorIterator accumiter=accum.begin();
  169. time_t maxtime=0;
  170. CTimeIndexedList<T>::accumulatorIterator fave=accumiter;
  171. T t= fave->first;
  172. for (accumiter;accumiter!=accum.end();++accumiter)
  173. {
  174. t= fave->first;
  175. time_t clicksPlayed=accumiter->second;
  176. if (clicksPlayed> maxtime)
  177. {
  178. maxtime=clicksPlayed;
  179. fave=accumiter;
  180. }
  181. }
  182. T ttt= fave->first;
  183. return ttt;
  184. }
  185. //------------------------------------------------------------------------------------------------------
  186. // Function: CTimeIndexedList::contains
  187. // Purpose: returns true if the element is in the list
  188. // Input: t, the element value that we're querying
  189. // Output: Returns true if the element was in the list
  190. //------------------------------------------------------------------------------------------------------
  191. template <class T>
  192. bool CTimeIndexedList<T>::contains(const T& t)
  193. {
  194. CTimeIndexedList<T>::iterator it=theList.begin();
  195. for (it=theList.begin();it!=theList.end();++it)
  196. {
  197. if (it->data==t)
  198. return true;
  199. }
  200. return false;
  201. }
  202. template <class T>
  203. time_t CTimeIndexedList<T>::howLong(const T& t)
  204. {
  205. if (theList.begin()==theList.end())
  206. return 0;
  207. CTimeIndexedList<T>::accumulator accum=accumulate(); //maps from a value of T, to the time that value was played
  208. return accum[t];
  209. }
  210. template <class T>
  211. CTimeIndexedList<T>::iterator CTimeIndexedList<T>::begin()
  212. {
  213. return theList.begin();
  214. }
  215. template <class T>
  216. CTimeIndexedList<T>::iterator CTimeIndexedList<T>::end()
  217. {
  218. return theList.end();
  219. }
  220. template <class T>
  221. int CTimeIndexedList<T>::size()
  222. {
  223. return theList.size();
  224. }
  225. template <class T>
  226. int CTimeIndexedList<T>::numDifferent()
  227. {
  228. if (theList.begin()==theList.end())
  229. return 0;
  230. //maps from a value of T, to the time that value was played
  231. CTimeIndexedList<T>::accumulator accum=accumulate();
  232. return accum.size();
  233. }
  234. template<class T>
  235. void CTimeIndexedList<T>::cut(time_t t)
  236. {
  237. if (t > endTime)
  238. endTime=t;
  239. if (!theList.empty())
  240. {
  241. //find the last element and fix up its end-time (if it's pending)
  242. CTimeIndexedList<T>::iterator last=theList.end();
  243. last--;
  244. if (last->end==PENDING)
  245. last->end=t;
  246. }
  247. }
  248. template<class T>
  249. void CTimeIndexedList<T>::remove(T b)
  250. {
  251. CTimeIndexedList<T>::iterator it=theList.begin();
  252. while(it!=theList.end())
  253. {
  254. if (it->data==b)
  255. it=theList.erase(it);
  256. else
  257. ++it;
  258. }
  259. }
  260. template <class T>
  261. bool CTimeIndexedList<T>::anythingAtTime(time_t tm)
  262. {
  263. /*
  264. //iterate through for debugging purposes
  265. {
  266. CTimeIndexedList<T>::iterator it=theList.begin();
  267. for (it;it!=theList.end();++it)
  268. {
  269. CTimeIndexedList<T>::listtype lt=*it;
  270. }
  271. }
  272. */
  273. CTimeIndexedList<T>::iterator it;
  274. if (theList.empty())
  275. return false;
  276. //nothing exists here!
  277. if (tm < theList.begin()->start)
  278. return false;
  279. for (it=theList.begin();it!=theList.end();++it)
  280. {
  281. time_t mark=it->start;
  282. time_t markend=it->end;
  283. if (tm >= mark && tm < markend)
  284. return true;
  285. }
  286. return false;
  287. }
  288. #endif // TIMEINDEXEDLIST_H