From 9da1685123387d5c59e455dd5fb278e97514e9ed Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Mon, 23 Apr 2018 20:51:18 +0200 Subject: cxx: ring: Move to C++ Straight port; improvements will come later. --- src/ring.cc | 1038 +++++++++++++++++++++++++--------------------------- src/ring.hh | 253 ++++++++++--- src/vte.cc | 27 +- src/vteinternal.hh | 27 +- src/vterowdata.cc | 8 +- src/vterowdata.hh | 9 - 6 files changed, 726 insertions(+), 636 deletions(-) diff --git a/src/ring.cc b/src/ring.cc index 449e525a..dd25224c 100644 --- a/src/ring.cc +++ b/src/ring.cc @@ -18,195 +18,159 @@ * Red Hat Author(s): Nalin Dahyabhai, Behdad Esfahbod */ -#include +#include "config.h" #include "debug.h" #include "ring.hh" +#include "vterowdata.hh" #include -typedef struct _VteCellAttrChange { - gsize text_end_offset; /* offset of first character no longer using this attr */ - VteStreamCellAttr attr; -} VteCellAttrChange; +/* + * Copy the common attributes from VteCellAttr to VteStreamCellAttr or vice versa. + */ +static inline void +_attrcpy (void *dst, void *src) +{ + memcpy(dst, src, VTE_CELL_ATTR_COMMON_BYTES); +} + +using namespace vte::base; /* * VteRing: A buffer ring */ -#define hyperlink_get(ring, idx) ((GString *) g_ptr_array_index((ring)->hyperlinks, (idx))) - #ifdef VTE_DEBUG -static void -_vte_ring_validate (VteRing * ring) +void +Ring::validate() const { - g_assert(ring != NULL); _vte_debug_print(VTE_DEBUG_RING, " Delta = %lu, Length = %lu, Next = %lu, Max = %lu, Writable = %lu.\n", - ring->start, ring->end - ring->start, ring->end, - ring->max, ring->end - ring->writable); + m_start, m_end - m_start, m_end, + m_max, m_end - m_writable); - g_assert (ring->start <= ring->writable); - g_assert (ring->writable <= ring->end); + g_assert_cmpuint(m_start, <=, m_writable); + g_assert_cmpuint(m_writable, <=, m_end); - g_assert (ring->end - ring->start <= ring->max); - g_assert (ring->end - ring->writable <= ring->mask); + g_assert_cmpuint(m_end - m_start, <=, m_max); + g_assert_cmpuint(m_end - m_writable, <=, m_mask); } #else -#define _vte_ring_validate(ring) G_STMT_START {} G_STMT_END +#define validate(...) do { } while(0) #endif - -void -_vte_ring_init (VteRing *ring, gulong max_rows, gboolean has_streams) +Ring::Ring(row_t max_rows, + bool has_streams) + : m_max{MAX(max_rows, 3)}, + m_has_streams{has_streams}, + m_last_attr{basic_cell.attr} { - GString *empty_str; - - _vte_debug_print(VTE_DEBUG_RING, "New ring %p.\n", ring); - - memset (ring, 0, sizeof (*ring)); - - ring->max = MAX (max_rows, 3); + _vte_debug_print(VTE_DEBUG_RING, "New ring %p.\n", this); - ring->mask = 31; - ring->array = (VteRowData *) g_malloc0 (sizeof (ring->array[0]) * (ring->mask + 1)); + m_array = (VteRowData* ) g_malloc0 (sizeof (m_array[0]) * (m_mask + 1)); - ring->has_streams = has_streams; if (has_streams) { - ring->attr_stream = _vte_file_stream_new (); - ring->text_stream = _vte_file_stream_new (); - ring->row_stream = _vte_file_stream_new (); + m_attr_stream = _vte_file_stream_new (); + m_text_stream = _vte_file_stream_new (); + m_row_stream = _vte_file_stream_new (); } else { - ring->attr_stream = ring->text_stream = ring->row_stream = NULL; + m_attr_stream = m_text_stream = m_row_stream = nullptr; } - ring->last_attr_text_start_offset = 0; - ring->last_attr = basic_cell.attr; - ring->utf8_buffer = g_string_sized_new (128); + m_utf8_buffer = g_string_sized_new (128); - _vte_row_data_init (&ring->cached_row); - ring->cached_row_num = (gulong) -1; + _vte_row_data_init (&m_cached_row); - ring->visible_rows = 0; + m_hyperlinks = g_ptr_array_new(); + auto empty_str = g_string_new_len("", 0); + g_ptr_array_add(m_hyperlinks, empty_str); - ring->hyperlinks = g_ptr_array_new(); - empty_str = g_string_new_len("", 0); - g_ptr_array_add(ring->hyperlinks, empty_str); - ring->hyperlink_highest_used_idx = 0; - ring->hyperlink_current_idx = 0; - ring->hyperlink_hover_idx = 0; - ring->hyperlink_maybe_gc_counter = 0; - - _vte_ring_validate(ring); + validate(); } -void -_vte_ring_fini (VteRing *ring) +Ring::~Ring() { - gulong i; - - for (i = 0; i <= ring->mask; i++) - _vte_row_data_fini (&ring->array[i]); + for (size_t i = 0; i <= m_mask; i++) + _vte_row_data_fini (&m_array[i]); - g_free (ring->array); + g_free (m_array); - if (ring->has_streams) { - g_object_unref (ring->attr_stream); - g_object_unref (ring->text_stream); - g_object_unref (ring->row_stream); + if (m_has_streams) { + g_object_unref (m_attr_stream); + g_object_unref (m_text_stream); + g_object_unref (m_row_stream); } - g_string_free (ring->utf8_buffer, TRUE); - - for (i = 0; i < ring->hyperlinks->len; i++) - g_string_free (hyperlink_get(ring, i), TRUE); - g_ptr_array_free (ring->hyperlinks, TRUE); - - _vte_row_data_fini (&ring->cached_row); -} - -typedef struct _VteRowRecord { - gsize text_start_offset; /* offset where text of this row begins */ - gsize attr_start_offset; /* offset of the first character's attributes */ - int soft_wrapped: 1; /* end of line is not '\n' */ - int is_ascii: 1; /* for rewrapping speedup: guarantees that line contains 32..126 bytes only. Can be 0 even when ascii only. */ -} VteRowRecord; - -/* Represents a cell position, see ../doc/rewrap.txt */ -typedef struct _VteCellTextOffset { - gsize text_offset; /* byte offset in text_stream (or perhaps beyond) */ - gint fragment_cells; /* extra number of cells to walk within a multicell character */ - gint eol_cells; /* -1 if over a character, >=0 if at EOL or beyond */ -} VteCellTextOffset; + g_string_free (m_utf8_buffer, TRUE); + for (size_t i = 0; i < m_hyperlinks->len; i++) + g_string_free (hyperlink_get(i), TRUE); + g_ptr_array_free (m_hyperlinks, TRUE); -static inline VteRowData * -_vte_ring_writable_index (VteRing *ring, gulong position) -{ - return &ring->array[position & ring->mask]; + _vte_row_data_fini(&m_cached_row); } - #define SET_BIT(buf, n) buf[(n) / 8] |= (1 << ((n) % 8)) #define GET_BIT(buf, n) ((buf[(n) / 8] >> ((n) % 8)) & 1) /* * Do a round of garbage collection. Hyperlinks that no longer occur in the ring are wiped out. */ -static void -_vte_ring_hyperlink_gc (VteRing *ring) +void +Ring::hyperlink_gc() { - gulong i, j; + row_t i, j; hyperlink_idx_t idx; - VteRowData *row; + VteRowData* row; char *used; _vte_debug_print (VTE_DEBUG_HYPERLINK, "hyperlink: GC starting (highest used idx is %d)\n", - ring->hyperlink_highest_used_idx); + m_hyperlink_highest_used_idx); - ring->hyperlink_maybe_gc_counter = 0; + m_hyperlink_maybe_gc_counter = 0; - if (ring->hyperlink_highest_used_idx == 0) { + if (m_hyperlink_highest_used_idx == 0) { _vte_debug_print (VTE_DEBUG_HYPERLINK, "hyperlink: GC done (no links at all, nothing to do)\n"); return; } /* One bit for each idx to see if it's used. */ - used = (char *) g_malloc0 (ring->hyperlink_highest_used_idx / 8 + 1); + used = (char *) g_malloc0 (m_hyperlink_highest_used_idx / 8 + 1); /* A few special values not to be garbage collected. */ - SET_BIT(used, ring->hyperlink_current_idx); - SET_BIT(used, ring->hyperlink_hover_idx); - SET_BIT(used, ring->last_attr.hyperlink_idx); + SET_BIT(used, m_hyperlink_current_idx); + SET_BIT(used, m_hyperlink_hover_idx); + SET_BIT(used, m_last_attr.hyperlink_idx); - for (i = ring->writable; i < ring->end; i++) { - row = _vte_ring_writable_index (ring, i); + for (i = m_writable; i < m_end; i++) { + row = get_writable_index(i); for (j = 0; j < row->len; j++) { idx = row->cells[j].attr.hyperlink_idx; SET_BIT(used, idx); } } - for (idx = 1; idx <= ring->hyperlink_highest_used_idx; idx++) { - if (!GET_BIT(used, idx) && hyperlink_get(ring, idx)->len != 0) { + for (idx = 1; idx <= m_hyperlink_highest_used_idx; idx++) { + if (!GET_BIT(used, idx) && hyperlink_get(idx)->len != 0) { _vte_debug_print (VTE_DEBUG_HYPERLINK, "hyperlink: GC purging link %d to id;uri=\"%s\"\n", - idx, hyperlink_get(ring, idx)->str); + idx, hyperlink_get(idx)->str); /* Wipe out the ID and URI itself so it doesn't linger on in the memory for a long time */ - memset(hyperlink_get(ring, idx)->str, 0, hyperlink_get(ring, idx)->len); - g_string_truncate (hyperlink_get(ring, idx), 0); + memset(hyperlink_get(idx)->str, 0, hyperlink_get(idx)->len); + g_string_truncate (hyperlink_get(idx), 0); } } - while (ring->hyperlink_highest_used_idx >= 1 && hyperlink_get(ring, ring->hyperlink_highest_used_idx)->len == 0) { - ring->hyperlink_highest_used_idx--; + while (m_hyperlink_highest_used_idx >= 1 && hyperlink_get(m_hyperlink_highest_used_idx)->len == 0) { + m_hyperlink_highest_used_idx--; } _vte_debug_print (VTE_DEBUG_HYPERLINK, "hyperlink: GC done (highest used idx is now %d)\n", - ring->hyperlink_highest_used_idx); + m_hyperlink_highest_used_idx); g_free (used); } @@ -215,16 +179,16 @@ _vte_ring_hyperlink_gc (VteRing *ring) * Cumulate the given value, and do a GC when 65536 is reached. */ void -_vte_ring_hyperlink_maybe_gc (VteRing *ring, gulong increment) +Ring::hyperlink_maybe_gc(row_t increment) { - ring->hyperlink_maybe_gc_counter += increment; + m_hyperlink_maybe_gc_counter += increment; _vte_debug_print (VTE_DEBUG_HYPERLINK, "hyperlink: maybe GC, counter at %ld\n", - ring->hyperlink_maybe_gc_counter); + m_hyperlink_maybe_gc_counter); - if (ring->hyperlink_maybe_gc_counter >= 65536) - _vte_ring_hyperlink_gc (ring); + if (m_hyperlink_maybe_gc_counter >= 65536) + hyperlink_gc(); } /* @@ -236,8 +200,8 @@ _vte_ring_hyperlink_maybe_gc (VteRing *ring, gulong increment) * * FIXME do something more effective than a linear search */ -static hyperlink_idx_t -_vte_ring_get_hyperlink_idx_no_update_current (VteRing *ring, const char *hyperlink) +Ring::hyperlink_idx_t +Ring::get_hyperlink_idx_no_update_current(char const* hyperlink) { hyperlink_idx_t idx; gsize len; @@ -249,9 +213,9 @@ _vte_ring_get_hyperlink_idx_no_update_current (VteRing *ring, const char *hyperl len = strlen(hyperlink); /* Linear search for this particular URI */ - auto const last_idx = ring->hyperlink_highest_used_idx + 1; - for (idx = 1; idx < last_idx; idx++) { - if (strcmp(hyperlink_get(ring, idx)->str, hyperlink) == 0) { + auto const last_idx = m_hyperlink_highest_used_idx + 1; + for (idx = 1; idx < last_idx; ++idx) { + if (strcmp(hyperlink_get(idx)->str, hyperlink) == 0) { _vte_debug_print (VTE_DEBUG_HYPERLINK, "get_hyperlink_idx: already existing idx %d for id;uri=\"%s\"\n", idx, hyperlink); @@ -259,42 +223,42 @@ _vte_ring_get_hyperlink_idx_no_update_current (VteRing *ring, const char *hyperl } } - /* FIXME it's the second time we're GCing if coming from _vte_ring_get_hyperlink_idx */ - _vte_ring_hyperlink_gc(ring); + /* FIXME it's the second time we're GCing if coming from get_hyperlink_idx */ + hyperlink_gc(); /* Another linear search for an empty slot where a GString is already allocated */ - for (idx = 1; idx < ring->hyperlinks->len; idx++) { - if (hyperlink_get(ring, idx)->len == 0) { + for (idx = 1; idx < m_hyperlinks->len; idx++) { + if (hyperlink_get(idx)->len == 0) { _vte_debug_print (VTE_DEBUG_HYPERLINK, "get_hyperlink_idx: reassigning old idx %d for id;uri=\"%s\"\n", idx, hyperlink); /* Grow size if required, however, never shrink to avoid long-term memory fragmentation. */ - g_string_append_len (hyperlink_get(ring, idx), hyperlink, len); - ring->hyperlink_highest_used_idx = MAX (ring->hyperlink_highest_used_idx, idx); + g_string_append_len (hyperlink_get(idx), hyperlink, len); + m_hyperlink_highest_used_idx = MAX (m_hyperlink_highest_used_idx, idx); return idx; } } /* All allocated slots are in use. Gotta allocate a new one */ - g_assert_cmpuint(ring->hyperlink_highest_used_idx + 1, ==, ring->hyperlinks->len); + g_assert_cmpuint(m_hyperlink_highest_used_idx + 1, ==, m_hyperlinks->len); /* VTE_HYPERLINK_COUNT_MAX should be big enough for this not to happen under normal circumstances. Anyway, it's cheap to protect against extreme ones. */ - if (ring->hyperlink_highest_used_idx == VTE_HYPERLINK_COUNT_MAX) { + if (m_hyperlink_highest_used_idx == VTE_HYPERLINK_COUNT_MAX) { _vte_debug_print (VTE_DEBUG_HYPERLINK, "get_hyperlink_idx: idx 0 (ran out of available idxs) for id;uri=\"%s\"\n", hyperlink); return 0; } - idx = ++ring->hyperlink_highest_used_idx; + idx = ++m_hyperlink_highest_used_idx; _vte_debug_print (VTE_DEBUG_HYPERLINK, "get_hyperlink_idx: brand new idx %d for id;uri=\"%s\"\n", idx, hyperlink); str = g_string_new_len (hyperlink, len); - g_ptr_array_add(ring->hyperlinks, str); + g_ptr_array_add(m_hyperlinks, str); - g_assert_cmpuint(ring->hyperlink_highest_used_idx + 1, ==, ring->hyperlinks->len); + g_assert_cmpuint(m_hyperlink_highest_used_idx + 1, ==, m_hyperlinks->len); return idx; } @@ -308,47 +272,36 @@ _vte_ring_get_hyperlink_idx_no_update_current (VteRing *ring, const char *hyperl * * The current idx is also updated, in order not to be garbage collected. */ -guint -_vte_ring_get_hyperlink_idx (VteRing *ring, const char *hyperlink) +Ring::hyperlink_idx_t +Ring::get_hyperlink_idx(char const* hyperlink) { /* Release current idx and do a round of GC to possibly purge its hyperlink, - * even if new hyperlink is NULL or empty. */ - ring->hyperlink_current_idx = 0; - _vte_ring_hyperlink_gc(ring); + * even if new hyperlink is nullptr or empty. */ + m_hyperlink_current_idx = 0; + hyperlink_gc(); - ring->hyperlink_current_idx = _vte_ring_get_hyperlink_idx_no_update_current(ring, hyperlink); - return ring->hyperlink_current_idx; + m_hyperlink_current_idx = get_hyperlink_idx_no_update_current(hyperlink); + return m_hyperlink_current_idx; } -static gboolean -_vte_ring_read_row_record (VteRing *ring, VteRowRecord *record, gulong position) -{ - return _vte_stream_read (ring->row_stream, position * sizeof (*record), (char *) record, sizeof (*record)); -} - -static void -_vte_ring_append_row_record (VteRing *ring, const VteRowRecord *record, gulong position) -{ - _vte_stream_append (ring->row_stream, (const char *) record, sizeof (*record)); -} - -static void -_vte_ring_freeze_row (VteRing *ring, gulong position, const VteRowData *row) +void +Ring::freeze_row(row_t position, + VteRowData const* row) { - VteRowRecord record; VteCell *cell; - GString *buffer = ring->utf8_buffer; + GString *buffer = m_utf8_buffer; GString *hyperlink; int i; gboolean froze_hyperlink = FALSE; _vte_debug_print (VTE_DEBUG_RING, "Freezing row %lu.\n", position); - g_assert(ring->has_streams); + g_assert(m_has_streams); - memset(&record, 0, sizeof (record)); - record.text_start_offset = _vte_stream_head (ring->text_stream); - record.attr_start_offset = _vte_stream_head (ring->attr_stream); + RowRecord record; + memset(&record, 0, sizeof(record)); + record.text_start_offset = _vte_stream_head(m_text_stream); + record.attr_start_offset = _vte_stream_head(m_attr_stream); record.is_ascii = 1; g_string_set_size (buffer, 0); @@ -369,48 +322,48 @@ _vte_ring_freeze_row (VteRing *ring, gulong position, const VteRowData *row) */ attr = cell->attr; if (G_LIKELY (!attr.fragment())) { - VteCellAttrChange attr_change; + CellAttrChange attr_change; guint16 hyperlink_length; - if (memcmp(&ring->last_attr, &attr, sizeof (VteCellAttr)) != 0) { - ring->last_attr_text_start_offset = record.text_start_offset + buffer->len; + if (memcmp(&m_last_attr, &attr, sizeof (VteCellAttr)) != 0) { + m_last_attr_text_start_offset = record.text_start_offset + buffer->len; memset(&attr_change, 0, sizeof (attr_change)); - attr_change.text_end_offset = ring->last_attr_text_start_offset; - _attrcpy(&attr_change.attr, &ring->last_attr); - hyperlink = hyperlink_get(ring, ring->last_attr.hyperlink_idx); + attr_change.text_end_offset = m_last_attr_text_start_offset; + _attrcpy(&attr_change.attr, &m_last_attr); + hyperlink = hyperlink_get(m_last_attr.hyperlink_idx); attr_change.attr.hyperlink_length = hyperlink->len; - _vte_stream_append (ring->attr_stream, (const char *) &attr_change, sizeof (attr_change)); + _vte_stream_append (m_attr_stream, (char const* ) &attr_change, sizeof (attr_change)); if (G_UNLIKELY (hyperlink->len != 0)) { - _vte_stream_append (ring->attr_stream, hyperlink->str, hyperlink->len); + _vte_stream_append (m_attr_stream, hyperlink->str, hyperlink->len); froze_hyperlink = TRUE; } hyperlink_length = attr_change.attr.hyperlink_length; - _vte_stream_append (ring->attr_stream, (const char *) &hyperlink_length, 2); + _vte_stream_append (m_attr_stream, (char const* ) &hyperlink_length, 2); if (!buffer->len) /* This row doesn't use last_attr, adjust */ record.attr_start_offset += sizeof (attr_change) + hyperlink_length + 2; - ring->last_attr = attr; + m_last_attr = attr; } num_chars = _vte_unistr_strlen (cell->c); if (num_chars > 1) { /* Combining chars */ attr.set_columns(0); - ring->last_attr_text_start_offset = record.text_start_offset + buffer->len - + g_unichar_to_utf8 (_vte_unistr_get_base (cell->c), NULL); + m_last_attr_text_start_offset = record.text_start_offset + buffer->len + + g_unichar_to_utf8 (_vte_unistr_get_base (cell->c), nullptr); memset(&attr_change, 0, sizeof (attr_change)); - attr_change.text_end_offset = ring->last_attr_text_start_offset; - _attrcpy(&attr_change.attr, &ring->last_attr); - hyperlink = hyperlink_get(ring, ring->last_attr.hyperlink_idx); + attr_change.text_end_offset = m_last_attr_text_start_offset; + _attrcpy(&attr_change.attr, &m_last_attr); + hyperlink = hyperlink_get(m_last_attr.hyperlink_idx); attr_change.attr.hyperlink_length = hyperlink->len; - _vte_stream_append (ring->attr_stream, (const char *) &attr_change, sizeof (attr_change)); + _vte_stream_append (m_attr_stream, (char const* ) &attr_change, sizeof (attr_change)); if (G_UNLIKELY (hyperlink->len != 0)) { - _vte_stream_append (ring->attr_stream, hyperlink->str, hyperlink->len); + _vte_stream_append (m_attr_stream, hyperlink->str, hyperlink->len); froze_hyperlink = TRUE; } hyperlink_length = attr_change.attr.hyperlink_length; - _vte_stream_append (ring->attr_stream, (const char *) &hyperlink_length, 2); - ring->last_attr = attr; + _vte_stream_append (m_attr_stream, (char const* ) &hyperlink_length, 2); + m_last_attr = attr; } if (cell->c < 32 || cell->c > 126) record.is_ascii = 0; @@ -421,12 +374,12 @@ _vte_ring_freeze_row (VteRing *ring, gulong position, const VteRowData *row) g_string_append_c (buffer, '\n'); record.soft_wrapped = row->attr.soft_wrapped; - _vte_stream_append (ring->text_stream, buffer->str, buffer->len); - _vte_ring_append_row_record (ring, &record, position); + _vte_stream_append(m_text_stream, buffer->str, buffer->len); + append_row_record(&record, position); /* After freezing some hyperlinks, do a hyperlink GC. The constant is totally arbitrary, feel free to fine tune. */ if (froze_hyperlink) - _vte_ring_hyperlink_maybe_gc(ring, 1024); + hyperlink_maybe_gc(1024); } /* If do_truncate (data is placed back from the stream to the ring), real new hyperlink idxs are looked up or allocated. @@ -435,42 +388,45 @@ _vte_ring_freeze_row (VteRing *ring, gulong position, const VteRowData *row) * except for the hyperlink_hover_idx which gets this real idx. This is important for hover underlining. * * Optionally updates the hyperlink parameter to point to the ring-owned hyperlink target. */ -static void -_vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do_truncate, - int hyperlink_column, const char **hyperlink) +void +Ring::thaw_row(row_t position, + VteRowData* row, + bool do_truncate, + int hyperlink_column, + char const** hyperlink) { - VteRowRecord records[2], record; + RowRecord records[2], record; VteCellAttr attr; - VteCellAttrChange attr_change; + CellAttrChange attr_change; VteCell cell; - const char *p, *q, *end; - GString *buffer = ring->utf8_buffer; + char const* p, *q, *end; + GString *buffer = m_utf8_buffer; char hyperlink_readbuf[VTE_HYPERLINK_TOTAL_LENGTH_MAX + 1]; hyperlink_readbuf[0] = '\0'; if (hyperlink) { - ring->hyperlink_buf[0] = '\0'; - *hyperlink = ring->hyperlink_buf; + m_hyperlink_buf[0] = '\0'; + *hyperlink = m_hyperlink_buf; } _vte_debug_print (VTE_DEBUG_RING, "Thawing row %lu.\n", position); - g_assert(ring->has_streams); + g_assert(m_has_streams); _vte_row_data_clear (row); attr_change.text_end_offset = 0; - if (!_vte_ring_read_row_record (ring, &records[0], position)) + if (!read_row_record(&records[0], position)) return; - if ((position + 1) * sizeof (records[0]) < _vte_stream_head (ring->row_stream)) { - if (!_vte_ring_read_row_record (ring, &records[1], position + 1)) + if ((position + 1) * sizeof (records[0]) < _vte_stream_head (m_row_stream)) { + if (!read_row_record(&records[1], position + 1)) return; } else - records[1].text_start_offset = _vte_stream_head (ring->text_stream); + records[1].text_start_offset = _vte_stream_head (m_text_stream); g_string_set_size (buffer, records[1].text_start_offset - records[0].text_start_offset); - if (!_vte_stream_read (ring->text_stream, records[0].text_start_offset, buffer->str, buffer->len)) + if (!_vte_stream_read (m_text_stream, records[0].text_start_offset, buffer->str, buffer->len)) return; record = records[0]; @@ -483,16 +439,16 @@ _vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do p = buffer->str; end = p + buffer->len; while (p < end) { - if (record.text_start_offset >= ring->last_attr_text_start_offset) { - attr = ring->last_attr; - strcpy(hyperlink_readbuf, hyperlink_get(ring, attr.hyperlink_idx)->str); + if (record.text_start_offset >= m_last_attr_text_start_offset) { + attr = m_last_attr; + strcpy(hyperlink_readbuf, hyperlink_get(attr.hyperlink_idx)->str); } else { if (record.text_start_offset >= attr_change.text_end_offset) { - if (!_vte_stream_read (ring->attr_stream, record.attr_start_offset, (char *) &attr_change, sizeof (attr_change))) + if (!_vte_stream_read (m_attr_stream, record.attr_start_offset, (char *) &attr_change, sizeof (attr_change))) return; record.attr_start_offset += sizeof (attr_change); g_assert_cmpuint (attr_change.attr.hyperlink_length, <=, VTE_HYPERLINK_TOTAL_LENGTH_MAX); - if (attr_change.attr.hyperlink_length && !_vte_stream_read (ring->attr_stream, record.attr_start_offset, hyperlink_readbuf, attr_change.attr.hyperlink_length)) + if (attr_change.attr.hyperlink_length && !_vte_stream_read (m_attr_stream, record.attr_start_offset, hyperlink_readbuf, attr_change.attr.hyperlink_length)) return; hyperlink_readbuf[attr_change.attr.hyperlink_length] = '\0'; record.attr_start_offset += attr_change.attr.hyperlink_length + 2; @@ -503,13 +459,13 @@ _vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do if (do_truncate) { /* Find the existing idx or allocate a new one, just as when receiving an OSC 8 escape sequence. * Do not update the current idx though. */ - attr.hyperlink_idx = _vte_ring_get_hyperlink_idx_no_update_current (ring, hyperlink_readbuf); + attr.hyperlink_idx = get_hyperlink_idx_no_update_current(hyperlink_readbuf); } else { /* Use a special hyperlink idx, except if to be underlined because the hyperlink is the same as the hovered cell's. */ attr.hyperlink_idx = VTE_HYPERLINK_IDX_TARGET_IN_STREAM; - if (ring->hyperlink_hover_idx != 0 && strcmp(hyperlink_readbuf, hyperlink_get(ring, ring->hyperlink_hover_idx)->str) == 0) { - /* FIXME here we're calling the expensive strcmp() above and _vte_ring_get_hyperlink_idx_no_update_current() way too many times. */ - attr.hyperlink_idx = _vte_ring_get_hyperlink_idx_no_update_current(ring, hyperlink_readbuf); + if (m_hyperlink_hover_idx != 0 && strcmp(hyperlink_readbuf, hyperlink_get(m_hyperlink_hover_idx)->str) == 0) { + /* FIXME here we're calling the expensive strcmp() above and get_hyperlink_idx_no_update_current() way too many times. */ + attr.hyperlink_idx = get_hyperlink_idx_no_update_current(hyperlink_readbuf); } } } @@ -535,13 +491,13 @@ _vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do row->cells[row->len - 1].c = _vte_unistr_append_unichar (row->cells[row->len - 1].c, cell.c); } else { cell.attr.set_columns(1); - if (row->len == hyperlink_column && hyperlink != NULL) - *hyperlink = strcpy(ring->hyperlink_buf, hyperlink_readbuf); + if (row->len == hyperlink_column && hyperlink != nullptr) + *hyperlink = strcpy(m_hyperlink_buf, hyperlink_readbuf); _vte_row_data_append (row, &cell); } } else { - if (row->len == hyperlink_column && hyperlink != NULL) - *hyperlink = strcpy(ring->hyperlink_buf, hyperlink_readbuf); + if (row->len == hyperlink_column && hyperlink != nullptr) + *hyperlink = strcpy(m_hyperlink_buf, hyperlink_readbuf); _vte_row_data_append (row, &cell); if (cell.attr.columns() > 1) { /* Add the fragments */ @@ -549,8 +505,8 @@ _vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do cell.attr.set_fragment(true); cell.attr.set_columns(1); for (i = 1; i < columns; i++) { - if (row->len == hyperlink_column && hyperlink != NULL) - *hyperlink = strcpy(ring->hyperlink_buf, hyperlink_readbuf); + if (row->len == hyperlink_column && hyperlink != nullptr) + *hyperlink = strcpy(m_hyperlink_buf, hyperlink_readbuf); _vte_row_data_append (row, &cell); } } @@ -563,12 +519,12 @@ _vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do if (do_truncate) { gsize attr_stream_truncate_at = records[0].attr_start_offset; _vte_debug_print (VTE_DEBUG_RING, "Truncating\n"); - if (records[0].text_start_offset <= ring->last_attr_text_start_offset) { + if (records[0].text_start_offset <= m_last_attr_text_start_offset) { /* Check the previous attr record. If its text ends where truncating, this attr record also needs to be removed. */ guint16 hyperlink_length; - if (_vte_stream_read (ring->attr_stream, attr_stream_truncate_at - 2, (char *) &hyperlink_length, 2)) { + if (_vte_stream_read (m_attr_stream, attr_stream_truncate_at - 2, (char *) &hyperlink_length, 2)) { g_assert_cmpuint (hyperlink_length, <=, VTE_HYPERLINK_TOTAL_LENGTH_MAX); - if (_vte_stream_read (ring->attr_stream, attr_stream_truncate_at - 2 - hyperlink_length - sizeof (attr_change), (char *) &attr_change, sizeof (attr_change))) { + if (_vte_stream_read (m_attr_stream, attr_stream_truncate_at - 2 - hyperlink_length - sizeof (attr_change), (char *) &attr_change, sizeof (attr_change))) { if (records[0].text_start_offset == attr_change.text_end_offset) { _vte_debug_print (VTE_DEBUG_RING, "... at attribute change\n"); attr_stream_truncate_at -= sizeof (attr_change) + hyperlink_length + 2; @@ -577,74 +533,74 @@ _vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do } /* Reconstruct last_attr from the first record of attr_stream that we cut off, last_attr_text_start_offset from the last record that we keep. */ - if (_vte_stream_read (ring->attr_stream, attr_stream_truncate_at, (char *) &attr_change, sizeof (attr_change))) { - _attrcpy(&ring->last_attr, &attr_change.attr); - ring->last_attr.hyperlink_idx = 0; - if (attr_change.attr.hyperlink_length && _vte_stream_read (ring->attr_stream, attr_stream_truncate_at + sizeof (attr_change), (char *) &hyperlink_readbuf, attr_change.attr.hyperlink_length)) { + if (_vte_stream_read (m_attr_stream, attr_stream_truncate_at, (char *) &attr_change, sizeof (attr_change))) { + _attrcpy(&m_last_attr, &attr_change.attr); + m_last_attr.hyperlink_idx = 0; + if (attr_change.attr.hyperlink_length && _vte_stream_read (m_attr_stream, attr_stream_truncate_at + sizeof (attr_change), (char *) &hyperlink_readbuf, attr_change.attr.hyperlink_length)) { hyperlink_readbuf[attr_change.attr.hyperlink_length] = '\0'; - ring->last_attr.hyperlink_idx = _vte_ring_get_hyperlink_idx (ring, hyperlink_readbuf); + m_last_attr.hyperlink_idx = get_hyperlink_idx(hyperlink_readbuf); } - if (_vte_stream_read (ring->attr_stream, attr_stream_truncate_at - 2, (char *) &hyperlink_length, 2)) { + if (_vte_stream_read (m_attr_stream, attr_stream_truncate_at - 2, (char *) &hyperlink_length, 2)) { g_assert_cmpuint (hyperlink_length, <=, VTE_HYPERLINK_TOTAL_LENGTH_MAX); - if (_vte_stream_read (ring->attr_stream, attr_stream_truncate_at - 2 - hyperlink_length - sizeof (attr_change), (char *) &attr_change, sizeof (attr_change))) { - ring->last_attr_text_start_offset = attr_change.text_end_offset; + if (_vte_stream_read (m_attr_stream, attr_stream_truncate_at - 2 - hyperlink_length - sizeof (attr_change), (char *) &attr_change, sizeof (attr_change))) { + m_last_attr_text_start_offset = attr_change.text_end_offset; } else { - ring->last_attr_text_start_offset = 0; + m_last_attr_text_start_offset = 0; } } else { - ring->last_attr_text_start_offset = 0; + m_last_attr_text_start_offset = 0; } } else { - ring->last_attr_text_start_offset = 0; - ring->last_attr = basic_cell.attr; + m_last_attr_text_start_offset = 0; + m_last_attr = basic_cell.attr; } } - _vte_stream_truncate (ring->row_stream, position * sizeof (record)); - _vte_stream_truncate (ring->attr_stream, attr_stream_truncate_at); - _vte_stream_truncate (ring->text_stream, records[0].text_start_offset); + _vte_stream_truncate (m_row_stream, position * sizeof (record)); + _vte_stream_truncate (m_attr_stream, attr_stream_truncate_at); + _vte_stream_truncate (m_text_stream, records[0].text_start_offset); } } -static void -_vte_ring_reset_streams (VteRing *ring, gulong position) +void +Ring::reset_streams(row_t position) { _vte_debug_print (VTE_DEBUG_RING, "Reseting streams to %lu.\n", position); - if (ring->has_streams) { - _vte_stream_reset (ring->row_stream, position * sizeof (VteRowRecord)); - _vte_stream_reset (ring->text_stream, _vte_stream_head (ring->text_stream)); - _vte_stream_reset (ring->attr_stream, _vte_stream_head (ring->attr_stream)); + if (m_has_streams) { + _vte_stream_reset(m_row_stream, position * sizeof(RowRecord)); + _vte_stream_reset(m_text_stream, _vte_stream_head(m_text_stream)); + _vte_stream_reset(m_attr_stream, _vte_stream_head(m_attr_stream)); } - ring->last_attr_text_start_offset = 0; - ring->last_attr = basic_cell.attr; + m_last_attr_text_start_offset = 0; + m_last_attr = basic_cell.attr; } -long -_vte_ring_reset (VteRing *ring) +Ring::row_t +Ring::reset() { - _vte_debug_print (VTE_DEBUG_RING, "Reseting the ring at %lu.\n", ring->end); + _vte_debug_print (VTE_DEBUG_RING, "Reseting the ring at %lu.\n", m_end); - _vte_ring_reset_streams (ring, ring->end); - ring->start = ring->writable = ring->end; - ring->cached_row_num = (gulong) -1; + reset_streams(m_end); + m_start = m_writable = m_end; + m_cached_row_num = (row_t)-1; - return ring->end; + return m_end; } -const VteRowData * -_vte_ring_index (VteRing *ring, gulong position) +VteRowData const* +Ring::index(row_t position) { - if (G_LIKELY (position >= ring->writable)) - return _vte_ring_writable_index (ring, position); + if (G_LIKELY (position >= m_writable)) + return get_writable_index(position); - if (ring->cached_row_num != position) { + if (m_cached_row_num != position) { _vte_debug_print(VTE_DEBUG_RING, "Caching row %lu.\n", position); - _vte_ring_thaw_row (ring, position, &ring->cached_row, FALSE, -1, NULL); - ring->cached_row_num = position; + thaw_row(position, &m_cached_row, false, -1, nullptr); + m_cached_row_num = position; } - return &ring->cached_row; + return &m_cached_row; } /* @@ -660,219 +616,222 @@ _vte_ring_index (VteRing *ring, gulong position) * * Otherwise cells from the stream might get the pseudo idx VTE_HYPERLINK_IDX_TARGET_IN_STREAM. */ -hyperlink_idx_t -_vte_ring_get_hyperlink_at_position (VteRing *ring, gulong position, int col, bool update_hover_idx, const char **hyperlink) +Ring::hyperlink_idx_t +Ring::get_hyperlink_at_position(row_t position, + column_t col, + bool update_hover_idx, + char const** hyperlink) { hyperlink_idx_t idx; - const char *hp; + char const* hp; - if (hyperlink == NULL) + if (hyperlink == nullptr) hyperlink = &hp; - *hyperlink = NULL; + *hyperlink = nullptr; if (update_hover_idx) { /* Invalidate the cache because new hover idx might result in new idxs to report. */ - ring->cached_row_num = (gulong) -1; + m_cached_row_num = (row_t)-1; } - if (G_UNLIKELY (position == (gulong) -1 || col == -1)) { + if (G_UNLIKELY (position == (row_t)-1 || col == -1)) { if (update_hover_idx) - ring->hyperlink_hover_idx = 0; + m_hyperlink_hover_idx = 0; return 0; } - if (G_LIKELY (position >= ring->writable)) { - VteRowData *row = _vte_ring_writable_index (ring, position); + if (G_LIKELY (position >= m_writable)) { + VteRowData* row = get_writable_index(position); if (col >= _vte_row_data_length(row)) { if (update_hover_idx) - ring->hyperlink_hover_idx = 0; + m_hyperlink_hover_idx = 0; return 0; } - *hyperlink = hyperlink_get(ring, row->cells[col].attr.hyperlink_idx)->str; + *hyperlink = hyperlink_get(row->cells[col].attr.hyperlink_idx)->str; idx = row->cells[col].attr.hyperlink_idx; } else { - _vte_ring_thaw_row (ring, position, &ring->cached_row, FALSE, col, hyperlink); + thaw_row(position, &m_cached_row, false, col, hyperlink); /* Note: Intentionally don't set cached_row_num. We're about to update - * ring->hyperlink_hover_idx which makes some idxs no longer valid. */ - idx = _vte_ring_get_hyperlink_idx_no_update_current(ring, *hyperlink); + * m_hyperlink_hover_idx which makes some idxs no longer valid. */ + idx = get_hyperlink_idx_no_update_current(*hyperlink); } if (**hyperlink == '\0') - *hyperlink = NULL; + *hyperlink = nullptr; if (update_hover_idx) - ring->hyperlink_hover_idx = idx; + m_hyperlink_hover_idx = idx; return idx; } -static void _vte_ring_ensure_writable (VteRing *ring, gulong position); -static void _vte_ring_ensure_writable_room (VteRing *ring); - -VteRowData * -_vte_ring_index_writable (VteRing *ring, gulong position) +VteRowData* +Ring::index_writable(row_t position) { - _vte_ring_ensure_writable (ring, position); - return _vte_ring_writable_index (ring, position); + ensure_writable(position); + return get_writable_index(position); } -static void -_vte_ring_freeze_one_row (VteRing *ring) +void +Ring::freeze_one_row() { - VteRowData *row; + VteRowData* row; - if (G_UNLIKELY (ring->writable == ring->start)) - _vte_ring_reset_streams (ring, ring->writable); + if (G_UNLIKELY (m_writable == m_start)) + reset_streams(m_writable); - row = _vte_ring_writable_index (ring, ring->writable); - _vte_ring_freeze_row (ring, ring->writable, row); + row = get_writable_index(m_writable); + freeze_row(m_writable, row); - ring->writable++; + m_writable++; } -static void -_vte_ring_thaw_one_row (VteRing *ring) +void +Ring::thaw_one_row() { - VteRowData *row; - - g_assert (ring->start < ring->writable); + VteRowData* row; - _vte_ring_ensure_writable_room (ring); + g_assert_cmpuint(m_start, <, m_writable); - ring->writable--; + ensure_writable_room(); - if (ring->writable == ring->cached_row_num) - ring->cached_row_num = (gulong) -1; /* Invalidate cached row */ + m_writable--; - row = _vte_ring_writable_index (ring, ring->writable); + if (m_writable == m_cached_row_num) + m_cached_row_num = (row_t)-1; /* Invalidate cached row */ - _vte_ring_thaw_row (ring, ring->writable, row, TRUE, -1, NULL); + row = get_writable_index(m_writable); + thaw_row(m_writable, row, true, -1, nullptr); } -static void -_vte_ring_discard_one_row (VteRing *ring) +void +Ring::discard_one_row() { - ring->start++; - if (G_UNLIKELY (ring->start == ring->writable)) { - _vte_ring_reset_streams (ring, ring->writable); - } else if (ring->start < ring->writable) { - VteRowRecord record; - _vte_stream_advance_tail (ring->row_stream, ring->start * sizeof (record)); - if (G_LIKELY (_vte_ring_read_row_record (ring, &record, ring->start))) { - _vte_stream_advance_tail (ring->text_stream, record.text_start_offset); - _vte_stream_advance_tail (ring->attr_stream, record.attr_start_offset); + m_start++; + if (G_UNLIKELY(m_start == m_writable)) { + reset_streams(m_writable); + } else if (m_start < m_writable) { + RowRecord record; + _vte_stream_advance_tail(m_row_stream, m_start * sizeof (record)); + if (G_LIKELY(read_row_record(&record, m_start))) { + _vte_stream_advance_tail(m_text_stream, record.text_start_offset); + _vte_stream_advance_tail(m_attr_stream, record.attr_start_offset); } } else { - ring->writable = ring->start; + m_writable = m_start; } } -static void -_vte_ring_maybe_freeze_one_row (VteRing *ring) +void +Ring::maybe_freeze_one_row() { - if (G_LIKELY (ring->mask >= ring->visible_rows && ring->writable + ring->mask + 1 == ring->end)) - _vte_ring_freeze_one_row (ring); + if (G_LIKELY(m_mask >= m_visible_rows && + m_writable + m_mask + 1 == m_end)) + freeze_one_row(); else - _vte_ring_ensure_writable_room (ring); + ensure_writable_room(); } -static void -_vte_ring_maybe_discard_one_row (VteRing *ring) +//FIXMEchpe maybe inline this one +void +Ring::maybe_discard_one_row() { - if ((gulong) _vte_ring_length (ring) == ring->max) - _vte_ring_discard_one_row (ring); + if (length() == m_max) + discard_one_row(); } -static void -_vte_ring_ensure_writable_room (VteRing *ring) +void +Ring::ensure_writable_room() { - gulong new_mask, old_mask, i, end; - VteRowData *old_array, *new_array;; + row_t new_mask, old_mask, i, end; + VteRowData* old_array, *new_array;; - if (G_LIKELY (ring->mask >= ring->visible_rows && ring->writable + ring->mask + 1 > ring->end)) + if (G_LIKELY(m_mask >= m_visible_rows && + m_writable + m_mask + 1 > m_end)) return; - old_mask = ring->mask; - old_array = ring->array; + old_mask = m_mask; + old_array = m_array; do { - ring->mask = (ring->mask << 1) + 1; - } while (ring->mask < ring->visible_rows || ring->writable + ring->mask + 1 <= ring->end); + m_mask = (m_mask << 1) + 1; + } while (m_mask < m_visible_rows || m_writable + m_mask + 1 <= m_end); - _vte_debug_print(VTE_DEBUG_RING, "Enlarging writable array from %lu to %lu\n", old_mask, ring->mask); + _vte_debug_print(VTE_DEBUG_RING, "Enlarging writable array from %lu to %lu\n", old_mask, m_mask); - ring->array = (VteRowData *) g_malloc0 (sizeof (ring->array[0]) * (ring->mask + 1)); + m_array = (VteRowData* ) g_malloc0(sizeof (m_array[0]) * (m_mask + 1)); - new_mask = ring->mask; - new_array = ring->array; + new_mask = m_mask; + new_array = m_array; - end = ring->writable + old_mask + 1; - for (i = ring->writable; i < end; i++) + end = m_writable + old_mask + 1; + for (i = m_writable; i < end; i++) new_array[i & new_mask] = old_array[i & old_mask]; g_free (old_array); } -static void -_vte_ring_ensure_writable (VteRing *ring, gulong position) +void +Ring::ensure_writable(row_t position) { - if (G_LIKELY (position >= ring->writable)) + if (G_LIKELY(position >= m_writable)) return; _vte_debug_print(VTE_DEBUG_RING, "Ensure writable %lu.\n", position); - while (position < ring->writable) - _vte_ring_thaw_one_row (ring); + //FIXMEchpe surely this can be optimised + while (position < m_writable) + thaw_one_row(); } /** - * _vte_ring_resize: - * @ring: a #VteRing + * Ring::resize: * @max_rows: new maximum numbers of rows in the ring * * Changes the number of lines the ring can contain. */ void -_vte_ring_resize (VteRing *ring, gulong max_rows) +Ring::resize(row_t max_rows) { _vte_debug_print(VTE_DEBUG_RING, "Resizing to %lu.\n", max_rows); - _vte_ring_validate(ring); + + validate(); /* Adjust the start of tail chunk now */ - if ((gulong) _vte_ring_length (ring) > max_rows) { - ring->start = ring->end - max_rows; - if (ring->start >= ring->writable) { - _vte_ring_reset_streams (ring, ring->writable); - ring->writable = ring->start; + if (length() > max_rows) { + m_start = m_end - max_rows; + if (m_start >= m_writable) { + reset_streams(m_writable); + m_writable = m_start; } } - ring->max = max_rows; + m_max = max_rows; } void -_vte_ring_shrink (VteRing *ring, gulong max_len) +Ring::shrink(row_t max_len) { - if ((gulong) _vte_ring_length (ring) <= max_len) + if (length() <= max_len) return; _vte_debug_print(VTE_DEBUG_RING, "Shrinking to %lu.\n", max_len); - _vte_ring_validate(ring); - if (ring->writable - ring->start <= max_len) - ring->end = ring->start + max_len; + validate(); + + if (m_writable - m_start <= max_len) + m_end = m_start + max_len; else { - while (ring->writable - ring->start > max_len) { - _vte_ring_ensure_writable (ring, ring->writable - 1); - ring->end = ring->writable; + while (m_writable - m_start > max_len) { + ensure_writable(m_writable - 1); + m_end = m_writable; } } - /* TODO May want to shrink down ring->array */ + /* TODO May want to shrink down m_array */ - _vte_ring_validate(ring); + validate(); } /** - * _vte_ring_insert_internal: - * @ring: a #VteRing + * Ring::insert: * @position: an index * * Inserts a new, empty, row into @ring at the @position'th offset. @@ -880,89 +839,87 @@ _vte_ring_shrink (VteRing *ring, gulong max_len) * * Return: the newly added row. */ -VteRowData * -_vte_ring_insert (VteRing *ring, gulong position) +VteRowData* +Ring::insert(row_t position) { - gulong i; - VteRowData *row, tmp; + row_t i; + VteRowData* row, tmp; _vte_debug_print(VTE_DEBUG_RING, "Inserting at position %lu.\n", position); - _vte_ring_validate(ring); - - _vte_ring_maybe_discard_one_row (ring); + validate(); - _vte_ring_ensure_writable (ring, position); - _vte_ring_ensure_writable_room (ring); + maybe_discard_one_row(); + ensure_writable(position); + ensure_writable_room(); - g_assert (position >= ring->writable && position <= ring->end); + g_assert_cmpuint (position, >=, m_writable); + g_assert_cmpuint (position, <=, m_end); - tmp = *_vte_ring_writable_index (ring, ring->end); - for (i = ring->end; i > position; i--) - *_vte_ring_writable_index (ring, i) = *_vte_ring_writable_index (ring, i - 1); - *_vte_ring_writable_index (ring, position) = tmp; + //FIXMEchpe WTF use better data structures! + tmp = *get_writable_index(m_end); + for (i = m_end; i > position; i--) + *get_writable_index(i) = *get_writable_index(i - 1); + *get_writable_index(position) = tmp; - row = _vte_ring_writable_index (ring, position); + row = get_writable_index(position); _vte_row_data_clear (row); - ring->end++; - - _vte_ring_maybe_freeze_one_row (ring); + m_end++; - _vte_ring_validate(ring); + maybe_freeze_one_row(); + validate(); return row; } /** - * _vte_ring_remove: - * @ring: a #VteRing + * Ring::remove: * @position: an index * * Removes the @position'th item from @ring. */ void -_vte_ring_remove (VteRing * ring, gulong position) +Ring::remove(row_t position) { - gulong i; + row_t i; VteRowData tmp; _vte_debug_print(VTE_DEBUG_RING, "Removing item at position %lu.\n", position); - _vte_ring_validate(ring); + validate(); - if (G_UNLIKELY (!_vte_ring_contains (ring, position))) + if (G_UNLIKELY(!contains(position))) return; - _vte_ring_ensure_writable (ring, position); + ensure_writable(position); - tmp = *_vte_ring_writable_index (ring, position); - for (i = position; i < ring->end - 1; i++) - *_vte_ring_writable_index (ring, i) = *_vte_ring_writable_index (ring, i + 1); - *_vte_ring_writable_index (ring, ring->end - 1) = tmp; + //FIXMEchpe WTF as above + tmp = *get_writable_index(position); + for (i = position; i < m_end - 1; i++) + *get_writable_index(i) = *get_writable_index(i + 1); + *get_writable_index(m_end - 1) = tmp; - if (ring->end > ring->writable) - ring->end--; + if (m_end > m_writable) + m_end--; - _vte_ring_validate(ring); + validate(); } /** - * _vte_ring_append: - * @ring: a #VteRing + * Ring::append: * @data: the new item * * Appends a new item to the ring. * * Return: the newly added row. */ -VteRowData * -_vte_ring_append (VteRing * ring) +VteRowData* +Ring::append() { - return _vte_ring_insert (ring, _vte_ring_next (ring)); + return insert(next()); } /** - * _vte_ring_drop_scrollback: - * @ring: a #VteRing + * Ring::drop_scrollback: * @position: drop contents up to this point, which must be in the writable region. * * Drop the scrollback (offscreen contents). @@ -970,77 +927,75 @@ _vte_ring_append (VteRing * ring) * TODOegmont: We wouldn't need the position argument after addressing 708213#c29. */ void -_vte_ring_drop_scrollback (VteRing * ring, gulong position) +Ring::drop_scrollback(row_t position) { - _vte_ring_ensure_writable (ring, position); + ensure_writable(position); - ring->start = ring->writable = position; - _vte_ring_reset_streams (ring, position); + m_start = m_writable = position; + reset_streams(position); } - /** - * _vte_ring_set_visible_rows: - * @ring: a #VteRing + * Ring::set_visible_rows: + * @rows: the number of visible rows * * Set the number of visible rows. * It's required to be set correctly for the alternate screen so that it * never hits the streams. It's also required for clearing the scrollback. */ void -_vte_ring_set_visible_rows (VteRing *ring, gulong rows) +Ring::set_visible_rows(row_t rows) { - ring->visible_rows = rows; + m_visible_rows = rows; } -/* Convert a (row,col) into a VteCellTextOffset. +/* Convert a (row,col) into a CellTextOffset. * Requires the row to be frozen, or be outsize the range covered by the ring. */ -static gboolean -_vte_frozen_row_column_to_text_offset (VteRing *ring, - gulong position, - gulong column, - VteCellTextOffset *offset) +bool +Ring::frozen_row_column_to_text_offset(row_t position, + column_t column, + CellTextOffset* offset) { - VteRowRecord records[2]; + RowRecord records[2]; VteCell *cell; - GString *buffer = ring->utf8_buffer; - const VteRowData *row; + GString *buffer = m_utf8_buffer; + VteRowData const* row; unsigned int i, num_chars, off; - if (position >= ring->end) { - offset->text_offset = _vte_stream_head (ring->text_stream) + position - ring->end; + if (position >= m_end) { + offset->text_offset = _vte_stream_head(m_text_stream) + position - m_end; offset->fragment_cells = 0; offset->eol_cells = column; - return TRUE; + return true; } - if (G_UNLIKELY (position < ring->start)) { + if (G_UNLIKELY (position < m_start)) { /* This happens when the marker (saved cursor position) is scrolled off at the top of the scrollback buffer. */ - position = ring->start; + position = m_start; column = 0; /* go on */ } - g_assert(position < ring->writable); - if (!_vte_ring_read_row_record (ring, &records[0], position)) - return FALSE; - if ((position + 1) * sizeof (records[0]) < _vte_stream_head (ring->row_stream)) { - if (!_vte_ring_read_row_record (ring, &records[1], position + 1)) - return FALSE; + g_assert_cmpuint(position, <, m_writable); + if (!read_row_record(&records[0], position)) + return false; + if ((position + 1) * sizeof (records[0]) < _vte_stream_head(m_row_stream)) { + if (!read_row_record(&records[1], position + 1)) + return false; } else - records[1].text_start_offset = _vte_stream_head (ring->text_stream); + records[1].text_start_offset = _vte_stream_head(m_text_stream); g_string_set_size (buffer, records[1].text_start_offset - records[0].text_start_offset); - if (!_vte_stream_read (ring->text_stream, records[0].text_start_offset, buffer->str, buffer->len)) - return FALSE; + if (!_vte_stream_read(m_text_stream, records[0].text_start_offset, buffer->str, buffer->len)) + return false; if (G_LIKELY (buffer->len && buffer->str[buffer->len - 1] == '\n')) buffer->len--; - row = _vte_ring_index(ring, position); + row = index(position); /* row and buffer now contain the same text, in different representation */ @@ -1068,57 +1023,57 @@ _vte_frozen_row_column_to_text_offset (VteRing *ring, if ((buffer->str[off] & 0xC0) != 0x80) num_chars--; } offset->text_offset = records[0].text_start_offset + off; - return TRUE; + return true; } -/* Given a row number and a VteCellTextOffset, compute the column within that row. - It's the caller's responsibility to ensure that VteCellTextOffset really falls into that row. +/* Given a row number and a CellTextOffset, compute the column within that row. + It's the caller's responsibility to ensure that CellTextOffset really falls into that row. Requires the row to be frozen, or be outsize the range covered by the ring. */ -static gboolean -_vte_frozen_row_text_offset_to_column (VteRing *ring, - gulong position, - const VteCellTextOffset *offset, - long *column) +bool +Ring::frozen_row_text_offset_to_column(row_t position, + CellTextOffset const* offset, + column_t* column) { - VteRowRecord records[2]; + RowRecord records[2]; VteCell *cell; - GString *buffer = ring->utf8_buffer; - const VteRowData *row; + GString *buffer = m_utf8_buffer; + VteRowData const* row; unsigned int i, off, num_chars, nc; - if (position >= ring->end) { + if (position >= m_end) { *column = offset->eol_cells; - return TRUE; + return true; } - if (G_UNLIKELY (position < ring->start)) { + if (G_UNLIKELY (position < m_start)) { /* This happens when the marker (saved cursor position) is scrolled off at the top of the scrollback buffer. */ *column = 0; - return TRUE; + return true; } - g_assert_cmpuint(position, <, ring->writable); - if (!_vte_ring_read_row_record (ring, &records[0], position)) - return FALSE; - if ((position + 1) * sizeof (records[0]) < _vte_stream_head (ring->row_stream)) { - if (!_vte_ring_read_row_record (ring, &records[1], position + 1)) - return FALSE; + g_assert_cmpuint(position, <, m_writable); + if (!read_row_record(&records[0], position)) + return false; + if ((position + 1) * sizeof (records[0]) < _vte_stream_head(m_row_stream)) { + if (!read_row_record(&records[1], position + 1)) + return false; } else - records[1].text_start_offset = _vte_stream_head (ring->text_stream); + records[1].text_start_offset = _vte_stream_head (m_text_stream); - g_assert(offset->text_offset >= records[0].text_start_offset && offset->text_offset < records[1].text_start_offset); + g_assert_cmpuint(offset->text_offset, >=, records[0].text_start_offset); + g_assert_cmpuint(offset->text_offset, <, records[1].text_start_offset); g_string_set_size (buffer, records[1].text_start_offset - records[0].text_start_offset); - if (!_vte_stream_read (ring->text_stream, records[0].text_start_offset, buffer->str, buffer->len)) - return FALSE; + if (!_vte_stream_read(m_text_stream, records[0].text_start_offset, buffer->str, buffer->len)) + return false; if (G_LIKELY (buffer->len && buffer->str[buffer->len - 1] == '\n')) buffer->len--; - row = _vte_ring_index(ring, position); + row = index(position); /* row and buffer now contain the same text, in different representation */ @@ -1144,15 +1099,14 @@ _vte_frozen_row_text_offset_to_column (VteRing *ring, if (G_UNLIKELY (offset->eol_cells >= 0 && i == row->len)) i += offset->eol_cells; *column = i; - return TRUE; + return true; } /** - * _vte_ring_rewrap: - * @ring: a #VteRing + * Ring::rewrap: * @columns: new number of columns - * @markers: NULL-terminated array of #VteVisualPosition + * @markers: 0-terminated array of #VteVisualPosition * * Reflow the @ring to match the new number of @columns. * For all @markers, find the cell at that position and update them to @@ -1160,17 +1114,16 @@ _vte_frozen_row_text_offset_to_column (VteRing *ring, */ /* See ../doc/rewrap.txt for design and implementation details. */ void -_vte_ring_rewrap (VteRing *ring, - glong columns, - VteVisualPosition **markers) +Ring::rewrap(column_t columns, + VteVisualPosition** markers) { - gulong old_row_index, new_row_index; + row_t old_row_index, new_row_index; int i; int num_markers = 0; - VteCellTextOffset *marker_text_offsets; + CellTextOffset *marker_text_offsets; VteVisualPosition *new_markers; - VteRowRecord old_record; - VteCellAttrChange attr_change; + RowRecord old_record; + CellAttrChange attr_change; VteStream *new_row_stream; gsize paragraph_start_text_offset; gsize paragraph_end_text_offset; @@ -1178,26 +1131,26 @@ _vte_ring_rewrap (VteRing *ring, gsize attr_offset; gsize old_ring_end; - if (_vte_ring_length(ring) == 0) + if (G_UNLIKELY(length() == 0)) return; _vte_debug_print(VTE_DEBUG_RING, "Ring before rewrapping:\n"); - _vte_ring_validate(ring); - new_row_stream = _vte_file_stream_new (); + validate(); + new_row_stream = _vte_file_stream_new(); /* Freeze everything, because rewrapping is really complicated and we don't want to duplicate the code for frozen and thawed rows. */ - while (ring->writable < ring->end) - _vte_ring_freeze_one_row(ring); + while (m_writable < m_end) + freeze_one_row(); /* For markers given as (row,col) pairs find their offsets in the text stream. This code requires that the rows are already frozen. */ - while (markers[num_markers] != NULL) + while (markers[num_markers] != nullptr) num_markers++; - marker_text_offsets = (VteCellTextOffset *) g_malloc(num_markers * sizeof (marker_text_offsets[0])); + marker_text_offsets = (CellTextOffset *) g_malloc(num_markers * sizeof (marker_text_offsets[0])); new_markers = (VteVisualPosition *) g_malloc(num_markers * sizeof (new_markers[0])); for (i = 0; i < num_markers; i++) { /* Convert visual column into byte offset */ - if (!_vte_frozen_row_column_to_text_offset(ring, markers[i]->row, markers[i]->col, &marker_text_offsets[i])) + if (!frozen_row_column_to_text_offset(markers[i]->row, markers[i]->col, &marker_text_offsets[i])) goto err; new_markers[i].row = new_markers[i].col = -1; _vte_debug_print(VTE_DEBUG_RING, @@ -1207,41 +1160,42 @@ _vte_ring_rewrap (VteRing *ring, } /* Prepare for rewrapping */ - if (!_vte_ring_read_row_record(ring, &old_record, ring->start)) + if (!read_row_record(&old_record, m_start)) goto err; paragraph_start_text_offset = old_record.text_start_offset; - paragraph_end_text_offset = _vte_stream_head (ring->text_stream); /* initialized to silence gcc */ + paragraph_end_text_offset = _vte_stream_head(m_text_stream); /* initialized to silence gcc */ new_row_index = 0; attr_offset = old_record.attr_start_offset; - if (!_vte_stream_read(ring->attr_stream, attr_offset, (char *) &attr_change, sizeof (attr_change))) { - _attrcpy(&attr_change.attr, &ring->last_attr); - attr_change.attr.hyperlink_length = hyperlink_get(ring, ring->last_attr.hyperlink_idx)->len; - attr_change.text_end_offset = _vte_stream_head (ring->text_stream); + if (!_vte_stream_read(m_attr_stream, attr_offset, (char *) &attr_change, sizeof (attr_change))) { + _attrcpy(&attr_change.attr, &m_last_attr); + attr_change.attr.hyperlink_length = hyperlink_get(m_last_attr.hyperlink_idx)->len; + attr_change.text_end_offset = _vte_stream_head(m_text_stream); } - old_row_index = ring->start + 1; - while (paragraph_start_text_offset < _vte_stream_head (ring->text_stream)) { + old_row_index = m_start + 1; + while (paragraph_start_text_offset < _vte_stream_head(m_text_stream)) { /* Find the boundaries of the next paragraph */ gboolean prev_record_was_soft_wrapped = FALSE; gboolean paragraph_is_ascii = TRUE; gsize paragraph_start_row = old_row_index - 1; gsize paragraph_end_row; /* points to beyond the end */ gsize text_offset = paragraph_start_text_offset; - VteRowRecord new_record; - glong col = 0; + RowRecord new_record; + column_t col = 0; + _vte_debug_print(VTE_DEBUG_RING, " Old paragraph: row %" G_GSIZE_FORMAT " (text_offset %" G_GSIZE_FORMAT ") up to (exclusive) ", /* no '\n' */ paragraph_start_row, paragraph_start_text_offset); - while (old_row_index <= ring->end) { + while (old_row_index <= m_end) { prev_record_was_soft_wrapped = old_record.soft_wrapped; paragraph_is_ascii = paragraph_is_ascii && old_record.is_ascii; - if (G_LIKELY (old_row_index < ring->end)) { - if (!_vte_ring_read_row_record(ring, &old_record, old_row_index)) + if (G_LIKELY (old_row_index < m_end)) { + if (!read_row_record(&old_record, old_row_index)) goto err; paragraph_end_text_offset = old_record.text_start_offset; } else { - paragraph_end_text_offset = _vte_stream_head (ring->text_stream); + paragraph_end_text_offset = _vte_stream_head (m_text_stream); } old_row_index++; if (!prev_record_was_soft_wrapped) @@ -1261,10 +1215,10 @@ _vte_ring_rewrap (VteRing *ring, if (attr_change.text_end_offset <= text_offset) { /* Attr change at paragraph boundary, advance to next attr. */ attr_offset += sizeof (attr_change) + attr_change.attr.hyperlink_length + 2; - if (!_vte_stream_read(ring->attr_stream, attr_offset, (char *) &attr_change, sizeof (attr_change))) { - _attrcpy(&attr_change.attr, &ring->last_attr); - attr_change.attr.hyperlink_length = hyperlink_get(ring, ring->last_attr.hyperlink_idx)->len; - attr_change.text_end_offset = _vte_stream_head (ring->text_stream); + if (!_vte_stream_read(m_attr_stream, attr_offset, (char *) &attr_change, sizeof (attr_change))) { + _attrcpy(&attr_change.attr, &m_last_attr); + attr_change.attr.hyperlink_length = hyperlink_get(m_last_attr.hyperlink_idx)->len; + attr_change.text_end_offset = _vte_stream_head(m_text_stream); } } memset(&new_record, 0, sizeof (new_record)); @@ -1278,10 +1232,10 @@ _vte_ring_rewrap (VteRing *ring, if (attr_change.text_end_offset <= text_offset) { /* Attr change at line boundary, advance to next attr. */ attr_offset += sizeof (attr_change) + attr_change.attr.hyperlink_length + 2; - if (!_vte_stream_read(ring->attr_stream, attr_offset, (char *) &attr_change, sizeof (attr_change))) { - _attrcpy(&attr_change.attr, &ring->last_attr); - attr_change.attr.hyperlink_length = hyperlink_get(ring, ring->last_attr.hyperlink_idx)->len; - attr_change.text_end_offset = _vte_stream_head (ring->text_stream); + if (!_vte_stream_read(m_attr_stream, attr_offset, (char *) &attr_change, sizeof (attr_change))) { + _attrcpy(&attr_change.attr, &m_last_attr); + attr_change.attr.hyperlink_length = hyperlink_get(m_last_attr.hyperlink_idx)->len; + attr_change.text_end_offset = _vte_stream_head(m_text_stream); } } runlength = MIN(paragraph_len, attr_change.text_end_offset - text_offset); @@ -1295,7 +1249,7 @@ _vte_ring_rewrap (VteRing *ring, if (col >= columns - attr_change.attr.columns() + 1) { /* Wrap now, write the soft wrapped row's record */ new_record.soft_wrapped = 1; - _vte_stream_append(new_row_stream, (const char *) &new_record, sizeof (new_record)); + _vte_stream_append(new_row_stream, (char const* ) &new_record, sizeof (new_record)); _vte_debug_print(VTE_DEBUG_RING, " New row %ld text_offset %" G_GSIZE_FORMAT " attr_offset %" G_GSIZE_FORMAT " soft_wrapped\n", new_row_index, @@ -1329,7 +1283,7 @@ _vte_ring_rewrap (VteRing *ring, /* Find beginning of next UTF-8 character */ text_offset++; paragraph_len--; runlength--; textbuf_len = MIN(runlength, sizeof (textbuf)); - if (!_vte_stream_read(ring->text_stream, text_offset, textbuf, textbuf_len)) + if (!_vte_stream_read(m_text_stream, text_offset, textbuf, textbuf_len)) goto err; for (i = 0; i < textbuf_len && (textbuf[i] & 0xC0) == 0x80; i++) { text_offset++; paragraph_len--; runlength--; @@ -1342,7 +1296,7 @@ _vte_ring_rewrap (VteRing *ring, /* Write the record of the paragraph's last row. */ /* Hard wrapped, except maybe at the end of the very last paragraph */ new_record.soft_wrapped = prev_record_was_soft_wrapped; - _vte_stream_append(new_row_stream, (const char *) &new_record, sizeof (new_record)); + _vte_stream_append(new_row_stream, (char const* ) &new_record, sizeof (new_record)); _vte_debug_print(VTE_DEBUG_RING, " New row %ld text_offset %" G_GSIZE_FORMAT " attr_offset %" G_GSIZE_FORMAT "\n", new_row_index, @@ -1360,22 +1314,22 @@ _vte_ring_rewrap (VteRing *ring, } /* Update the ring. */ - old_ring_end = ring->end; - g_object_unref(ring->row_stream); - ring->row_stream = new_row_stream; - ring->writable = ring->end = new_row_index; - ring->start = 0; - if (ring->end > ring->max) - ring->start = ring->end - ring->max; - ring->cached_row_num = (gulong) -1; + old_ring_end = m_end; + g_object_unref(m_row_stream); + m_row_stream = new_row_stream; + m_writable = m_end = new_row_index; + m_start = 0; + if (m_end > m_max) + m_start = m_end - m_max; + m_cached_row_num = (row_t) -1; /* Find the markers. This requires that the ring is already updated. */ for (i = 0; i < num_markers; i++) { /* Compute the row for markers beyond the ring */ if (new_markers[i].row == -1) - new_markers[i].row = markers[i]->row - old_ring_end + ring->end; + new_markers[i].row = markers[i]->row - old_ring_end + m_end; /* Convert byte offset into visual column */ - if (!_vte_frozen_row_text_offset_to_column(ring, new_markers[i].row, &marker_text_offsets[i], &new_markers[i].col)) + if (!frozen_row_text_offset_to_column(new_markers[i].row, &marker_text_offsets[i], &new_markers[i].col)) goto err; _vte_debug_print(VTE_DEBUG_RING, "Marker #%d new coords: text_offset %" G_GSIZE_FORMAT " fragment_cells %d eol_cells %d -> row %ld col %ld\n", @@ -1388,7 +1342,7 @@ _vte_ring_rewrap (VteRing *ring, g_free(new_markers); _vte_debug_print(VTE_DEBUG_RING, "Ring after rewrapping:\n"); - _vte_ring_validate(ring); + validate(); return; err: @@ -1403,20 +1357,19 @@ err: } -static gboolean -_vte_ring_write_row (VteRing *ring, - GOutputStream *stream, - VteRowData *row, - VteWriteFlags flags, - GCancellable *cancellable, - GError **error) +bool +Ring::write_row(GOutputStream* stream, + VteRowData* row, + VteWriteFlags flags, + GCancellable* cancellable, + GError** error) { VteCell *cell; - GString *buffer = ring->utf8_buffer; + GString *buffer = m_utf8_buffer; int i; gsize bytes_written; - /* Simple version of the loop in _vte_ring_freeze_row(). + /* Simple version of the loop in freeze_row(). * TODO Should unify one day */ g_string_set_size (buffer, 0); for (i = 0, cell = row->cells; i < row->len; i++, cell++) { @@ -1430,36 +1383,34 @@ _vte_ring_write_row (VteRing *ring, } /** - * _vte_ring_write_contents: - * @ring: a #VteRing + * Ring::write_contents: * @stream: a #GOutputStream to write to * @flags: a set of #VteWriteFlags - * @cancellable: optional #GCancellable object, %NULL to ignore - * @error: a #GError location to store the error occuring, or %NULL to ignore + * @cancellable: optional #GCancellable object, %nullptr to ignore + * @error: a #GError location to store the error occuring, or %nullptr to ignore * * Write entire ring contents to @stream according to @flags. * * Return: %TRUE on success, %FALSE if there was an error */ -gboolean -_vte_ring_write_contents (VteRing *ring, - GOutputStream *stream, - VteWriteFlags flags, - GCancellable *cancellable, - GError **error) +bool +Ring::write_contents(GOutputStream* stream, + VteWriteFlags flags, + GCancellable* cancellable, + GError** error) { - gulong i; + row_t i; _vte_debug_print(VTE_DEBUG_RING, "Writing contents to GOutputStream.\n"); - if (ring->start < ring->writable) + if (m_start < m_writable) { - VteRowRecord record; + RowRecord record; - if (_vte_ring_read_row_record (ring, &record, ring->start)) + if (read_row_record(&record, m_start)) { gsize start_offset = record.text_start_offset; - gsize end_offset = _vte_stream_head (ring->text_stream); + gsize end_offset = _vte_stream_head(m_text_stream); char buf[4096]; while (start_offset < end_offset) { @@ -1467,28 +1418,29 @@ _vte_ring_write_contents (VteRing *ring, len = MIN (G_N_ELEMENTS (buf), end_offset - start_offset); - if (!_vte_stream_read (ring->text_stream, start_offset, + if (!_vte_stream_read (m_text_stream, start_offset, buf, len)) - return FALSE; + return false; if (!g_output_stream_write_all (stream, buf, len, &bytes_written, cancellable, error)) - return FALSE; + return false; start_offset += len; } } else - return FALSE; + //FIXMEchpe g_set_error!! + return false; } - for (i = ring->writable; i < ring->end; i++) { - if (!_vte_ring_write_row (ring, stream, - _vte_ring_writable_index (ring, i), - flags, cancellable, error)) - return FALSE; + for (i = m_writable; i < m_end; i++) { + if (!write_row(stream, + get_writable_index(i), + flags, cancellable, error)) + return false; } - return TRUE; + return true; } diff --git a/src/ring.hh b/src/ring.hh index b5df883e..1b17ca7a 100644 --- a/src/ring.hh +++ b/src/ring.hh @@ -28,28 +28,167 @@ #include "vterowdata.hh" #include "vtestream.h" -G_BEGIN_DECLS - - -typedef guint32 hyperlink_idx_t; +#include typedef struct _VteVisualPosition { long row, col; } VteVisualPosition; -/* - * VteRing: A scrollback buffer ring +namespace vte { + +namespace base { + +/** + * ring: A scrollback buffer ring */ +class Ring { +public: + typedef guint32 hyperlink_idx_t; + // FIXME make this size_t (or off_t?) + typedef gulong row_t; + typedef glong column_t; + + static const row_t kDefaultMaxRows = VTE_SCROLLBACK_INIT; + + Ring(row_t max_rows = kDefaultMaxRows, + bool has_streams = false); + ~Ring(); + + // prevent accidents + Ring(Ring& o) = delete; + Ring(Ring const& o) = delete; + Ring(Ring&& o) = delete; + Ring& operator= (Ring& o) = delete; + Ring& operator= (Ring const& o) = delete; + Ring& operator= (Ring&& o) = delete; + + inline bool contains(row_t position) const { + return (position >= m_start && position < m_end); + } + + inline row_t delta() const { return m_start; } + inline row_t length() const { return m_end - m_start; } + inline row_t next() const { return m_end; } + + //FIXMEchpe rename this to at() + //FIXMEchpe use references not pointers + VteRowData const* index(row_t position); /* const? */ + VteRowData* index_writable(row_t position); + + void hyperlink_maybe_gc(row_t increment); + hyperlink_idx_t get_hyperlink_idx(char const* hyperlink); + hyperlink_idx_t get_hyperlink_at_position(row_t position, + column_t col, + bool update_hover_idx, + char const** hyperlink); + + row_t reset(); + void resize(row_t max_rows = kDefaultMaxRows); + void shrink(row_t max_len = kDefaultMaxRows); + VteRowData* insert(row_t position); + VteRowData* append(); + void remove(row_t position); + void drop_scrollback(row_t position); + void set_visible_rows(row_t rows); + void rewrap(column_t columns, + VteVisualPosition** markers); + bool write_contents(GOutputStream* stream, + VteWriteFlags flags, + GCancellable* cancellable, + GError** error); + +private: + + #ifdef VTE_DEBUG + void validate() const; + #endif + + inline GString* hyperlink_get(hyperlink_idx_t idx) const { return (GString*)g_ptr_array_index(m_hyperlinks, idx); } + + inline VteRowData* get_writable_index(row_t position) const { return &m_array[position & m_mask]; } -typedef struct _VteRing VteRing; -struct _VteRing { - gulong max; + void hyperlink_gc(); + hyperlink_idx_t get_hyperlink_idx_no_update_current(char const* hyperlink); - gulong start, end; + typedef struct _CellAttrChange { + gsize text_end_offset; /* offset of first character no longer using this attr */ + VteStreamCellAttr attr; + } CellAttrChange; + + typedef struct _RowRecord { + size_t text_start_offset; /* offset where text of this row begins */ + size_t attr_start_offset; /* offset of the first character's attributes */ + int soft_wrapped: 1; /* end of line is not '\n' */ + int is_ascii: 1; /* for rewrapping speedup: guarantees that line contains 32..126 bytes only. Can be 0 even when ascii only. */ + } RowRecord; + + static_assert(std::is_pod::value, "Ring::RowRecord is not POD"); + + /* Represents a cell position, see ../doc/rewrap.txt */ + typedef struct _CellTextOffset { + size_t text_offset; /* byte offset in text_stream (or perhaps beyond) */ + int fragment_cells; /* extra number of cells to walk within a multicell character */ + int eol_cells; /* -1 if over a character, >=0 if at EOL or beyond */ + } CellTextOffset; + + static_assert(std::is_pod::value, "Ring::CellTextOffset is not POD"); + + inline bool read_row_record(RowRecord* record /* out */, + row_t position) + { + return _vte_stream_read(m_row_stream, + position * sizeof(*record), + (char*)record, + sizeof(*record)); + } + + inline void append_row_record(RowRecord const* record, + row_t position) + { + _vte_stream_append(m_row_stream, + (char const*)record, + sizeof(*record)); + } + + bool frozen_row_column_to_text_offset(row_t position, + column_t column, + CellTextOffset* offset); + bool frozen_row_text_offset_to_column(row_t position, + CellTextOffset const* offset, + column_t* column); + + bool write_row(GOutputStream* stream, + VteRowData* row, + VteWriteFlags flags, + GCancellable* cancellable, + GError** error); + + void ensure_writable(row_t position); + void ensure_writable_room(); + + void freeze_one_row(); + void maybe_freeze_one_row(); + void thaw_one_row(); + void discard_one_row(); + void maybe_discard_one_row(); + + void freeze_row(row_t position, + VteRowData const* row); + void thaw_row(row_t position, + VteRowData* row, + bool do_truncate, + int hyperlink_column, + char const** hyperlink); + void reset_streams(row_t position); + + row_t m_max; + row_t m_start{0}; + row_t m_end{0}; /* Writable */ - gulong writable, mask; - VteRowData *array; + row_t m_writable{0}; + row_t m_mask{31}; + VteRowData *m_array; /* Storage: * @@ -65,56 +204,60 @@ struct _VteRing { * if nonempty, it actually contains the ID and URI separated with a semicolon. Not NUL terminated. * - 2 bytes repeating attr.hyperlink_length so that we can walk backwards. */ - VteStream *attr_stream, *text_stream, *row_stream; - gsize last_attr_text_start_offset; - VteCellAttr last_attr; - GString *utf8_buffer; + bool m_has_streams; + VteStream *m_attr_stream, *m_text_stream, *m_row_stream; + size_t m_last_attr_text_start_offset{0}; + VteCellAttr m_last_attr; + GString *m_utf8_buffer; - VteRowData cached_row; - gulong cached_row_num; + VteRowData m_cached_row; + row_t m_cached_row_num{(row_t)-1}; - gboolean has_streams; - gulong visible_rows; /* to keep at least a screenful of lines in memory, bug 646098 comment 12 */ + row_t m_visible_rows{0}; /* to keep at least a screenful of lines in memory, bug 646098 comment 12 */ - GPtrArray *hyperlinks; /* The hyperlink pool. Contains GString* items. + GPtrArray *m_hyperlinks; /* The hyperlink pool. Contains GString* items. [0] points to an empty GString, [1] to [VTE_HYPERLINK_COUNT_MAX] contain the id;uri pairs. */ - char hyperlink_buf[VTE_HYPERLINK_TOTAL_LENGTH_MAX + 1]; /* One more hyperlink buffer to get the value if it's not placed in the pool. */ - hyperlink_idx_t hyperlink_highest_used_idx; /* 0 if no hyperlinks at all in the pool. */ - hyperlink_idx_t hyperlink_current_idx; /* The hyperlink idx used for newly created cells. + char m_hyperlink_buf[VTE_HYPERLINK_TOTAL_LENGTH_MAX + 1]; /* One more hyperlink buffer to get the value if it's not placed in the pool. */ + hyperlink_idx_t m_hyperlink_highest_used_idx{0}; /* 0 if no hyperlinks at all in the pool. */ + hyperlink_idx_t m_hyperlink_current_idx{0}; /* The hyperlink idx used for newly created cells. Must not be GC'd even if doesn't occur onscreen. */ - hyperlink_idx_t hyperlink_hover_idx; /* The hyperlink idx of the hovered cell. + hyperlink_idx_t m_hyperlink_hover_idx{0}; /* The hyperlink idx of the hovered cell. An idx is allocated on hover even if the cell is scrolled out to the streams. */ - gulong hyperlink_maybe_gc_counter; /* Do a GC when it reaches 65536. */ + row_t m_hyperlink_maybe_gc_counter{0}; /* Do a GC when it reaches 65536. */ }; -#define _vte_ring_contains(__ring, __position) \ - (((gulong) (__position) >= (__ring)->start) && \ - ((gulong) (__position) < (__ring)->end)) -#define _vte_ring_delta(__ring) ((glong) (__ring)->start) -#define _vte_ring_length(__ring) ((glong) ((__ring)->end - (__ring)->start)) -#define _vte_ring_next(__ring) ((glong) (__ring)->end) - -const VteRowData *_vte_ring_index (VteRing *ring, gulong position); -VteRowData *_vte_ring_index_writable (VteRing *ring, gulong position); - -void _vte_ring_init (VteRing *ring, gulong max_rows, gboolean has_streams); -void _vte_ring_fini (VteRing *ring); -void _vte_ring_hyperlink_maybe_gc (VteRing *ring, gulong increment); -hyperlink_idx_t _vte_ring_get_hyperlink_idx (VteRing *ring, const char *hyperlink); -hyperlink_idx_t _vte_ring_get_hyperlink_at_position (VteRing *ring, gulong position, int col, bool update_hover_idx, const char **hyperlink); -long _vte_ring_reset (VteRing *ring); -void _vte_ring_resize (VteRing *ring, gulong max_rows); -void _vte_ring_shrink (VteRing *ring, gulong max_len); -VteRowData *_vte_ring_insert (VteRing *ring, gulong position); -VteRowData *_vte_ring_append (VteRing *ring); -void _vte_ring_remove (VteRing *ring, gulong position); -void _vte_ring_drop_scrollback (VteRing *ring, gulong position); -void _vte_ring_set_visible_rows (VteRing *ring, gulong rows); -void _vte_ring_rewrap (VteRing *ring, glong columns, VteVisualPosition **markers); -gboolean _vte_ring_write_contents (VteRing *ring, - GOutputStream *stream, - VteWriteFlags flags, - GCancellable *cancellable, - GError **error); +}; /* namespace base */ + +}; /* namespace vte */ + +G_BEGIN_DECLS + +/* temp compat API */ + +typedef vte::base::Ring VteRing; + +static inline bool _vte_ring_contains(VteRing *ring, gulong position) { return ring->contains(position); } +static inline glong _vte_ring_delta(VteRing *ring) { return ring->delta(); } +static inline glong _vte_ring_length(VteRing *ring) { return ring->length(); } +static inline glong _vte_ring_next(VteRing *ring) { return ring->next(); } +static inline const VteRowData *_vte_ring_index (VteRing *ring, gulong position) { return ring->index(position); } +static inline VteRowData *_vte_ring_index_writable (VteRing *ring, gulong position) { return ring->index_writable(position); } +static inline void _vte_ring_hyperlink_maybe_gc (VteRing *ring, gulong increment) { ring->hyperlink_maybe_gc(increment); } +static inline auto _vte_ring_get_hyperlink_idx (VteRing *ring, const char *hyperlink) { return ring->get_hyperlink_idx(hyperlink); } +static inline auto _vte_ring_get_hyperlink_at_position (VteRing *ring, gulong position, int col, bool update_hover_idx, const char **hyperlink) { return ring->get_hyperlink_at_position(position, col, update_hover_idx, hyperlink); } +static inline long _vte_ring_reset (VteRing *ring) { return ring->reset(); } +static inline void _vte_ring_resize (VteRing *ring, gulong max_rows) { ring->resize(max_rows); } +static inline void _vte_ring_shrink (VteRing *ring, gulong max_len) { ring->shrink(max_len); } +static inline VteRowData *_vte_ring_insert (VteRing *ring, gulong position) { return ring->insert(position); } +static inline VteRowData *_vte_ring_append (VteRing *ring) { return ring->append(); } +static inline void _vte_ring_remove (VteRing *ring, gulong position) { ring->remove(position); } +static inline void _vte_ring_drop_scrollback (VteRing *ring, gulong position) { ring->drop_scrollback(position); } +static inline void _vte_ring_set_visible_rows (VteRing *ring, gulong rows) { ring->set_visible_rows(rows); } +static inline void _vte_ring_rewrap (VteRing *ring, glong columns, VteVisualPosition **markers) { ring->rewrap(columns, markers); } +static inline gboolean _vte_ring_write_contents (VteRing *ring, + GOutputStream *stream, + VteWriteFlags flags, + GCancellable *cancellable, + GError **error) { return ring->write_contents(stream, flags, cancellable, error); } G_END_DECLS diff --git a/src/vte.cc b/src/vte.cc index 70dc0810..caf7c533 100644 --- a/src/vte.cc +++ b/src/vte.cc @@ -262,7 +262,7 @@ VteTerminalPrivate::ring_remove(vte::grid::row_t position) void VteTerminalPrivate::reset_default_attributes(bool reset_hyperlink) { - hyperlink_idx_t hyperlink_idx_save = m_defaults.attr.hyperlink_idx; + auto const hyperlink_idx_save = m_defaults.attr.hyperlink_idx; m_defaults = m_color_defaults = m_fill_defaults = basic_cell; if (!reset_hyperlink) m_defaults.attr.hyperlink_idx = hyperlink_idx_save; @@ -5504,7 +5504,8 @@ VteTerminalPrivate::maybe_send_mouse_drag(vte::grid::coords const& unconfined_ro * the new one. Optionally stores the coordinates of the bounding box. */ void -VteTerminalPrivate::hyperlink_invalidate_and_get_bbox(hyperlink_idx_t idx, GdkRectangle *bbox) +VteTerminalPrivate::hyperlink_invalidate_and_get_bbox(vte::base::Ring::hyperlink_idx_t idx, + GdkRectangle *bbox) { auto first_row = first_displayed_row(); auto end_row = last_displayed_row() + 1; @@ -5557,7 +5558,7 @@ VteTerminalPrivate::hyperlink_hilite_update() const VteRowData *rowdata; bool do_check_hilite; vte::grid::coords rowcol; - hyperlink_idx_t new_hyperlink_hover_idx = 0; + vte::base::Ring::hyperlink_idx_t new_hyperlink_hover_idx = 0; GdkRectangle bbox; const char *separator; @@ -7966,7 +7967,12 @@ VteTerminalPrivate::widget_set_vadjustment(GtkAdjustment *adjustment) VteTerminalPrivate::VteTerminalPrivate(VteTerminal *t) : m_terminal(t), - m_widget(&t->widget) + m_widget(&t->widget), + m_row_count(VTE_ROWS), + m_column_count(VTE_COLUMNS), + m_normal_screen(VTE_SCROLLBACK_INIT, true), + m_alternate_screen(VTE_ROWS, false), + m_screen(&m_normal_screen) { /* Inits allocation to 1x1 @ -1,-1 */ cairo_rectangle_int_t allocation; @@ -8021,15 +8027,6 @@ VteTerminalPrivate::VteTerminalPrivate(VteTerminal *t) : m_regex_underline_position = 1; m_regex_underline_thickness = 1; - m_row_count = VTE_ROWS; - m_column_count = VTE_COLUMNS; - - /* Initialize the screens and histories. */ - _vte_ring_init (m_alternate_screen.row_data, m_row_count, FALSE); - m_screen = &m_alternate_screen; - _vte_ring_init (m_normal_screen.row_data, VTE_SCROLLBACK_INIT, TRUE); - m_screen = &m_normal_screen; - reset_default_attributes(true); /* Initialize charset modes. */ @@ -8502,10 +8499,6 @@ VteTerminalPrivate::~VteTerminalPrivate() } } - /* Clear the output histories. */ - _vte_ring_fini(m_normal_screen.row_data); - _vte_ring_fini(m_alternate_screen.row_data); - /* Free conversion descriptors. */ if (m_outgoing_conv != VTE_INVALID_CONV) { _vte_conv_close(m_outgoing_conv); diff --git a/src/vteinternal.hh b/src/vteinternal.hh index 1562255a..90e54d0d 100644 --- a/src/vteinternal.hh +++ b/src/vteinternal.hh @@ -177,12 +177,21 @@ struct _vte_incoming_chunk{ guchar data[VTE_INPUT_CHUNK_SIZE - 2 * sizeof(void *) - 1]; }; -typedef struct _VteScreen VteScreen; -struct _VteScreen { - VteRing row_data[1]; /* buffer contents */ +struct VteScreen { +public: + VteScreen(gulong max_rows, + bool has_streams) : + m_ring{max_rows, has_streams}, + row_data(&m_ring), + cursor{0,0} + { + } + + vte::base::Ring m_ring; /* buffer contents */ + VteRing* row_data; VteVisualPosition cursor; /* absolute value, from the beginning of the terminal history */ - double scroll_delta; /* scroll offset */ - long insert_delta; /* insertion offset */ + double scroll_delta{0.0}; /* scroll offset */ + long insert_delta{0}; /* insertion offset */ /* Stuff saved along with the cursor */ struct { @@ -379,7 +388,9 @@ public: /* Screen data. We support the normal screen, and an alternate * screen, which seems to be a DEC-specific feature. */ - struct _VteScreen m_normal_screen, m_alternate_screen, *m_screen; + VteScreen m_normal_screen; + VteScreen m_alternate_screen; + VteScreen *m_screen; /* points to either m_normal_screen or m_alternate_screen */ VteCell m_defaults; /* default characteristics for insertion of any new @@ -609,7 +620,7 @@ public: /* Hyperlinks */ gboolean m_allow_hyperlink; - hyperlink_idx_t m_hyperlink_hover_idx; + vte::base::Ring::hyperlink_idx_t m_hyperlink_hover_idx; const char *m_hyperlink_hover_uri; /* data is owned by the ring */ long m_hyperlink_auto_id; @@ -1029,7 +1040,7 @@ public: void emit_paste_clipboard(); void emit_hyperlink_hover_uri_changed(const GdkRectangle *bbox); - void hyperlink_invalidate_and_get_bbox(hyperlink_idx_t idx, GdkRectangle *bbox); + void hyperlink_invalidate_and_get_bbox(vte::base::Ring::hyperlink_idx_t idx, GdkRectangle *bbox); void hyperlink_hilite_update(); void match_contents_clear(); diff --git a/src/vterowdata.cc b/src/vterowdata.cc index 1f00ae53..6b8efbdd 100644 --- a/src/vterowdata.cc +++ b/src/vterowdata.cc @@ -30,11 +30,11 @@ /* This will be true now that VteCell is POD, but make sure it'll be true * once that changes. */ -static_assert(std::is_trivially_copy_constructible::value, "VteCell is not trivially copyable"); -static_assert(std::is_trivially_move_constructible::value, "VteCell is not trivially copyable"); +static_assert(std::is_trivially_copy_constructible::value, "VteCell is not copy constructible"); +static_assert(std::is_trivially_move_constructible::value, "VteCell is not move constructible"); static_assert(std::is_trivially_copyable::value, "VteCell is not trivially copyable"); -static_assert(std::is_trivially_copy_assignable::value, "VteCell is not trivially movable"); -static_assert(std::is_trivially_move_assignable::value, "VteCell is not trivially movable"); +static_assert(std::is_trivially_copy_assignable::value, "VteCell is not copy assignable"); +static_assert(std::is_trivially_move_assignable::value, "VteCell is not move assignable"); /* * VteCells: A row's cell array diff --git a/src/vterowdata.hh b/src/vterowdata.hh index 7c6af830..2d66b603 100644 --- a/src/vterowdata.hh +++ b/src/vterowdata.hh @@ -227,15 +227,6 @@ _vte_row_data_get_writable (VteRowData *row, gulong col) return &row->cells[col]; } -/* - * Copy the common attributes from VteCellAttr to VteStreamCellAttr or vice versa. - */ -static inline void -_attrcpy (void *dst, void *src) -{ - memcpy(dst, src, VTE_CELL_ATTR_COMMON_BYTES); -} - void _vte_row_data_init (VteRowData *row); void _vte_row_data_clear (VteRowData *row); void _vte_row_data_fini (VteRowData *row); -- cgit v1.2.1