Rename cached_esc_sequences_t to layout_cache_t

Preparation for migrating the prompt cache into this struct.
This commit is contained in:
ridiculousfish 2018-02-04 15:03:50 -08:00
parent 634feac600
commit d1436486e2
4 changed files with 54 additions and 45 deletions

View file

@ -606,7 +606,7 @@ static void init_curses() {
term_has_xn = tigetflag((char *)"xenl") == 1; // does terminal have the eat_newline_glitch
update_fish_color_support();
// Invalidate the cached escape sequences since they may no longer be valid.
cached_esc_sequences.clear();
cached_layouts.clear();
curses_initialized = true;
}

View file

@ -4333,27 +4333,27 @@ void test_maybe() {
}
void test_cached_esc_sequences() {
cached_esc_sequences_t seqs;
do_test(seqs.find_entry(L"abc") == 0);
seqs.add_entry(L"abc");
seqs.add_entry(L"abc");
do_test(seqs.size() == 1);
do_test(seqs.find_entry(L"abc") == 3);
do_test(seqs.find_entry(L"abcd") == 3);
do_test(seqs.find_entry(L"abcde") == 3);
do_test(seqs.find_entry(L"xabcde") == 0);
seqs.add_entry(L"ac");
do_test(seqs.find_entry(L"abcd") == 3);
do_test(seqs.find_entry(L"acbd") == 2);
seqs.add_entry(L"wxyz");
do_test(seqs.find_entry(L"abc") == 3);
do_test(seqs.find_entry(L"abcd") == 3);
do_test(seqs.find_entry(L"wxyz123") == 4);
do_test(seqs.find_entry(L"qwxyz123") == 0);
do_test(seqs.size() == 3);
layout_cache_t seqs;
do_test(seqs.find_escape_code(L"abc") == 0);
seqs.add_escape_code(L"abc");
seqs.add_escape_code(L"abc");
do_test(seqs.esc_cache_size() == 1);
do_test(seqs.find_escape_code(L"abc") == 3);
do_test(seqs.find_escape_code(L"abcd") == 3);
do_test(seqs.find_escape_code(L"abcde") == 3);
do_test(seqs.find_escape_code(L"xabcde") == 0);
seqs.add_escape_code(L"ac");
do_test(seqs.find_escape_code(L"abcd") == 3);
do_test(seqs.find_escape_code(L"acbd") == 2);
seqs.add_escape_code(L"wxyz");
do_test(seqs.find_escape_code(L"abc") == 3);
do_test(seqs.find_escape_code(L"abcd") == 3);
do_test(seqs.find_escape_code(L"wxyz123") == 4);
do_test(seqs.find_escape_code(L"qwxyz123") == 0);
do_test(seqs.esc_cache_size() == 3);
seqs.clear();
do_test(seqs.size() == 0);
do_test(seqs.find_entry(L"abcd") == 0);
do_test(seqs.esc_cache_size() == 0);
do_test(seqs.find_escape_code(L"abcd") == 0);
}
/// Main test.

View file

