Skip to content

Instantly share code, notes, and snippets.

@NolanDeveloper
Last active February 7, 2019 13:38
Show Gist options
  • Save NolanDeveloper/612569cf1df424f3d7328eb59073d28a to your computer and use it in GitHub Desktop.
Save NolanDeveloper/612569cf1df424f3d7328eb59073d28a to your computer and use it in GitHub Desktop.
Implementation of observer pattern written in c
#if 0
/* Usage: */
int avg(int a, int b) { return (a + b) / 2; }
struct OInt * a;
struct OInt * b;
struct OInt * c;
void show_updates(void * extra) {
struct OInt * oint;
oint = extra;
printf("c = %d\n", oint_get(oint));
}
int main() {
a = oint_create(0);
b = oint_create(0);
c = oint_create(0);
oint_bind2(a, b, c, avg);
oint_listen(c, c, show_updates); /* c = 0 */
oint_set(a, 100); /* c = 50 */
oint_set(b, 200); /* c = 150 */
oint_set(b, 300); /* c = 200 */
oint_set(a, 300); /* c = 300 */
return 0;
}
#endif
void *
ecalloc(size_t nmemb, size_t size) {
void *p;
p = calloc(nmemb, size);
if (!p) die("calloc:");
return p;
}
struct Observer {
void * extra;
void (*value_changed)(void * extra);
struct Observer * next;
};
/* OInt is shorthand for ObservableInt */
struct OInt {
int value;
struct Observer * first_observer; /* list of observers */
};
/* Contains data required for linking one observable
to another. */
struct Binding {
struct OInt * s; /* Source observable */
struct OInt * d; /* Destination observable */
int (*map)(int); /* Function that creates destination
value from source value */
struct Observer * observer; /* Observer of s */
};
/* This one is analogous to Binding but destionation
observable depends on two instead of one. */
struct Binding2 {
struct OInt * s[2];
struct OInt * d;
int (*map)(int, int);
struct Observer * observers[2];
};
static struct Observer *
create_observer(void * extra, void (*value_changed)(void * extra)) {
struct Observer * new_observer;
new_observer = ecalloc(1, sizeof(struct Observer));
new_observer->extra = extra;
new_observer->value_changed = value_changed;
return new_observer;
}
static void
notify_observers(struct OInt * oint) {
struct Observer * observer;
observer = oint->first_observer;
while (observer) {
observer->value_changed(observer->extra);
observer = observer->next;
}
}
extern struct OInt *
oint_create(int initial_value) {
struct OInt * new_oint;
new_oint = ecalloc(1, sizeof(struct OInt));
new_oint->value = initial_value;
new_oint->first_observer = NULL;
return new_oint;
}
extern void
oint_free(struct OInt * oint) {
struct Observer * observer, * next;
observer = oint->first_observer;
while (observer) {
next = observer->next;
free(observer);
observer = next;
}
free(oint);
}
extern struct Observer *
oint_listen(struct OInt * oint, void * extra, void (*value_changed)(void * extra)) {
struct Observer * observer;
observer = create_observer(extra, value_changed);
observer->next = oint->first_observer;
oint->first_observer = observer;
value_changed(extra);
return observer;
}
extern void
oint_stop_listening(struct OInt * oint, struct Observer * observer) {
struct Observer * * p;
p = &oint->first_observer;
while (*p && *p != observer) p = &(*p)->next;
if (!p) return;
*p = (*p)->next;
free(observer);
}
extern void
oint_set(struct OInt * oint, int value) {
oint->value = value;
notify_observers(oint);
}
extern int
oint_get(struct OInt * oint) { return oint->value; }
static void
binder(void * extra) {
struct Binding * binding;
binding = extra;
oint_set(binding->d, binding->map(oint_get(binding->s)));
}
extern struct Binding *
oint_bind(struct OInt * s, struct OInt * d, int (*map)(int)) {
struct Binding * binding;
binding = ecalloc(1, sizeof(struct Binding));
binding->s = s;
binding->d = d;
binding->map = map;
binding->observer = oint_listen(s, binding, binder);
return binding;
}
extern void
oint_unbind(struct Binding * binding) {
oint_stop_listening(binding->s, binding->observer);
free(binding);
}
static void
binder2(void * extra) {
struct Binding2 * binding;
int args[2];
binding = extra;
args[0] = oint_get(binding->s[0]);
args[1] = oint_get(binding->s[1]);
oint_set(binding->d, binding->map(args[0], args[1]));
}
extern struct Binding2 *
oint_bind2(struct OInt * s0, struct OInt * s1, struct OInt * d, int (*map)(int, int)) {
struct Binding2 * binding;
binding = ecalloc(1, sizeof(struct Binding2));
binding->s[0] = s0;
binding->s[1] = s1;
binding->d = d;
binding->map = map;
binding->observers[0] = oint_listen(s0, binding, binder2);
binding->observers[1] = oint_listen(s1, binding, binder2);
return binding;
}
extern void
oint_unbind2(struct Binding2 * binding) {
oint_stop_listening(binding->s[0], binding->observers[0]);
oint_stop_listening(binding->s[1], binding->observers[1]);
free(binding);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment