-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconvcluster.c
270 lines (225 loc) · 5.43 KB
/
convcluster.c
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#include "convcluster.h"
#define INFO_LVL 5
#include "info/info.h"
#include <stdlib.h>
#include <string.h>
#define MAX_PATH_LENGTH 512
struct CC_Task
{
enum CC_STATE start;
union CC_Data *input;
enum CC_STATE end;
void *additional;
union CC_Data *data;
struct CC_Context
{
struct CC_Rule *rules;
int rules_count;
enum CC_STATE previous[MAX_PATH_LENGTH];
int indexes[MAX_PATH_LENGTH];
int path_length;
int depth;
int load_depth;
} context;
bool valid;
};
typedef struct CC_Context* CC_Context;
struct CC_internal_step
{
enum CC_STATE in;
enum CC_STATE out;
};
#if INFO_LVL>4
static const char* CC_internal_STATE_names[] = {
FOREACH_FUNC(GENERATE_STRING)
"internal_state_counter",
"Unknown"
};
#endif
CC_Task CC_Task_create()
{
CC_Task task = malloc(sizeof(struct CC_Task));
memset(task, 0, sizeof(struct CC_Task));
task->start=UNKNOWN;
task->end=UNKNOWN;
return task;
}
bool CC_Task_target_set(CC_Task task, union CC_Data *data)
{
task->data=data;
return false;
}
bool CC_Task_state_start_set(CC_Task task, enum CC_STATE start)
{
if(start>COUNT){
start=UNKNOWN;
return true;
}
task->valid=false;
task->start=start;
return false;
}
bool CC_Task_state_end_set(CC_Task task, enum CC_STATE end)
{
if(end>COUNT){
end=UNKNOWN;
return true;
}
task->valid=false;
task->end=end;
return false;
}
bool CC_Task_additional_set(CC_Task task, void *data)
{
task->additional = data;
return false;
}
bool CC_Task_rules_set(CC_Task task, struct CC_Rule *rules, int rules_count)
{
task->valid=0;
task->context.rules = rules;
task->context.rules_count = rules_count;
return false;
}
void CC_Task_free(CC_Task task)
{
free(task);
}
bool CC_internal_is_previous_state(CC_Context context, enum CC_STATE state)
{
for(int i=0; i<context->depth; i++)
{
if(state==context->previous[i])
return true;
}
return false;
}
bool CC_internal_context_state_set(CC_Context context, enum CC_STATE state)
{
// set up context for next level
if(context->depth<0)
return true;
context->previous[context->depth]=state;
return false;
}
bool CC_internal_context_index_set(CC_Context context, int index)
{
context->indexes[context->depth] = index;
return false;
}
#if INFO_LVL > 4
void CC_internal_error_path(CC_Context context, int index)
{
PRINT(" [")
for(int i=0; i<context->path_length; i++)
{
if(i==index)
COLOR(255,0,0)
PRINT(CC_internal_STATE_names[context->previous[i]])
if(i==index)
COLOR(255,255,255)
if(i<context->path_length-1)
PRINT(", ")
}
PRINT("]")
}
#endif
bool CC_internal_solve(struct CC_internal_step task, CC_Context context)
{
if(context->depth>=MAX_PATH_LENGTH-1)
return true;
CC_internal_context_state_set(context, task.in);
// set start index if it has to be loaded
int start=0;
if(context->depth<context->load_depth){
start=context->indexes[context->depth];
}
context->depth++;
// look for direct path first
for(int i=start; i<context->rules_count; i++)
{
if(context->rules[i].in==task.in && context->rules[i].out==task.out){
HOLD
INFO("Found conversion path! depth: %d", context->depth)
#if INFO_LVL > 4
CC_internal_error_path(context, -1);
#endif
RELEASE
context->path_length=context->depth;
// push index for potential continuation
context->depth--;
CC_internal_context_index_set(context, i);
return false;
}
}
// try all subpaths
for(int i=start; i<context->rules_count; i++)
{
if(context->rules[i].in==task.in && !CC_internal_is_previous_state(context, context->rules[i].out)){
struct CC_internal_step child = { context->rules[i].out, task.out };
if(!CC_internal_solve(child, context)){
context->depth--;
// push index for potential continuation
CC_internal_context_index_set(context, i);
return false;
}
}
}
context->depth--;
return true;
}
void CC_internal_continue(CC_Context context)
{
// setup context to continue search after current path
// force loops to load startvalue
context->load_depth=context->depth+1;
// skip last path
context->indexes[context->depth]++;
}
bool CC_solve(CC_Task task)
{
task->context.depth=0;
task->context.load_depth=0;
if(task->start == UNKNOWN || task->end == UNKNOWN) {
ERROR("Task contains unknown fields!")
return true;
}
// if gaol already reached
if(task->start==task->end)
goto success;
struct CC_internal_step step = { task->start, task->end };
if(!task->valid){
#if INFO_LVL > 4
INFO("Searching conversion Path! %s -> %s", CC_internal_STATE_names[task->start], CC_internal_STATE_names[task->end])
#else
INFO("Searching conversion Path!")
#endif
search:
if(CC_internal_solve(step, &task->context)){
ERROR("Cannot find conversion path!")
return true;
}
}
SEG_BEGIN("Excecute conversion path")
for(int i=0; i<task->context.path_length; i++)
{
if(task->context.rules[task->context.indexes[i]].convert(task->data, task->additional)){
HOLD
ERROR("Path exceution failed!")
#if INFO_LVL > 4
CC_internal_error_path(&task->context, i);
#endif
RELEASE
task->valid=false;
CC_internal_continue(&task->context);
SEG_END
INFO("Continue search!")
goto search;
}
}
SEG_END
success:
task->valid=true;
SUCCESS("Conversion was successful!")
return false;
}