@ -81,7 +81,7 @@ class scoped_buffer_t {
// Singleton of the cached escape sequences seen in prompts and similar strings.
// Note this is deliberately exported so that init_curses can clear it.
cached_esc_sequences_t cached_esc_sequences;
layout_cache_t cached_layouts;
/// Tests if the specified narrow character sequence is present at the specified position of the
/// specified wide character string. All of \c seq must match, but str may be longer than seq.
@ -269,7 +269,7 @@ size_t escape_code_length(const wchar_t *code) {
assert(code != NULL);
if (*code != L'\e') return 0;
size_t esc_seq_len = cached_esc_sequences.find_entry(code);
size_t esc_seq_len = cached_layouts.find_escape_code(code);
if (esc_seq_len) return esc_seq_len;
bool found = is_color_escape_seq(code, &esc_seq_len);
@ -279,17 +279,10 @@ size_t escape_code_length(const wchar_t *code) {
if (!found) found = is_single_byte_escape_seq(code, &esc_seq_len);
if (!found) found = is_csi_style_escape_seq(code, &esc_seq_len);
if (!found) found = is_two_byte_escape_seq(code, &esc_seq_len);
if (found) cached_esc_sequences.add_entry(wcstring(code, esc_seq_len));
if (found) cached_layouts.add_escape_code(wcstring(code, esc_seq_len));
return esc_seq_len;
}
// Information about the layout of a prompt.
struct prompt_layout_t {
size_t line_count; // how many lines the prompt consumes
size_t max_line_width; // width of the longest line
size_t last_line_width; // width of the last line
};
// These are used by `calc_prompt_layout()` to avoid redundant calculations.
static const wchar_t *cached_left_prompt = wcsdup(L"");
static const wchar_t *cached_right_prompt = wcsdup(L"");

View file

@ -16,9 +16,10 @@
#include <algorithm>
#include <cstddef>
#include <list>
#include <memory>
#include <unordered_set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "common.h"
@ -199,45 +200,60 @@ bool screen_force_clear_to_end();
/// Returns the length of an escape code. Exposed for testing purposes only.
size_t escape_code_length(const wchar_t *code);
// Information about the layout of a prompt.
struct prompt_layout_t {
size_t line_count; // how many lines the prompt consumes
size_t max_line_width; // width of the longest line
size_t last_line_width; // width of the last line
};
// Maintain a mapping of escape sequences to their length for fast lookup.
class cached_esc_sequences_t {
class layout_cache_t {
private:
// Cached escape sequences we've already detected in the prompt and similar strings, ordered
// lexicographically.
std::vector<wcstring> cache_;
std::vector<wcstring> esc_cache_;
// LRU-list of prompts and their layouts.
// Use a list so we can promote to the front on a cache hit.
using prompt_layout_pair_t = std::pair<wcstring, prompt_layout_t>;
std::list<prompt_layout_pair_t> prompt_cache_;
public:
/// \return the size of the cache.
size_t size() const { return cache_.size(); }
/// \return the size of the escape code cache.
size_t esc_cache_size() const { return esc_cache_.size(); }
/// Insert the entry \p str in its sorted position, if it is not already present in the cache.
void add_entry(wcstring str) {
auto where = std::upper_bound(cache_.begin(), cache_.end(), str);
if (where == cache_.begin() || where[-1] != str) {
cache_.emplace(where, std::move(str));
void add_escape_code(wcstring str) {
auto where = std::upper_bound(esc_cache_.begin(), esc_cache_.end(), str);
if (where == esc_cache_.begin() || where[-1] != str) {
esc_cache_.emplace(where, std::move(str));
}
}
/// \return the length of a string that matches a prefix of \p entry.
size_t find_entry(const wchar_t *entry) const {
size_t find_escape_code(const wchar_t *entry) const {
// Do a binary search and see if the escape code right before our entry is a prefix of our
// entry. Note this assumes that escape codes are prefix-free: no escape code is a prefix of
// another one. This seems like a safe assumption.
auto where = std::upper_bound(cache_.begin(), cache_.end(), entry);
auto where = std::upper_bound(esc_cache_.begin(), esc_cache_.end(), entry);
// 'where' is now the first element that is greater than entry. Thus where-1 is the last
// element that is less than or equal to entry.
if (where != cache_.begin()) {
if (where != esc_cache_.begin()) {
const wcstring &candidate = where[-1];
if (string_prefixes_string(candidate.c_str(), entry)) return candidate.size();
}
return 0;
}
void clear() { cache_.clear(); }
void clear() {
esc_cache_.clear();
prompt_cache_.clear();
}
};
// Singleton that is exposed so that the cache can be invalidated when terminal related variables
// change by calling `cached_esc_sequences.clear()`.
extern cached_esc_sequences_t cached_esc_sequences;
extern layout_cache_t cached_layouts;
#endif