From e644f0a5047185e96300c743fde44f79cd010c4e Mon Sep 17 00:00:00 2001 From: seleznevae Date: Sun, 19 Jan 2020 13:37:31 +0300 Subject: [PATCH 1/5] [A] add function `ft_delete_range` --- ChangeLog.md | 1 + lib/fort.c | 80 +++++++++++++++++++ lib/fort.h | 24 ++++++ src/fort.h | 24 ++++++ src/fort_impl.c | 52 +++++++++++++ src/row.c | 21 +++++ src/row.h | 4 + src/vector.h | 3 + tests/bb_tests/test_table_basic.c | 125 ++++++++++++++++++++++++++++++ tests/main_test.c | 2 + 10 files changed, 336 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 5351a78..fbbfd9e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -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). diff --git a/lib/fort.c b/lib/fort.c index 86d147f..d525227 100644 --- a/lib/fort.c +++ b/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) diff --git a/lib/fort.h b/lib/fort.h index 0e9aed5..06b8695 100644 --- a/lib/fort.h +++ b/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) /** diff --git a/src/fort.h b/src/fort.h index 0e9aed5..06b8695 100644 --- a/src/fort.h +++ b/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) /** diff --git a/src/fort_impl.c b/src/fort_impl.c index d52ecea..f493f6b 100644 --- a/src/fort_impl.c +++ b/src/fort_impl.c @@ -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; diff --git a/src/row.c b/src/row.c index 4f45329..da67664 100644 --- a/src/row.c +++ b/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) diff --git a/src/row.h b/src/row.h index ec45b19..ae68a15 100644 --- a/src/row.h +++ b/src/row.h @@ -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); diff --git a/src/vector.h b/src/vector.h index a83c96d..fbae084 100644 --- a/src/vector.h +++ b/src/vector.h @@ -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 */ diff --git a/tests/bb_tests/test_table_basic.c b/tests/bb_tests/test_table_basic.c index 3fecb53..e68c562 100644 --- a/tests/bb_tests/test_table_basic.c +++ b/tests/bb_tests/test_table_basic.c @@ -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); + } + +} diff --git a/tests/main_test.c b/tests/main_test.c index 0a990e0..fa93034 100644 --- a/tests/main_test.c +++ b/tests/main_test.c @@ -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}, From 4e922a7ecab468562beb9a058b16f6adfd1d325c Mon Sep 17 00:00:00 2001 From: seleznevae Date: Sun, 19 Jan 2020 13:50:00 +0300 Subject: [PATCH 2/5] [F] Fix compilation error --- lib/fort.c | 7 +++---- src/fort_impl.c | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/fort.c b/lib/fort.c index d525227..6e34a69 100644 --- a/lib/fort.c +++ b/lib/fort.c @@ -2841,7 +2841,7 @@ int ft_delete_range(ft_table_t *table, 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; + return status; ++i; } @@ -2856,12 +2856,11 @@ int ft_delete_range(ft_table_t *table, destroy_row(row); status = vector_erase(table->rows, i); if (FT_IS_ERROR(status)) - goto clear; + return status; } } -clear: - return status; + return FT_SUCCESS; } diff --git a/src/fort_impl.c b/src/fort_impl.c index f493f6b..8590c8f 100644 --- a/src/fort_impl.c +++ b/src/fort_impl.c @@ -261,7 +261,7 @@ int ft_delete_range(ft_table_t *table, 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; + return status; ++i; } @@ -276,12 +276,11 @@ int ft_delete_range(ft_table_t *table, destroy_row(row); status = vector_erase(table->rows, i); if (FT_IS_ERROR(status)) - goto clear; + return status; } } -clear: - return status; + return FT_SUCCESS; } From 1ed13718d52d60df035ad0b717dc3ff3d953cccb Mon Sep 17 00:00:00 2001 From: seleznevae Date: Sun, 19 Jan 2020 22:06:25 +0300 Subject: [PATCH 3/5] [C] Rename `ft_delete_range` to `ft_erase_range` --- ChangeLog.md | 2 +- lib/fort.c | 12 ++-- lib/fort.h | 8 +-- lib/fort.hpp | 43 ++++++++++++++ src/fort.h | 8 +-- src/fort.hpp | 43 ++++++++++++++ src/fort_impl.c | 8 +-- src/row.c | 2 +- src/row.h | 2 +- tests/bb_tests/test_table_basic.c | 30 +++++----- tests/bb_tests_cpp/test_table_basic.cpp | 74 +++++++++++++++++++++++++ tests/main_test.c | 4 +- tests/main_test_cpp.cpp | 2 + 13 files changed, 200 insertions(+), 38 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index fbbfd9e..7450683 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,7 +2,7 @@ ### API -- Add function `ft_delete_range` to delete range of the cells. +- Add function `ft_erase_range` to erase 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). diff --git a/lib/fort.c b/lib/fort.c index 6e34a69..c145d67 100644 --- a/lib/fort.c +++ b/lib/fort.c @@ -2152,7 +2152,7 @@ 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); +int ft_row_erase_range(f_row_t *row, size_t left, size_t right); FT_INTERNAL f_row_t *create_row_from_string(const char *str); @@ -2813,9 +2813,9 @@ 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) +int ft_erase_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; @@ -2839,7 +2839,7 @@ int ft_delete_range(ft_table_t *table, 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); + status = ft_row_erase_range(row, top_left_col, bottom_right_col); if (FT_IS_ERROR(status)) return status; ++i; @@ -5329,7 +5329,7 @@ f_row_t *split_row(f_row_t *row, size_t pos) } FT_INTERNAL -int ft_row_delete_range(f_row_t *row, size_t left, size_t right) +int ft_row_erase_range(f_row_t *row, size_t left, size_t right) { assert(row); size_t cols_n = vector_size(row->cells); diff --git a/lib/fort.h b/lib/fort.h index 06b8695..4d39e51 100644 --- a/lib/fort.h +++ b/lib/fort.h @@ -341,7 +341,7 @@ int ft_is_empty(const ft_table_t *table); size_t ft_row_count(const ft_table_t *table); /** - * Delete range of cells. + * Erase range of cells. * * Range of cells is determined by 2 points (top-left and bottom-right) (both * ends are included). @@ -360,9 +360,9 @@ size_t ft_row_count(const ft_table_t *table); * - 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); +int ft_erase_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) diff --git a/lib/fort.hpp b/lib/fort.hpp index 2591814..4cc02bf 100644 --- a/lib/fort.hpp +++ b/lib/fort.hpp @@ -990,6 +990,15 @@ public: { return table_cell(ps_row_idx_, coll_idx, *ps_table_); } + + void erase() + { + if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, + property_owner_t::ps_row_idx_, 0, + property_owner_t::ps_row_idx_, (UINT_MAX - 2)))) { + throw std::runtime_error("Failed to erase row"); + } + } }; /** @@ -997,11 +1006,45 @@ public: */ class table_column: public property_owner_t { + using property_owner_t::ps_coll_idx_; + using property_owner_t::ps_table_; public: table_column(std::size_t col_idx, table &tbl) : property_owner_t(FT_ANY_ROW, col_idx, &tbl) {} + + void erase() + { + if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, + 0, ps_coll_idx_, + (UINT_MAX - 2), ps_coll_idx_))) { + throw std::runtime_error("Failed to erase column"); + } + } }; + /** + * Table column. + */ + class cell_range: public property_owner_t + { + using property_owner_t::ps_coll_idx_; + using property_owner_t::ps_row_idx_; + using property_owner_t::ps_table_; + public: + table_column(std::size_t col_idx, table &tbl) + : property_owner_t(FT_ANY_ROW, col_idx, &tbl) {} + + void erase() + { + if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, + 0, ps_coll_idx_, + (UINT_MAX - 2), ps_coll_idx_))) { + throw std::runtime_error("Failed to erase column"); + } + } + }; + + class default_properties: public property_owner_t { public: diff --git a/src/fort.h b/src/fort.h index 06b8695..4d39e51 100644 --- a/src/fort.h +++ b/src/fort.h @@ -341,7 +341,7 @@ int ft_is_empty(const ft_table_t *table); size_t ft_row_count(const ft_table_t *table); /** - * Delete range of cells. + * Erase range of cells. * * Range of cells is determined by 2 points (top-left and bottom-right) (both * ends are included). @@ -360,9 +360,9 @@ size_t ft_row_count(const ft_table_t *table); * - 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); +int ft_erase_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) diff --git a/src/fort.hpp b/src/fort.hpp index 2591814..4cc02bf 100644 --- a/src/fort.hpp +++ b/src/fort.hpp @@ -990,6 +990,15 @@ public: { return table_cell(ps_row_idx_, coll_idx, *ps_table_); } + + void erase() + { + if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, + property_owner_t::ps_row_idx_, 0, + property_owner_t::ps_row_idx_, (UINT_MAX - 2)))) { + throw std::runtime_error("Failed to erase row"); + } + } }; /** @@ -997,11 +1006,45 @@ public: */ class table_column: public property_owner_t { + using property_owner_t::ps_coll_idx_; + using property_owner_t::ps_table_; public: table_column(std::size_t col_idx, table &tbl) : property_owner_t(FT_ANY_ROW, col_idx, &tbl) {} + + void erase() + { + if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, + 0, ps_coll_idx_, + (UINT_MAX - 2), ps_coll_idx_))) { + throw std::runtime_error("Failed to erase column"); + } + } }; + /** + * Table column. + */ + class cell_range: public property_owner_t + { + using property_owner_t::ps_coll_idx_; + using property_owner_t::ps_row_idx_; + using property_owner_t::ps_table_; + public: + table_column(std::size_t col_idx, table &tbl) + : property_owner_t(FT_ANY_ROW, col_idx, &tbl) {} + + void erase() + { + if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, + 0, ps_coll_idx_, + (UINT_MAX - 2), ps_coll_idx_))) { + throw std::runtime_error("Failed to erase column"); + } + } + }; + + class default_properties: public property_owner_t { public: diff --git a/src/fort_impl.c b/src/fort_impl.c index 8590c8f..d06447c 100644 --- a/src/fort_impl.c +++ b/src/fort_impl.c @@ -233,9 +233,9 @@ 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) +int ft_erase_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; @@ -259,7 +259,7 @@ int ft_delete_range(ft_table_t *table, 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); + status = ft_row_erase_range(row, top_left_col, bottom_right_col); if (FT_IS_ERROR(status)) return status; ++i; diff --git a/src/row.c b/src/row.c index da67664..64ca37b 100644 --- a/src/row.c +++ b/src/row.c @@ -99,7 +99,7 @@ f_row_t *split_row(f_row_t *row, size_t pos) } FT_INTERNAL -int ft_row_delete_range(f_row_t *row, size_t left, size_t right) +int ft_row_erase_range(f_row_t *row, size_t left, size_t right) { assert(row); size_t cols_n = vector_size(row->cells); diff --git a/src/row.h b/src/row.h index ae68a15..2402fff 100644 --- a/src/row.h +++ b/src/row.h @@ -23,7 +23,7 @@ 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); +int ft_row_erase_range(f_row_t *row, size_t left, size_t right); FT_INTERNAL f_row_t *create_row_from_string(const char *str); diff --git a/tests/bb_tests/test_table_basic.c b/tests/bb_tests/test_table_basic.c index e68c562..3424ccf 100644 --- a/tests/bb_tests/test_table_basic.c +++ b/tests/bb_tests/test_table_basic.c @@ -1823,23 +1823,23 @@ static struct ft_table *create_test_table() return table; } -void test_table_cell_deletion(void) +void test_table_erase(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); + assert_true(ft_erase_range(table, 1, 1, 0, 2) == FT_EINVAL); // invalid colums - assert_true(ft_delete_range(table, 1, 1, 2, 0) == FT_EINVAL); + assert_true(ft_erase_range(table, 1, 1, 2, 0) == FT_EINVAL); ft_destroy_table(table); } - WHEN("Delete one cell") { + WHEN("Erase one cell") { ft_table_t *table = create_test_table(); - assert_true(FT_IS_SUCCESS(ft_delete_range(table, 1, 1, 1, 1))); + assert_true(FT_IS_SUCCESS(ft_erase_range(table, 1, 1, 1, 1))); const char *table_str = ft_to_string(table); assert_true(table_str != NULL); @@ -1853,10 +1853,10 @@ void test_table_cell_deletion(void) ft_destroy_table(table); } - WHEN("Delete one last cell") { + WHEN("Erase 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))); + assert_true(FT_IS_SUCCESS(ft_erase_range(table, 3, 0, 3, 0))); const char *table_str = ft_to_string(table); assert_true(table_str != NULL); @@ -1870,9 +1870,9 @@ void test_table_cell_deletion(void) ft_destroy_table(table); } - WHEN("Delete row") { + WHEN("Erase row") { ft_table_t *table = create_test_table(); - assert_true(FT_IS_SUCCESS(ft_delete_range(table, 1, 0, 1, 999))); + assert_true(FT_IS_SUCCESS(ft_erase_range(table, 1, 0, 1, 999))); const char *table_str = ft_to_string(table); assert_true(table_str != NULL); @@ -1885,9 +1885,9 @@ void test_table_cell_deletion(void) ft_destroy_table(table); } - WHEN("Delete last row") { + WHEN("Erase last row") { ft_table_t *table = create_test_table(); - assert_true(FT_IS_SUCCESS(ft_delete_range(table, 2, 0, 2, 999))); + assert_true(FT_IS_SUCCESS(ft_erase_range(table, 2, 0, 2, 999))); const char *table_str = ft_to_string(table); assert_true(table_str != NULL); @@ -1900,9 +1900,9 @@ void test_table_cell_deletion(void) ft_destroy_table(table); } - WHEN("Delete column") { + WHEN("Erase column") { ft_table_t *table = create_test_table(); - assert_true(FT_IS_SUCCESS(ft_delete_range(table, 0, 1, 999, 1))); + assert_true(FT_IS_SUCCESS(ft_erase_range(table, 0, 1, 999, 1))); const char *table_str = ft_to_string(table); assert_true(table_str != NULL); @@ -1916,9 +1916,9 @@ void test_table_cell_deletion(void) ft_destroy_table(table); } - WHEN("Delete last column") { + WHEN("Erase last column") { ft_table_t *table = create_test_table(); - assert_true(FT_IS_SUCCESS(ft_delete_range(table, 0, 2, 999, 2))); + assert_true(FT_IS_SUCCESS(ft_erase_range(table, 0, 2, 999, 2))); const char *table_str = ft_to_string(table); assert_true(table_str != NULL); diff --git a/tests/bb_tests_cpp/test_table_basic.cpp b/tests/bb_tests_cpp/test_table_basic.cpp index baf180e..f3091df 100644 --- a/tests/bb_tests_cpp/test_table_basic.cpp +++ b/tests/bb_tests_cpp/test_table_basic.cpp @@ -388,3 +388,77 @@ void test_cpp_table_changing_cell(void) assert_string_equal(table_str, table_str_etalon); } } + +static fort::char_table create_test_table() +{ + fort::char_table table; + table.write_ln("00", "01", "02"); + table.write_ln("10", "11", "12"); + table.write_ln("20", "21", "22"); + + return table; +} + +void test_cpp_table_erase(void) +{ + WHEN("Erase row") { + fort::char_table table = create_test_table(); + table[1].erase(); + + std::string table_str = table.to_string(); + std::string table_str_etalon = + "+----+----+----+\n" + "| 00 | 01 | 02 |\n" + "| 20 | 21 | 22 |\n" + "+----+----+----+\n"; + assert_string_equal(table_str, table_str_etalon); + } + +// WHEN("Erase last row") { +// ft_table_t *table = create_test_table(); +// assert_true(FT_IS_SUCCESS(ft_erase_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("Erase column") { +// ft_table_t *table = create_test_table(); +// assert_true(FT_IS_SUCCESS(ft_erase_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("Erase last column") { +// ft_table_t *table = create_test_table(); +// assert_true(FT_IS_SUCCESS(ft_erase_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); +// } + +} diff --git a/tests/main_test.c b/tests/main_test.c index fa93034..6ea2a1a 100644 --- a/tests/main_test.c +++ b/tests/main_test.c @@ -12,7 +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); +void test_table_erase(void); #ifdef FT_HAVE_WCHAR void test_wcs_table_boundaries(void); #endif @@ -53,7 +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_erase", test_table_erase}, {"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}, diff --git a/tests/main_test_cpp.cpp b/tests/main_test_cpp.cpp index 7c92e83..d9c8d0e 100644 --- a/tests/main_test_cpp.cpp +++ b/tests/main_test_cpp.cpp @@ -6,6 +6,7 @@ void test_cpp_table_basic(void); void test_cpp_table_write(void); void test_cpp_table_insert(void); +void test_cpp_table_erase(void); void test_cpp_table_changing_cell(void); void test_cpp_table_tbl_properties(void); void test_cpp_table_cell_properties(void); @@ -17,6 +18,7 @@ struct test_case bb_test_suite [] = { {"test_cpp_table_basic", test_cpp_table_basic}, {"test_cpp_table_write", test_cpp_table_write}, {"test_cpp_table_insert", test_cpp_table_insert}, + {"test_cpp_table_erase", test_cpp_table_erase}, {"test_cpp_table_changing_cell", test_cpp_table_changing_cell}, {"test_cpp_table_tbl_properties", test_cpp_table_tbl_properties}, {"test_cpp_table_cell_properties", test_cpp_table_cell_properties}, From 4871105b0fec67c184764952e6c23e6315fa6dee Mon Sep 17 00:00:00 2001 From: seleznevae Date: Sun, 19 Jan 2020 22:24:17 +0300 Subject: [PATCH 4/5] [F] Fix compilation error --- lib/fort.hpp | 40 ++++++++-- src/fort.hpp | 40 ++++++++-- tests/bb_tests/test_table_basic.c | 2 +- tests/bb_tests_cpp/test_table_basic.cpp | 102 ++++++++++++++---------- 4 files changed, 131 insertions(+), 53 deletions(-) diff --git a/lib/fort.hpp b/lib/fort.hpp index 4cc02bf..cf2dc7c 100644 --- a/lib/fort.hpp +++ b/lib/fort.hpp @@ -1023,7 +1023,11 @@ public: }; /** - * Table column. + * Range of cells. + * + * @note: at the moment function of propery owener will work only on the + * top left cell. + * @todo: Implement their work on the whole range. */ class cell_range: public property_owner_t { @@ -1031,17 +1035,26 @@ public: using property_owner_t::ps_row_idx_; using property_owner_t::ps_table_; public: - table_column(std::size_t col_idx, table &tbl) - : property_owner_t(FT_ANY_ROW, col_idx, &tbl) {} + cell_range(size_t top_left_row, size_t top_left_col, + size_t bottom_right_row, size_t bottom_right_col, + table &tbl) + : property_owner_t(top_left_row, top_left_col, &tbl), + bottom_right_row_(bottom_right_row), + bottom_right_col_(bottom_right_col) + {} void erase() { if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, - 0, ps_coll_idx_, - (UINT_MAX - 2), ps_coll_idx_))) { + ps_row_idx_, ps_coll_idx_, + bottom_right_row_, bottom_right_col_))) { throw std::runtime_error("Failed to erase column"); } } + + private: + std::size_t bottom_right_row_; + std::size_t bottom_right_col_; }; @@ -1164,6 +1177,23 @@ public: return table_column(col_idx, *this); } + /** + * Get range of cells. + * + * @param col_idx + * Column index. + * @return + * table_column object. + */ + class cell_range + range(std::size_t top_left_row, std::size_t top_left_col, + std::size_t bottom_right_row, std::size_t bottom_right_col) + { + return cell_range(top_left_row, top_left_col, + bottom_right_row, bottom_right_col, + *this); + } + static class default_properties default_props() { diff --git a/src/fort.hpp b/src/fort.hpp index 4cc02bf..cf2dc7c 100644 --- a/src/fort.hpp +++ b/src/fort.hpp @@ -1023,7 +1023,11 @@ public: }; /** - * Table column. + * Range of cells. + * + * @note: at the moment function of propery owener will work only on the + * top left cell. + * @todo: Implement their work on the whole range. */ class cell_range: public property_owner_t { @@ -1031,17 +1035,26 @@ public: using property_owner_t::ps_row_idx_; using property_owner_t::ps_table_; public: - table_column(std::size_t col_idx, table &tbl) - : property_owner_t(FT_ANY_ROW, col_idx, &tbl) {} + cell_range(size_t top_left_row, size_t top_left_col, + size_t bottom_right_row, size_t bottom_right_col, + table &tbl) + : property_owner_t(top_left_row, top_left_col, &tbl), + bottom_right_row_(bottom_right_row), + bottom_right_col_(bottom_right_col) + {} void erase() { if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, - 0, ps_coll_idx_, - (UINT_MAX - 2), ps_coll_idx_))) { + ps_row_idx_, ps_coll_idx_, + bottom_right_row_, bottom_right_col_))) { throw std::runtime_error("Failed to erase column"); } } + + private: + std::size_t bottom_right_row_; + std::size_t bottom_right_col_; }; @@ -1164,6 +1177,23 @@ public: return table_column(col_idx, *this); } + /** + * Get range of cells. + * + * @param col_idx + * Column index. + * @return + * table_column object. + */ + class cell_range + range(std::size_t top_left_row, std::size_t top_left_col, + std::size_t bottom_right_row, std::size_t bottom_right_col) + { + return cell_range(top_left_row, top_left_col, + bottom_right_row, bottom_right_col, + *this); + } + static class default_properties default_props() { diff --git a/tests/bb_tests/test_table_basic.c b/tests/bb_tests/test_table_basic.c index 3424ccf..c8424ce 100644 --- a/tests/bb_tests/test_table_basic.c +++ b/tests/bb_tests/test_table_basic.c @@ -1825,7 +1825,7 @@ static struct ft_table *create_test_table() void test_table_erase(void) { - WHEN("Test invalid arguments") { + WHEN("Invalid arguments") { ft_table_t *table = create_test_table(); // invalid rows diff --git a/tests/bb_tests_cpp/test_table_basic.cpp b/tests/bb_tests_cpp/test_table_basic.cpp index f3091df..6f839a5 100644 --- a/tests/bb_tests_cpp/test_table_basic.cpp +++ b/tests/bb_tests_cpp/test_table_basic.cpp @@ -401,6 +401,31 @@ static fort::char_table create_test_table() void test_cpp_table_erase(void) { + WHEN("Invalid arguments") { + std::string err_msg; + try { + fort::char_table table = create_test_table(); + table.range(1, 1, 0, 0).erase(); + } catch (std::exception &e) { + err_msg = e.what(); + } + assert_string_equal(err_msg, std::string("Failed to erase column")); + } + + WHEN("Erase one cell") { + fort::char_table table = create_test_table(); + table.range(1, 1, 1, 1).erase(); + + std::string table_str = table.to_string(); + std::string table_str_etalon = + "+----+----+----+\n" + "| 00 | 01 | 02 |\n" + "| 10 | 12 | |\n" + "| 20 | 21 | 22 |\n" + "+----+----+----+\n"; + assert_string_equal(table_str, table_str_etalon); + } + WHEN("Erase row") { fort::char_table table = create_test_table(); table[1].erase(); @@ -414,51 +439,44 @@ void test_cpp_table_erase(void) assert_string_equal(table_str, table_str_etalon); } -// WHEN("Erase last row") { -// ft_table_t *table = create_test_table(); -// assert_true(FT_IS_SUCCESS(ft_erase_range(table, 2, 0, 2, 999))); + WHEN("Erase last row") { + fort::char_table table = create_test_table(); + table[2].erase(); -// 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); -// } + std::string table_str = table.to_string(); + std::string table_str_etalon = + "+----+----+----+\n" + "| 00 | 01 | 02 |\n" + "| 10 | 11 | 12 |\n" + "+----+----+----+\n"; + assert_string_equal(table_str, table_str_etalon); + } -// WHEN("Erase column") { -// ft_table_t *table = create_test_table(); -// assert_true(FT_IS_SUCCESS(ft_erase_range(table, 0, 1, 999, 1))); + WHEN("Erase column") { + fort::char_table table = create_test_table(); + table.column(1).erase(); -// 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); -// } + std::string table_str = table.to_string(); + std::string table_str_etalon = + "+----+----+\n" + "| 00 | 02 |\n" + "| 10 | 12 |\n" + "| 20 | 22 |\n" + "+----+----+\n"; + assert_string_equal(table_str, table_str_etalon); + } -// WHEN("Erase last column") { -// ft_table_t *table = create_test_table(); -// assert_true(FT_IS_SUCCESS(ft_erase_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); -// } + WHEN("Erase last column") { + fort::char_table table = create_test_table(); + table.column(2).erase(); + std::string table_str = table.to_string(); + std::string table_str_etalon = + "+----+----+\n" + "| 00 | 01 |\n" + "| 10 | 11 |\n" + "| 20 | 21 |\n" + "+----+----+\n"; + assert_string_equal(table_str, table_str_etalon); + } } From 8080378736afeec840dc90581b1190377e8e980f Mon Sep 17 00:00:00 2001 From: seleznevae Date: Tue, 21 Jan 2020 19:03:57 +0300 Subject: [PATCH 5/5] [U] Updated docs --- docs/index.md | 3 +++ lib/fort.h | 2 ++ lib/fort.hpp | 4 ++-- src/fort.h | 2 ++ src/fort.hpp | 4 ++-- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/index.md b/docs/index.md index 43fc3d9..b78f258 100644 --- a/docs/index.md +++ b/docs/index.md @@ -27,6 +27,9 @@ These pages contain the API documentation of **libfort** - simple library to cre - @link ft_table_write_ln ft_table_write_ln @endlink -- fill cells with the strings from the 2D array and move to the next line - @link ft_add_separator ft_add_separator @endlink -- add horizontal separator + - Remove content + - @link ft_erase_range ft_erase_range @endlink -- erase range of cells + - Modify appearance of the table - @link ft_set_default_border_style ft_set_default_border_style @endlink -- set default border style for all new created tables - @link ft_set_border_style ft_set_border_style @endlink -- modify border style of the table diff --git a/lib/fort.h b/lib/fort.h index 4d39e51..94b9154 100644 --- a/lib/fort.h +++ b/lib/fort.h @@ -738,6 +738,8 @@ int ft_set_border_style(ft_table_t *table, const struct ft_border_style *style); #define FT_CUR_ROW (UINT_MAX - 1) /**< Current row */ /** @} */ +#define FT_MAX_ROW_INDEX (UINT_MAX - 2) +#define FT_MAX_COL_INDEX (UINT_MAX - 2) /** diff --git a/lib/fort.hpp b/lib/fort.hpp index cf2dc7c..5ebb51b 100644 --- a/lib/fort.hpp +++ b/lib/fort.hpp @@ -995,7 +995,7 @@ public: { if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, property_owner_t::ps_row_idx_, 0, - property_owner_t::ps_row_idx_, (UINT_MAX - 2)))) { + property_owner_t::ps_row_idx_, FT_MAX_COL_INDEX))) { throw std::runtime_error("Failed to erase row"); } } @@ -1016,7 +1016,7 @@ public: { if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, 0, ps_coll_idx_, - (UINT_MAX - 2), ps_coll_idx_))) { + FT_MAX_ROW_INDEX, ps_coll_idx_))) { throw std::runtime_error("Failed to erase column"); } } diff --git a/src/fort.h b/src/fort.h index 4d39e51..94b9154 100644 --- a/src/fort.h +++ b/src/fort.h @@ -738,6 +738,8 @@ int ft_set_border_style(ft_table_t *table, const struct ft_border_style *style); #define FT_CUR_ROW (UINT_MAX - 1) /**< Current row */ /** @} */ +#define FT_MAX_ROW_INDEX (UINT_MAX - 2) +#define FT_MAX_COL_INDEX (UINT_MAX - 2) /** diff --git a/src/fort.hpp b/src/fort.hpp index cf2dc7c..5ebb51b 100644 --- a/src/fort.hpp +++ b/src/fort.hpp @@ -995,7 +995,7 @@ public: { if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, property_owner_t::ps_row_idx_, 0, - property_owner_t::ps_row_idx_, (UINT_MAX - 2)))) { + property_owner_t::ps_row_idx_, FT_MAX_COL_INDEX))) { throw std::runtime_error("Failed to erase row"); } } @@ -1016,7 +1016,7 @@ public: { if (FT_IS_ERROR(ft_erase_range(ps_table_->table_, 0, ps_coll_idx_, - (UINT_MAX - 2), ps_coll_idx_))) { + FT_MAX_ROW_INDEX, ps_coll_idx_))) { throw std::runtime_error("Failed to erase column"); } }