Merge pull request #32 from seleznevae/issue-31
[A] add function `ft_erase_range`
This commit is contained in:
		@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
### API
 | 
			
		||||
 | 
			
		||||
- 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).
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										79
									
								
								lib/fort.c
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								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_erase_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,57 @@ size_t ft_row_count(const ft_table_t *table)
 | 
			
		||||
    return vector_size(table->rows);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    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_erase_range(row, top_left_col, bottom_right_col);
 | 
			
		||||
        if (FT_IS_ERROR(status))
 | 
			
		||||
            return status;
 | 
			
		||||
        ++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))
 | 
			
		||||
                return status;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return FT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 +5328,27 @@ f_row_t *split_row(f_row_t *row, size_t pos)
 | 
			
		||||
    return tail;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FT_INTERNAL
 | 
			
		||||
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);
 | 
			
		||||
    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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								lib/fort.h
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								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);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Erase 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_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)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -714,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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								lib/fort.hpp
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								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_, FT_MAX_COL_INDEX))) {
 | 
			
		||||
                throw std::runtime_error("Failed to erase row");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -997,11 +1006,58 @@ 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_,
 | 
			
		||||
                                           FT_MAX_ROW_INDEX, ps_coll_idx_))) {
 | 
			
		||||
                throw std::runtime_error("Failed to erase 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
 | 
			
		||||
    {
 | 
			
		||||
        using property_owner_t::ps_coll_idx_;
 | 
			
		||||
        using property_owner_t::ps_row_idx_;
 | 
			
		||||
        using property_owner_t::ps_table_;
 | 
			
		||||
    public:
 | 
			
		||||
        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_,
 | 
			
		||||
                                           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_;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class default_properties: public property_owner_t
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
@@ -1121,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()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								src/fort.h
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								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);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Erase 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_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)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -714,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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								src/fort.hpp
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								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_, FT_MAX_COL_INDEX))) {
 | 
			
		||||
                throw std::runtime_error("Failed to erase row");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -997,11 +1006,58 @@ 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_,
 | 
			
		||||
                                           FT_MAX_ROW_INDEX, ps_coll_idx_))) {
 | 
			
		||||
                throw std::runtime_error("Failed to erase 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
 | 
			
		||||
    {
 | 
			
		||||
        using property_owner_t::ps_coll_idx_;
 | 
			
		||||
        using property_owner_t::ps_row_idx_;
 | 
			
		||||
        using property_owner_t::ps_table_;
 | 
			
		||||
    public:
 | 
			
		||||
        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_,
 | 
			
		||||
                                           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_;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class default_properties: public property_owner_t
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
@@ -1121,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()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -233,6 +233,57 @@ size_t ft_row_count(const ft_table_t *table)
 | 
			
		||||
    return vector_size(table->rows);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    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_erase_range(row, top_left_col, bottom_right_col);
 | 
			
		||||
        if (FT_IS_ERROR(status))
 | 
			
		||||
            return status;
 | 
			
		||||
        ++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))
 | 
			
		||||
                return status;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return FT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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_erase_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_erase_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_erase(void)
 | 
			
		||||
{
 | 
			
		||||
    WHEN("Invalid arguments") {
 | 
			
		||||
        ft_table_t *table = create_test_table();
 | 
			
		||||
 | 
			
		||||
        // invalid rows
 | 
			
		||||
        assert_true(ft_erase_range(table, 1, 1, 0, 2) == FT_EINVAL);
 | 
			
		||||
 | 
			
		||||
        // invalid colums
 | 
			
		||||
        assert_true(ft_erase_range(table, 1, 1, 2, 0) == FT_EINVAL);
 | 
			
		||||
 | 
			
		||||
        ft_destroy_table(table);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    WHEN("Erase one cell") {
 | 
			
		||||
        ft_table_t *table = create_test_table();
 | 
			
		||||
        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);
 | 
			
		||||
        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("Erase one last cell") {
 | 
			
		||||
        ft_table_t *table = create_test_table();
 | 
			
		||||
        ft_write_ln(table, "30");
 | 
			
		||||
        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);
 | 
			
		||||
        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("Erase row") {
 | 
			
		||||
        ft_table_t *table = create_test_table();
 | 
			
		||||
        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);
 | 
			
		||||
        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("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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -388,3 +388,95 @@ 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("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();
 | 
			
		||||
 | 
			
		||||
        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") {
 | 
			
		||||
        fort::char_table table = create_test_table();
 | 
			
		||||
        table[2].erase();
 | 
			
		||||
 | 
			
		||||
        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") {
 | 
			
		||||
        fort::char_table table = create_test_table();
 | 
			
		||||
        table.column(1).erase();
 | 
			
		||||
 | 
			
		||||
        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") {
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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_erase(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_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},
 | 
			
		||||
 
 | 
			
		||||
@@ -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},
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user