From 4e6f7e55af1cb63f27d49f56d9568df72f11aa8f Mon Sep 17 00:00:00 2001 From: "exercism-solutions-syncer[bot]" <211797793+exercism-solutions-syncer[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:48:20 +0000 Subject: [PATCH] [Sync Iteration] c/react/1 --- solutions/c/react/1/react.c | 289 ++++++++++++++++++++++++++++++++++++ solutions/c/react/1/react.h | 29 ++++ 2 files changed, 318 insertions(+) create mode 100644 solutions/c/react/1/react.c create mode 100644 solutions/c/react/1/react.h diff --git a/solutions/c/react/1/react.c b/solutions/c/react/1/react.c new file mode 100644 index 0000000..1272afd --- /dev/null +++ b/solutions/c/react/1/react.c @@ -0,0 +1,289 @@ +#include "react.h" +#include +#include +#include + +struct cell_node { + struct cell *cell; + struct cell_node *next; +}; + +struct callback_node { + callback_id id; + void *obj; + callback func; + struct callback_node *next; +}; + +struct reactor { + struct cell_node *cells; +}; + +enum cell_type { INPUT_CELL, COMPUTE1_CELL, COMPUTE2_CELL }; + +struct cell{ + int value; + int old_value; + enum cell_type type; + + struct cell *parent1; + struct cell *parent2; + + union { + compute1 fun1; + compute2 fun2; + } fun; + + struct cell_node *dependents; + struct callback_node *callbacks; + + bool changed; +}; + +struct reactor *create_reactor(void){ + return calloc(1, sizeof(struct reactor)); +} + +void destroy_reactor(struct reactor *reactor) { + if (reactor) { + struct cell_node *node = reactor->cells; + while (node) { + struct callback_node *callback = node->cell->callbacks; + while (callback) { + struct callback_node *temp1 = callback->next; + free(callback); + callback = temp1; + } + + struct cell_node *dependent = node->cell->dependents; + while (dependent) { + struct cell_node *temp1 = dependent->next; + free(dependent); + dependent = temp1; + } + + struct cell_node *temp = node->next; + + free(node->cell); + free(node); + node = temp; + } + free(reactor); + } +} + +struct cell *create_input_cell(struct reactor *reactor, int initial_value){ + if (!reactor) return NULL; + + struct cell_node *new_node = malloc(sizeof(struct cell_node)); + if (!new_node) return NULL; + + struct cell *new_cell = calloc(1, sizeof(struct cell)); + if (!new_cell) return NULL; + + new_cell->type = INPUT_CELL; + new_cell->value = initial_value; + + new_node->cell = new_cell; + new_node->next = reactor->cells; + reactor->cells = new_node; + + return new_cell; +} + +struct cell *create_compute1_cell(struct reactor *reactor, struct cell *parent, compute1 fun){ + if (!reactor) return NULL; + + struct cell_node *new_node = malloc(sizeof(struct cell_node)); + if (!new_node) return NULL; + + struct cell_node *new_dependent = malloc(sizeof(struct cell_node)); + if (!new_dependent) return NULL; + + struct cell *new_cell = calloc(1, sizeof(struct cell)); + if (!new_cell) return NULL; + + new_cell->type = COMPUTE1_CELL; + new_cell->fun.fun1 = fun; + new_cell->parent1 = parent; + + new_cell->value = fun(parent->value); + + new_dependent->cell = new_cell; + new_dependent->next = parent->dependents; + parent->dependents = new_dependent; + + new_node->cell = new_cell; + new_node->next = reactor->cells; + reactor->cells = new_node; + + return new_cell; +} + +struct cell *create_compute2_cell(struct reactor *reactor, struct cell *parent1, + struct cell *parent2, compute2 fun){ + if (!reactor) return NULL; + + struct cell_node *new_node = malloc(sizeof(struct cell_node)); + if (!new_node) return NULL; + + struct cell_node *new_dependent_node1 = malloc(sizeof(struct cell_node)); + if (!new_dependent_node1) return NULL; + + struct cell_node *new_dependent_node2 = malloc(sizeof(struct cell_node)); + if (!new_dependent_node2) return NULL; + + struct cell *new_cell = calloc(1, sizeof(struct cell)); + if (!new_cell) return NULL; + + new_cell->type = COMPUTE2_CELL; + new_cell->fun.fun2 = fun; + new_cell->parent1 = parent1; + new_cell->parent2 = parent2; + + new_cell->value = fun(parent1->value, parent2->value); + + new_dependent_node1->cell = new_cell; + new_dependent_node2->cell = new_cell; + + new_dependent_node1->next = parent1->dependents; + parent1->dependents = new_dependent_node1; + + new_dependent_node2->next = parent2->dependents; + parent2->dependents = new_dependent_node2; + + new_node->cell = new_cell; + new_node->next = reactor->cells; + reactor->cells = new_node; + + return new_cell; +} + +static inline bool update_value(struct cell *cell){ + if (cell->type == INPUT_CELL) return false; + + int new_value; + if (cell->type == COMPUTE1_CELL) { + new_value = cell->fun.fun1(cell->parent1->value); + } else { + new_value = cell->fun.fun2(cell->parent1->value, cell->parent2->value); + } + + if (cell->value == new_value) return false; + + cell->value = new_value; + + return true; +} + +int get_cell_value(struct cell *cell){ + return cell->value; +} + +static void push_dependents(struct cell_node **work, struct cell_node *dependents){ + while (dependents) { + struct cell_node *node = malloc(sizeof(struct cell_node)); + node->cell = dependents->cell; + node->next = *work; + *work = node; + dependents = dependents->next; + } +} + +void set_cell_value(struct cell *cell, int new_value){ + if (cell->type != INPUT_CELL || cell->value == new_value) { + return; + } + + cell->value = new_value; + + struct cell_node *work_list = NULL; + struct cell_node *changed_cells = NULL; + + push_dependents(&work_list, cell->dependents); + + while (work_list) { + struct cell_node *current_node = work_list; + struct cell *current_cell = current_node->cell; + + work_list = current_node->next; + free(current_node); + + int previous_value = current_cell->value; + + if (update_value(current_cell)) { + + if (!current_cell->changed) { + current_cell->changed = true; + + current_cell->old_value = previous_value; + + struct cell_node *changed_node = malloc(sizeof(struct cell_node)); + changed_node->cell = current_cell; + changed_node->next = changed_cells; + changed_cells = changed_node; + } + + push_dependents(&work_list, current_cell->dependents); + } + } + + while (changed_cells) { + struct cell_node *current_node = changed_cells; + struct cell *current_cell = current_node->cell; + + if (current_cell->value != current_cell->old_value) { + struct callback_node *callback = current_cell->callbacks; + while (callback) { + callback->func(callback->obj, current_cell->value); + callback = callback->next; + } + } + + current_cell->changed = false; + changed_cells = current_node->next; + free(current_node); + } +} + +// The callback should be called with the same void * given in add_callback. +callback_id add_callback(struct cell *cell, void *obj, callback callback){ + static callback_id id = 0; + + struct callback_node *new_node = calloc(1, sizeof(struct callback_node)); + assert(new_node); + + new_node->func = callback; + new_node->obj = obj; + + new_node->next = cell->callbacks; + cell->callbacks = new_node; + new_node->id = id; + + id++; + return new_node->id; +} + +void remove_callback(struct cell *cell, callback_id id){ + struct callback_node *callback = cell->callbacks; + if (!callback) return; + + if (callback->id == id) { + cell->callbacks = callback->next; + free(callback); + return; + } + + struct callback_node *next_callback = callback->next; + + while (next_callback) { + if (next_callback->id == id) { + callback->next = next_callback->next; + free(next_callback); + return; + } + + callback = next_callback; + next_callback = next_callback->next; + } +} diff --git a/solutions/c/react/1/react.h b/solutions/c/react/1/react.h new file mode 100644 index 0000000..9a0ff89 --- /dev/null +++ b/solutions/c/react/1/react.h @@ -0,0 +1,29 @@ +#ifndef REACT_H +#define REACT_H + +struct reactor; +struct cell; + +typedef int (*compute1)(int); +typedef int (*compute2)(int, int); + +struct reactor *create_reactor(void); +// destroy_reactor should free all cells created under that reactor. +void destroy_reactor(struct reactor *); + +struct cell *create_input_cell(struct reactor *, int initial_value); +struct cell *create_compute1_cell(struct reactor *, struct cell *, compute1); +struct cell *create_compute2_cell(struct reactor *, struct cell *, + struct cell *, compute2); + +int get_cell_value(struct cell *); +void set_cell_value(struct cell *, int new_value); + +typedef void (*callback)(void *, int); +typedef int callback_id; + +// The callback should be called with the same void * given in add_callback. +callback_id add_callback(struct cell *, void *, callback); +void remove_callback(struct cell *, callback_id); + +#endif