/*++ Copyright (c) 2006 Microsoft Corporation Module Name: trail.h Abstract: Author: Leonardo de Moura (leonardo) 2008-06-02. Revision History: --*/ #ifndef _TRAIL_H_ #define _TRAIL_H_ #include"ast.h" #include"obj_hashtable.h" #include"region.h" template class trail { public: virtual ~trail() { } virtual void undo(Ctx & ctx) = 0; }; template class value_trail : public trail { T & m_value; T m_old_value; public: value_trail(T & value): m_value(value), m_old_value(value) { } virtual ~value_trail() { } virtual void undo(Ctx & ctx) { m_value = m_old_value; } }; template class reset_flag_trail : public trail { bool & m_value; public: reset_flag_trail(bool & value): m_value(value) { } virtual ~reset_flag_trail() { } virtual void undo(Ctx & ctx) { m_value = false; } }; template class set_ptr_trail : public trail { T * & m_ptr; public: set_ptr_trail(T * & ptr): m_ptr(ptr) { SASSERT(m_ptr == 0); } virtual void undo(Ctx & ctx) { m_ptr = 0; } }; template class restore_size_trail : public trail { vector & m_vector; unsigned m_old_size; public: restore_size_trail(vector & v, unsigned sz): m_vector(v), m_old_size(sz) { } restore_size_trail(vector & v): m_vector(v), m_old_size(v.size()) { } virtual ~restore_size_trail() { } virtual void undo(Ctx & ctx) { m_vector.shrink(m_old_size); } }; template class vector_value_trail : public trail { vector & m_vector; unsigned m_idx; T m_old_value; public: vector_value_trail(vector & v, unsigned idx): m_vector(v), m_idx(idx), m_old_value(v[idx]) { } virtual ~vector_value_trail() { } virtual void undo(Ctx & ctx) { m_vector[m_idx] = m_old_value; } }; template class insert_obj_map : public trail { obj_map& m_map; D* m_obj; public: insert_obj_map(obj_map& t, D* o) : m_map(t), m_obj(o) {} virtual ~insert_obj_map() {} virtual void undo(Ctx & ctx) { m_map.remove(m_obj); } }; template class insert_map : public trail { M& m_map; D m_obj; public: insert_map(M& t, D o) : m_map(t), m_obj(o) {} virtual ~insert_map() {} virtual void undo(Ctx & ctx) { m_map.remove(m_obj); } }; template class push_back_vector : public trail { V & m_vector; public: push_back_vector(V & v): m_vector(v) { } virtual void undo(Ctx & ctx) { m_vector.pop_back(); } }; template class set_vector_idx_trail : public trail { ptr_vector & m_vector; unsigned m_idx; public: set_vector_idx_trail(ptr_vector & v, unsigned idx): m_vector(v), m_idx(idx) { } virtual ~set_vector_idx_trail() { } virtual void undo(Ctx & ctx) { m_vector[m_idx] = 0; } }; template class pop_back_trail : public trail { vector & m_vector; T m_value; public: pop_back_trail(vector & v): m_vector(v), m_value(m_vector.back()) { } virtual void undo(Ctx & ctx) { m_vector.push_back(m_value); } }; template class pop_back2_trail : public trail { vector & m_vector; typedef vector, true> vector_t; unsigned m_index; T m_value; public: pop_back2_trail(vector & v, unsigned index): m_vector(v), m_index(index), m_value(m_vector[index].back()) { } virtual void undo(Ctx & ctx) { m_vector[m_index].push_back(m_value); } }; template class ast2ast_trailmap { ref_vector m_domain; ref_vector m_range; obj_map m_map; public: ast2ast_trailmap(ast_manager& m): m_domain(m), m_range(m), m_map() {} bool find(S* s, T*& t) { return m_map.find(s,t); } void insert(S* s, T* t) { SASSERT(!m_map.contains(s)); m_domain.push_back(s); m_range.push_back(t); m_map.insert(s,t); } void pop() { SASSERT(!m_domain.empty()); m_map.remove(m_domain.back()); m_domain.pop_back(); m_range.pop_back(); } }; template class ast2ast_trail : public trail { ast2ast_trailmap& m_map; public: ast2ast_trail(ast2ast_trailmap& m, S* s, T* t) : m_map(m) { m.insert(s,t); } virtual void undo(Ctx& ctx) { m_map.pop(); } }; template class push_back_trail : public trail { vector & m_vector; public: push_back_trail(vector & v): m_vector(v) { } virtual void undo(Ctx & ctx) { m_vector.pop_back(); } }; template class push_back2_trail : public trail { typedef vector, true> vector_t; vector_t & m_vector; unsigned m_index; public: push_back2_trail(vector_t & v, unsigned index) : m_vector(v), m_index(index) { } virtual void undo(Ctx & ctx) { m_vector[m_index].pop_back(); } }; template class set_bitvector_trail : public trail { svector & m_vector; unsigned m_idx; public: set_bitvector_trail(svector & v, unsigned idx): m_vector(v), m_idx(idx) { SASSERT(m_vector[m_idx] == false); m_vector[m_idx] = true; } virtual void undo(Ctx & ctx) { m_vector[m_idx] = false; } }; template class new_obj_trail : public trail { T * m_obj; public: new_obj_trail(T * obj): m_obj(obj) { } virtual void undo(Ctx & ctx) { dealloc(m_obj); } }; template class obj_ref_trail : public trail { obj_ref m_obj; public: obj_ref_trail(obj_ref& obj): m_obj(obj) { } virtual void undo(Ctx & ctx) { m_obj.reset(); } }; template class insert_obj_trail : public trail { obj_hashtable& m_table; T* m_obj; public: insert_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {} virtual ~insert_obj_trail() {} virtual void undo(Ctx & ctx) { m_table.remove(m_obj); } }; template class remove_obj_trail : public trail { obj_hashtable& m_table; T* m_obj; public: remove_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {} virtual ~remove_obj_trail() {} virtual void undo(Ctx & ctx) { m_table.insert(m_obj); } }; template void undo_trail_stack(Ctx & ctx, ptr_vector > & s, unsigned old_size) { SASSERT(old_size <= s.size()); typename ptr_vector >::iterator begin = s.begin() + old_size; typename ptr_vector >::iterator it = s.end(); while (it != begin) { --it; (*it)->undo(ctx); } s.shrink(old_size); } template class trail_stack { Ctx & m_ctx; ptr_vector > m_trail_stack; unsigned_vector m_scopes; region m_region; public: trail_stack(Ctx & c):m_ctx(c) {} ~trail_stack() {} region & get_region() { return m_region; } void reset() { pop_scope(m_scopes.size()); // Undo trail objects stored at lvl 0 (avoid memory leaks if lvl 0 contains new_obj_trail objects). undo_trail_stack(m_ctx, m_trail_stack, 0); } void push_ptr(trail * t) { m_trail_stack.push_back(t); } template void push(TrailObject const & obj) { m_trail_stack.push_back(new (m_region) TrailObject(obj)); } unsigned get_num_scopes() const { return m_scopes.size(); } void push_scope() { m_region.push_scope(); m_scopes.push_back(m_trail_stack.size()); } void pop_scope(unsigned num_scopes) { if (num_scopes == 0) return; unsigned lvl = m_scopes.size(); SASSERT(num_scopes <= lvl); unsigned new_lvl = lvl - num_scopes; unsigned old_size = m_scopes[new_lvl]; undo_trail_stack(m_ctx, m_trail_stack, old_size); m_scopes.shrink(new_lvl); m_region.pop_scope(num_scopes); } }; #endif /* _TRAIL_H_ */