Refactor to make me->newgame_undo a small struct.

The three related buf/len/size fields are now a sub-structure of the
main midend, and the serialise/deserialise functions that address
those fields now take a pointer to that sub-structure rather than to
the midend as a whole. This will make it easy for me to drop in a
second substructure alongside it, for redo, and reuse those read and
write functions by just changing the context pointer.
This commit is contained in:
Simon Tatham
2017-11-18 19:36:10 +00:00
parent 5c6fcf10a3
commit e2514a72e6

View File

@ -25,6 +25,11 @@ struct midend_state_entry {
int movetype; int movetype;
}; };
struct midend_serialise_buf {
char *buf;
int len, size;
};
struct midend { struct midend {
frontend *frontend; frontend *frontend;
random_state *random; random_state *random;
@ -63,8 +68,7 @@ struct midend {
int nstates, statesize, statepos; int nstates, statesize, statepos;
struct midend_state_entry *states; struct midend_state_entry *states;
char *newgame_undo_buf; struct midend_serialise_buf newgame_undo;
int newgame_undo_len, newgame_undo_size;
game_params *params, *curparams; game_params *params, *curparams;
game_drawstate *drawstate; game_drawstate *drawstate;
@ -158,8 +162,8 @@ midend *midend_new(frontend *fe, const game *ourgame,
me->random = random_new(randseed, randseedsize); me->random = random_new(randseed, randseedsize);
me->nstates = me->statesize = me->statepos = 0; me->nstates = me->statesize = me->statepos = 0;
me->states = NULL; me->states = NULL;
me->newgame_undo_buf = NULL; me->newgame_undo.buf = NULL;
me->newgame_undo_size = me->newgame_undo_len = 0; me->newgame_undo.size = me->newgame_undo.len = 0;
me->params = ourgame->default_params(); me->params = ourgame->default_params();
me->game_id_change_notify_function = NULL; me->game_id_change_notify_function = NULL;
me->game_id_change_notify_ctx = NULL; me->game_id_change_notify_ctx = NULL;
@ -257,7 +261,7 @@ void midend_free(midend *me)
if (me->drawing) if (me->drawing)
drawing_free(me->drawing); drawing_free(me->drawing);
random_free(me->random); random_free(me->random);
sfree(me->newgame_undo_buf); sfree(me->newgame_undo.buf);
sfree(me->states); sfree(me->states);
sfree(me->desc); sfree(me->desc);
sfree(me->privdesc); sfree(me->privdesc);
@ -386,23 +390,22 @@ void midend_force_redraw(midend *me)
static void newgame_serialise_write(void *ctx, const void *buf, int len) static void newgame_serialise_write(void *ctx, const void *buf, int len)
{ {
midend *const me = ctx; struct midend_serialise_buf *ser = (struct midend_serialise_buf *)ctx;
int new_len; int new_len;
assert(len < INT_MAX - me->newgame_undo_len); assert(len < INT_MAX - ser->len);
new_len = me->newgame_undo_len + len; new_len = ser->len + len;
if (new_len > me->newgame_undo_size) { if (new_len > ser->size) {
me->newgame_undo_size = new_len + new_len / 4 + 1024; ser->size = new_len + new_len / 4 + 1024;
me->newgame_undo_buf = sresize(me->newgame_undo_buf, ser->buf = sresize(ser->buf, ser->size, char);
me->newgame_undo_size, char);
} }
memcpy(me->newgame_undo_buf + me->newgame_undo_len, buf, len); memcpy(ser->buf + ser->len, buf, len);
me->newgame_undo_len = new_len; ser->len = new_len;
} }
void midend_new_game(midend *me) void midend_new_game(midend *me)
{ {
me->newgame_undo_len = 0; me->newgame_undo.len = 0;
if (me->nstates != 0) { if (me->nstates != 0) {
/* /*
* Serialise the whole of the game that we're about to * Serialise the whole of the game that we're about to
@ -415,7 +418,7 @@ void midend_new_game(midend *me)
* and just confuse us into thinking we had something to undo * and just confuse us into thinking we had something to undo
* to. * to.
*/ */
midend_serialise(me, newgame_serialise_write, me); midend_serialise(me, newgame_serialise_write, &me->newgame_undo);
} }
midend_stop_anim(me); midend_stop_anim(me);
@ -532,7 +535,7 @@ void midend_new_game(midend *me)
int midend_can_undo(midend *me) int midend_can_undo(midend *me)
{ {
return (me->statepos > 1 || me->newgame_undo_len); return (me->statepos > 1 || me->newgame_undo.len);
} }
int midend_can_redo(midend *me) int midend_can_redo(midend *me)
@ -541,17 +544,16 @@ int midend_can_redo(midend *me)
} }
struct newgame_undo_deserialise_read_ctx { struct newgame_undo_deserialise_read_ctx {
midend *me; struct midend_serialise_buf *ser;
int len, pos; int len, pos;
}; };
static int newgame_undo_deserialise_read(void *ctx, void *buf, int len) static int newgame_undo_deserialise_read(void *ctx, void *buf, int len)
{ {
struct newgame_undo_deserialise_read_ctx *const rctx = ctx; struct newgame_undo_deserialise_read_ctx *const rctx = ctx;
midend *const me = rctx->me;
int use = min(len, rctx->len - rctx->pos); int use = min(len, rctx->len - rctx->pos);
memcpy(buf, me->newgame_undo_buf + rctx->pos, use); memcpy(buf, rctx->ser->buf + rctx->pos, use);
rctx->pos += use; rctx->pos += use;
return use; return use;
} }
@ -624,12 +626,12 @@ static int midend_undo(midend *me)
me->statepos--; me->statepos--;
me->dir = -1; me->dir = -1;
return 1; return 1;
} else if (me->newgame_undo_len) { } else if (me->newgame_undo.len) {
/* This undo cannot be undone with redo */ /* This undo cannot be undone with redo */
struct newgame_undo_deserialise_read_ctx rctx; struct newgame_undo_deserialise_read_ctx rctx;
struct newgame_undo_deserialise_check_ctx cctx; struct newgame_undo_deserialise_check_ctx cctx;
rctx.me = me; rctx.ser = &me->newgame_undo;
rctx.len = me->newgame_undo_len; /* copy for reentrancy safety */ rctx.len = me->newgame_undo.len; /* copy for reentrancy safety */
rctx.pos = 0; rctx.pos = 0;
cctx.refused = FALSE; cctx.refused = FALSE;
deserialise_error = midend_deserialise_internal( deserialise_error = midend_deserialise_internal(
@ -2230,7 +2232,7 @@ static const char *midend_deserialise_internal(
* more sophisticated way to decide when to discard the previous * more sophisticated way to decide when to discard the previous
* game state. * game state.
*/ */
me->newgame_undo_len = 0; me->newgame_undo.len = 0;
{ {
game_params *tmp; game_params *tmp;