Undo?

Mr. Jonse Jonse at Theory.uni
Thu Oct 12 02:18:49 UTC 2017


A simple(incomplete) undo system.

I'm curious about the overhead. The idea is to wrap any system 
changes using the Add function. This function stores both the 
forward and backward state changes using delegates.

By using forward, we call the action passed to set the data and 
backward will call the action to set the original data.

Delegates are used to avoid having to save the actual data 
manually, but I'm wondering if there is a lot of overhead and how 
the GC will be trashed by this, is there a better way or a better 
mechanism to use?



module undo;
import std.variant;


auto apply(T)(T t, Variant[] values) {
     import std.traits : ParameterTypeTuple;
     import std.conv : emplace;
     alias Types = ParameterTypeTuple!T;
     assert(values.length == Types.length);
     Types args = void;
     foreach(i, ref arg; args) { emplace!(typeof(arg))(&arg, 
values[i].get!typeof(arg))); }

	return { t(args); };
}

class Undo
{
	UndoNode Root;
	UndoNode CurrentNode;


	void Add(T, S, A...)(T t, S s, A a)
	{
		pragma(msg, T, " ------ ", S);
		pragma(msg, A);


	        UndoNode n = new UndoNode();
		n.Parent = CurrentNode;
		if (CurrentNode !is null)
			n.ParentBranch = CurrentNode.ParentBranch;
		foreach(_; a)
			n.Action.Data ~= Variant(_);
		if (CurrentNode !is null)
			CurrentNode.Children ~= n;
		CurrentNode = n;

		//t();		
		n.Action.cmd = { t(); };
		n.Action.inv = apply!S(s, n.Action.Data);

	}

	void Forward()
	{	
		CurrentNode.Action.cmd();
	}

	void Backward()
	{		
		CurrentNode.Action.inv();
	}	

	this()
	{
		CurrentNode = Root;
	}
}

struct UndoAction
{
	Variant[] Data;
	void delegate() cmd;
	void delegate() inv;
}


class UndoNode
{
	UndoNode Parent;
	UndoNode ParentBranch;
	UndoNode[] Children;
	UndoAction Action;
}




test code


import std.stdio;
import mUndo;


class Data
{
	int x = 0;
}






__gshared Undo GlobalUndo = new Undo();

int main(string[] argv)
{

	__gshared Data data = new Data();
	data.x = -1;
	auto globalUndo = GlobalUndo;


	globalUndo.Add(
				   {
					auto oldx = data.x;
					data.x = 4;
					return oldx;
				   },
				   (int d){
					auto oldx = data.x;
					data.x = d;
					return oldx;
				   }, data.x);

	writeln(data.x);
	globalUndo.Forward();
	writeln(data.x);
	globalUndo.Backward();
	writeln(data.x);

     writeln("------");
	getchar();
     return 0;
}




More information about the Digitalmars-d-learn mailing list