Last active
February 7, 2019 13:38
-
-
Save NolanDeveloper/612569cf1df424f3d7328eb59073d28a to your computer and use it in GitHub Desktop.
Implementation of observer pattern written in c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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