Use a circular buffer for the savepoints
Avoids mallocs during normal operation.
This commit is contained in:
parent
6293b37ead
commit
e3b9bfd4bb
@ -55,6 +55,12 @@ void cursor_reset(Cursor *self) {
|
||||
self->color = 0; self->hidden = false;
|
||||
}
|
||||
|
||||
void cursor_copy_to(Cursor *src, Cursor *dest) {
|
||||
#define CCY(x) dest->x = src->x;
|
||||
CCY(x); CCY(y); CCY(shape); CCY(blink); CCY(color); CCY(hidden);
|
||||
CCY(bold); CCY(italic); CCY(strikethrough); CCY(reverse); CCY(decoration); CCY(fg); CCY(bg); CCY(decoration_fg);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
copy(Cursor *self);
|
||||
#define copy_doc "Create a clone of this cursor"
|
||||
@ -127,12 +133,10 @@ RICHCMP(Cursor)
|
||||
|
||||
Cursor*
|
||||
cursor_copy(Cursor *self) {
|
||||
#define CCY(x) ans->x = self->x;
|
||||
Cursor* ans;
|
||||
ans = alloc_cursor();
|
||||
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
||||
CCY(x); CCY(y); CCY(shape); CCY(blink); CCY(color); CCY(hidden);
|
||||
CCY(bold); CCY(italic); CCY(strikethrough); CCY(reverse); CCY(decoration); CCY(fg); CCY(bg); CCY(decoration_fg);
|
||||
cursor_copy_to(self, ans);
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
@ -213,17 +213,22 @@ typedef struct {
|
||||
PyTypeObject ScreenModes_Type;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
unsigned int current_charset;
|
||||
uint16_t *g0_charset, *g1_charset;
|
||||
uint32_t utf8_state;
|
||||
Cursor *cursor;
|
||||
Cursor cursor;
|
||||
bool mDECOM;
|
||||
bool mDECAWM;
|
||||
|
||||
} Savepoint;
|
||||
PyTypeObject Savepoint_Type;
|
||||
|
||||
#define SAVEPOINTS_SZ 256
|
||||
|
||||
typedef struct {
|
||||
Savepoint buf[SAVEPOINTS_SZ];
|
||||
Savepoint *start_of_data;
|
||||
Savepoint *end_of_data;
|
||||
} SavepointBuffer;
|
||||
|
||||
#define PARSER_BUF_SZ 8192
|
||||
|
||||
@ -235,7 +240,8 @@ typedef struct {
|
||||
uint32_t utf8_state;
|
||||
uint16_t *g0_charset, *g1_charset;
|
||||
Cursor *cursor;
|
||||
PyObject *savepoints, *main_savepoints, *alt_savepoints, *callbacks;
|
||||
SavepointBuffer main_savepoints, alt_savepoints;
|
||||
PyObject *callbacks;
|
||||
LineBuf *linebuf, *main_linebuf, *alt_linebuf;
|
||||
bool *tabstops;
|
||||
ChangeTracker *change_tracker;
|
||||
@ -273,8 +279,11 @@ PyObject* parse_bytes_dump(PyObject UNUSED *, PyObject *);
|
||||
PyObject* parse_bytes(PyObject UNUSED *, PyObject *);
|
||||
uint16_t* translation_table(char);
|
||||
uint32_t decode_utf8(uint32_t*, uint32_t*, uint8_t byte);
|
||||
Savepoint* savepoints_pop(SavepointBuffer *pts);
|
||||
Savepoint* savepoints_push(SavepointBuffer *pts);
|
||||
void cursor_reset(Cursor*);
|
||||
Cursor* cursor_copy(Cursor*);
|
||||
void cursor_copy_to(Cursor *src, Cursor *dest);
|
||||
void cursor_reset_display_attrs(Cursor*);
|
||||
bool update_cell_range_data(SpriteMap *, Line *, unsigned int, unsigned int, ColorProfile *, const uint32_t, const uint32_t, unsigned int *);
|
||||
uint32_t to_color(ColorProfile *, uint32_t, uint32_t);
|
||||
|
||||
@ -7,41 +7,20 @@
|
||||
|
||||
#include "data-types.h"
|
||||
|
||||
static PyObject *
|
||||
new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
||||
Savepoint *self;
|
||||
self = (Savepoint *)type->tp_alloc(type, 0);
|
||||
return (PyObject*) self;
|
||||
#define ADVANCE(x) \
|
||||
self->x = (self->x >= self->buf + SAVEPOINTS_SZ - 1) ? self->buf : self->x + 1;
|
||||
|
||||
#define RETREAT(x) \
|
||||
self->x = self->x == self->buf ? self->buf + SAVEPOINTS_SZ - 1 : self->x - 1;
|
||||
|
||||
Savepoint* savepoints_push(SavepointBuffer *self) {
|
||||
ADVANCE(end_of_data);
|
||||
if (self->end_of_data == self->start_of_data) ADVANCE(start_of_data);
|
||||
return self->end_of_data;
|
||||
}
|
||||
|
||||
static void
|
||||
dealloc(Savepoint* self) {
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
Savepoint* savepoints_pop(SavepointBuffer *self) {
|
||||
if (self->start_of_data == self->end_of_data) return NULL;
|
||||
RETREAT(end_of_data);
|
||||
return self->end_of_data;
|
||||
}
|
||||
|
||||
|
||||
// Boilerplate {{{
|
||||
|
||||
static PyMethodDef methods[] = {
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
PyTypeObject Savepoint_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.Savepoint",
|
||||
.tp_basicsize = sizeof(Savepoint),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "Savepoint",
|
||||
.tp_methods = methods,
|
||||
.tp_new = new,
|
||||
};
|
||||
|
||||
INIT_TYPE(Savepoint)
|
||||
|
||||
Savepoint *alloc_savepoint() {
|
||||
return (Savepoint*)new(&Savepoint_Type, NULL, NULL);
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
@ -34,12 +34,9 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
self->cursor = alloc_cursor();
|
||||
self->main_linebuf = alloc_linebuf(lines, columns); self->alt_linebuf = alloc_linebuf(lines, columns);
|
||||
self->linebuf = self->main_linebuf;
|
||||
// TODO: Change the savepoints objects to use a circular buffer, so there are no mallocs during normal operation
|
||||
self->main_savepoints = PyList_New(0); self->alt_savepoints = PyList_New(0);
|
||||
self->savepoints = self->main_savepoints;
|
||||
self->change_tracker = alloc_change_tracker(lines, columns);
|
||||
self->tabstops = PyMem_Calloc(self->columns, sizeof(bool));
|
||||
if (self->cursor == NULL || self->main_linebuf == NULL || self->alt_linebuf == NULL || self->main_savepoints == NULL || self->alt_savepoints == NULL || self->change_tracker == NULL || self->tabstops == NULL) {
|
||||
if (self->cursor == NULL || self->main_linebuf == NULL || self->alt_linebuf == NULL || self->change_tracker == NULL || self->tabstops == NULL) {
|
||||
Py_CLEAR(self); return NULL;
|
||||
}
|
||||
}
|
||||
@ -114,7 +111,7 @@ dealloc(Screen* self) {
|
||||
Py_CLEAR(self->cursor);
|
||||
Py_CLEAR(self->main_linebuf);
|
||||
Py_CLEAR(self->alt_linebuf);
|
||||
Py_CLEAR(self->main_savepoints); Py_CLEAR(self->alt_savepoints); Py_CLEAR(self->change_tracker);
|
||||
Py_CLEAR(self->change_tracker);
|
||||
PyMem_Free(self->tabstops);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
} // }}}
|
||||
@ -341,10 +338,8 @@ void screen_toggle_screen_buffer(Screen *self) {
|
||||
screen_save_cursor(self);
|
||||
if (self->linebuf == self->main_linebuf) {
|
||||
self->linebuf = self->alt_linebuf;
|
||||
self->savepoints = self->alt_savepoints;
|
||||
} else {
|
||||
self->linebuf = self->main_linebuf;
|
||||
self->savepoints = self->main_savepoints;
|
||||
}
|
||||
screen_restore_cursor(self);
|
||||
tracker_update_screen(self->change_tracker);
|
||||
@ -573,38 +568,33 @@ void screen_linefeed(Screen *self, uint8_t UNUSED ch) {
|
||||
}
|
||||
|
||||
void screen_save_cursor(Screen *self) {
|
||||
// We fail silently on out of memory errors
|
||||
Savepoint *sp = alloc_savepoint();
|
||||
if (sp == NULL) { PyErr_Clear(); return; }
|
||||
sp->cursor = cursor_copy(self->cursor);
|
||||
if (sp->cursor == NULL) { Py_CLEAR(sp); PyErr_Clear(); return; }
|
||||
SavepointBuffer *pts = self->linebuf == self->main_linebuf ? &self->main_savepoints : &self->alt_savepoints;
|
||||
Savepoint *sp = savepoints_push(pts);
|
||||
cursor_copy_to(self->cursor, &(sp->cursor));
|
||||
sp->g0_charset = self->g0_charset;
|
||||
sp->g1_charset = self->g1_charset;
|
||||
sp->current_charset = self->current_charset;
|
||||
sp->mDECOM = self->modes.mDECOM;
|
||||
sp->mDECAWM = self->modes.mDECAWM;
|
||||
sp->utf8_state = self->utf8_state;
|
||||
PyList_Append(self->savepoints, (PyObject*)sp); // We ignore failures
|
||||
Py_CLEAR(sp);
|
||||
}
|
||||
|
||||
void screen_restore_cursor(Screen *self) {
|
||||
Py_ssize_t sz = PyList_GET_SIZE(self->savepoints);
|
||||
if (sz > 0) {
|
||||
Savepoint *sp = (Savepoint*)PyList_GET_ITEM(self->savepoints, sz - 1);
|
||||
SavepointBuffer *pts = self->linebuf == self->main_linebuf ? &self->main_savepoints : &self->alt_savepoints;
|
||||
Savepoint *sp = savepoints_pop(pts);
|
||||
if (sp == NULL) {
|
||||
screen_cursor_position(self, 1, 1);
|
||||
tracker_cursor_changed(self->change_tracker);
|
||||
screen_reset_mode(self, DECOM);
|
||||
} else {
|
||||
self->g0_charset = sp->g0_charset;
|
||||
self->g1_charset = sp->g1_charset;
|
||||
self->current_charset = sp->current_charset;
|
||||
self->utf8_state = sp->utf8_state;
|
||||
if (sp->mDECOM) screen_set_mode(self, DECOM);
|
||||
if (sp->mDECAWM) screen_set_mode(self, DECAWM);
|
||||
self->cursor = cursor_copy(sp->cursor);
|
||||
cursor_copy_to(&(sp->cursor), self->cursor);
|
||||
screen_ensure_bounds(self, false);
|
||||
PyList_SetSlice(self->savepoints, sz-1, sz, NULL);
|
||||
} else {
|
||||
screen_cursor_position(self, 1, 1);
|
||||
tracker_cursor_changed(self->change_tracker);
|
||||
screen_reset_mode(self, DECOM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user