mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[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:
parent
5e8d18a774
commit
48e5848a41
6 changed files with 101 additions and 97 deletions
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue