diff --git a/include/fort.h b/include/fort.h index f0093aa..e34fd26 100644 --- a/include/fort.h +++ b/include/fort.h @@ -244,25 +244,41 @@ FT_EXTERN void ft_destroy_table(FTABLE *table); FT_EXTERN void ft_ln(FTABLE *table); /** - * Get row number of the current cell + * Get row number of the current cell. * * @param table * Pointer to formatted table. * @return - * Row number of the current cell + * Row number of the current cell. */ FT_EXTERN size_t ft_cur_row(FTABLE *table); /** - * Get column number of the current cell + * Get column number of the current cell. * * @param table * Pointer to formatted table. * @return - * Column number of the current cell + * Column number of the current cell. */ FT_EXTERN size_t ft_cur_col(FTABLE *table); +/** + * Set current cell position. + * + * Current cell - cell that will be edited with all modifiing functions + * (ft_printf, ft_write ...). + * + * @param table + * Pointer to formatted table. + * @param row + * New row number for the current cell. + * @param col + * New row number for the current cell. + */ +FT_EXTERN void ft_set_cur_cell(FTABLE *table, size_t row, size_t col); + + #if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER) @@ -287,7 +303,8 @@ FT_EXTERN size_t ft_cur_col(FTABLE *table); * more arguments than required by format, the extraneous arguments are * evaluated and ignored. * @return - * todo ????? + * - Number of printed cells + * - (<0): In case of error */ FT_EXTERN int ft_printf(FTABLE *table, const char *fmt, ...) FT_PRINTF_ATTRIBUTE_FORMAT(2, 3); @@ -312,7 +329,8 @@ FT_EXTERN int ft_printf(FTABLE *table, const char *fmt, ...) FT_PRINTF_ATTRIBUTE * more arguments than required by format, the extraneous arguments are * evaluated and ignored. * @return - * todo ????? + * - Number of printed cells. + * - (<0): In case of error. */ FT_EXTERN int ft_printf_ln(FTABLE *table, const char *fmt, ...) FT_PRINTF_ATTRIBUTE_FORMAT(2, 3); @@ -380,8 +398,8 @@ FT_EXTERN int ft_add_separator(FTABLE *table); * string with strdup or similar functions. * * Returned pointer may be later invalidated by: - * - Calling ft_destroy_table - * - Other invocations of ft_to_string + * - Calling ft_destroy_table; + * - Other invocations of ft_to_string. * * @param table * Formatted table. @@ -404,7 +422,7 @@ FT_EXTERN const char *ft_to_string(const FTABLE *table); /** - * Structure describing border appearance + * Structure describing border appearance. */ struct ft_border_chars { char top_border_ch; @@ -416,7 +434,7 @@ struct ft_border_chars { }; /** - * Structure describing border style + * Structure describing border style. */ struct ft_border_style { struct ft_border_chars border_chs; @@ -425,7 +443,7 @@ struct ft_border_style { }; /** - * Built-in table border styles + * Built-in table border styles. */ extern struct ft_border_style *FT_BASIC_STYLE; extern struct ft_border_style *FT_SIMPLE_STYLE; @@ -437,7 +455,7 @@ extern struct ft_border_style *FT_EMPTY_STYLE; * Set default border style for all new formatted tables. * * @param style - * Pointer to border style + * Pointer to border style. * @return * - 0: Success; default border style was changed. * - (-1): !!!!!!!! todo @@ -448,9 +466,9 @@ FT_EXTERN int ft_set_default_border_style(struct ft_border_style *style); * Set border style for the table. * * @param table - * A pointer to the FTABLE structure + * A pointer to the FTABLE structure. * @param style - * Pointer to border style + * Pointer to border style. * @return * - 0: Success; table border style was changed. * - (-1): !!!!!!!! todo @@ -458,7 +476,7 @@ FT_EXTERN int ft_set_default_border_style(struct ft_border_style *style); FT_EXTERN int ft_set_border_style(FTABLE *table, struct ft_border_style *style); /** - * Special macros to define cell position (row and column) + * Special macros to define cell position (row and column). */ #define FT_ANY_COLUMN (UINT_MAX) #define FT_CUR_COLUMN (UINT_MAX - 1) @@ -466,7 +484,7 @@ FT_EXTERN int ft_set_border_style(FTABLE *table, struct ft_border_style *style); #define FT_CUR_ROW (UINT_MAX - 1) /** - * Cell options identifiers + * Cell options identifiers. */ #define FT_COPT_MIN_WIDTH (0x01U << 0) /**< Minimum width */ #define FT_COPT_TEXT_ALIGN (0x01U << 1) /**< Text alignmemnt */ @@ -478,7 +496,7 @@ FT_EXTERN int ft_set_border_style(FTABLE *table, struct ft_border_style *style); #define FT_COPT_ROW_TYPE (0x01U << 7) /**< Row type */ /** - * Alignment of cell content + * Alignment of cell content. */ enum ft_text_alignment { FT_ALIGNED_LEFT, @@ -487,7 +505,7 @@ enum ft_text_alignment { }; /** - * Type of table row + * Type of table row. */ enum ft_row_type { FT_ROW_COMMON, @@ -498,9 +516,9 @@ enum ft_row_type { * Set default cell option for all new formatted tables. * * @param option - * Cell option identifier + * Cell option identifier. * @param value - * Cell option value + * Cell option value. * @return * - 0: Success; default cell option was changed. * - (-1): !!!!!!!! todo @@ -511,15 +529,15 @@ FT_EXTERN int ft_set_default_cell_option(uint32_t option, int value); * Set option for the specified cell of the table. * * @param table - * A pointer to the FTABLE structure + * A pointer to the FTABLE structure. * @param row - * Cell row + * Cell row. * @param col - * Cell column + * Cell column. * @param option - * Cell option identifier + * Cell option identifier. * @param value - * Cell option value + * Cell option value. * @return * - 0: Success; cell option was changed. * - (-1): !!!!!!!! todo @@ -527,7 +545,7 @@ FT_EXTERN int ft_set_default_cell_option(uint32_t option, int value); FT_EXTERN int ft_set_cell_option(FTABLE *table, size_t row, size_t col, uint32_t option, int value); /** - * Table options identifiers + * Table options identifiers. */ #define FT_TOPT_LEFT_MARGIN (0x01U << 0) #define FT_TOPT_TOP_MARGIN (0x01U << 1) @@ -538,9 +556,9 @@ FT_EXTERN int ft_set_cell_option(FTABLE *table, size_t row, size_t col, uint32_t * Set default table option. * * @param option - * Table option identifier + * Table option identifier. * @param value - * Table option value + * Table option value. * @return * - 0: Success; default table option was changed. * - (-1): !!!!!!!! todo @@ -551,11 +569,11 @@ FT_EXTERN int ft_set_default_tbl_option(uint32_t option, int value); * Set table option. * * @param table - * A pointer to the FTABLE structure + * A pointer to the FTABLE structure. * @param option - * Table option identifier + * Table option identifier. * @param value - * Table option value + * Table option value. * @return * - 0: Success; default table option was changed. * - (-1): !!!!!!!! todo diff --git a/src/fort.c b/src/fort.c index 5273a49..c7ab551 100644 --- a/src/fort.c +++ b/src/fort.c @@ -117,6 +117,14 @@ size_t ft_cur_col(FTABLE *table) return table->cur_col; } +void ft_set_cur_cell(FTABLE *table, size_t row, size_t col) +{ + assert(table); + table->cur_row = row; + table->cur_col = col; +} + + static int ft_row_printf_impl(FTABLE *table, size_t row, const char *fmt, va_list *va) { size_t i = 0; @@ -146,15 +154,14 @@ static int ft_row_printf_impl(FTABLE *table, size_t row, const char *fmt, va_lis } } } - /* todo: clearing pushed items in case of error */ - /* todo: this function always create new row, this is not correct, it should be more complicated */ + /* todo: clearing pushed items in case of error ?? */ - cur_row_p = (fort_row_t **)vector_at(table->rows, row); - - destroy_row(*cur_row_p); - *cur_row_p = new_row; new_cols = columns_in_row(new_row); + cur_row_p = (fort_row_t **)vector_at(table->rows, row); + swap_row(*cur_row_p, new_row, table->cur_col); + table->cur_col += new_cols; + destroy_row(new_row); return new_cols; clear: diff --git a/src/row.c b/src/row.c index 422b6ef..9a2be71 100644 --- a/src/row.c +++ b/src/row.c @@ -106,6 +106,22 @@ fort_cell_t *get_cell_and_create_if_not_exists(fort_row_t *row, size_t col) return get_cell_implementation(row, col, Create); } +fort_status_t swap_row(fort_row_t *cur_row, fort_row_t *ins_row, size_t pos) +{ + assert(cur_row); + assert(ins_row); + size_t cur_sz = vector_size(cur_row->cells); + if (cur_sz == 0 && pos == 0) { + fort_row_t tmp; + memcpy(&tmp, cur_row, sizeof(fort_row_t)); + memcpy(cur_row, ins_row, sizeof(fort_row_t)); + memcpy(ins_row, &tmp, sizeof(fort_row_t)); + return FT_SUCCESS; + } + + return vector_swap(cur_row->cells, ins_row->cells, pos); +} + diff --git a/src/row.h b/src/row.h index 68f3701..dcfdbf7 100644 --- a/src/row.h +++ b/src/row.h @@ -30,6 +30,7 @@ fort_cell_t *get_cell_implementation(fort_row_t *row, size_t col, enum PolicyOnN fort_cell_t *get_cell(fort_row_t *row, size_t col); const fort_cell_t *get_cell_c(const fort_row_t *row, size_t col); fort_cell_t *get_cell_and_create_if_not_exists(fort_row_t *row, size_t col); +fort_status_t swap_row(fort_row_t *cur_row, fort_row_t *ins_row, size_t pos); diff --git a/src/vector.c b/src/vector.c index 1353fca..2604c27 100644 --- a/src/vector.c +++ b/src/vector.c @@ -165,4 +165,50 @@ void *vector_at(vector_t *vector, size_t index) return (char *)vector->m_data + index * vector->m_item_size; } +fort_status_t vector_swap(vector_t *cur_vec, vector_t *mv_vec, size_t pos) +{ + assert(cur_vec); + assert(mv_vec); + assert(cur_vec->m_item_size == mv_vec->m_item_size); + + size_t cur_sz = vector_size(cur_vec); + size_t mv_sz = vector_size(mv_vec); + if (mv_sz == 0) { + return FT_SUCCESS; + } + + size_t min_targ_size = pos + mv_sz; + if (cur_sz < min_targ_size) { + if (vector_reallocate_(cur_vec, min_targ_size) == -1) + return FT_ERROR; + cur_vec->m_capacity = min_targ_size; + } + + ptrdiff_t deviation = pos * cur_vec->m_item_size; + void *tmp = NULL; + size_t new_mv_sz = 0; + if (cur_sz > pos) { + new_mv_sz = MIN(cur_sz - pos, mv_sz); + tmp = F_MALLOC(cur_vec->m_item_size * new_mv_sz); + if (tmp == NULL) { + return FT_MEMORY_ERROR; + } + } + + memcpy(tmp, + cur_vec->m_data + deviation, + cur_vec->m_item_size * (cur_sz - pos)); + memcpy(cur_vec->m_data + deviation, + mv_vec->m_data, + cur_vec->m_item_size * mv_sz); + memcpy(mv_vec->m_data, + tmp, + cur_vec->m_item_size * new_mv_sz); + + mv_vec->m_size = new_mv_sz; + F_FREE(tmp); + return FT_SUCCESS; +} + + diff --git a/src/vector.h b/src/vector.h index a2e765e..7e768a1 100644 --- a/src/vector.h +++ b/src/vector.h @@ -26,6 +26,7 @@ extern int vector_erase(vector_t*, size_t index); extern void vector_clear(vector_t*); extern const void *vector_at_c(const vector_t *vector, size_t index); extern void* vector_at(vector_t*, size_t index); +extern fort_status_t vector_swap(vector_t *cur_vec, vector_t *mv_vec, size_t pos); #define FOR_EACH_(type, item, vector, index_name) \ diff --git a/tests/test.c b/tests/test.c index f9ae571..10684e3 100644 --- a/tests/test.c +++ b/tests/test.c @@ -3,6 +3,7 @@ struct test_case test_suit [] = { {"test_vector_basic", test_vector_basic}, + {"test_vector_stress", test_vector_stress}, {"test_string_buffer", test_string_buffer}, {"test_table_sizes", test_table_sizes}, {"test_table_geometry", test_table_geometry}, diff --git a/tests/test_table_basic.c b/tests/test_table_basic.c index d028807..6a429c3 100644 --- a/tests/test_table_basic.c +++ b/tests/test_table_basic.c @@ -312,15 +312,21 @@ void test_table_write(void) assert_true(ft_write(table, "3.140000") == FT_SUCCESS); ft_ln(table); assert_true(ft_write(table, "c") == FT_SUCCESS); - assert_true(ft_write(table, "234") == FT_SUCCESS); - assert_true(ft_write(table, "3.140000") == FT_SUCCESS); - assert_true(ft_write_ln(table, "3") == FT_SUCCESS); + assert_true(ft_write(table, "235") == FT_SUCCESS); + assert_true(ft_write(table, "3.150000") == FT_SUCCESS); + assert_true(ft_write_ln(table, "5") == FT_SUCCESS); assert_true(ft_write(table, "234") == FT_SUCCESS); assert_true(ft_write(table, "3.140000") == FT_SUCCESS); assert_true(ft_write(table, "3") == FT_SUCCESS); assert_true(ft_write_ln(table, "c") == FT_SUCCESS); + /* Replace old values */ + ft_set_cur_cell(table, 1, 1); + assert_true(ft_write(table, "234") == FT_SUCCESS); + assert_true(ft_write(table, "3.140000") == FT_SUCCESS); + assert_true(ft_write_ln(table, "3") == FT_SUCCESS); + const char *table_str = ft_to_string(table); assert_true(table_str != NULL); const char *table_str_etalon = @@ -354,15 +360,21 @@ void test_table_write(void) assert_true(ft_wwrite(table, L"3.140000") == FT_SUCCESS); ft_ln(table); assert_true(ft_wwrite(table, L"c") == FT_SUCCESS); - assert_true(ft_wwrite(table, L"234") == FT_SUCCESS); - assert_true(ft_wwrite(table, L"3.140000") == FT_SUCCESS); - assert_true(ft_wwrite_ln(table, L"3") == FT_SUCCESS); + assert_true(ft_wwrite(table, L"235") == FT_SUCCESS); + assert_true(ft_wwrite(table, L"3.150000") == FT_SUCCESS); + assert_true(ft_wwrite_ln(table, L"5") == FT_SUCCESS); assert_true(ft_wwrite(table, L"234") == FT_SUCCESS); assert_true(ft_wwrite(table, L"3.140000") == FT_SUCCESS); assert_true(ft_wwrite(table, L"3") == FT_SUCCESS); assert_true(ft_wwrite_ln(table, L"c") == FT_SUCCESS); + /* Replace old values */ + ft_set_cur_cell(table, 1, 1); + assert_true(ft_wwrite(table, L"234") == FT_SUCCESS); + assert_true(ft_wwrite(table, L"3.140000") == FT_SUCCESS); + assert_true(ft_wwrite_ln(table, L"3") == FT_SUCCESS); + const wchar_t *table_str = ft_to_wstring(table); assert_true(table_str != NULL); const wchar_t *table_str_etalon = @@ -392,9 +404,13 @@ void test_table_write(void) ft_set_cell_option(table, 0, FT_ANY_COLUMN, FT_COPT_ROW_TYPE, FT_ROW_HEADER); assert_true(ft_nwrite(table, 4, "3", "c", "234", "3.140000") == FT_SUCCESS); ft_ln(table); - assert_true(ft_nwrite_ln(table, 4, "c", "234", "3.140000", "3") == FT_SUCCESS); + assert_true(ft_nwrite_ln(table, 4, "c", "235", "3.150000", "5") == FT_SUCCESS); assert_true(ft_nwrite_ln(table, 4, "234", "3.140000", "3", "c") == FT_SUCCESS); + /* Replace old values */ + ft_set_cur_cell(table, 1, 1); + assert_true(ft_nwrite_ln(table, 3, "234", "3.140000", "3") == FT_SUCCESS); + const char *table_str = ft_to_string(table); assert_true(table_str != NULL); const char *table_str_etalon = @@ -424,9 +440,13 @@ void test_table_write(void) ft_set_cell_option(table, 0, FT_ANY_COLUMN, FT_COPT_ROW_TYPE, FT_ROW_HEADER); assert_true(ft_nwwrite(table, 4, L"3", L"c", L"234", L"3.140000") == FT_SUCCESS); ft_ln(table); - assert_true(ft_nwwrite_ln(table, 4, L"c", L"234", L"3.140000", L"3") == FT_SUCCESS); + assert_true(ft_nwwrite_ln(table, 4, L"c", L"235", L"3.150000", L"5") == FT_SUCCESS); assert_true(ft_nwwrite_ln(table, 4, L"234", L"3.140000", L"3", L"c") == FT_SUCCESS); + /* Replace old values */ + ft_set_cur_cell(table, 1, 1); + assert_true(ft_nwwrite_ln(table, 3, L"234", L"3.140000", L"3") == FT_SUCCESS); + const wchar_t *table_str = ft_to_wstring(table); assert_true(table_str != NULL); const wchar_t *table_str_etalon = @@ -456,13 +476,19 @@ void test_table_write(void) ft_set_cell_option(table, 0, FT_ANY_COLUMN, FT_COPT_ROW_TYPE, FT_ROW_HEADER); const char *row_0[4] = {"3", "c", "234", "3.140000"}; - const char *row_1[4] = {"c", "234", "3.140000", "3"}; + const char *row_1[4] = {"c", "235", "3.150000", "5"}; const char *row_2[4] = {"234", "3.140000", "3", "c"}; assert_true(ft_row_write_ln(table, 4, row_0) == FT_SUCCESS); assert_true(ft_row_write(table, 4, row_1) == FT_SUCCESS); ft_ln(table); assert_true(ft_row_write_ln(table, 4, row_2) == FT_SUCCESS); + /* Replace old values */ + ft_set_cur_cell(table, 1, 1); + const char *row_11[3] = {"234", "3.140000", "3"}; + assert_true(ft_row_write(table, 3, row_11) == FT_SUCCESS); + ft_ln(table); + const char *table_str = ft_to_string(table); assert_true(table_str != NULL); const char *table_str_etalon = @@ -491,13 +517,19 @@ void test_table_write(void) ft_set_cell_option(table, 0, FT_ANY_COLUMN, FT_COPT_ROW_TYPE, FT_ROW_HEADER); const wchar_t *row_0[4] = {L"3", L"c", L"234", L"3.140000"}; - const wchar_t *row_1[4] = {L"c", L"234", L"3.140000", L"3"}; + const wchar_t *row_1[4] = {L"c", L"235", L"3.150000", L"5"}; const wchar_t *row_2[4] = {L"234", L"3.140000", L"3", L"c"}; assert_true(ft_row_wwrite_ln(table, 4, row_0) == FT_SUCCESS); assert_true(ft_row_wwrite(table, 4, row_1) == FT_SUCCESS); ft_ln(table); assert_true(ft_row_wwrite_ln(table, 4, row_2) == FT_SUCCESS); + /* Replace old values */ + ft_set_cur_cell(table, 1, 1); + const wchar_t *row_11[3] = {L"234", L"3.140000", L"3"}; + assert_true(ft_row_wwrite(table, 3, row_11) == FT_SUCCESS); + ft_ln(table); + const wchar_t *table_str = ft_to_wstring(table); assert_true(table_str != NULL); const wchar_t *table_str_etalon = @@ -528,12 +560,17 @@ void test_table_write(void) ft_set_cell_option(table, 0, FT_ANY_COLUMN, FT_COPT_ROW_TYPE, FT_ROW_HEADER); int n = ft_printf_ln(table, "%d|%c|%s|%f", 3, 'c', "234", 3.14); assert_true(n == 4); - n = ft_printf(table, "%c|%s|%f|%d", 'c', "234", 3.14, 3); + n = ft_printf(table, "%c|%s|%f|%d", 'c', "235", 3.15, 5); assert_true(n == 4); ft_ln(table); n = ft_printf_ln(table, "%s|%f|%d|%c", "234", 3.14, 3, 'c'); assert_true(n == 4); + /* Replace old values */ + ft_set_cur_cell(table, 1, 1); + n = ft_printf(table, "%s|%f|%d", "234", 3.14, 3); + assert_true(n == 3); + const char *table_str = ft_to_string(table); assert_true(table_str != NULL); const char *table_str_etalon = diff --git a/tests/test_vector.c b/tests/test_vector.c index 187ec85..748a2bf 100644 --- a/tests/test_vector.c +++ b/tests/test_vector.c @@ -87,3 +87,34 @@ void test_vector_basic(void) destroy_vector(vector); } + + +void test_vector_stress(void) +{ + size_t i = 0; + + typedef short item_t; + const size_t init_capacity = 10; + vector_t *vector = create_vector(sizeof(item_t), init_capacity); + + assert_true(vector != NULL); + assert_true(vector_size(vector) == 0); + assert_true(vector_capacity(vector) == init_capacity); + + WHEN("Pushing a lot of items into vector") { + for (i = 0; i < 1000 * init_capacity; ++i) { + item_t item = (item_t)i; + vector_push(vector, &item); + } + + THEN("Then capacity is not changed") { + assert_true(vector_size(vector) == 1000 * init_capacity); + assert_true(vector_capacity(vector) >= 1000 * init_capacity); + } + } + + /* + * Destroy without previously called clear + */ + destroy_vector(vector); +} diff --git a/tests/tests.h b/tests/tests.h index 9059908..138fcbb 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -15,6 +15,7 @@ /* Test cases */ void test_vector_basic(void); +void test_vector_stress(void); void test_string_buffer(void); void test_table_sizes(void); void test_table_geometry(void);