[console] Rework con_buffer ring buffers to have gaps

I really don't know why I tried to do ring-buffers without gaps, the
code complication is just not worth the tiny savings in memory. In fact,
just the switch from pointers to 32-bit offsets saves more memory than
not having gaps (on 64-bit systems, no change on 32-bit).
This commit is contained in:
Bill Currie 2022-09-18 11:30:40 +09:00
parent 5e8d18a774
commit 48e5848a41
6 changed files with 101 additions and 97 deletions

View file

@ -28,9 +28,8 @@
#ifndef __QF_console_h
#define __QF_console_h
#include <stdarg.h>
#include <stdint.h>
#include "QF/keys.h"
#include "QF/qtypes.h"
/** \defgroup console 2d Console Stuff
@ -47,17 +46,17 @@ typedef struct
} old_console_t;
typedef struct {
byte *text;
size_t len;
uint32_t text;
uint32_t len;
} con_line_t;
typedef struct {
byte *buffer;
size_t buffer_size;
con_line_t *lines;
int max_lines; // size of lines array
int num_lines; // number of lines used
int cur_line; // current line
byte *buffer;
con_line_t *lines;
uint32_t buffer_size;
uint32_t max_lines; // size of lines array
uint32_t line_head; // number of lines used
uint32_t line_tail; // current line
} con_buffer_t;
typedef enum {

View file

@ -43,6 +43,7 @@
#include "QF/cvar.h"
#include "QF/dstring.h"
#include "QF/input.h"
#include "QF/keys.h"
#include "QF/plist.h"
#include "QF/sys.h"

View file

@ -55,9 +55,8 @@ Con_CreateBuffer (size_t buffer_size, int max_lines)
if (!(buffer->lines = calloc (max_lines, sizeof (con_line_t))))
goto err;
buffer->max_lines = max_lines;
buffer->num_lines = 1;
buffer->cur_line = 0;
buffer->lines[0].text = buffer->buffer;
buffer->line_head = 1;
buffer->line_tail = 0;
return buffer;
err:
if (buffer->buffer)
@ -77,54 +76,52 @@ Con_DestroyBuffer (con_buffer_t *buffer)
VISIBLE void
Con_BufferAddText (con_buffer_t *buf, const char *text)
{
con_line_t *cur_line = &buf->lines[buf->cur_line];
size_t len = strlen (text);
// Point to the oldest line in the buffer (first to be dropped when
// the buffer overflows).
con_line_t *tail_line = buf->lines + (buf->cur_line + 1 - buf->num_lines
+ buf->max_lines) % buf->max_lines;
con_line_t *cur_line = &buf->lines[(buf->line_head - 1 + buf->max_lines)
% buf->max_lines];
con_line_t *tail_line = &buf->lines[buf->line_tail];
uint32_t text_head = (cur_line->text + cur_line->len) % buf->buffer_size;
byte c;
byte *pos = cur_line->text + cur_line->len;
if (pos >= buf->buffer + buf->buffer_size)
pos -= buf->buffer_size;
// Limit the appended text to the size of the buffer. The entire buffer
// may be overwritten.
if (len > buf->buffer_size) {
text += len - buf->buffer_size;
len = buf->buffer_size;
}
while (len--) {
// Drop the oldest line if it will be overwritten by the next
// character to be inserted. However, if there is only one line,
// then tail_line is effectively invalid and should not be touched.
// This happens when the buffer is filled with a single line of text.
if (buf->num_lines > 1 && pos == tail_line->text) {
buf->num_lines--;
tail_line->text = 0;
tail_line->len = 0;
tail_line++;
if (tail_line - buf->lines >= buf->max_lines)
tail_line = buf->lines;
}
// Copy character into the buffer, updating the current line length
// (trailing \n is part of the line).
byte c = *pos++ = *text++;
if (pos >= buf->buffer + buf->buffer_size)
pos = buf->buffer;
while ((c = *text++)) {
cur_line->len++;
buf->buffer[text_head++] = c;
if (text_head >= buf->buffer_size) {
text_head -= buf->buffer_size;
}
if (text_head == tail_line->text) {
tail_line->len--;
buf->buffer[tail_line->text++] = 0;
if (tail_line->text >= buf->buffer_size) {
tail_line->text -= buf->buffer_size;
}
if (!tail_line->len) {
buf->line_tail++;
buf->line_tail %= buf->max_lines;
tail_line = &buf->lines[buf->line_tail];
}
}
if (c == '\n') {
if (buf->num_lines < buf->max_lines)
buf->num_lines++;
cur_line++;
buf->cur_line++;
if (cur_line - buf->lines >= buf->max_lines)
cur_line = buf->lines;
cur_line->text = pos;
if (cur_line - buf->lines >= buf->max_lines) {
cur_line -= buf->max_lines;
}
cur_line->text = text_head;
cur_line->len = 0;
buf->line_head++;
if (buf->line_head >= buf->max_lines) {
buf->line_head -= buf->max_lines;
}
if (buf->line_head == buf->line_tail) {
buf->lines[buf->line_tail].text = 0;
buf->lines[buf->line_tail].len = 0;
buf->line_tail++;
if (buf->line_tail >= buf->max_lines) {
buf->line_tail -= buf->max_lines;
}
}
}
}
buf->cur_line %= buf->max_lines;
}

View file

@ -40,6 +40,7 @@
#include "QF/cvar.h"
#include "QF/draw.h"
#include "QF/hash.h"
#include "QF/keys.h"
#include "QF/progs.h"
#include "QF/quakefs.h"
#include "QF/render.h"

View file

@ -277,7 +277,7 @@ draw_output (view_t *view)
// this is not the most efficient way to update the screen, but oh well
int lines = view->ylen - 1; // leave a blank line
int width = view->xlen;
int cur_line = output_buffer->cur_line + view_offset;
int cur_line = output_buffer->line_head - 1 + view_offset;
int i, y;
if (lines < 1)
@ -297,7 +297,7 @@ draw_output (view_t *view)
wmove (win, 0, 0);
do {
con_line_t *l = Con_BufferLine (output_buffer, cur_line++);
byte *text = l->text;
byte *text = output_buffer->buffer + l->text;
int len = l->len;
if (y > 0) {
@ -306,12 +306,12 @@ draw_output (view_t *view)
y = 0;
if (len < 1) {
len = 1;
text = l->text + l->len - 1;
text = output_buffer->buffer + l->text + l->len - 1;
}
}
while (len--)
draw_fun_char (win, *text++, 0);
} while (cur_line < output_buffer->cur_line + view_offset);
} while (cur_line < (int) output_buffer->line_head - 1 + view_offset);
}
static void
@ -526,14 +526,17 @@ key_event (knum_t key, short unicode, qboolean down)
int ovf = view_offset;
sv_view_t *sv_view;
con_buffer_t *buffer;
int num_lines;
switch (key) {
case QFK_PAGEUP:
view_offset -= 10;
sv_view = output->data;
buffer = sv_view->obj;
if (view_offset <= -(buffer->num_lines - (screen_y - 3)))
view_offset = -(buffer->num_lines - (screen_y - 3)) + 1;
num_lines = (buffer->line_head - buffer->line_tail
+ buffer->max_lines) % buffer->max_lines;
if (view_offset <= -(num_lines - (screen_y - 3)))
view_offset = -(num_lines - (screen_y - 3)) + 1;
if (ovf != view_offset)
sv_draw (output);
break;

View file

@ -26,29 +26,29 @@ test_1 (void)
goto fail;
}
if (con->buffer_size != 1024) {
printf ("con_buffer buffer_size incorrect: %zd\n", con->buffer_size);
printf ("con_buffer buffer_size incorrect: %u\n", con->buffer_size);
goto fail;
}
if (con->max_lines != 25) {
printf ("con_buffer max_lines incorrect: %d\n", con->max_lines);
goto fail;
}
if (con->num_lines != 1) {
printf ("con_buffer num_lines incorrect: %d\n", con->num_lines);
if (con->line_head != 1) {
printf ("con_buffer line_head incorrect: %d\n", con->line_head);
goto fail;
}
if (con->cur_line != 0) {
printf ("con_buffer cur_line incorrect: %d\n", con->cur_line);
if (con->line_tail != 0) {
printf ("con_buffer line_tail incorrect: %d\n", con->line_tail);
goto fail;
}
if (con->lines[con->cur_line].text != con->buffer) {
printf ("con_buffer cur_line.text incorrect: %p, %p\n",
con->lines[con->cur_line].text, con->buffer);
if (con->lines[con->line_tail].text != 0) {
printf ("con_buffer line_tail.text incorrect: %u\n",
con->lines[con->line_tail].text);
goto fail;
}
if (con->lines[con->cur_line].len != 0) {
printf ("con_buffer cur_line.line incorrect: %zd\n",
con->lines[con->cur_line].len);
if (con->lines[con->line_tail].len != 0) {
printf ("con_buffer line_tail.len incorrect: %u\n",
con->lines[con->line_tail].len);
goto fail;
}
@ -73,55 +73,58 @@ test_2 (void)
__auto_type con = Con_CreateBuffer (1024, 25);
Con_BufferAddText (con, text);
if (con->num_lines != 1) {
printf ("con_buffer num_lines incorrect: %d\n", con->num_lines);
if (con->line_head != 1) {
printf ("con_buffer num_lines incorrect: %d\n", con->line_head);
goto fail;
}
if (con->cur_line != 0) {
printf ("con_buffer cur_line incorrect: %d\n", con->cur_line);
if (con->line_tail != 0) {
printf ("con_buffer line_tail incorrect: %d\n", con->line_tail);
goto fail;
}
if (con->lines[con->cur_line].text != con->buffer) {
printf ("con_buffer cur_line.text incorrect: %p, %p\n",
con->lines[con->cur_line].text, con->buffer);
if (con->lines[con->line_tail].text != 1) {
printf ("con_buffer line_tail.text incorrect: %u\n",
con->lines[con->line_tail].text);
goto fail;
}
if (con->lines[con->cur_line].len != 1024) {
printf ("con_buffer cur_line.line incorrect: %zd\n",
con->lines[con->cur_line].len);
if (con->lines[con->line_tail].len != 1023) {
printf ("con_buffer line_tail.len incorrect: %u\n",
con->lines[con->line_tail].len);
goto fail;
}
if (memcmp (con->buffer, text + 1024, 1024)) {
if (memcmp (con->buffer + 1, text + 1025, 1023)
|| con->buffer[0] != 0) {
printf ("con_buffer incorrect\n");
goto fail;
}
// add a single char at the end of the full buffer the buffer should
// Add a single char at the end of the full buffer. The buffer should
// just effectively scroll through the text as chars are added (via
// the single line object maintaining constant length but updating its
// text pointer)
Con_BufferAddText (con, "N");
if (con->num_lines != 1) {
printf ("con_buffer num_lines incorrect: %d\n", con->num_lines);
if (con->line_head != 1) {
printf ("2 con_buffer num_lines incorrect: %d\n", con->line_head);
goto fail;
}
if (con->cur_line != 0) {
printf ("con_buffer cur_line incorrect: %d\n", con->cur_line);
if (con->line_tail != 0) {
printf ("2 con_buffer line_tail incorrect: %d\n", con->line_tail);
goto fail;
}
if (con->lines[con->cur_line].text != con->buffer + 1) {
printf ("con_buffer cur_line.text incorrect: %p, %p\n",
con->lines[con->cur_line].text, con->buffer + 1);
if (con->lines[con->line_tail].text != 2) {
printf ("2 con_buffer line_tail.text incorrect: %u\n",
con->lines[con->line_tail].text);
goto fail;
}
if (con->lines[con->cur_line].len != 1024) {
printf ("con_buffer cur_line.line incorrect: %zd\n",
con->lines[con->cur_line].len);
if (con->lines[con->line_tail].len != 1023) {
printf ("2 con_buffer line_tail.len incorrect: %u\n",
con->lines[con->line_tail].len);
goto fail;
}
if (memcmp (con->buffer + 1, text + 1024 + 1, 1024 - 1)
|| con->buffer[0] != 'N') {
printf ("con_buffer incorrect\n");
if (memcmp (con->buffer + 2, text + 1026, 1022)
|| con->buffer[0] != 'N'
|| con->buffer[1] != 0) {
printf ("2 con_buffer incorrect\n");
goto fail;
}