/*
* Copyright (C) 2002,2009 Red Hat, Inc.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
*
* Red Hat Author(s): Nalin Dahyabhai, Behdad Esfahbod
*/
#include
#include "debug.h"
#include "vterowdata.hh"
#include
#include
/* 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 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 copy assignable");
static_assert(std::is_trivially_move_assignable::value, "VteCell is not move assignable");
/*
* VteCells: A row's cell array
*/
typedef struct _VteCells VteCells;
struct _VteCells {
guint32 alloc_len;
VteCell cells[1];
};
static inline VteCells *
_vte_cells_for_cell_array (VteCell *cells)
{
if (G_UNLIKELY (!cells))
return NULL;
return (VteCells *) (((guchar *) cells) - G_STRUCT_OFFSET (VteCells, cells));
}
static VteCells *
_vte_cells_realloc (VteCells *cells, guint32 len)
{
guint32 alloc_len = (1 << g_bit_storage (MAX (len, 80))) - 1;
_vte_debug_print(VTE_DEBUG_RING, "Enlarging cell array of %d cells to %d cells\n", cells ? cells->alloc_len : 0, alloc_len);
cells = (VteCells *)g_realloc (cells, G_STRUCT_OFFSET (VteCells, cells) + alloc_len * sizeof (cells->cells[0]));
cells->alloc_len = alloc_len;
return cells;
}
static void
_vte_cells_free (VteCells *cells)
{
_vte_debug_print(VTE_DEBUG_RING, "Freeing cell array of %d cells\n", cells->alloc_len);
g_free (cells);
}
/*
* VteRowData: A row's data
*/
void
_vte_row_data_init (VteRowData *row)
{
memset (row, 0, sizeof (*row));
}
void
_vte_row_data_clear (VteRowData *row)
{
VteCell *cells = row->cells;
_vte_row_data_init (row);
row->cells = cells;
}
void
_vte_row_data_fini (VteRowData *row)
{
if (row->cells)
_vte_cells_free (_vte_cells_for_cell_array (row->cells));
row->cells = NULL;
}
static inline gboolean
_vte_row_data_ensure (VteRowData *row, gulong len)
{
VteCells *cells = _vte_cells_for_cell_array (row->cells);
if (G_LIKELY (cells && len <= cells->alloc_len))
return TRUE;
if (G_UNLIKELY (len >= 0xFFFF))
return FALSE;
row->cells = _vte_cells_realloc (cells, len)->cells;
return TRUE;
}
void
_vte_row_data_insert (VteRowData *row, gulong col, const VteCell *cell)
{
gulong i;
if (G_UNLIKELY (!_vte_row_data_ensure (row, row->len + 1)))
return;
for (i = row->len; i > col; i--)
row->cells[i] = row->cells[i - 1];
row->cells[col] = *cell;
row->len++;
}
void _vte_row_data_append (VteRowData *row, const VteCell *cell)
{
if (G_UNLIKELY (!_vte_row_data_ensure (row, row->len + 1)))
return;
row->cells[row->len] = *cell;
row->len++;
}
void _vte_row_data_remove (VteRowData *row, gulong col)
{
gulong i;
for (i = col + 1; i < row->len; i++)
row->cells[i - 1] = row->cells[i];
if (G_LIKELY (row->len))
row->len--;
}
void _vte_row_data_fill (VteRowData *row, const VteCell *cell, gulong len)
{
if (row->len < len) {
gulong i;
if (G_UNLIKELY (!_vte_row_data_ensure (row, len)))
return;
for (i = row->len; i < len; i++)
row->cells[i] = *cell;
row->len = len;
}
}
void _vte_row_data_shrink (VteRowData *row, gulong max_len)
{
if (max_len < row->len)
row->len = max_len;
}
void _vte_row_data_copy (const VteRowData *src, VteRowData *dst)
{
_vte_row_data_ensure (dst, src->len);
dst->len = src->len;
dst->attr = src->attr;
memcpy(dst->cells, src->cells, src->len * sizeof (src->cells[0]));
}
/* Get the length, ignoring trailing empty cells (with a custom background color). */
guint16 _vte_row_data_nonempty_length (const VteRowData *row)
{
guint16 len;
const VteCell *cell;
for (len = row->len; len > 0; len--) {
cell = &row->cells[len - 1];
if (cell->attr.fragment() || cell->c != 0)
break;
}
return len;
}