diff --git a/cstack.c b/cstack.c index 72e36b4..5309197 100644 --- a/cstack.c +++ b/cstack.c @@ -1,42 +1,203 @@ #include "cstack.h" #include +#include +#include +#include +#include -#define UNUSED(VAR) (void)(VAR) +#define RESULT_OK 0 +#define RESULT_NOT_OK 1 +#define INVALID_HANDLER -1 +#define INITIAL_SIZE 10 + +typedef struct node +{ + struct node *prev; + unsigned int size; + char data[0]; +} node; + +typedef struct stack +{ + node *top; + unsigned int size; +} stack; + +typedef struct stack_entry +{ + int valid; + stack stack; +} stack_entry; + +typedef struct stack_entries_table +{ + hstack_t size; + stack_entry *entries; +} stack_entries_table; + +stack_entries_table stacks = {0u, NULL}; + +int allocate_table(void) +{ + assert(!stacks.entries); + stacks.entries = calloc(INITIAL_SIZE, sizeof(stack_entry)); + if (stacks.entries) + stacks.size = INITIAL_SIZE; + else + { + stacks.entries = calloc(1, sizeof(stack_entry)); + if (stacks.entries) + stacks.size = 1; + else + return RESULT_NOT_OK; + } + return RESULT_OK; +} + +void reallocate_table(void) +{ + assert(stacks.entries); + hstack_t new_size = stacks.size * 2; + stack_entry *new_array = calloc(new_size, sizeof(stack_entry)); + + if (!new_array) + { + new_size = stacks.size + 1; + new_array = calloc(new_size, sizeof(stack_entry)); + } + + if (new_array) + { + memcpy(new_array, stacks.entries, stacks.size * sizeof(stack_entry)); + free(stacks.entries); + stacks.entries = new_array; + stacks.size = new_size; + } +} + +void deallocate_table(void) +{ + free(stacks.entries); + stacks.entries = NULL; + stacks.size = 0; +} + +int is_table_empty(void) +{ + for (hstack_t index = 0; index < stacks.size; ++index) + { + if (stacks.entries[index].valid) + return RESULT_NOT_OK; + } + return RESULT_OK; +} + +hstack_t get_free_index(void) +{ + hstack_t index = 0; + for (; index < stacks.size && stacks.entries[index].valid; ++index) + ; + return index; +} hstack_t stack_new(void) { - return -1; + if (!stacks.entries) + if (allocate_table() != RESULT_OK) + return INVALID_HANDLER; + + hstack_t index = get_free_index(); + + if (index >= stacks.size) + reallocate_table(); + + if (index < stacks.size) + { + stacks.entries[index].valid = 1; + return index; + } + return INVALID_HANDLER; } void stack_free(const hstack_t hstack) { - UNUSED(hstack); + if (stack_valid_handler(hstack) != RESULT_OK) + return; + + stack *stack = &stacks.entries[hstack].stack; + node *cur_node = stack->top; + + stacks.entries[hstack].valid = 0; + stack->top = NULL; + stack->size = 0; + + node *prev_node; + while (cur_node) + { + prev_node = cur_node->prev; + free(cur_node); + cur_node = prev_node; + } + + if (is_table_empty() == RESULT_OK) + deallocate_table(); } int stack_valid_handler(const hstack_t hstack) { - UNUSED(hstack); - return 1; + if (hstack >= 0 && hstack < stacks.size && stacks.entries[hstack].valid) + return RESULT_OK; + return RESULT_NOT_OK; } unsigned int stack_size(const hstack_t hstack) { - UNUSED(hstack); + if (stack_valid_handler(hstack) == RESULT_OK) + return stacks.entries[hstack].stack.size; return 0; } -void stack_push(const hstack_t hstack, const void* data_in, const unsigned int size) +void stack_push(const hstack_t hstack, const void *data_in, const unsigned int size) { - UNUSED(hstack); - UNUSED(data_in); - UNUSED(size); + if (!data_in || !size || stack_valid_handler(hstack) != RESULT_OK) + return; + + stack *stack = &stacks.entries[hstack].stack; + if (stack->size == UINT_MAX) + return; + + node *new_node = malloc(sizeof(node) + size); + if (!new_node) + return; + + new_node->prev = stack->top; + new_node->size = size; + memcpy(new_node->data, data_in, size); + + stack->top = new_node; + stack->size += 1; } -unsigned int stack_pop(const hstack_t hstack, void* data_out, const unsigned int size) +unsigned int stack_pop(const hstack_t hstack, void *data_out, const unsigned int size) { - UNUSED(hstack); - UNUSED(data_out); - UNUSED(size); - return 0; -} + if (!data_out || !size || stack_valid_handler(hstack) != RESULT_OK) + return 0; + stack *stack = &stacks.entries[hstack].stack; + node *cur_node = stack->top; + + if (!cur_node) + return 0; + assert(stack->size > 0); + + unsigned int data_size = cur_node->size; + if (data_size > size) + return 0; + + stack->top = cur_node->prev; + stack->size -= 1; + + memcpy(data_out, cur_node->data, data_size); + free(cur_node); + return data_size; +} diff --git a/test.cpp b/test.cpp index 657219b..5881483 100644 --- a/test.cpp +++ b/test.cpp @@ -124,3 +124,100 @@ TEST_F(ModifyTests, SeveralPushPop) EXPECT_THAT(data_out, ::testing::ElementsAre(2, 1, 0)); } +TEST(CustomTests, NewPushFreePop) +{ + const size_t count = 10; + hstack_t stacks[count] = {-1}; + for (size_t i = 0; i < count; ++i) + { + stacks[i] = stack_new(); + EXPECT_EQ(stack_valid_handler(stacks[i]), 0); + EXPECT_EQ(stack_size(stacks[i]), 0u); + int data_out = 1; + EXPECT_EQ(stack_pop(stacks[i], &data_out, sizeof(data_out)), 0u); + EXPECT_EQ(data_out, 1); + EXPECT_EQ(stack_valid_handler(stacks[i]), 0); + EXPECT_EQ(stack_size(stacks[i]), 0u); + } + for (size_t i = 0; i < count; ++i) + { + EXPECT_EQ(stack_valid_handler(stacks[i]), 0); + EXPECT_EQ(stack_size(stacks[i]), 0u); + const int data_in = 1; + stack_push(stacks[i], &data_in, sizeof(data_in)); + EXPECT_EQ(stack_valid_handler(stacks[i]), 0); + EXPECT_EQ(stack_size(stacks[i]), 1u); + } + for (size_t i = 1; i < count; ++i) + { + stack_free(stacks[i]); + EXPECT_EQ(stack_valid_handler(stacks[i]), 1); + } + for (size_t i = 1; i < count; ++i) + { + stacks[i] = stack_new(); + EXPECT_EQ(stack_valid_handler(stacks[i]), 0); + EXPECT_EQ(stack_size(stacks[i]), 0u); + int data_out = 0; + EXPECT_EQ(stack_pop(stacks[i], &data_out, sizeof(data_out)), 0u); + EXPECT_EQ(data_out, 0); + EXPECT_EQ(stack_valid_handler(stacks[i]), 0); + EXPECT_EQ(stack_size(stacks[i]), 0u); + } + for (size_t i = 0; i < count; ++i) + { + stack_free(stacks[i]); + EXPECT_EQ(stack_valid_handler(stacks[i]), 1); + } +} + +TEST(CustomTests, FreeAfterFree) +{ + const size_t count = 10; + hstack_t stacks[count] = {-1}; + for (size_t i = 0; i < count; ++i) + { + stacks[i] = stack_new(); + EXPECT_EQ(stack_valid_handler(stacks[i]), 0); + EXPECT_EQ(stack_size(stacks[i]), 0u); + } + for (size_t i = 1; i < count; ++i) + { + stack_free(stacks[i]); + EXPECT_EQ(stack_valid_handler(stacks[i]), 1); + } + for (size_t i = 0; i < count; ++i) + { + stack_free(stacks[i]); + EXPECT_EQ(stack_valid_handler(stacks[i]), 1); + } + for (size_t i = 0; i < count; ++i) + { + stack_free(stacks[i]); + EXPECT_EQ(stack_valid_handler(stacks[i]), 1); + } +} + +TEST(CustomTests, BigSizeStack) +{ + const char example = 'a'; + const size_t limit = 100000; + hstack_t stack = stack_new(); + EXPECT_EQ(stack_valid_handler(stack), 0); + for (unsigned int i = 0; i < limit; ++i) + { + char c = example; + stack_push(stack, &c, sizeof(c)); + EXPECT_EQ(stack_size(stack), i + 1); + } + for (unsigned int i = 0; i < limit; ++i) + { + char c = 0; + unsigned int size = stack_pop(stack, &c, sizeof(c)); + EXPECT_EQ(size, sizeof(c)); + EXPECT_EQ(c, example); + EXPECT_EQ(stack_size(stack), limit - (i + 1)); + } + stack_free(stack); + EXPECT_EQ(stack_valid_handler(stack), 1); +} \ No newline at end of file