Not long ago, I posted this dynamic stack for review. Now I wrote a new version, which is hopefully a better one.
Please take a look and let me know how I could improve performance and increase code quality.
It works by storing pointers to the content. If there's not enough memory, it will try to increase the allocated space.
header
#ifndef DYNAMIC_STACK
#define DYNAMIC_STACK
#define DSTACK_SUCCESS 1
#define DSTACK_ERROR 0
//The stack just stores pointers
typedef struct Dynamic_Stack Dynamic_Stack;
struct Dynamic_Stack {
void **start; //Array of pointer to void
void **position;
void **end;
};
//Set up stack
int dstack_init(Dynamic_Stack *stack, size_t slots);
void dstack_free(Dynamic_Stack *stack);
void dstack_clear(Dynamic_Stack *stack);
int dstack_push(Dynamic_Stack *stack, void *new_element);
void *dstack_pop(Dynamic_Stack *stack);
//0 is the top of the stack
void *dstack_peek(Dynamic_Stack *stack, size_t levels);
int dstack_increase_capacity(Dynamic_Stack *stack, size_t new_slots);
int dstack_decrease_capacity(Dynamic_Stack *stack, size_t remove_total);
void dstack_shrink_to_fit(Dynamic_Stack *stack);
#endif
c file
#include <stdlib.h>
#include "dynamic_stack.h"
#define MULTIPLIER 1.00 //Increase by 100% on every expansion
#define FIXED_EXPANSION 0 //Overrides multiplier
//Internal
//Must keep at least 1 slot or it will break
static int dstack_resize(Dynamic_Stack *stack, size_t new_slot_capacity)
{
size_t position = stack->position - stack->start;
void *temp = realloc(stack->start, new_slot_capacity * sizeof(void *));
if(temp == NULL)
return DSTACK_ERROR;
stack->start = temp;
stack->end = stack->start + new_slot_capacity;
//Put position back if needed
stack->position = (position < new_slot_capacity)
? stack->start + position
: stack->end;
return DSTACK_SUCCESS;
}
#if FIXED_EXPANSION >= 1
static int expand(Dynamic_Stack *stack)
{
return dstack_resize(stack, stack->end - stack->start + FIXED_EXPANSION);
}
#else
static int expand(Dynamic_Stack *stack)
{
//Check if multiplier is producing at least 1 new slot
size_t old_slots = stack->end - stack->start;
size_t new_slots = old_slots * MULTIPLIER;
if(new_slots == 0)
return DSTACK_ERROR;
return dstack_resize(stack, old_slots + new_slots);
}
#endif
//Public
//Set up stack
int dstack_init(Dynamic_Stack *stack, size_t slots)
{
if((stack->start = malloc(sizeof(void *) * slots)) == NULL)
return DSTACK_ERROR;
stack->position = stack->start;
stack->end = stack->start + slots;
return DSTACK_SUCCESS;
}
void dstack_free(Dynamic_Stack *stack)
{
free(stack->start);
}
void dstack_clear(Dynamic_Stack *stack)
{
stack->position = stack->start;
}
int dstack_push(Dynamic_Stack *stack, void *new_element)
{
if(stack->position == stack->end && expand(stack) == DSTACK_ERROR)
return DSTACK_ERROR;
*stack->position = new_element;
++stack->position;
return DSTACK_SUCCESS;
}
void *dstack_pop(Dynamic_Stack *stack)
{
if(stack->position == stack->start)
return NULL;
return *--stack->position;
}
//0 is the top of the stack
void *dstack_peek(Dynamic_Stack *stack, size_t levels)
{
if(levels >= stack->position - stack->start)
return NULL;
return *(stack->position - 1 - levels);
}
int dstack_increase_capacity(Dynamic_Stack *stack, size_t new_slots)
{
return dstack_resize(stack, stack->end - stack->start + new_slots);
}
int dstack_decrease_capacity(Dynamic_Stack *stack, size_t remove_total)
{
if(remove_total >= stack->end - stack->start)
return DSTACK_ERROR;
return dstack_resize(stack, stack->end - stack->start - remove_total);
}
//Always leave 1 extra slot so there's no risk of resizing to 0
void dstack_shrink_to_fit(Dynamic_Stack *stack)
{
dstack_resize(stack, stack->position - stack->start + 1);
}
example
#include <stdio.h>
#include "dynamic_stack.h"
int main(void)
{
char *words[] = {
"One",
"Two",
"Three",
"Four",
"Five",
"Six",
"Seven",
"Eight",
"Nine",
"Ten",
"Eleven",
"Twelve",
""
};
Dynamic_Stack stack;
if(!dstack_init(&stack, 12))
return 1;
for(char **ite = words; **ite != '\0'; ++ite){
dstack_push(&stack, *ite);
}
size_t i = 0;
for(char **ite = words; **ite != '\0'; ++ite)
puts(dstack_peek(&stack, i++));
dstack_increase_capacity(&stack, 8);
dstack_shrink_to_fit(&stack);
for(char *ite; (ite = dstack_pop(&stack)) != NULL; ++ite)
puts(ite);
dstack_free(&stack);
return 0;
}