src/dynarray.c
src/system/file.h
src/system/file.c
+ src/ring_buffer.h
+ src/ring_buffer.c
)
target_link_libraries(nothing ${SDL2_LIBRARIES})
#include "src/system/str.c"
#include "src/dynarray.c"
#include "src/system/file.c"
+#include "src/ring_buffer.c"
// #define RENDERER_CONFIG SDL_RENDERER_SOFTWARE
#define RENDERER_CONFIG (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)
+#define UNDO_HISTORY_CAPACITY 256
+
#endif // CONFIG_H_
} break;
case SDL_KEYDOWN: {
- if (event->key.keysym.sym == SDLK_q && event->key.keysym.mod & KMOD_CTRL) {
+ if ((event->key.keysym.sym == SDLK_q && event->key.keysym.mod & KMOD_CTRL) ||
+ (event->key.keysym.sym == SDLK_F4 && event->key.keysym.mod & KMOD_ALT)) {
game_switch_state(game, GAME_STATE_QUIT);
return 0;
}
level_editor->camera_scale = 1.0f;
+ level_editor->undo_history = create_undo_history();
+
return level_editor;
}
level_editor->camera_scale = 1.0f;
- log_info("%ld bytes of tmp memory consumed during parsing the level\n", tmpmem.size);
+ level_editor->undo_history = create_undo_history();
free(tmpmem.buffer);
#include "system/lt.h"
#include "system/stacktrace.h"
#include "undo_history.h"
+#include "config.h"
typedef struct {
RevertAction revert;
-} HistoryAction;
+ void *context_data;
+ size_t context_data_size;
+} HistoryItem;
+
+static
+void undo_history_destroy_item(void *item)
+{
+ free(((HistoryItem*)item)->context_data);
+}
+
+UndoHistory create_undo_history(void)
+{
+ UndoHistory result;
+ result.actions = create_ring_buffer(
+ sizeof(HistoryItem),
+ UNDO_HISTORY_CAPACITY,
+ undo_history_destroy_item);
+ return result;
+}
void undo_history_push(UndoHistory *undo_history,
RevertAction revert,
{
trace_assert(undo_history);
- HistoryAction action = {
+ HistoryItem item = {
.revert = revert,
+ .context_data = malloc(context_data_size),
+ .context_data_size = context_data_size
};
+ trace_assert(item.context_data);
+ memcpy(item.context_data, context_data, context_data_size);
- stack_push(&undo_history->actions, context_data, context_data_size);
- stack_push(&undo_history->actions, &action, sizeof(action));
+ ring_buffer_push(&undo_history->actions, &item);
}
void undo_history_pop(UndoHistory *undo_history)
{
trace_assert(undo_history);
- if (stack_empty(&undo_history->actions) > 0) {
- HistoryAction action = *(HistoryAction *)stack_top_element(&undo_history->actions);
- stack_pop(&undo_history->actions);
-
- size_t context_size = stack_top_size(&undo_history->actions);
- void *context = stack_top_element(&undo_history->actions);
-
- action.revert(context, context_size);
- stack_pop(&undo_history->actions);
+ if (undo_history->actions.count > 0) {
+ HistoryItem *item = ring_buffer_top(&undo_history->actions);
+ item->revert(item->context_data, item->context_data_size);
+ ring_buffer_pop(&undo_history->actions);
}
}
#ifndef UNDO_HISTORY_H_
#define UNDO_HISTORY_H_
-#include "stack.h"
+#include "ring_buffer.h"
typedef void (*RevertAction)(void *context, size_t context_size);
typedef struct {
- Stack actions;
+ RingBuffer actions;
} UndoHistory;
+UndoHistory create_undo_history(void);
+
static inline
void destroy_undo_history(UndoHistory undo_history)
{
- destroy_stack(undo_history.actions);
+ destroy_ring_buffer(undo_history.actions);
}
void undo_history_push(UndoHistory *undo_history,
static inline
int undo_history_empty(UndoHistory *undo_history)
{
- return undo_history->actions.size == 0;
+ return undo_history->actions.count == 0;
}
#endif // UNDO_HISTORY_H_
--- /dev/null
+#include "ring_buffer.h"
+#include "system/stacktrace.h"
+
+void ring_buffer_push(RingBuffer *buffer,
+ void *element)
+{
+ trace_assert(buffer);
+ trace_assert(element);
+
+ size_t i = (buffer->begin + buffer->count) % buffer->capacity;
+
+ if (buffer->count < buffer->capacity) {
+ memcpy(
+ buffer->data + i * buffer->element_size,
+ element,
+ buffer->element_size);
+ buffer->count += 1;
+ } else {
+ if (buffer->dtor) buffer->dtor(buffer->data + i * buffer->element_size);
+ memcpy(
+ buffer->data + i * buffer->element_size,
+ element,
+ buffer->element_size);
+ buffer->begin = (buffer->begin + 1) % buffer->capacity;
+ }
+}
+
+int ring_buffer_pop(RingBuffer *buffer)
+{
+ trace_assert(buffer);
+
+ if (buffer->count == 0) return 0;
+
+ if (buffer->dtor) {
+ size_t i = (buffer->begin + buffer->count - 1) % buffer->capacity;
+ buffer->dtor(buffer->data + i * buffer->element_size);
+ }
+
+ buffer->count--;
+
+ return 1;
+}
+
+void *ring_buffer_top(RingBuffer *buffer)
+{
+ trace_assert(buffer);
+ if (buffer->count == 0) return NULL;
+ size_t i = (buffer->begin + buffer->count - 1) % buffer->capacity;
+ return buffer->data + i * buffer->element_size;
+}
--- /dev/null
+#ifndef RING_BUFFER_H_
+#define RING_BUFFER_H_
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+typedef void (*RingBufferDtor)(void *element);
+
+typedef struct {
+ size_t element_size;
+ size_t capacity;
+ size_t count;
+ size_t begin;
+ uint8_t *data;
+ RingBufferDtor dtor;
+} RingBuffer;
+
+static inline
+RingBuffer create_ring_buffer(size_t element_size,
+ size_t capacity,
+ RingBufferDtor dtor)
+{
+ RingBuffer result = {0};
+ result.element_size = element_size;
+ result.capacity = capacity;
+ result.dtor = dtor;
+ result.data = malloc(result.element_size * result.capacity);
+ return result;
+}
+
+static inline
+void destroy_ring_buffer(RingBuffer buffer)
+{
+ free(buffer.data);
+}
+
+void ring_buffer_push(RingBuffer *buffer, void *element);
+int ring_buffer_pop(RingBuffer *buffer);
+void *ring_buffer_top(RingBuffer *buffer);
+
+#endif // RING_BUFFER_H_
+++ /dev/null
-#ifndef STACK_H_
-#define STACK_H_
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <system/stacktrace.h>
-
-typedef struct {
- size_t capacity;
- size_t size;
- char *bottom;
-} Stack;
-
-static inline
-void destroy_stack(Stack stack)
-{
- free(stack.bottom);
-}
-
-static inline
-void stack_grow(Stack *stack, size_t new_capacity)
-{
- trace_assert(stack);
- trace_assert(stack->capacity < new_capacity);
-
- stack->bottom = realloc(stack->bottom, new_capacity);
- stack->capacity = new_capacity;
-}
-
-static inline
-void stack_push(Stack *stack, const void *element, size_t element_size)
-{
- trace_assert(stack);
- trace_assert(element);
- trace_assert(element_size > 0);
-
- size_t frame_size = element_size + sizeof(element_size);
-
- if (frame_size >= (stack->capacity - stack->size)) {
- stack_grow(stack, stack->capacity * 2 + frame_size);
- }
-
- trace_assert(stack->bottom);
-
- memcpy(stack->bottom + stack->size, element, element_size);
- stack->size += element_size;
- memcpy(stack->bottom + stack->size, &element_size, sizeof(element_size));
- stack->size += sizeof(element_size);
-}
-
-static inline
-size_t stack_top_size(const Stack *stack)
-{
- trace_assert(stack);
- trace_assert(stack->size > 0);
- trace_assert(stack->bottom);
- size_t stack_size = 0;
- memcpy(&stack_size, stack->bottom + stack->size - sizeof(size_t), sizeof(size_t));
- return stack_size;
-}
-
-static inline
-void *stack_top_element(const Stack *stack)
-{
- trace_assert(stack);
- trace_assert(stack->size > 0);
- trace_assert(stack->bottom);
- size_t element_size = stack_top_size(stack);
- return stack->bottom + stack->size - element_size - sizeof(size_t);
-}
-
-static inline
-void stack_pop(Stack *stack)
-{
- trace_assert(stack);
- trace_assert(stack->size > 0);
- size_t element_size = stack_top_size(stack);
- stack->size -= element_size + sizeof(size_t);
-}
-
-static inline
-int stack_empty(Stack *stack)
-{
- trace_assert(stack);
- return stack->size > 0;
-}
-
-#endif // STACK_H_
return mem;
}
-
-void *nth_realloc(void *ptr, size_t new_size)
-{
- void *mem = realloc(ptr, new_size);
-
- if (mem == NULL) {
- log_fail("nth_realloc(0x%x, %lu) failed", ptr, new_size);
- }
-
- return mem;
-}
#include <stdlib.h>
void *nth_calloc(size_t num, size_t size);
-void *nth_realloc(void *ptr, size_t new_size);
#endif // NTH_ALLOC_H_