1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
|
/*
* Copyright (C) 2012-2017 Robin Haberkorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __UNDO_H
#define __UNDO_H
#include <string.h>
#include <bsd/sys/queue.h>
#include <glib.h>
#include <glib/gprintf.h>
#include "memory.h"
#ifdef DEBUG
#include "parser.h"
#endif
namespace SciTECO {
class UndoToken : public Object {
public:
SLIST_ENTRY(UndoToken) tokens;
/**
* Command-line character position (program counter)
* corresponding to this token.
*
* @todo This wastes memory in macro calls and loops
* because all undo tokens will have the same
* value. It may be better to redesign the undo
* stack data structure - as a list/array pointing
* to undo stacks per character.
*/
gint pc;
virtual ~UndoToken() {}
virtual void run(void) = 0;
};
template <typename Type>
class UndoTokenVariable : public UndoToken {
Type *ptr;
Type value;
public:
UndoTokenVariable(Type &variable, Type _value)
: ptr(&variable), value(_value) {}
void
run(void)
{
#ifdef DEBUG
if ((State **)ptr == &States::current)
g_printf("undo state -> %p\n", (void *)value);
#endif
*ptr = value;
}
};
class UndoTokenString : public UndoToken {
gchar **ptr;
gchar *str;
public:
UndoTokenString(gchar *&variable, gchar *_str)
: ptr(&variable)
{
str = _str ? g_strdup(_str) : NULL;
}
~UndoTokenString()
{
g_free(str);
}
void
run(void)
{
g_free(*ptr);
*ptr = str;
str = NULL;
}
};
template <class Type>
class UndoTokenObject : public UndoToken {
Type **ptr;
Type *obj;
public:
UndoTokenObject(Type *&variable, Type *_obj)
: ptr(&variable), obj(_obj) {}
~UndoTokenObject()
{
delete obj;
}
void
run(void)
{
delete *ptr;
*ptr = obj;
obj = NULL;
}
};
extern class UndoStack : public Object {
SLIST_HEAD(Head, UndoToken) head;
void push(UndoToken *token);
public:
bool enabled;
UndoStack(bool _enabled = false) : enabled(_enabled)
{
SLIST_INIT(&head);
}
~UndoStack();
/**
* Allocate and push undo token.
*
* This does nothing if undo is disabled and should
* not be used when ownership of some data is to be
* passed to the undo token.
*/
template <class TokenType, typename... Params>
inline void
push(Params && ... params)
{
if (enabled)
push(new TokenType(params...));
}
/**
* Allocate and push undo token, passing ownership.
*
* This creates and deletes the undo token cheaply
* if undo is disabled, so that data whose ownership
* is passed to the undo token is correctly reclaimed.
*
* @bug We must know which version of push to call
* depending on the token type. This could be hidden
* if UndoTokens had static push methods that take care
* of reclaiming memory.
*/
template <class TokenType, typename... Params>
inline void
push_own(Params && ... params)
{
if (enabled) {
push(new TokenType(params...));
} else {
/* ensures that all memory is reclaimed */
TokenType dummy(params...);
}
}
template <typename Type>
inline Type &
push_var(Type &variable, Type value)
{
push<UndoTokenVariable<Type>>(variable, value);
return variable;
}
template <typename Type>
inline Type &
push_var(Type &variable)
{
return push_var<Type>(variable, variable);
}
inline gchar *&
push_str(gchar *&variable, gchar *str)
{
push<UndoTokenString>(variable, str);
return variable;
}
inline gchar *&
push_str(gchar *&variable)
{
return push_str(variable, variable);
}
template <class Type>
inline Type *&
push_obj(Type *&variable, Type *obj)
{
/* pass ownership of original object */
push_own<UndoTokenObject<Type>>(variable, obj);
return variable;
}
template <class Type>
inline Type *&
push_obj(Type *&variable)
{
return push_obj<Type>(variable, variable);
}
void pop(gint pc);
void clear(void);
} undo;
} /* namespace SciTECO */
#endif
|