From 0a48c0f1af4b35338d2360f6efa4c467ec60b60d Mon Sep 17 00:00:00 2001 From: Bardur Arantsson Date: Sat, 17 Sep 2016 09:58:15 +0200 Subject: Refactor messages.cc to use boost::circular_buffer We might as well delegate the massive implementation complexity and get rid of a ton of legacy code. --- src/messages.cc | 370 ++++++-------------------------------------------------- 1 file changed, 34 insertions(+), 336 deletions(-) (limited to 'src/messages.cc') diff --git a/src/messages.cc b/src/messages.cc index a4ce949d..c2f8d079 100644 --- a/src/messages.cc +++ b/src/messages.cc @@ -1,10 +1,8 @@ #include "messages.hpp" -#include "tome/make_array.hpp" - -#include "z-term.h" -#include "z-form.h" -#include "z-util.h" +#include +#include +#include /* * OPTION: Maximum number of messages to remember (see "io.c") @@ -12,357 +10,57 @@ */ #define MESSAGE_MAX 2048 -/* - * OPTION: Maximum space for the message text buffer (see "io.c") - * Default: assume that each of the 2048 messages is repeated an - * average of three times, and has an average length of 48 - */ -#define MESSAGE_BUF 32768 - - - - -/* - * The next "free" index to use - */ -static u16b message__next; - -/* - * The index of the oldest message (none yet) - */ -static u16b message__last; - -/* - * The next "free" offset +/** + * Circular buffer for the messages */ -static u16b message__head; - -/* - * The offset to the oldest used char (none yet) - */ -static u16b message__tail; - -/* - * The array of offsets, by index [MESSAGE_MAX] - */ -static u16b *message__ptr; - -/* - * The array of colors, by index [MESSAGE_MAX] - */ -static byte *message__color; - -/* - * The array of message counts, by index [MESSAGE_MAX] - */ -static u16b *message__count; - -/* - * The array of chars, by offset [MESSAGE_BUF] - */ -static char *message__buf; - - -/* -* Second try for the "message" handling routines. -* -* Each call to "message_add(s)" will add a new "most recent" message -* to the "message recall list", using the contents of the string "s". -* -* The messages will be stored in such a way as to maximize "efficiency", -* that is, we attempt to maximize the number of sequential messages that -* can be retrieved, given a limited amount of storage space. -* -* We keep a buffer of chars to hold the "text" of the messages, not -* necessarily in "order", and an array of offsets into that buffer, -* representing the actual messages. This is made more complicated -* by the fact that both the array of indexes, and the buffer itself, -* are both treated as "circular arrays" for efficiency purposes, but -* the strings may not be "broken" across the ends of the array. -* -* The "message_add()" function is rather "complex", because it must be -* extremely efficient, both in space and time, for use with the Borg. -*/ - -void message_init() +static boost::circular_buffer *buffer() { - /* Message variables */ - message__ptr = make_array(MESSAGE_MAX); - message__color = make_array(MESSAGE_MAX); - message__count = make_array(MESSAGE_MAX); - message__buf = make_array(MESSAGE_BUF); - - /* Hack -- No messages yet */ - message__tail = MESSAGE_BUF; + static auto *instance = new boost::circular_buffer(MESSAGE_MAX); + return instance; } -/* -* How many messages are "available"? -*/ s16b message_num(void) { - int last, next, n; - - /* Extract the indexes */ - last = message__last; - next = message__next; - - /* Handle "wrap" */ - if (next < last) next += MESSAGE_MAX; - - /* Extract the space */ - n = (next - last); - - /* Return the result */ - return (n); -} - - - -/* -* Recall the "text" of a saved message -*/ -cptr message_str(int age) -{ - static char buf[1024]; - s16b x; - s16b o; - cptr s; - - /* Forgotten messages have no text */ - if ((age < 0) || (age >= message_num())) return (""); - - /* Acquire the "logical" index */ - x = (message__next + MESSAGE_MAX - (age + 1)) % MESSAGE_MAX; - - /* Get the "offset" for the message */ - o = message__ptr[x]; - - /* Access the message text */ - s = &message__buf[o]; - - /* Hack -- Handle repeated messages */ - if (message__count[x] > 1) - { - strnfmt(buf, 1024, "%s <%dx>", s, message__count[x]); - s = buf; - } - - /* Return the message text */ - return (s); + return buffer()->size(); } -/* -* Recall the color of a saved message -*/ -byte message_color(int age) +message const &message_at(int age) { - s16b x; - byte color = TERM_WHITE; + assert(age >= 0); + assert(age < message_num()); - /* Forgotten messages have no text */ - if ((age < 0) || (age >= message_num())) return (TERM_WHITE); + // Age indexes backward through history and is zero-based, so... + std::size_t i = buffer()->size() - 1 - age; - /* Acquire the "logical" index */ - x = (message__next + MESSAGE_MAX - (age + 1)) % MESSAGE_MAX; - - /* Get the "offset" for the message */ - color = message__color[x]; - - /* Return the message text */ - return (color); + // Get the message + return buffer()->at(i); } - -/* -* Add a new message, with great efficiency -*/ void message_add(cptr str, byte color) { - int i, k, x, n; - cptr s; - - - /*** Step 1 -- Analyze the message ***/ - - /* Hack -- Ignore "non-messages" */ - if (!str) return; + assert(str != nullptr); - /* Message length */ - n = strlen(str); + // Shorthand to avoid syntactic clutter + auto buf = buffer(); - /* Important Hack -- Ignore "long" messages */ - if (n >= MESSAGE_BUF / 4) return; - - - /*** Step 2 -- Handle repeated messages ***/ - - /* Acquire the "logical" last index */ - x = (message__next + MESSAGE_MAX - 1) % MESSAGE_MAX; - - /* Get the last message text */ - s = &message__buf[message__ptr[x]]; - - /* Last message repeated? */ - if (streq(str, s)) + // If the message is the same as the last message, + // we just increment the counter instead of adding + // the message. + if ((!buf->empty()) && (buf->back().text == str)) { - /* Increase the message count */ - message__count[x]++; - - /* Success */ - return; - } - - - /*** Step 3 -- Attempt to optimize ***/ - - /* Limit number of messages to check */ - k = message_num() / 4; - - /* Limit number of messages to check */ - if (k > MESSAGE_MAX / 32) k = MESSAGE_MAX / 32; - - /* Check the last few messages (if any to count) */ - for (i = message__next; k; k--) - { - u16b q; - - cptr old; - - /* Back up and wrap if needed */ - if (i-- == 0) i = MESSAGE_MAX - 1; - - /* Stop before oldest message */ - if (i == message__last) break; - - /* Extract "distance" from "head" */ - q = (message__head + MESSAGE_BUF - message__ptr[i]) % MESSAGE_BUF; - - /* Do not optimize over large distance */ - if (q > MESSAGE_BUF / 2) continue; - - /* Access the old string */ - old = &message__buf[message__ptr[i]]; - - /* Compare */ - if (!streq(old, str)) continue; - - /* Get the next message index, advance */ - x = message__next++; - - /* Handle wrap */ - if (message__next == MESSAGE_MAX) message__next = 0; - - /* Kill last message if needed */ - if (message__next == message__last) message__last++; - - /* Handle wrap */ - if (message__last == MESSAGE_MAX) message__last = 0; - - /* Assign the starting address */ - message__ptr[x] = message__ptr[i]; - message__color[x] = color; - message__count[x] = 1; - - /* Success */ + buf->back().count += 1; return; } + // Push onto the end of the buffer. + message message; + message.color = color; + message.count = 1; + message.text = str; + buf->push_back(message); +} - /*** Step 4 -- Ensure space before end of buffer ***/ - - /* Kill messages and Wrap if needed */ - if (message__head + n + 1 >= MESSAGE_BUF) - { - /* Kill all "dead" messages */ - for (i = message__last; TRUE; i++) - { - /* Wrap if needed */ - if (i == MESSAGE_MAX) i = 0; - - /* Stop before the new message */ - if (i == message__next) break; - - /* Kill "dead" messages */ - if (message__ptr[i] >= message__head) - { - /* Track oldest message */ - message__last = i + 1; - } - } - - /* Wrap "tail" if needed */ - if (message__tail >= message__head) message__tail = 0; - - /* Start over */ - message__head = 0; - } - - - /*** Step 5 -- Ensure space before next message ***/ - - /* Kill messages if needed */ - if (message__head + n + 1 > message__tail) - { - /* Grab new "tail" */ - message__tail = message__head + n + 1; - - /* Advance tail while possible past first "nul" */ - while (message__buf[message__tail - 1]) message__tail++; - - /* Kill all "dead" messages */ - for (i = message__last; TRUE; i++) - { - /* Wrap if needed */ - if (i == MESSAGE_MAX) i = 0; - - /* Stop before the new message */ - if (i == message__next) break; - - /* Kill "dead" messages */ - if ((message__ptr[i] >= message__head) && - (message__ptr[i] < message__tail)) - { - /* Track oldest message */ - message__last = i + 1; - } - } - } - - - /*** Step 6 -- Grab a new message index ***/ - - /* Get the next message index, advance */ - x = message__next++; - - /* Handle wrap */ - if (message__next == MESSAGE_MAX) message__next = 0; - - /* Kill last message if needed */ - if (message__next == message__last) message__last++; - - /* Handle wrap */ - if (message__last == MESSAGE_MAX) message__last = 0; - - - - /*** Step 7 -- Insert the message text ***/ - - /* Assign the starting address */ - message__ptr[x] = message__head; - message__color[x] = color; - message__count[x] = 1; - - /* Append the new part of the message */ - for (i = 0; i < n; i++) - { - /* Copy the message */ - message__buf[message__head + i] = str[i]; - } - - /* Terminate */ - message__buf[message__head + i] = '\0'; - - /* Advance the "head" pointer */ - message__head += n + 1; +void message_add(message const &message) +{ + buffer()->push_back(message); } -- cgit v1.2.3