-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathcedux.h
163 lines (154 loc) · 13 KB
/
cedux.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#ifndef CEDUX_H
#define CEDUX_H
#include <stddef.h>
#include <stdbool.h>
#include "queue.h"
#include "list.h"
#ifndef CEDUX_MAX_REDUCERS
// Maximum number of reducers that can be registered
// IMPORTANT: MUST BE A FACTROR OF TWO
#define CEDUX_MAX_REDUCERS 32
#endif
#ifndef CEDUX_MAX_SUBSCRIBERS
// Maximum number of subscribers that can be registered
// IMPORTANT: MUST BE A FACTROR OF TWO
#define CEDUX_MAX_SUBSCRIBERS 32
#endif
#ifndef CEDUX_MAX_ACTIONS
// Maximum number of actions that can be dispatched between runs of the cedux_run_store()
// IMPORTANT: MUST BE A FACTROR OF TWO
#define CEDUX_MAX_ACTIONS 16
#endif
#define CEDUX_DECLARE_STORE(TREE_TYPE, ACTION_TYPE, STORE_NAME) \
\
struct STORE_NAME##_handle; \
typedef bool(*STORE_NAME##_REDUCER)(TREE_TYPE * p_tree, ACTION_TYPE action); \
typedef void(*STORE_NAME##_SUBSCRIBER)(struct STORE_NAME##_handle * p_store, \
TREE_TYPE const * const p_tree, void *data); \
struct STORE_NAME##_subscriber_container \
{ \
STORE_NAME##_SUBSCRIBER subscriber; \
void *data; \
STORE_NAME##_REDUCER linked_reducer; \
}; \
QUEUE_TYPE_DECLARATION(STORE_NAME##_action_queue, ACTION_TYPE, CEDUX_MAX_ACTIONS) \
QUEUE_DECLARATION(STORE_NAME##_action_queue, ACTION_TYPE) \
LIST_DECLARATION(STORE_NAME##_reducer_list, STORE_NAME##_REDUCER, CEDUX_MAX_REDUCERS) \
LIST_DECLARATION(STORE_NAME##_subscriber_list, struct STORE_NAME##_subscriber_container, CEDUX_MAX_SUBSCRIBERS) \
\
void cedux_register_##STORE_NAME##_reducer(struct STORE_NAME##_handle * p_store, \
STORE_NAME##_REDUCER reducer); \
void cedux_register_##STORE_NAME##_subscriber(struct STORE_NAME##_handle * p_store, \
STORE_NAME##_SUBSCRIBER subscriber, \
void *data); \
void cedux_register_##STORE_NAME##_linked_subscriber(struct STORE_NAME##_handle * p_store, \
STORE_NAME##_SUBSCRIBER subscriber, \
void *data, \
STORE_NAME##_REDUCER linked_reducer); \
struct STORE_NAME##_handle cedux_init_##STORE_NAME(void); \
void cedux_dispatch_##STORE_NAME(struct STORE_NAME##_handle * p_store, ACTION_TYPE action); \
bool cedux_run_##STORE_NAME(struct STORE_NAME##_handle * p_store); \
void cedux_set_threadsafe_##STORE_NAME(struct STORE_NAME##_handle * p_store, void * lock, \
cedux_lock_func_t lock_get, cedux_lock_func_t lock_release); \
struct STORE_NAME##_handle \
{ \
TREE_TYPE tree; \
struct STORE_NAME##_action_queue action_queue; \
struct STORE_NAME##_reducer_list reducer_list; \
struct STORE_NAME##_subscriber_list subscriber_list; \
void *lock; \
cedux_lock_func_t lock_get; \
cedux_lock_func_t lock_release; \
};
#define CEDUX_DEFINE_STORE(TREE_TYPE, ACTION_TYPE, STORE_NAME) \
\
QUEUE_DEFINITION(STORE_NAME##_action_queue, ACTION_TYPE) \
LIST_DEFINITION(STORE_NAME##_reducer_list, STORE_NAME##_REDUCER) \
LIST_DEFINITION(STORE_NAME##_subscriber_list, struct STORE_NAME##_subscriber_container) \
\
void cedux_register_##STORE_NAME##_reducer(struct STORE_NAME##_handle * p_store, \
STORE_NAME##_REDUCER reducer) { \
STORE_NAME##_reducer_list_push(&p_store->reducer_list, &reducer); \
} \
\
void cedux_register_##STORE_NAME##_subscriber(struct STORE_NAME##_handle * p_store, \
STORE_NAME##_SUBSCRIBER subscriber, \
void * p_data) { \
cedux_register_##STORE_NAME##_linked_subscriber(p_store, subscriber, p_data, NULL); \
} \
\
void cedux_register_##STORE_NAME##_linked_subscriber(struct STORE_NAME##_handle * p_store, \
STORE_NAME##_SUBSCRIBER subscriber, \
void * p_data, \
STORE_NAME##_REDUCER linked_reducer) { \
struct STORE_NAME##_subscriber_container container; \
container.subscriber = subscriber; \
container.data = p_data; \
container.linked_reducer = linked_reducer; \
STORE_NAME##_subscriber_list_push(&p_store->subscriber_list, &container); \
} \
\
struct STORE_NAME##_handle cedux_init_##STORE_NAME(void) { \
struct STORE_NAME##_handle new_store; \
STORE_NAME##_action_queue_init(&new_store.action_queue); \
STORE_NAME##_reducer_list_init(&new_store.reducer_list); \
STORE_NAME##_subscriber_list_init(&new_store.subscriber_list); \
new_store.lock = NULL; \
new_store.lock_get = NULL; \
new_store.lock_release = NULL; \
return new_store; \
} \
\
void cedux_dispatch_##STORE_NAME(struct STORE_NAME##_handle * p_store, ACTION_TYPE action) { \
if (p_store->lock_get) p_store->lock_get(p_store->lock); \
STORE_NAME##_action_queue_enqueue(&p_store->action_queue, &action); \
if (p_store->lock_release) p_store->lock_release(p_store->lock); \
} \
\
bool cedux_run_##STORE_NAME(struct STORE_NAME##_handle * p_store) { \
ACTION_TYPE action; \
STORE_NAME##_REDUCER reducer; \
struct STORE_NAME##_subscriber_container subscriber_container; \
bool did_work = false; \
if (p_store->lock_get) p_store->lock_get(p_store->lock); \
while(STORE_NAME##_action_queue_dequeue(&p_store->action_queue, &action) == DEQUEUE_RESULT_SUCCESS) \
{ \
LIST_FOR_EACH(p_store->reducer_list, reducer) \
{ \
bool reducer_did_work = reducer(&p_store->tree, action); \
if (reducer_did_work) \
{ \
did_work = true; \
LIST_FOR_EACH(p_store->subscriber_list, subscriber_container) \
{ \
if (subscriber_container.linked_reducer == reducer) \
{ \
subscriber_container.subscriber(p_store, &p_store->tree, subscriber_container.data);\
} \
} \
} \
} \
} \
if (p_store->lock_release) p_store->lock_release(p_store->lock); \
if (did_work) \
{ \
LIST_FOR_EACH(p_store->subscriber_list, subscriber_container) \
{ \
if (subscriber_container.linked_reducer == NULL) { \
subscriber_container.subscriber(p_store, &p_store->tree, subscriber_container.data); \
} \
} \
} \
return did_work; \
} \
\
void cedux_set_threadsafe_##STORE_NAME(struct STORE_NAME##_handle * p_store, void * lock, \
cedux_lock_func_t lock_get, cedux_lock_func_t lock_release) \
{ \
p_store->lock = lock; \
p_store->lock_get = lock_get; \
p_store->lock_release = lock_release; \
}
#define STORE_TREE(STORE) STORE.tree
typedef void(*cedux_lock_func_t)(void *lock);
#endif