1 /************************************************************************
2 ** **
3 ** The YapTab/YapOr/OPTYap systems **
4 ** **
5 ** YapTab extends the Yap Prolog engine to support sequential tabling **
6 ** YapOr extends the Yap Prolog engine to support or-parallelism **
7 ** OPTYap extends the Yap Prolog engine to support or-parallel tabling **
8 ** **
9 ** **
10 ** Yap Prolog was developed at University of Porto, Portugal **
11 ** **
12 ************************************************************************/
13
14 /* -------------------- **
15 ** Prototypes **
16 ** -------------------- */
17
18 /* get a def for NULL */
19 #include <stdlib.h>
20
21 STD_PROTO(static inline void PUT_IN_EXECUTING, (int));
22 STD_PROTO(static inline void PUT_OUT_EXECUTING, (int));
23 STD_PROTO(static inline void PUT_IN_FINISHED, (int));
24 #ifdef TABLING_INNER_CUTS
25 STD_PROTO(static inline void PUT_IN_PRUNING, (int));
26 STD_PROTO(static inline void PUT_OUT_PRUNING, (int));
27 #endif /* TABLING_INNER_CUTS */
28
29 STD_PROTO(static inline void PUT_IN_REQUESTABLE, (int));
30 STD_PROTO(static inline void PUT_OUT_REQUESTABLE, (int));
31 STD_PROTO(static inline void SCH_update_local_or_tops, (void));
32 STD_PROTO(static inline void SCH_refuse_share_request_if_any, (void));
33 STD_PROTO(static inline void SCH_set_load, (choiceptr));
34 STD_PROTO(static inline void SCH_new_alternative, (yamop *,yamop *));
35
36 STD_PROTO(static inline void CUT_send_prune_request, (int, choiceptr));
37 STD_PROTO(static inline void CUT_reset_prune_request, (void));
38
39 STD_PROTO(static inline int CUT_last_worker_left_pending_prune, (or_fr_ptr));
40 STD_PROTO(static inline or_fr_ptr CUT_leftmost_or_frame, (void));
41 #ifdef TABLING_INNER_CUTS
42 STD_PROTO(static inline or_fr_ptr CUT_leftmost_until, (or_fr_ptr, int));
43 #endif /* TABLING_INNER_CUTS */
44
45 STD_PROTO(static inline void CUT_store_answer, (or_fr_ptr, qg_ans_fr_ptr));
46 STD_PROTO(static inline void CUT_store_answers, (or_fr_ptr, qg_sol_fr_ptr));
47 STD_PROTO(static inline void CUT_join_answers_in_an_unique_frame, (qg_sol_fr_ptr));
48 STD_PROTO(static inline void CUT_free_solution_frame, (qg_sol_fr_ptr));
49 STD_PROTO(static inline void CUT_free_solution_frames, (qg_sol_fr_ptr));
50 STD_PROTO(static inline qg_sol_fr_ptr CUT_prune_solution_frames, (qg_sol_fr_ptr, int));
51
52
53
54 /* ---------------------------- **
55 ** Instruction Macros **
56 ** ---------------------------- */
57
58 #if SIZEOF_INT == 2
59 #define YAMOP_CUT_FLAG 0x8000
60 #define YAMOP_SEQ_FLAG 0x4000
61 #define YAMOP_FLAGS_BITS 0xc000
62 #define YAMOP_LTT_BITS 0x3fff
63 #elif SIZEOF_INT == 4
64 #define YAMOP_CUT_FLAG 0x80000000
65 #define YAMOP_SEQ_FLAG 0x40000000
66 #define YAMOP_FLAGS_BITS 0xc0000000
67 #define YAMOP_LTT_BITS 0x3fffffff
68 #elif SIZEOF_INT == 8
69 #define YAMOP_CUT_FLAG 0x8000000000000000
70 #define YAMOP_SEQ_FLAG 0x4000000000000000
71 #define YAMOP_FLAGS_BITS 0xc000000000000000
72 #define YAMOP_LTT_BITS 0x3fffffffffffffff
73 #else
74 #define YAMOP_CUT_FLAG OOOOPPS!!! Unknown Integer Sizeof
75 #define YAMOP_SEQ_FLAG OOOOPPS!!! Unknown Integer Sizeof
76 #define YAMOP_FLAGS_BITS OOOOPPS!!! Unknown Integer Sizeof
77 #define YAMOP_LTT_BITS OOOOPPS!!! Unknown Integer Sizeof
78 #endif /* SIZEOF_INT */
79
80 #define YAMOP_OR_ARG(INST) ((INST)->u.Otapl.or_arg)
81 #define YAMOP_LTT(INST) (((INST)->u.Otapl.or_arg) & YAMOP_LTT_BITS)
82 #define YAMOP_SEQ(INST) (((INST)->u.Otapl.or_arg) & YAMOP_SEQ_FLAG)
83 #define YAMOP_CUT(INST) (((INST)->u.Otapl.or_arg) & YAMOP_CUT_FLAG)
84 #define YAMOP_FLAGS(INST) (((INST)->u.Otapl.or_arg) & YAMOP_FLAGS_BITS)
85
86 #define INIT_YAMOP_LTT(INST, LTT) ((INST)->u.Otapl.or_arg = LTT+1)
87 #define PUT_YAMOP_LTT(INST, LTT) (INST)->u.Otapl.or_arg = YAMOP_FLAGS(INST) | (LTT+1)
88 #define PUT_YAMOP_SEQ(INST) (INST)->u.Otapl.or_arg |= YAMOP_SEQ_FLAG
89 #define PUT_YAMOP_CUT(INST) (INST)->u.Otapl.or_arg |= YAMOP_CUT_FLAG
90
91 #define BRANCH(WORKER, DEPTH) GLOBAL_branch(WORKER, DEPTH)
92 #define BRANCH_LTT(WORKER, DEPTH) (BRANCH(WORKER, DEPTH) & YAMOP_LTT_BITS)
93 #define BRANCH_CUT(WORKER, DEPTH) (BRANCH(WORKER, DEPTH) & YAMOP_CUT_FLAG)
94
95
96
97 /* ---------------------------- **
98 ** Performance Macros **
99 ** ---------------------------- */
100
101 #define PERFORMANCE_OFF 0x0
102 #define PERFORMANCE_ON 0x1
103 #define PERFORMANCE_IN_EXECUTION 0x2
104
105
106
107 /* ----------------------- **
108 ** Engine Macros **
109 ** ----------------------- */
110
111 #define LOCK_OR_FRAME(fr) LOCK(OrFr_lock(fr))
112 #define UNLOCK_OR_FRAME(fr) UNLOCK(OrFr_lock(fr))
113
114 #define LOCK_WORKER(w) LOCK(REMOTE_lock(w))
115 #define UNLOCK_WORKER(w) UNLOCK(REMOTE_lock(w))
116
117
118
119 /* -------------------------- **
120 ** Scheduler Macros **
121 ** -------------------------- */
122
123 #define SCH_top_shared_cp(CP) (Get_LOCAL_top_cp() == CP)
124
125 #define SCH_any_share_request (LOCAL_share_request != MAX_WORKERS)
126
127 #define SCHEDULER_GET_WORK() \
128 if (get_work()) \
129 goto shared_fail; \
130 else \
131 goto shared_end
132
133 #define SCH_check_prune_request() \
134 if (Get_LOCAL_prune_request()) { \
135 SCHEDULER_GET_WORK(); \
136 }
137
138 #if defined(ENV_COPY) || defined(SBA) || defined(THREADS)
139 #define SCH_check_share_request() \
140 if (SCH_any_share_request) { \
141 ASP = YENV; \
142 saveregs(); \
143 p_share_work(); \
144 setregs(); \
145 }
146 #else /* ACOW */
147 #define SCH_check_share_request() \
148 if (SCH_any_share_request) { \
149 if (! p_share_work()) \
150 goto shared_fail; \
151 }
152 #endif /* ENV_COPY || SBA || ACOW */
153
154 #define SCH_check_requests() \
155 SCH_check_prune_request(); \
156 SCH_check_share_request()
157
158 #define SCH_last_alternative(curpc, CP_PTR) \
159 H = HBREG = PROTECT_FROZEN_H(CP_PTR); \
160 CPREG = CP_PTR->cp_cp; \
161 ENV = CP_PTR->cp_env; \
162 SCH_new_alternative(curpc, NULL)
163
164
165
166 /* -------------------- **
167 ** Cut Macros **
168 ** -------------------- */
169
170 #define CUT_prune_to(PRUNE_CP) \
171 if (YOUNGER_CP(Get_LOCAL_top_cp(), PRUNE_CP)) { \
172 if (! Get_LOCAL_prune_request()) \
173 prune_shared_branch(PRUNE_CP); \
174 PRUNE_CP = Get_LOCAL_top_cp(); \
175 }
176
177 #define CUT_wait_leftmost() \
178 if (PARALLEL_EXECUTION_MODE) { \
179 /* parallel execution mode --> wait until leftmost */ \
180 int i, loop, depth, ltt; \
181 bitmap members; \
182 or_fr_ptr leftmost_or_fr; \
183 leftmost_or_fr = LOCAL_top_or_fr; \
184 do { \
185 depth = OrFr_depth(leftmost_or_fr); \
186 ltt = BRANCH_LTT(worker_id, depth); \
187 do { \
188 loop = FALSE; \
189 SCH_check_requests(); \
190 BITMAP_copy(members, OrFr_members(leftmost_or_fr)); \
191 BITMAP_delete(members, worker_id); \
192 for (i = 0; i < number_workers; i++) { \
193 /* not leftmost in current frame if there is a */ \
194 /* worker in a left branch and it is not idle or */ \
195 /* if it is idle it is in a younger node */ \
196 if (BITMAP_member(members, i) && \
197 BRANCH_LTT(i, depth) > ltt && \
198 (! BITMAP_member(GLOBAL_bm_idle_workers, i) || \
199 leftmost_or_fr != REMOTE_top_or_fr(i))) { \
200 loop = TRUE; \
201 break; \
202 } \
203 } \
204 } while (loop); \
205 leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr); \
206 } while (leftmost_or_fr != GLOBAL_root_or_fr); \
207 }
208
209
210
211 /* ---------------------- **
212 ** Engine Stuff **
213 ** ---------------------- */
214
215 static inline
PUT_IN_EXECUTING(int w)216 void PUT_IN_EXECUTING(int w) {
217 LOCK(GLOBAL_LOCKS_bm_executing_workers);
218 BITMAP_insert(GLOBAL_bm_executing_workers, w);
219 UNLOCK(GLOBAL_LOCKS_bm_executing_workers);
220 return;
221 }
222
223
224 static inline
PUT_OUT_EXECUTING(int w)225 void PUT_OUT_EXECUTING(int w) {
226 LOCK(GLOBAL_LOCKS_bm_executing_workers);
227 BITMAP_delete(GLOBAL_bm_executing_workers, w);
228 UNLOCK(GLOBAL_LOCKS_bm_executing_workers);
229 return;
230 }
231
232
233 static inline
PUT_IN_FINISHED(int w)234 void PUT_IN_FINISHED(int w) {
235 LOCK(GLOBAL_LOCKS_bm_finished_workers);
236 BITMAP_insert(GLOBAL_bm_finished_workers, w);
237 UNLOCK(GLOBAL_LOCKS_bm_finished_workers);
238 return;
239 }
240
241
242 #ifdef TABLING_INNER_CUTS
243 static inline
PUT_IN_PRUNING(int w)244 void PUT_IN_PRUNING(int w) {
245 LOCK(GLOBAL_LOCKS_bm_pruning_workers);
246 BITMAP_insert(GLOBAL_bm_pruning_workers, w);
247 UNLOCK(GLOBAL_LOCKS_bm_pruning_workers);
248 return;
249 }
250
251
252 static inline
PUT_OUT_PRUNING(int w)253 void PUT_OUT_PRUNING(int w) {
254 LOCK(GLOBAL_LOCKS_bm_pruning_workers);
255 BITMAP_delete(GLOBAL_bm_pruning_workers, w);
256 UNLOCK(GLOBAL_LOCKS_bm_pruning_workers);
257 return;
258 }
259 #endif /* TABLING_INNER_CUTS */
260
261
262
263 /* ------------------------- **
264 ** Scheduler Stuff **
265 ** ------------------------- */
266
267 static inline
PUT_IN_REQUESTABLE(int p)268 void PUT_IN_REQUESTABLE(int p) {
269 LOCK(GLOBAL_LOCKS_bm_requestable_workers);
270 BITMAP_insert(GLOBAL_bm_requestable_workers, p);
271 UNLOCK(GLOBAL_LOCKS_bm_requestable_workers);
272 return;
273 }
274
275
276 static inline
PUT_OUT_REQUESTABLE(int p)277 void PUT_OUT_REQUESTABLE(int p) {
278 LOCK(GLOBAL_LOCKS_bm_requestable_workers);
279 BITMAP_delete(GLOBAL_bm_requestable_workers, p);
280 UNLOCK(GLOBAL_LOCKS_bm_requestable_workers);
281 return;
282 }
283
284
285 static inline
SCH_update_local_or_tops(void)286 void SCH_update_local_or_tops(void) {
287 Set_LOCAL_top_cp(Get_LOCAL_top_cp()->cp_b);
288 LOCAL_top_or_fr = Get_LOCAL_top_cp()->cp_or_fr;
289 return;
290 }
291
292
293 static inline
SCH_refuse_share_request_if_any(void)294 void SCH_refuse_share_request_if_any(void) {
295 if (SCH_any_share_request) {
296 REMOTE_reply_signal(LOCAL_share_request) = no_sharing;
297 LOCAL_share_request = MAX_WORKERS;
298 PUT_OUT_REQUESTABLE(worker_id);
299 }
300 return;
301 }
302
303
304 static inline
SCH_set_load(choiceptr current_cp)305 void SCH_set_load(choiceptr current_cp) {
306 Int lub; /* local untried branches */
307 choiceptr previous_cp = current_cp->cp_b;
308
309 #define INIT_CP_LUB(CP, LUB) CP->cp_or_fr = (struct or_frame *)(LUB)
310 #define CP_LUB(CP) (Int)(CP->cp_or_fr)
311
312 if (SCH_top_shared_cp(previous_cp))
313 lub = 0;
314 else if (YAMOP_SEQ(previous_cp->cp_ap))
315 lub = CP_LUB(previous_cp);
316 else
317 lub = CP_LUB(previous_cp) + YAMOP_LTT(previous_cp->cp_ap);
318 INIT_CP_LUB(current_cp, lub);
319
320 if (YAMOP_SEQ(current_cp->cp_ap))
321 LOCAL_load = lub;
322 else
323 LOCAL_load = lub + YAMOP_LTT(current_cp->cp_ap);
324 return;
325 }
326
327 static inline
SCH_new_alternative(yamop * curpc,yamop * new)328 void SCH_new_alternative(yamop *curpc, yamop *new) {
329 OrFr_alternative(LOCAL_top_or_fr) = new;
330 BRANCH(worker_id, OrFr_depth(LOCAL_top_or_fr)) = YAMOP_OR_ARG(curpc);
331 UNLOCK_OR_FRAME(LOCAL_top_or_fr);
332 return;
333 }
334
335
336
337 /* ---------------------------- **
338 ** Cut Stuff: Pruning **
339 ** ---------------------------- */
340
341 static inline
CUT_send_prune_request(int worker,choiceptr prune_cp)342 void CUT_send_prune_request(int worker, choiceptr prune_cp) {
343 LOCK_WORKER(worker);
344 if (YOUNGER_CP(REMOTE_top_cp(worker), prune_cp) &&
345 (! Get_REMOTE_prune_request(worker) || YOUNGER_CP(Get_REMOTE_prune_request(worker), prune_cp)))
346 Set_REMOTE_prune_request(worker, prune_cp);
347 UNLOCK_WORKER(worker);
348 return;
349 }
350
351
352 static inline
CUT_reset_prune_request(void)353 void CUT_reset_prune_request(void) {
354 LOCK_WORKER(worker_id);
355 if (Get_LOCAL_prune_request() && EQUAL_OR_YOUNGER_CP(Get_LOCAL_prune_request(), Get_LOCAL_top_cp()))
356 Set_LOCAL_prune_request(NULL);
357 UNLOCK_WORKER(worker_id);
358 return;
359 }
360
361
362
363 /* ----------------------------- **
364 ** Cut Stuff: Leftmost **
365 ** ----------------------------- */
366
367 static inline
CUT_last_worker_left_pending_prune(or_fr_ptr or_frame)368 int CUT_last_worker_left_pending_prune(or_fr_ptr or_frame) {
369 int i, depth, ltt;
370 bitmap members;
371
372 depth = OrFr_depth(or_frame);
373 ltt = OrFr_pend_prune_ltt(or_frame);
374 members = OrFr_members(or_frame);
375 BITMAP_delete(members, worker_id);
376 for (i = 0; i < number_workers; i++) {
377 if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt)
378 return FALSE;
379 }
380 return TRUE;
381 }
382
383
384 static inline
CUT_leftmost_or_frame(void)385 or_fr_ptr CUT_leftmost_or_frame(void) {
386 int i, depth, ltt;
387 bitmap members;
388 or_fr_ptr leftmost_or_fr, or_fr, nearest_or_fr;
389
390 BITMAP_clear(members);
391 BITMAP_insert(members, worker_id);
392 leftmost_or_fr = LOCAL_top_or_fr;
393 depth = OrFr_depth(leftmost_or_fr);
394 do {
395 ltt = BRANCH_LTT(worker_id, depth);
396 BITMAP_difference(members, OrFr_members(leftmost_or_fr), members);
397 if (members)
398 for (i = 0; i < number_workers; i++)
399 if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt)
400 goto update_nearest_leftnode_data;
401 BITMAP_copy(members, OrFr_members(leftmost_or_fr));
402 leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr);
403 depth = OrFr_depth(leftmost_or_fr);
404 } while (depth);
405
406 update_nearest_leftnode_data:
407 or_fr = LOCAL_top_or_fr;
408 nearest_or_fr = OrFr_nearest_leftnode(or_fr);
409 while (OrFr_depth(nearest_or_fr) > depth) {
410 LOCK_OR_FRAME(or_fr);
411 OrFr_nearest_leftnode(or_fr) = leftmost_or_fr;
412 UNLOCK_OR_FRAME(or_fr);
413 or_fr = nearest_or_fr;
414 nearest_or_fr = OrFr_nearest_leftnode(or_fr);
415 }
416
417 return leftmost_or_fr;
418 }
419
420
421 #ifdef TABLING_INNER_CUTS
422 static inline
CUT_leftmost_until(or_fr_ptr start_or_fr,int until_depth)423 or_fr_ptr CUT_leftmost_until(or_fr_ptr start_or_fr, int until_depth) {
424 int i, ltt, depth;
425 bitmap prune_members, members;
426 or_fr_ptr leftmost_or_fr, nearest_or_fr;
427
428 /* we assume that the start_or_fr frame is locked and empty (without members) */
429 leftmost_or_fr = OrFr_nearest_leftnode(start_or_fr);
430 depth = OrFr_depth(leftmost_or_fr);
431 if (depth > until_depth) {
432 BITMAP_copy(prune_members, GLOBAL_bm_pruning_workers);
433 BITMAP_delete(prune_members, worker_id);
434 ltt = BRANCH_LTT(worker_id, depth);
435 BITMAP_intersection(members, prune_members, OrFr_members(leftmost_or_fr));
436 if (members) {
437 for (i = 0; i < number_workers; i++) {
438 if (BITMAP_member(members, i) &&
439 BRANCH_LTT(i, depth) > ltt &&
440 EQUAL_OR_YOUNGER_CP(GetOrFr_node(leftmost_or_fr), REMOTE_pruning_scope(i)))
441 return leftmost_or_fr;
442 }
443 BITMAP_minus(prune_members, members);
444 }
445 /* reaching that point we should update the nearest leftnode data before return */
446 leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr);
447 depth = OrFr_depth(leftmost_or_fr);
448 while (depth > until_depth) {
449 ltt = BRANCH_LTT(worker_id, depth);
450 BITMAP_intersection(members, prune_members, OrFr_members(leftmost_or_fr));
451 if (members) {
452 for (i = 0; i < number_workers; i++) {
453 if (BITMAP_member(members, i) &&
454 BRANCH_LTT(i, depth) > ltt &&
455 EQUAL_OR_YOUNGER_CP(GetOrFr_node(leftmost_or_fr), REMOTE_pruning_scope(i))) {
456 /* update nearest leftnode data */
457 OrFr_nearest_leftnode(start_or_fr) = leftmost_or_fr;
458 start_or_fr = OrFr_nearest_leftnode(start_or_fr);
459 nearest_or_fr = OrFr_nearest_leftnode(start_or_fr);
460 while (OrFr_depth(nearest_or_fr) > depth) {
461 LOCK_OR_FRAME(start_or_fr);
462 OrFr_nearest_leftnode(start_or_fr) = leftmost_or_fr;
463 UNLOCK_OR_FRAME(start_or_fr);
464 start_or_fr = nearest_or_fr;
465 nearest_or_fr = OrFr_nearest_leftnode(start_or_fr);
466 }
467 return leftmost_or_fr;
468 }
469 }
470 BITMAP_minus(prune_members, members);
471 }
472 leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr);
473 depth = OrFr_depth(leftmost_or_fr);
474 }
475 /* update nearest leftnode data */
476 OrFr_nearest_leftnode(start_or_fr) = leftmost_or_fr;
477 start_or_fr = OrFr_nearest_leftnode(start_or_fr);
478 nearest_or_fr = OrFr_nearest_leftnode(start_or_fr);
479 while (OrFr_depth(nearest_or_fr) > depth) {
480 LOCK_OR_FRAME(start_or_fr);
481 OrFr_nearest_leftnode(start_or_fr) = leftmost_or_fr;
482 UNLOCK_OR_FRAME(start_or_fr);
483 start_or_fr = nearest_or_fr;
484 nearest_or_fr = OrFr_nearest_leftnode(start_or_fr);
485 }
486 }
487 return NULL;
488 }
489 #endif /* TABLING_INNER_CUTS */
490
491
492
493 /* ------------------------------------------------ **
494 ** Cut Stuff: Managing query goal answers **
495 ** ------------------------------------------------ */
496
497 static inline
CUT_store_answer(or_fr_ptr or_frame,qg_ans_fr_ptr new_answer)498 void CUT_store_answer(or_fr_ptr or_frame, qg_ans_fr_ptr new_answer) {
499 int ltt;
500 qg_sol_fr_ptr *solution_ptr;
501
502 ltt = BRANCH_LTT(worker_id, OrFr_depth(or_frame));
503 solution_ptr = & OrFr_qg_solutions(or_frame);
504 while (*solution_ptr && ltt > SolFr_ltt(*solution_ptr)) {
505 solution_ptr = & SolFr_next(*solution_ptr);
506 }
507 if (*solution_ptr && ltt == SolFr_ltt(*solution_ptr)) {
508 AnsFr_next(SolFr_last(*solution_ptr)) = new_answer;
509 SolFr_last(*solution_ptr) = new_answer;
510 } else {
511 qg_sol_fr_ptr new_solution;
512 ALLOC_QG_SOLUTION_FRAME(new_solution);
513 SolFr_next(new_solution) = *solution_ptr;
514 SolFr_ltt(new_solution) = ltt;
515 SolFr_first(new_solution) = new_answer;
516 SolFr_last(new_solution) = new_answer;
517 *solution_ptr = new_solution;
518 }
519 return;
520 }
521
522
523 static inline
CUT_store_answers(or_fr_ptr or_frame,qg_sol_fr_ptr new_solution)524 void CUT_store_answers(or_fr_ptr or_frame, qg_sol_fr_ptr new_solution) {
525 int ltt;
526 qg_sol_fr_ptr *solution_ptr;
527
528 ltt = BRANCH_LTT(worker_id, OrFr_depth(or_frame));
529 solution_ptr = & OrFr_qg_solutions(or_frame);
530 while (*solution_ptr && ltt > SolFr_ltt(*solution_ptr)) {
531 solution_ptr = & SolFr_next(*solution_ptr);
532 }
533 if (*solution_ptr && ltt == SolFr_ltt(*solution_ptr)) {
534 AnsFr_next(SolFr_last(*solution_ptr)) = SolFr_first(new_solution);
535 SolFr_last(*solution_ptr) = SolFr_last(new_solution);
536 FREE_QG_SOLUTION_FRAME(new_solution);
537 } else {
538 SolFr_next(new_solution) = *solution_ptr;
539 SolFr_ltt(new_solution) = ltt;
540 *solution_ptr = new_solution;
541 }
542 return;
543 }
544
545
546 static inline
CUT_join_answers_in_an_unique_frame(qg_sol_fr_ptr join_solution)547 void CUT_join_answers_in_an_unique_frame(qg_sol_fr_ptr join_solution) {
548 qg_sol_fr_ptr next_solution;
549
550 while ((next_solution = SolFr_next(join_solution))) {
551 AnsFr_next(SolFr_last(join_solution)) = SolFr_first(next_solution);
552 SolFr_last(join_solution) = SolFr_last(next_solution);
553 SolFr_next(join_solution) = SolFr_next(next_solution);
554 FREE_QG_SOLUTION_FRAME(next_solution);
555 }
556 return;
557 }
558
559
560 static inline
CUT_free_solution_frame(qg_sol_fr_ptr solution)561 void CUT_free_solution_frame(qg_sol_fr_ptr solution) {
562 qg_ans_fr_ptr current_answer, next_answer;
563
564 current_answer = SolFr_first(solution);
565 do {
566 next_answer = AnsFr_next(current_answer);
567 FREE_QG_ANSWER_FRAME(current_answer);
568 current_answer = next_answer;
569 } while (current_answer);
570 FREE_QG_SOLUTION_FRAME(solution);
571 return;
572 }
573
574
575 static inline
CUT_free_solution_frames(qg_sol_fr_ptr current_solution)576 void CUT_free_solution_frames(qg_sol_fr_ptr current_solution) {
577 qg_sol_fr_ptr next_solution;
578
579 while (current_solution) {
580 next_solution = SolFr_next(current_solution);
581 CUT_free_solution_frame(current_solution);
582 current_solution = next_solution;
583 }
584 return;
585 }
586
587
588 static inline
CUT_prune_solution_frames(qg_sol_fr_ptr solutions,int ltt)589 qg_sol_fr_ptr CUT_prune_solution_frames(qg_sol_fr_ptr solutions, int ltt) {
590 qg_sol_fr_ptr next_solution;
591
592 while (solutions && ltt > SolFr_ltt(solutions)) {
593 next_solution = SolFr_next(solutions);
594 CUT_free_solution_frame(solutions);
595 solutions = next_solution;
596 }
597 return solutions;
598 }
599