[A] Added adding_strategy property to the tables

This commit is contained in:
seleznevae
2020-01-08 15:32:06 +03:00
parent 7d313ee078
commit 27e1102878
19 changed files with 823 additions and 94 deletions

View File

@@ -311,6 +311,12 @@ size_t vector_capacity(const f_vector_t *);
FT_INTERNAL
int vector_push(f_vector_t *, const void *item);
FT_INTERNAL
int vector_insert(f_vector_t *, const void *item, size_t pos);
FT_INTERNAL
f_vector_t *vector_split(f_vector_t *, size_t pos);
FT_INTERNAL
const void *vector_at_c(const f_vector_t *vector, size_t index);
@@ -320,12 +326,15 @@ void *vector_at(f_vector_t *, size_t index);
FT_INTERNAL
f_status vector_swap(f_vector_t *cur_vec, f_vector_t *mv_vec, size_t pos);
FT_INTERNAL
void vector_clear(f_vector_t *);
FT_INTERNAL
int vector_erase(f_vector_t *, size_t index);
#ifdef FT_TEST_BUILD
f_vector_t *copy_vector(f_vector_t *);
size_t vector_index_of(const f_vector_t *, const void *item);
int vector_erase(f_vector_t *, size_t index);
void vector_clear(f_vector_t *);
#endif
#endif /* VECTOR_H */
@@ -2020,6 +2029,7 @@ struct fort_entire_table_properties {
unsigned int top_margin;
unsigned int right_margin;
unsigned int bottom_margin;
enum ft_adding_strategy add_strategy;
};
typedef struct fort_entire_table_properties fort_entire_table_properties_t;
extern fort_entire_table_properties_t g_entire_table_properties;
@@ -2134,6 +2144,9 @@ void destroy_row(f_row_t *row);
FT_INTERNAL
f_row_t *copy_row(f_row_t *row);
FT_INTERNAL
f_row_t *split_row(f_row_t *row, size_t pos);
FT_INTERNAL
f_row_t *create_row_from_string(const char *str);
@@ -2152,9 +2165,15 @@ const f_cell_t *get_cell_c(const f_row_t *row, size_t col);
FT_INTERNAL
f_cell_t *get_cell_and_create_if_not_exists(f_row_t *row, size_t col);
FT_INTERNAL
f_cell_t *create_cell_in_position(f_row_t *row, size_t col);
FT_INTERNAL
f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos);
FT_INTERNAL
f_status insert_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos);
FT_INTERNAL
size_t group_cell_number(const f_row_t *row, size_t master_cell_col);
@@ -2611,7 +2630,14 @@ ft_table_t *ft_create_table(void)
F_FREE(result);
return NULL;
}
result->properties = NULL;
result->properties = create_table_properties();
if (result->properties == NULL) {
destroy_vector(result->separators);
destroy_vector(result->rows);
F_FREE(result);
return NULL;
}
result->conv_buffer = NULL;
result->cur_row = 0;
result->cur_col = 0;
@@ -2677,7 +2703,12 @@ ft_table_t *ft_copy_table(ft_table_t *table)
vector_push(result->separators, &new_sep);
}
/* note: by default new table has allocated default properties, so we
* have to destroy them first.
*/
if (result->properties) {
destroy_table_properties(result->properties);
}
result->properties = copy_table_properties(table->properties);
if (result->properties == NULL) {
ft_destroy_table(result);
@@ -2691,12 +2722,57 @@ ft_table_t *ft_copy_table(ft_table_t *table)
return result;
}
static int split_cur_row(ft_table_t *table, f_row_t **tail_of_cur_row)
{
if (table->cur_row >= vector_size(table->rows)) {
tail_of_cur_row = NULL;
return 0;
}
void ft_ln(ft_table_t *table)
f_row_t *row = *(f_row_t **)vector_at(table->rows, table->cur_row);
if (table->cur_col >= columns_in_row(row)) {
tail_of_cur_row = NULL;
return 0;
}
f_row_t *tail = split_row(row, table->cur_col);
if (!tail) {
tail_of_cur_row = NULL;
return FT_ERROR;
}
*tail_of_cur_row = tail;
return 0;
}
int ft_ln(ft_table_t *table)
{
assert(table);
fort_entire_table_properties_t *table_props = &table->properties->entire_table_properties;
switch (table_props->add_strategy) {
case FT_STRATEGY_INSERT: {
f_row_t *new_row = NULL;
if (FT_IS_ERROR(split_cur_row(table, &new_row))) {
return FT_ERROR;
}
if (new_row) {
if (FT_IS_ERROR(vector_insert(table->rows, &new_row, table->cur_row + 1))) {
destroy_row(new_row);
return FT_ERROR;
}
}
break;
}
case FT_STRATEGY_REPLACE:
// do nothing
break;
default:
assert(0 && "Unexpected situation inside libfort");
break;
}
table->cur_col = 0;
table->cur_row++;
return FT_SUCCESS;
}
size_t ft_cur_row(const ft_table_t *table)
@@ -2760,7 +2836,23 @@ static int ft_row_printf_impl_(ft_table_t *table, size_t row, const struct f_str
new_cols = columns_in_row(new_row);
cur_row_p = (f_row_t **)vector_at(table->rows, row);
swap_row(*cur_row_p, new_row, table->cur_col);
fort_entire_table_properties_t *table_props = &table->properties->entire_table_properties;
switch (table_props->add_strategy) {
case FT_STRATEGY_INSERT: {
if (FT_IS_ERROR(insert_row(*cur_row_p, new_row, table->cur_col)))
goto clear;
break;
}
case FT_STRATEGY_REPLACE: {
if (FT_IS_ERROR(swap_row(*cur_row_p, new_row, table->cur_col)))
goto clear;
break;
}
default:
assert(0 && "Unexpected situation inside libfort");
break;
}
table->cur_col += new_cols;
destroy_row(new_row);
@@ -4920,6 +5012,7 @@ fort_entire_table_properties_t g_entire_table_properties = {
0, /* top_margin */
0, /* right_margin */
0, /* bottom_margin */
FT_STRATEGY_REPLACE, /* add_strategy */
};
static f_status set_entire_table_property_internal(fort_entire_table_properties_t *properties, uint32_t property, int value)
@@ -4934,6 +5027,8 @@ static f_status set_entire_table_property_internal(fort_entire_table_properties_
properties->right_margin = value;
} else if (PROP_IS_SET(property, FT_TPROP_BOTTOM_MARGIN)) {
properties->bottom_margin = value;
} else if (PROP_IS_SET(property, FT_TPROP_ADDING_STRATEGY)) {
properties->add_strategy = (enum ft_adding_strategy)value;
} else {
return FT_EINVAL;
}
@@ -4989,7 +5084,8 @@ f_table_properties_t g_table_properties = {
0, /* left_margin */
0, /* top_margin */
0, /* right_margin */
0 /* bottom_margin */
0, /* bottom_margin */
FT_STRATEGY_REPLACE, /* add_strategy */
}
};
@@ -5084,21 +5180,41 @@ struct f_row {
f_vector_t *cells;
};
FT_INTERNAL
f_row_t *create_row(void)
static
f_row_t *create_row_impl(f_vector_t *cells)
{
f_row_t *row = (f_row_t *)F_CALLOC(1, sizeof(f_row_t));
if (row == NULL)
return NULL;
row->cells = create_vector(sizeof(f_cell_t *), DEFAULT_VECTOR_CAPACITY);
if (row->cells == NULL) {
F_FREE(row);
return NULL;
if (cells) {
row->cells = cells;
} else {
row->cells = create_vector(sizeof(f_cell_t *), DEFAULT_VECTOR_CAPACITY);
if (row->cells == NULL) {
F_FREE(row);
return NULL;
}
}
return row;
}
FT_INTERNAL
f_row_t *create_row(void)
{
return create_row_impl(NULL);
}
static
void destroy_each_cell(f_vector_t *cells)
{
size_t i = 0;
size_t cells_n = vector_size(cells);
for (i = 0; i < cells_n; ++i) {
f_cell_t *cell = *(f_cell_t **)vector_at(cells, i);
destroy_cell(cell);
}
}
FT_INTERNAL
void destroy_row(f_row_t *row)
{
@@ -5106,12 +5222,7 @@ void destroy_row(f_row_t *row)
return;
if (row->cells) {
size_t i = 0;
size_t cells_n = vector_size(row->cells);
for (i = 0; i < cells_n; ++i) {
f_cell_t *cell = *(f_cell_t **)vector_at(row->cells, i);
destroy_cell(cell);
}
destroy_each_cell(row->cells);
destroy_vector(row->cells);
}
@@ -5141,6 +5252,23 @@ f_row_t *copy_row(f_row_t *row)
return result;
}
FT_INTERNAL
f_row_t *split_row(f_row_t *row, size_t pos)
{
assert(row);
f_vector_t *cells = vector_split(row->cells, pos);
if (!cells)
return NULL;
f_row_t *tail = create_row_impl(cells);
if (!tail) {
destroy_each_cell(cells);
destroy_vector(cells);
}
return tail;
}
FT_INTERNAL
size_t columns_in_row(const f_row_t *row)
{
@@ -5202,6 +5330,23 @@ f_cell_t *get_cell_and_create_if_not_exists(f_row_t *row, size_t col)
return get_cell_impl(row, col, CREATE_ON_NULL);
}
FT_INTERNAL
f_cell_t *create_cell_in_position(f_row_t *row, size_t col)
{
if (row == NULL || row->cells == NULL) {
return NULL;
}
f_cell_t *new_cell = create_cell();
if (new_cell == NULL)
return NULL;
if (FT_IS_ERROR(vector_insert(row->cells, &new_cell, col))) {
destroy_cell(new_cell);
return NULL;
}
return *(f_cell_t **)vector_at(row->cells, col);
}
FT_INTERNAL
f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos)
@@ -5220,6 +5365,37 @@ f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos)
return vector_swap(cur_row->cells, ins_row->cells, pos);
}
/* Ownership of cells of `ins_row` is passed to `cur_row`. */
FT_INTERNAL
f_status insert_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos)
{
assert(cur_row);
assert(ins_row);
while (vector_size(cur_row->cells) < pos) {
f_cell_t *new_cell = create_cell();
if (!new_cell)
return FT_ERROR;
vector_push(cur_row->cells, &new_cell);
}
size_t sz = vector_size(ins_row->cells);
size_t i = 0;
for (i = 0; i < sz; ++i) {
f_cell_t *cell = *(f_cell_t **)vector_at(ins_row->cells, i);
if (FT_IS_ERROR(vector_insert(cur_row->cells, &cell, pos + i))) {
/* clean up what we have inserted */
while (i--) {
vector_erase(cur_row->cells, pos);
}
return FT_ERROR;
}
}
/* Clear cells so that it will be safe to destroy this row */
vector_clear(ins_row->cells);
return FT_SUCCESS;
}
FT_INTERNAL
size_t group_cell_number(const f_row_t *row, size_t master_cell_col)
@@ -6672,7 +6848,6 @@ f_row_t *get_row_and_create_if_not_exists(ft_table_t *table, size_t row)
return get_row_impl(table, row, CREATE_ON_NULL);
}
FT_INTERNAL
f_string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table)
{
@@ -6681,7 +6856,21 @@ f_string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table
f_row_t *row = get_row_and_create_if_not_exists(table, table->cur_row);
if (row == NULL)
return NULL;
f_cell_t *cell = get_cell_and_create_if_not_exists(row, table->cur_col);
f_cell_t *cell = NULL;
fort_entire_table_properties_t *table_props = &table->properties->entire_table_properties;
switch (table_props->add_strategy) {
case FT_STRATEGY_INSERT:
cell = create_cell_in_position(row, table->cur_col);
break;
case FT_STRATEGY_REPLACE:
cell = get_cell_and_create_if_not_exists(row, table->cur_col);
break;
default:
assert(0 && "Unexpected situation inside libfort");
break;
}
if (cell == NULL)
return NULL;
@@ -6983,6 +7172,56 @@ int vector_push(f_vector_t *vector, const void *item)
return FT_SUCCESS;
}
FT_INTERNAL
int vector_insert(f_vector_t *vector, const void *item, size_t pos)
{
assert(vector);
assert(item);
size_t needed_capacity = MAX(pos + 1, vector->m_size + 1);
if (vector->m_capacity < needed_capacity) {
if (vector_reallocate_(vector, needed_capacity) == -1)
return FT_ERROR;
vector->m_capacity = needed_capacity;
}
size_t offset = pos * vector->m_item_size;
if (pos >= vector->m_size) {
/* Data in the middle are not initialized */
memcpy((char *)vector->m_data + offset, item, vector->m_item_size);
vector->m_size = pos + 1;
return FT_SUCCESS;
} else {
/* Shift following data by one position */
memmove((char *)vector->m_data + offset + vector->m_item_size,
(char *)vector->m_data + offset,
vector->m_item_size * (vector->m_size - pos));
memcpy((char *)vector->m_data + offset, item, vector->m_item_size);
++(vector->m_size);
return FT_SUCCESS;
}
}
FT_INTERNAL
f_vector_t *vector_split(f_vector_t *vector, size_t pos)
{
size_t trailing_sz = vector->m_size > pos ? vector->m_size - pos : 0;
f_vector_t *new_vector = create_vector(vector->m_item_size, trailing_sz);
if (!new_vector)
return new_vector;
if (new_vector->m_capacity < trailing_sz) {
destroy_vector(new_vector);
return NULL;
}
if (trailing_sz == 0)
return new_vector;
size_t offset = vector->m_item_size * pos;
memcpy(new_vector->m_data, (char *)vector->m_data + offset,
trailing_sz * vector->m_item_size);
new_vector->m_size = trailing_sz;
vector->m_size = pos;
return new_vector;
}
FT_INTERNAL
const void *vector_at_c(const f_vector_t *vector, size_t index)
@@ -7058,6 +7297,26 @@ f_status vector_swap(f_vector_t *cur_vec, f_vector_t *mv_vec, size_t pos)
return FT_SUCCESS;
}
FT_INTERNAL
void vector_clear(f_vector_t *vector)
{
vector->m_size = 0;
}
FT_INTERNAL
int vector_erase(f_vector_t *vector, size_t index)
{
assert(vector);
if (vector->m_size == 0 || index >= vector->m_size)
return FT_ERROR;
memmove((char *)vector->m_data + vector->m_item_size * index,
(char *)vector->m_data + vector->m_item_size * (index + 1),
(vector->m_size - 1 - index) * vector->m_item_size);
vector->m_size--;
return FT_SUCCESS;
}
#ifdef FT_TEST_BUILD
@@ -7091,26 +7350,6 @@ size_t vector_index_of(const f_vector_t *vector, const void *item)
return INVALID_VEC_INDEX;
}
int vector_erase(f_vector_t *vector, size_t index)
{
assert(vector);
if (vector->m_size == 0 || index >= vector->m_size)
return FT_ERROR;
memmove((char *)vector->m_data + vector->m_item_size * index,
(char *)vector->m_data + vector->m_item_size * (index + 1),
(vector->m_size - 1 - index) * vector->m_item_size);
vector->m_size--;
return FT_SUCCESS;
}
void vector_clear(f_vector_t *vector)
{
vector->m_size = 0;
}
#endif
/********************************************************

View File

@@ -275,8 +275,14 @@ ft_table_t *ft_copy_table(ft_table_t *table);
*
* @param table
* Pointer to formatted table.
* @return
* - 0: Success; data were written
* - (<0): In case of error.
* @note
* This function can fail only in case FT_STRATEGY_INSERT adding strategy
* was set for the table.
*/
void ft_ln(ft_table_t *table);
int ft_ln(ft_table_t *table);
/**
* Get row number of the current cell.
@@ -812,12 +818,23 @@ int ft_set_cell_prop(ft_table_t *table, size_t row, size_t col, uint32_t propert
* @name Table properties identifiers.
* @{
*/
#define FT_TPROP_LEFT_MARGIN (0x01U << 0)
#define FT_TPROP_TOP_MARGIN (0x01U << 1)
#define FT_TPROP_RIGHT_MARGIN (0x01U << 2)
#define FT_TPROP_BOTTOM_MARGIN (0x01U << 3)
#define FT_TPROP_LEFT_MARGIN (0x01U << 0)
#define FT_TPROP_TOP_MARGIN (0x01U << 1)
#define FT_TPROP_RIGHT_MARGIN (0x01U << 2)
#define FT_TPROP_BOTTOM_MARGIN (0x01U << 3)
#define FT_TPROP_ADDING_STRATEGY (0x01U << 4)
/** @} */
/**
* Adding strategy.
*
* Determines what happens with old content if current cell is not empty after
* adding data to it. Default strategy is FT_STRATEGY_REPLACE.
*/
enum ft_adding_strategy {
FT_STRATEGY_REPLACE = 0, /**< Replace old content. */
FT_STRATEGY_INSERT /**< Insert new conten. Old content is shifted. */
};
/**

View File

@@ -60,6 +60,17 @@ enum class row_type {
header = FT_ROW_HEADER
};
/**
* Adding strategy.
*
* Determines what happens with old content if current cell is not empty after
* adding data to it. Default strategy is 'replace'.
*/
enum class add_strategy {
replace = FT_STRATEGY_REPLACE,
insert = FT_STRATEGY_INSERT
};
/**
* Colors.
*/
@@ -893,6 +904,22 @@ public:
{
return FT_IS_SUCCESS(ft_set_tbl_prop(table_, FT_TPROP_BOTTOM_MARGIN, value));
}
/**
* Set table adding strategy.
*
* @param value
* Adding strategy.
* @return
* - true: Success; table property was changed.
* - false: In case of error.
*/
bool set_adding_strategy(fort::add_strategy value)
{
return FT_IS_SUCCESS(ft_set_tbl_prop(table_,
FT_TPROP_ADDING_STRATEGY,
static_cast<int>(value)));
}
private:
ft_table_t *table_;
mutable std::stringstream stream_;