00001 //---------------------------------------------------------------------------- 00002 /** @file 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #ifndef CHANGELOG_HPP 00007 #define CHANGELOG_HPP 00008 00009 #include <list> 00010 #include <vector> 00011 #include <string> 00012 #include <sstream> 00013 #include "Benzene.hpp" 00014 00015 _BEGIN_BENZENE_NAMESPACE_ 00016 00017 //---------------------------------------------------------------------------- 00018 00019 /** General purpose changelog; allows incremental changes made to a 00020 datastructure to be undone quickly. 00021 00022 A changelog is a stack that tracks the changes to some data 00023 structure with data type T. There are three actions: ADD, REMOVE, 00024 and MARKER. And ADD action means the data was recently added to the 00025 datastructure, and REMOVE means it was recently removed. MARKER is 00026 used to mark how far back to go when you want to undo the changes 00027 made. 00028 */ 00029 template<typename T> 00030 class ChangeLog 00031 { 00032 public: 00033 00034 /** Constructor. */ 00035 ChangeLog(); 00036 00037 /** Available actions. */ 00038 typedef enum {ADD, REMOVE, PROCESSED, MARKER} Action; 00039 00040 /** Returns true if changelog is empty. */ 00041 bool empty() const; 00042 00043 /** Returns size of changelog. */ 00044 int size() const; 00045 00046 /** Adds an entry onto the changelog. */ 00047 void push(Action action, const T& data); 00048 00049 /** Pops the top entry off of the changelog. Asserts log is not 00050 empty. 00051 */ 00052 void pop(); 00053 00054 /** Returns the action on top of the changelog. Asserts log is not 00055 empty. 00056 00057 @todo how to write this method using the 'inline' syntax? I 00058 keep getting compile errors. 00059 */ 00060 Action topAction() const { assert(!empty()); return m_action.back(); } 00061 00062 /** Returns a copy of the data on top of the changelog. Asserts log is 00063 not empty. 00064 */ 00065 T topData() const; 00066 00067 /** Clears the log. */ 00068 void clear(); 00069 00070 /** Dump the contents of the log to a string. */ 00071 std::string dump() const; 00072 00073 private: 00074 std::vector<T> m_data; 00075 std::vector<Action> m_action; 00076 }; 00077 00078 template<typename T> 00079 inline ChangeLog<T>::ChangeLog() 00080 { 00081 } 00082 00083 template<typename T> 00084 inline bool ChangeLog<T>::empty() const 00085 { 00086 return m_action.empty(); 00087 } 00088 00089 template<typename T> 00090 inline int ChangeLog<T>::size() const 00091 { 00092 return m_action.size(); 00093 } 00094 00095 template<typename T> 00096 inline void ChangeLog<T>::push(Action action, const T& data) 00097 { 00098 m_action.push_back(action); 00099 m_data.push_back(data); 00100 } 00101 00102 template<typename T> 00103 inline void ChangeLog<T>::pop() 00104 { 00105 assert(!empty()); 00106 m_action.pop_back(); 00107 m_data.pop_back(); 00108 } 00109 00110 template<typename T> 00111 inline T ChangeLog<T>::topData() const 00112 { 00113 assert(!empty()); 00114 return m_data.back(); 00115 } 00116 00117 /// @todo vector::clear() takes linear time. Is this a problem? 00118 template<typename T> 00119 inline void ChangeLog<T>::clear() 00120 { 00121 m_action.clear(); 00122 m_data.clear(); 00123 } 00124 00125 template<typename T> 00126 std::string ChangeLog<T>::dump() const 00127 { 00128 std::ostringstream os; 00129 00130 for (int i=0; i<(int)m_action.size(); ++i) { 00131 os << i << ": "; 00132 if (m_action[i] == MARKER) 00133 os << "MARKER"; 00134 else { 00135 if (m_action[i] == ADD) 00136 os << " ADD: "; 00137 else if (m_action[i] == REMOVE) 00138 os << "REMOVE: "; 00139 else if (m_action[i] == PROCESSED) 00140 os << "PROCESSED: "; 00141 os << m_data[i]; 00142 } 00143 os << std::endl; 00144 } 00145 return os.str(); 00146 } 00147 00148 //---------------------------------------------------------------------------- 00149 00150 _END_BENZENE_NAMESPACE_ 00151 00152 #endif // CHANGELOG_HPP