[A] add function ft_delete_range
This commit is contained in:
parent
bd1c28a2cd
commit
e644f0a504
@ -2,6 +2,7 @@
|
||||
|
||||
### API
|
||||
|
||||
- Add function `ft_delete_range` to delete range of the cells.
|
||||
- Add functions to check if table is empty to the API.
|
||||
- `ft_ln` returns status of operation.
|
||||
- Add new table property `adding_strategy` (2 strategies available - replace(default) and insert).
|
||||
|
80
lib/fort.c
80
lib/fort.c
@ -337,6 +337,9 @@ f_vector_t *copy_vector(f_vector_t *);
|
||||
size_t vector_index_of(const f_vector_t *, const void *item);
|
||||
#endif
|
||||
|
||||
#define VECTOR_AT(vector, pos, data_type) \
|
||||
*(data_type *)vector_at((vector), (pos))
|
||||
|
||||
#endif /* VECTOR_H */
|
||||
|
||||
/********************************************************
|
||||
@ -2147,6 +2150,10 @@ f_row_t *copy_row(f_row_t *row);
|
||||
FT_INTERNAL
|
||||
f_row_t *split_row(f_row_t *row, size_t pos);
|
||||
|
||||
// Delete range [left; right] of cells (both ends included)
|
||||
FT_INTERNAL
|
||||
int ft_row_delete_range(f_row_t *row, size_t left, size_t right);
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *create_row_from_string(const char *str);
|
||||
|
||||
@ -2806,6 +2813,58 @@ size_t ft_row_count(const ft_table_t *table)
|
||||
return vector_size(table->rows);
|
||||
}
|
||||
|
||||
int ft_delete_range(ft_table_t *table,
|
||||
size_t top_left_row, size_t top_left_col,
|
||||
size_t bottom_right_row, size_t bottom_right_col)
|
||||
{
|
||||
assert(table && table->rows);
|
||||
int status = FT_SUCCESS;
|
||||
|
||||
size_t rows_n = vector_size(table->rows);
|
||||
|
||||
if (top_left_row == FT_CUR_ROW)
|
||||
top_left_row = table->cur_row;
|
||||
if (bottom_right_row == FT_CUR_ROW)
|
||||
bottom_right_row = table->cur_row;
|
||||
|
||||
if (top_left_col == FT_CUR_COLUMN)
|
||||
top_left_col = table->cur_row;
|
||||
if (bottom_right_col == FT_CUR_COLUMN)
|
||||
bottom_right_col = table->cur_row;
|
||||
|
||||
if (top_left_row > bottom_right_row || top_left_col > bottom_right_col)
|
||||
return FT_EINVAL;
|
||||
|
||||
f_row_t *row = NULL;
|
||||
size_t i = top_left_row;
|
||||
while (i < rows_n && i <= bottom_right_row) {
|
||||
row = VECTOR_AT(table->rows, i, f_row_t *);
|
||||
status = ft_row_delete_range(row, top_left_col, bottom_right_col);
|
||||
if (FT_IS_ERROR(status))
|
||||
goto clear;
|
||||
++i;
|
||||
}
|
||||
|
||||
size_t n_iterations = MIN(rows_n - 1, bottom_right_row) - top_left_row + 1;
|
||||
size_t j = 0;
|
||||
i = top_left_row;
|
||||
for (j = 0; j < n_iterations; ++j) {
|
||||
row = VECTOR_AT(table->rows, i, f_row_t *);
|
||||
if (columns_in_row(row)) {
|
||||
++i;
|
||||
} else {
|
||||
destroy_row(row);
|
||||
status = vector_erase(table->rows, i);
|
||||
if (FT_IS_ERROR(status))
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
clear:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static int ft_row_printf_impl_(ft_table_t *table, size_t row, const struct f_string_view *fmt, va_list *va)
|
||||
{
|
||||
size_t i = 0;
|
||||
@ -5270,6 +5329,27 @@ f_row_t *split_row(f_row_t *row, size_t pos)
|
||||
return tail;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
int ft_row_delete_range(f_row_t *row, size_t left, size_t right)
|
||||
{
|
||||
assert(row);
|
||||
size_t cols_n = vector_size(row->cells);
|
||||
if (cols_n == 0 || (right < left))
|
||||
return FT_SUCCESS;
|
||||
|
||||
f_cell_t *cell = NULL;
|
||||
size_t i = left;
|
||||
while (i < cols_n && i <= right) {
|
||||
cell = VECTOR_AT(row->cells, i, f_cell_t *);
|
||||
destroy_cell(cell);
|
||||
++i;
|
||||
}
|
||||
size_t n_destroy = MIN(cols_n - 1, right) - left + 1;
|
||||
while (n_destroy--) {
|
||||
vector_erase(row->cells, left);
|
||||
}
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
size_t columns_in_row(const f_row_t *row)
|
||||
|
24
lib/fort.h
24
lib/fort.h
@ -340,6 +340,30 @@ int ft_is_empty(const ft_table_t *table);
|
||||
*/
|
||||
size_t ft_row_count(const ft_table_t *table);
|
||||
|
||||
/**
|
||||
* Delete range of cells.
|
||||
*
|
||||
* Range of cells is determined by 2 points (top-left and bottom-right) (both
|
||||
* ends are included).
|
||||
*
|
||||
* @param table
|
||||
* Pointer to formatted table.
|
||||
* @param top_left_row
|
||||
* Row number of the top left cell in the range.
|
||||
* @param top_left_col
|
||||
* Column number of the top left cell in the range.
|
||||
* @param bottom_right_row
|
||||
* Row number of the bottom right cell in the range.
|
||||
* @param bottom_right_col
|
||||
* Column number of the bottom right cell in the range.
|
||||
* @return
|
||||
* - 0 - Operation was successfully implemented
|
||||
* - (<0): In case of error
|
||||
*/
|
||||
int ft_delete_range(ft_table_t *table,
|
||||
size_t top_left_row, size_t top_left_col,
|
||||
size_t bottom_right_row, size_t bottom_right_col);
|
||||
|
||||
#if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER)
|
||||
|
||||
/**
|
||||
|
24
src/fort.h
24
src/fort.h
@ -340,6 +340,30 @@ int ft_is_empty(const ft_table_t *table);
|
||||
*/
|
||||
size_t ft_row_count(const ft_table_t *table);
|
||||
|
||||
/**
|
||||
* Delete range of cells.
|
||||
*
|
||||
* Range of cells is determined by 2 points (top-left and bottom-right) (both
|
||||
* ends are included).
|
||||
*
|
||||
* @param table
|
||||
* Pointer to formatted table.
|
||||
* @param top_left_row
|
||||
* Row number of the top left cell in the range.
|
||||
* @param top_left_col
|
||||
* Column number of the top left cell in the range.
|
||||
* @param bottom_right_row
|
||||
* Row number of the bottom right cell in the range.
|
||||
* @param bottom_right_col
|
||||
* Column number of the bottom right cell in the range.
|
||||
* @return
|
||||
* - 0 - Operation was successfully implemented
|
||||
* - (<0): In case of error
|
||||
*/
|
||||
int ft_delete_range(ft_table_t *table,
|
||||
size_t top_left_row, size_t top_left_col,
|
||||
size_t bottom_right_row, size_t bottom_right_col);
|
||||
|
||||
#if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER)
|
||||
|
||||
/**
|
||||
|
@ -233,6 +233,58 @@ size_t ft_row_count(const ft_table_t *table)
|
||||
return vector_size(table->rows);
|
||||
}
|
||||
|
||||
int ft_delete_range(ft_table_t *table,
|
||||
size_t top_left_row, size_t top_left_col,
|
||||
size_t bottom_right_row, size_t bottom_right_col)
|
||||
{
|
||||
assert(table && table->rows);
|
||||
int status = FT_SUCCESS;
|
||||
|
||||
size_t rows_n = vector_size(table->rows);
|
||||
|
||||
if (top_left_row == FT_CUR_ROW)
|
||||
top_left_row = table->cur_row;
|
||||
if (bottom_right_row == FT_CUR_ROW)
|
||||
bottom_right_row = table->cur_row;
|
||||
|
||||
if (top_left_col == FT_CUR_COLUMN)
|
||||
top_left_col = table->cur_row;
|
||||
if (bottom_right_col == FT_CUR_COLUMN)
|
||||
bottom_right_col = table->cur_row;
|
||||
|
||||
if (top_left_row > bottom_right_row || top_left_col > bottom_right_col)
|
||||
return FT_EINVAL;
|
||||
|
||||
f_row_t *row = NULL;
|
||||
size_t i = top_left_row;
|
||||
while (i < rows_n && i <= bottom_right_row) {
|
||||
row = VECTOR_AT(table->rows, i, f_row_t *);
|
||||
status = ft_row_delete_range(row, top_left_col, bottom_right_col);
|
||||
if (FT_IS_ERROR(status))
|
||||
goto clear;
|
||||
++i;
|
||||
}
|
||||
|
||||
size_t n_iterations = MIN(rows_n - 1, bottom_right_row) - top_left_row + 1;
|
||||
size_t j = 0;
|
||||
i = top_left_row;
|
||||
for (j = 0; j < n_iterations; ++j) {
|
||||
row = VECTOR_AT(table->rows, i, f_row_t *);
|
||||
if (columns_in_row(row)) {
|
||||
++i;
|
||||
} else {
|
||||
destroy_row(row);
|
||||
status = vector_erase(table->rows, i);
|
||||
if (FT_IS_ERROR(status))
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
clear:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static int ft_row_printf_impl_(ft_table_t *table, size_t row, const struct f_string_view *fmt, va_list *va)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
21
src/row.c
21
src/row.c
@ -98,6 +98,27 @@ f_row_t *split_row(f_row_t *row, size_t pos)
|
||||
return tail;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
int ft_row_delete_range(f_row_t *row, size_t left, size_t right)
|
||||
{
|
||||
assert(row);
|
||||
size_t cols_n = vector_size(row->cells);
|
||||
if (cols_n == 0 || (right < left))
|
||||
return FT_SUCCESS;
|
||||
|
||||
f_cell_t *cell = NULL;
|
||||
size_t i = left;
|
||||
while (i < cols_n && i <= right) {
|
||||
cell = VECTOR_AT(row->cells, i, f_cell_t *);
|
||||
destroy_cell(cell);
|
||||
++i;
|
||||
}
|
||||
size_t n_destroy = MIN(cols_n - 1, right) - left + 1;
|
||||
while (n_destroy--) {
|
||||
vector_erase(row->cells, left);
|
||||
}
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
size_t columns_in_row(const f_row_t *row)
|
||||
|
@ -21,6 +21,10 @@ f_row_t *copy_row(f_row_t *row);
|
||||
FT_INTERNAL
|
||||
f_row_t *split_row(f_row_t *row, size_t pos);
|
||||
|
||||
// Delete range [left; right] of cells (both ends included)
|
||||
FT_INTERNAL
|
||||
int ft_row_delete_range(f_row_t *row, size_t left, size_t right);
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *create_row_from_string(const char *str);
|
||||
|
||||
|
@ -47,4 +47,7 @@ f_vector_t *copy_vector(f_vector_t *);
|
||||
size_t vector_index_of(const f_vector_t *, const void *item);
|
||||
#endif
|
||||
|
||||
#define VECTOR_AT(vector, pos, data_type) \
|
||||
*(data_type *)vector_at((vector), (pos))
|
||||
|
||||
#endif /* VECTOR_H */
|
||||
|
@ -1808,3 +1808,128 @@ void test_table_changing_cell(void)
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ft_table *create_test_table()
|
||||
{
|
||||
ft_table_t *table = ft_create_table();
|
||||
assert_true(table != NULL);
|
||||
ft_set_cell_prop(table, FT_ANY_ROW, FT_ANY_COLUMN, FT_CPROP_BOTTOM_PADDING, 0);
|
||||
ft_set_cell_prop(table, FT_ANY_ROW, FT_ANY_COLUMN, FT_CPROP_TOP_PADDING, 0);
|
||||
|
||||
ft_write_ln(table, "00", "01", "02");
|
||||
ft_write_ln(table, "10", "11", "12");
|
||||
ft_write_ln(table, "20", "21", "22");
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void test_table_cell_deletion(void)
|
||||
{
|
||||
WHEN("Test invalid arguments") {
|
||||
ft_table_t *table = create_test_table();
|
||||
|
||||
// invalid rows
|
||||
assert_true(ft_delete_range(table, 1, 1, 0, 2) == FT_EINVAL);
|
||||
|
||||
// invalid colums
|
||||
assert_true(ft_delete_range(table, 1, 1, 2, 0) == FT_EINVAL);
|
||||
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
WHEN("Delete one cell") {
|
||||
ft_table_t *table = create_test_table();
|
||||
assert_true(FT_IS_SUCCESS(ft_delete_range(table, 1, 1, 1, 1)));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+----+----+----+\n"
|
||||
"| 00 | 01 | 02 |\n"
|
||||
"| 10 | 12 | |\n"
|
||||
"| 20 | 21 | 22 |\n"
|
||||
"+----+----+----+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
WHEN("Delete one last cell") {
|
||||
ft_table_t *table = create_test_table();
|
||||
ft_write_ln(table, "30");
|
||||
assert_true(FT_IS_SUCCESS(ft_delete_range(table, 3, 0, 3, 0)));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+----+----+----+\n"
|
||||
"| 00 | 01 | 02 |\n"
|
||||
"| 10 | 11 | 12 |\n"
|
||||
"| 20 | 21 | 22 |\n"
|
||||
"+----+----+----+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
WHEN("Delete row") {
|
||||
ft_table_t *table = create_test_table();
|
||||
assert_true(FT_IS_SUCCESS(ft_delete_range(table, 1, 0, 1, 999)));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+----+----+----+\n"
|
||||
"| 00 | 01 | 02 |\n"
|
||||
"| 20 | 21 | 22 |\n"
|
||||
"+----+----+----+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
WHEN("Delete last row") {
|
||||
ft_table_t *table = create_test_table();
|
||||
assert_true(FT_IS_SUCCESS(ft_delete_range(table, 2, 0, 2, 999)));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+----+----+----+\n"
|
||||
"| 00 | 01 | 02 |\n"
|
||||
"| 10 | 11 | 12 |\n"
|
||||
"+----+----+----+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
WHEN("Delete column") {
|
||||
ft_table_t *table = create_test_table();
|
||||
assert_true(FT_IS_SUCCESS(ft_delete_range(table, 0, 1, 999, 1)));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+----+----+\n"
|
||||
"| 00 | 02 |\n"
|
||||
"| 10 | 12 |\n"
|
||||
"| 20 | 22 |\n"
|
||||
"+----+----+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
WHEN("Delete last column") {
|
||||
ft_table_t *table = create_test_table();
|
||||
assert_true(FT_IS_SUCCESS(ft_delete_range(table, 0, 2, 999, 2)));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+----+----+\n"
|
||||
"| 00 | 01 |\n"
|
||||
"| 10 | 11 |\n"
|
||||
"| 20 | 21 |\n"
|
||||
"+----+----+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ void test_table_geometry(void);
|
||||
void test_table_basic(void);
|
||||
void test_table_copy(void);
|
||||
void test_table_changing_cell(void);
|
||||
void test_table_cell_deletion(void);
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
void test_wcs_table_boundaries(void);
|
||||
#endif
|
||||
@ -52,6 +53,7 @@ struct test_case bb_test_suite [] = {
|
||||
{"test_table_write", test_table_write},
|
||||
{"test_table_insert_strategy", test_table_insert_strategy},
|
||||
{"test_table_changing_cell", test_table_changing_cell},
|
||||
{"test_table_cell_deletion", test_table_cell_deletion},
|
||||
{"test_table_border_style", test_table_border_style},
|
||||
{"test_table_builtin_border_styles", test_table_builtin_border_styles},
|
||||
{"test_table_cell_properties", test_table_cell_properties},
|
||||
|
Loading…
Reference in New Issue
Block a user