36 if( _apply_undo ) _db.undo();
43 if( _disable_on_exit ) _db.disable();
48 if( _disabled && !force_enable )
return session(*
this);
49 bool disable_on_exit = _disabled && force_enable;
56 _stack.emplace_back();
58 return session(*
this, disable_on_exit );
62 if( _disabled )
return;
65 _stack.emplace_back();
66 auto& state = _stack.back();
68 auto itr = state.old_index_next_ids.find( index_id );
69 if( itr == state.old_index_next_ids.end() )
70 state.old_index_next_ids[index_id] = obj.
id;
71 state.new_ids.insert(obj.
id);
75 if( _disabled )
return;
78 _stack.emplace_back();
79 auto& state = _stack.back();
80 if( state.new_ids.find(obj.
id) != state.new_ids.end() )
82 auto itr = state.old_values.find(obj.
id);
83 if( itr != state.old_values.end() )
return;
84 state.old_values[obj.
id] = obj.
clone();
88 if( _disabled )
return;
91 _stack.emplace_back();
104 if( state.
removed.count(obj.
id) > 0 )
return;
108 void undo_database::undo()
114 auto& state = _stack.back();
115 for(
auto& item : state.old_values )
120 for(
auto ritr = state.new_ids.begin(); ritr != state.new_ids.end(); ++ritr )
125 for(
auto& item : state.old_index_next_ids )
127 _db.
get_mutable_index( item.first.space(), item.first.type() ).set_next_id( item.second );
130 for(
auto& item : state.removed )
131 _db.
insert( std::move(*item.second) );
138 void undo_database::merge()
141 if( _active_sessions == 1 && _stack.size() == 1 )
148 auto& state = _stack.back();
149 auto& prev_state = _stack[_stack.size()-2];
194 for(
auto& obj : state.old_values )
196 if( prev_state.new_ids.find(obj.second->id) != prev_state.new_ids.end() )
201 if( prev_state.old_values.find(obj.second->id) != prev_state.old_values.end() )
207 assert( prev_state.removed.find(obj.second->id) == prev_state.removed.end() );
209 prev_state.old_values[obj.second->id] = std::move(obj.second);
213 for(
auto id : state.new_ids )
214 prev_state.new_ids.insert(
id);
217 for(
auto& item : state.old_index_next_ids )
219 if( prev_state.old_index_next_ids.find( item.first ) == prev_state.old_index_next_ids.end() )
222 prev_state.old_index_next_ids[item.first] = item.second;
234 for(
auto& obj : state.removed )
236 if( prev_state.new_ids.find(obj.second->id) != prev_state.new_ids.end() )
239 prev_state.new_ids.erase(obj.second->id);
242 auto it = prev_state.old_values.find(obj.second->id);
243 if( it != prev_state.old_values.end() )
246 prev_state.removed[obj.second->id] = std::move(it->second);
247 prev_state.old_values.erase(obj.second->id);
251 assert( prev_state.removed.find( obj.second->id ) == prev_state.removed.end() );
253 prev_state.removed[obj.second->id] = std::move(obj.second);
258 void undo_database::commit()
271 auto& state = _stack.back();
273 for(
auto& item : state.old_values )
278 for(
auto ritr = state.new_ids.begin(); ritr != state.new_ids.end(); ++ritr )
283 for(
auto& item : state.old_index_next_ids )
285 _db.
get_mutable_index( item.first.space(), item.first.type() ).set_next_id( item.second );
288 for(
auto& item : state.removed )
289 _db.
insert( std::move(*item.second) );
304 return _stack.back();
const object & insert(object &&obj)
void modify(const T &obj, const Lambda &m)
const undo_state & head() const
Used to generate a useful error report when an exception is thrown.At each level in the stack where t...
void on_create(const object &obj)
index & get_mutable_index()
std::unordered_set< object_id_type > new_ids
const object & get_object(const object_id_type &id) const
#define FC_CAPTURE_AND_RETHROW(...)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
void on_modify(const object &obj)
session start_undo_session(bool force_enable=false)
std::string to_detail_string(log_level ll=log_level::all) const
virtual void move_from(object &obj)=0
void remove(const object &obj)
virtual std::unique_ptr< object > clone() const =0
void on_remove(const object &obj)
std::unordered_map< object_id_type, std::unique_ptr< object > > old_values
std::unordered_map< object_id_type, std::unique_ptr< object > > removed