[m-dev.] for review: use `impure' to implement builtin_aggregate
Fergus Henderson
fjh at cs.mu.OZ.AU
Tue Oct 19 05:32:49 AEST 1999
Estimated hours taken: 4
library/std_util.m:
Implement `builtin_aggregate' using impure Mercury
and some `pragma c_code' fragments, rather than
using completely hand-coded low-level C code.
This has several benefits:
- it should allow the accurate garbage collector
to trace code using solutions/2, without
needing to hand-code the liveness information
- the compiler can specialize the higher-order
calls in builtin_aggregate
- the code is simpler and much more high-level,
and thus should be easier to maintain.
Workspace: /d-drive/home/hg/fjh/mercury
Index: library/std_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/std_util.m,v
retrieving revision 1.164
diff -u -c -r1.164 std_util.m
cvs diff: conflicting specifications of output style
*** library/std_util.m 1999/10/18 11:13:41 1.164
--- library/std_util.m 1999/10/18 19:12:30
***************
*** 482,487 ****
--- 482,494 ----
%-----------------------------------------------------------------------------%
+ /*
+ ** This section defines builtin_aggregate/4 which takes a closure of type
+ ** pred(T) in which the remaining argument is output, and backtracks over
+ ** solutions for this, using the second argument to aggregate them however the
+ ** user wishes. This is basically a generalization of solutions/2.
+ */
+
:- pred builtin_aggregate(pred(T), pred(T, U, U), U, U).
:- mode builtin_aggregate(pred(out) is multi, pred(in, in, out) is det,
in, out) is det. /* really cc_multi */
***************
*** 496,594 ****
:- mode builtin_aggregate(pred(muo) is nondet, pred(mdi, di, uo) is det,
di, uo) is det. /* really cc_multi */
- :- external(builtin_aggregate/4).
- % builtin_aggregate is implemented in c_code.
-
- :- pragma c_code("
-
- /*
- ** This module defines builtin_aggregate/4 which takes a closure of type
- ** pred(T) in which the remaining argument is output, and backtracks over
- ** solutions for this, using the second argument to aggregate them however the
- ** user wishes. This is basically a generalization of solutions/2.
- */
-
- #include ""mercury_imp.h""
- #include ""mercury_deep_copy.h""
-
- Declare_entry(mercury__do_call_closure);
-
- Define_extern_entry(mercury__std_util__builtin_aggregate_4_0);
- Define_extern_entry(mercury__std_util__builtin_aggregate_4_1);
- Define_extern_entry(mercury__std_util__builtin_aggregate_4_2);
- Define_extern_entry(mercury__std_util__builtin_aggregate_4_3);
- Define_extern_entry(mercury__std_util__builtin_aggregate_4_4);
- Define_extern_entry(mercury__std_util__builtin_aggregate_4_5);
- Declare_label(mercury__std_util__builtin_aggregate_4_0_i1);
- Declare_label(mercury__std_util__builtin_aggregate_4_0_i2);
- Declare_label(mercury__std_util__builtin_aggregate_4_0_i3);
-
- MR_MAKE_PROC_LAYOUT(mercury__std_util__builtin_aggregate_4_0,
- MR_DETISM_MULTI, MR_ENTRY_NO_SLOT_COUNT, MR_LONG_LVAL_TYPE_UNKNOWN,
- MR_PREDICATE, ""std_util"", ""builtin_aggregate"", 4, 0);
-
- MR_MAKE_INTERNAL_LAYOUT(mercury__std_util__builtin_aggregate_4_0, 1);
- MR_MAKE_INTERNAL_LAYOUT(mercury__std_util__builtin_aggregate_4_0, 2);
- MR_MAKE_INTERNAL_LAYOUT(mercury__std_util__builtin_aggregate_4_0, 3);
-
- BEGIN_MODULE(builtin_aggregate_module)
- init_entry_sl(mercury__std_util__builtin_aggregate_4_0);
- MR_INIT_PROC_LAYOUT_ADDR(mercury__std_util__builtin_aggregate_4_0);
- init_entry(mercury__std_util__builtin_aggregate_4_1);
- init_entry(mercury__std_util__builtin_aggregate_4_2);
- init_entry(mercury__std_util__builtin_aggregate_4_3);
- init_entry(mercury__std_util__builtin_aggregate_4_4);
- init_entry(mercury__std_util__builtin_aggregate_4_5);
- init_label_sl(mercury__std_util__builtin_aggregate_4_0_i1);
- init_label_sl(mercury__std_util__builtin_aggregate_4_0_i2);
- init_label_sl(mercury__std_util__builtin_aggregate_4_0_i3);
- BEGIN_CODE
-
/*
- ** :- pred builtin_aggregate(pred(T), pred(T,T2,T2), T2, T2).
- ** :- mode builtin_aggregate(pred([out/muo]) is [multi/nondet],
- ** pred([in/mdi],[in/di],[out/uo]) is det, in, out) is cc_multi.
- **
- ** Polymorphism will add two extra input parameters, type_infos for T and T2,
- ** which we don't use at the moment (later they could be used to find
- ** the address of the respective deep copy routines).
- **
- ** The type_info structures will be in r1 and r2, the closures will be in
- ** r3 and r4, and the 'initial value' will be in r5.
- */
-
- #ifdef PROFILE_CALLS
- #define fallthru(target, caller) { tailcall((target), (caller)); }
- #else
- #define fallthru(target, caller)
- #endif
-
- Define_entry(mercury__std_util__builtin_aggregate_4_1);
- fallthru(ENTRY(mercury__std_util__builtin_aggregate_4_0),
- LABEL(mercury__std_util__builtin_aggregate_4_1))
- Define_entry(mercury__std_util__builtin_aggregate_4_2);
- fallthru(ENTRY(mercury__std_util__builtin_aggregate_4_0),
- LABEL(mercury__std_util__builtin_aggregate_4_2))
- Define_entry(mercury__std_util__builtin_aggregate_4_3);
- fallthru(ENTRY(mercury__std_util__builtin_aggregate_4_0),
- LABEL(mercury__std_util__builtin_aggregate_4_3))
- Define_entry(mercury__std_util__builtin_aggregate_4_4);
- fallthru(ENTRY(mercury__std_util__builtin_aggregate_4_0),
- LABEL(mercury__std_util__builtin_aggregate_4_4))
- Define_entry(mercury__std_util__builtin_aggregate_4_5);
- fallthru(ENTRY(mercury__std_util__builtin_aggregate_4_0),
- LABEL(mercury__std_util__builtin_aggregate_4_5))
- Define_entry(mercury__std_util__builtin_aggregate_4_0);
-
- #ifndef CONSERVATIVE_GC
-
- #ifndef USE_TYPE_LAYOUT
- fatal_error(""builtin_aggregate/4 not supported with this grade ""
- ""on this system.\\n""
- ""Try using a `.gc' (conservative gc) grade.\\n"");
- #endif
-
- /*
** In order to implement any sort of code that requires terms to survive
** backtracking, we need to (deeply) copy them out of the heap and into some
** other area before backtracking. The obvious thing to do then is just call
--- 503,509 ----
***************
*** 625,929 ****
** are 'swapped.' This will work out fine, because the real heap isn't needed
** while the collector pred is executing, and by the time the nested do_ is
** completed, the 'real' heap pointer will have been reset.
*/
! /* Define a macro to swap the heap and solutions heap */
! #define swap_heap_and_solutions_heap() \
! do { \
! Word temp; \
! temp = (Word) MR_ENGINE(heap_zone); \
! MR_ENGINE(heap_zone) = MR_ENGINE(solutions_heap_zone); \
! LVALUE_CAST(Word, MR_ENGINE(solutions_heap_zone)) = temp; \
! temp = (Word) MR_hp; \
! MR_hp = MR_sol_hp; \
! LVALUE_CAST(Word, MR_sol_hp) = temp; \
! } while (0)
!
! /*
! ** Define some framevars we will be using - we need to keep the
! ** value of hp and the solutions hp (solhp) before we entered
! ** solutions, so we can reset the hp after each solution, and
! ** reset the solhp after all solutions have been found.
! ** To do a deep copy, we need the type_info of the type of a solution,
! ** so we save the type_info in type_info_fv.
! ** Finally, we store the collection of solutions so far in sofar_fv.
! */
! #ifdef MR_USE_TRAIL
! #define num_framevars 7
! #else
! #define num_framevars 6
! #endif
! #define saved_hp_fv (MR_framevar(1))
! #define saved_solhp_fv (MR_framevar(2))
! #define collector_pred_fv (MR_framevar(3))
! #define sofar_fv (MR_framevar(4))
! #define element_type_info_fv (MR_framevar(5))
! #define collection_type_info_fv (MR_framevar(6))
! #ifdef MR_USE_TRAIL
! #define saved_trail_ticket_fv (MR_framevar(7))
! #endif
! /*
! ** Create a nondet frame and set the failure continuation.
! ** The frame slots are used to hold heap and trail states and the
! ** collector pred and the collection, and type infos for copying
! ** each solution, and for copying the collection back to the heap
! ** when we're done.
! */
! MR_mkframe(""builtin_aggregate"", num_framevars,
! LABEL(mercury__std_util__builtin_aggregate_4_0_i3));
!
/* save heap states */
! saved_solhp_fv = (Word) MR_sol_hp;
! mark_hp(saved_hp_fv);
- #ifdef MR_USE_TRAIL
/* save trail state */
! MR_store_ticket(saved_trail_ticket_fv);
#endif
!
! /* save arguments into framevars */
! collector_pred_fv = r4;
! sofar_fv = r5;
! element_type_info_fv = r1;
! collection_type_info_fv = r2;
!
! /* we do not (yet) need the type_info we are passed in r1 */
! /* call the higher-order pred closure that we were passed in r3 */
! r1 = r3;
! r2 = (Word) 0; /* the higher-order call has 0 extra input arguments */
! r3 = (Word) 1; /* the higher-order call has 1 extra output argument */
!
! call(ENTRY(mercury__do_call_closure),
! LABEL(mercury__std_util__builtin_aggregate_4_0_i1),
! LABEL(mercury__std_util__builtin_aggregate_4_0));
!
! Define_label(mercury__std_util__builtin_aggregate_4_0_i1);
! update_prof_current_proc(
! LABEL(mercury__std_util__builtin_aggregate_4_0));
! {
! Word copied_solution, solution;
!
! /* we found a solution (in r1) */
! solution = r1;
#ifdef MR_USE_TRAIL
/* check for outstanding delayed goals (``floundering'') */
! MR_reset_ticket(saved_trail_ticket_fv, MR_solve);
#endif
!
! /* swap heaps so we build on solution heap */
! swap_heap_and_solutions_heap();
!
! /*
! ** deep copy solution to the solutions heap, up to the saved_hp.
! ** Note that we need to save/restore the hp register, if it
! ** is transient, before/after calling deep_copy().
! */
! save_transient_registers();
! copied_solution = deep_copy(&solution, (Word *) element_type_info_fv,
! (Word *) saved_hp_fv,
! MR_ENGINE(solutions_heap_zone)->top);
! restore_transient_registers();
!
! /* call the collector closure */
! r1 = collector_pred_fv;
! r2 = (Word) 2; /* higher-order call has 2 extra input args */
! r3 = (Word) 1; /* higher-order call has 1 extra output arg */
! r4 = copied_solution;
! r5 = sofar_fv;
! call(ENTRY(mercury__do_call_closure),
! LABEL(mercury__std_util__builtin_aggregate_4_0_i2),
! LABEL(mercury__std_util__builtin_aggregate_4_0));
! }
! Define_label(mercury__std_util__builtin_aggregate_4_0_i2);
! update_prof_current_proc(
! LABEL(mercury__std_util__builtin_aggregate_4_0));
!
! sofar_fv = r1;
!
! /* swap heaps back the way they were */
! swap_heap_and_solutions_heap();
!
! /* look for the next solution */
! MR_redo();
!
! Define_label(mercury__std_util__builtin_aggregate_4_0_i3);
! update_prof_current_proc(
! LABEL(mercury__std_util__builtin_aggregate_4_0));
! {
! Word copied_collection;
!
! /* there were no more solutions */
!
! /* reset heap */
! restore_hp(saved_hp_fv);
! #ifdef MR_USE_TRAIL
! /*
! ** Reset the trail. This is necessary to undo any updates performed
! ** by the called goal before it failed, and to avoid leaking memory
! ** on the trail.
! */
! MR_reset_ticket(saved_trail_ticket_fv, MR_undo);
#endif
!
! /*
! ** deep_copy() the result to the mercury heap, copying
! ** everything between where we started on the solutions
! ** heap, and the top of the solutions heap.
! ** Note that we need to save/restore the hp register, if it
! ** is transient, before/after calling deep_copy().
! **/
! save_transient_registers();
! copied_collection = deep_copy(&sofar_fv,
! (Word *) collection_type_info_fv,
! (Word *) saved_solhp_fv,
! MR_ENGINE(solutions_heap_zone)->top);
! restore_transient_registers();
!
! r1 = copied_collection;
!
! /* reset solutions heap to where it was before call to solutions */
! MR_sol_hp = (Word *) saved_solhp_fv;
!
! /* discard the frame we made */
! MR_succeed_discard();
! }
! #undef num_framevars
! #undef saved_hp_fv
! #undef saved_solhp_fv
! #undef collector_pred_fv
! #undef sofar_fv
! #undef element_type_info_fv
! #undef collection_type_info_fv
! #undef saved_trail_ticket_fv
! #else
! /*
! ** The following algorithm is very straight-forward implementation
! ** but only works with `--gc conservative'.
! ** Since with conservative gc, we don't reclaim any memory on failure,
! ** but instead leave it to the garbage collector, there is no need to
! ** make deep copies of the solutions. This is a `copy-zero' implementation ;-)
! */
! #ifdef MR_USE_TRAIL
! #define num_framevars 3
#else
! #define num_framevars 2
#endif
! #define collector_pred_fv (MR_framevar(1))
! #define sofar_fv (MR_framevar(2))
! #ifdef MR_USE_TRAIL
! #define saved_trail_ticket_fv (MR_framevar(3))
! #endif
! /* create a nondet stack frame with two slots, to hold the collector
! pred and the collection, and set the failure continuation */
! MR_mkframe(""builtin_aggregate"", num_framevars,
! LABEL(mercury__std_util__builtin_aggregate_4_0_i3));
! #ifdef MR_USE_TRAIL
! /* save trail state */
! MR_store_ticket(saved_trail_ticket_fv);
#endif
! /* save our arguments in framevars */
! collector_pred_fv = r4;
! sofar_fv = r5;
!
! /* we do not (yet) need the type_info we are passed in r1 */
! /* call the higher-order pred closure that we were passed in r3 */
! r1 = r3;
! r2 = (Word) 0; /* the higher-order call has 0 extra input arguments */
! r3 = (Word) 1; /* the higher-order call has 1 extra output argument */
! call(ENTRY(mercury__do_call_closure),
! LABEL(mercury__std_util__builtin_aggregate_4_0_i1),
! LABEL(mercury__std_util__builtin_aggregate_4_0));
!
! Define_label(mercury__std_util__builtin_aggregate_4_0_i1);
! update_prof_current_proc(
! LABEL(mercury__std_util__builtin_aggregate_4_0));
! /* we found a solution (in r1) */
! #ifdef MR_USE_TRAIL
! /* check for outstanding delayed goals (``floundering'') */
! MR_reset_ticket(saved_trail_ticket_fv, MR_solve);
! #endif
! /* setup for calling the collector closure */
! r4 = r1; /* put solution to be collected where we need it */
! r1 = collector_pred_fv;
! r2 = (Word) 2; /* the higher-order call has 2 extra input arguments */
! r3 = (Word) 1; /* the higher-order call has 1 extra output argument */
! r5 = sofar_fv;
!
! call(ENTRY(mercury__do_call_closure),
! LABEL(mercury__std_util__builtin_aggregate_4_0_i2),
! LABEL(mercury__std_util__builtin_aggregate_4_0));
!
! Define_label(mercury__std_util__builtin_aggregate_4_0_i2);
! update_prof_current_proc(
! LABEL(mercury__std_util__builtin_aggregate_4_0));
! /*
! ** we inserted the solution into the collection,
! ** and we've now got a new collection (in r1)
! */
! sofar_fv = r1;
! /* look for the next solution */
! MR_redo();
!
! Define_label(mercury__std_util__builtin_aggregate_4_0_i3);
! update_prof_current_proc(
! LABEL(mercury__std_util__builtin_aggregate_4_0));
! /* no more solutions */
! #ifdef MR_USE_TRAIL
! /*
! ** Reset the trail. This is necessary to undo any updates performed
! ** by the called goal before it failed, and to avoid leaking memory
! ** on the trail.
! */
! MR_reset_ticket(saved_trail_ticket_fv, MR_undo);
! #endif
!
! /* return the collection and discard the frame we made */
! r1 = sofar_fv;
! MR_succeed_discard();
!
! #undef num_framevars
! #undef collector_pred_fv
! #undef sofar_fv
! #undef saved_trail_ticket_fv
!
! #endif
! END_MODULE
! #undef swap_heap_and_solutions_heap
! /* Ensure that the initialization code for the above module gets run. */
! /*
! INIT sys_init_builtin_aggregate_module
! */
! extern ModuleFunc builtin_aggregate_module;
! /* the extra declaration is to suppress a gcc -Wmissing-decl warning */
! void sys_init_builtin_aggregate_module(void);
! void sys_init_builtin_aggregate_module(void) {
! builtin_aggregate_module();
! }
! ").
solutions(Pred, List) :-
builtin_solutions(Pred, UnsortedList),
--- 540,805 ----
** are 'swapped.' This will work out fine, because the real heap isn't needed
** while the collector pred is executing, and by the time the nested do_ is
** completed, the 'real' heap pointer will have been reset.
+ **
+ ** If the collector predicate throws an exception while they are swapped.
+ ** then the code for builtin_throw/1 will unswap the heaps.
+ ** So we don't need to create our own exception handlers to here to
+ ** cover that case.
+ **
+ ** If we're using conservative GC, then all of the heap-swapping
+ ** and copying operations are no-ops, so we get a "zero-copy" solution.
*/
! :- pragma promise_pure(builtin_aggregate/4).
! builtin_aggregate(GeneratorPred, CollectorPred, Accumulator0, Accumulator) :-
! %
! % Save some of the Mercury virtual machine registers
! %
! impure get_registers(HeapPtr, SolutionsHeapPtr, TrailPtr),
!
! %
! % Initialize the accumulator
! %
! % Mutvar := Accumulator0
! %
! impure new_mutvar(Accumulator0, Mutvar),
!
! (
! %
! % Get a solution
! %
! GeneratorPred(Answer0),
!
! %
! % Check that the generator didn't leave any
! % delayed goals outstanding
! %
! impure check_for_floundering(TrailPtr),
!
! %
! % Update the accumulator
! %
! % MutVar := CollectorPred(MutVar)
! %
! impure swap_heap_and_solutions_heap,
! impure partial_deep_copy(HeapPtr, Answer0, Answer),
! impure get_mutvar(Mutvar, Acc0),
! CollectorPred(Answer, Acc0, Acc1),
! impure set_mutvar(Mutvar, Acc1),
! impure swap_heap_and_solutions_heap,
!
! %
! % Force backtracking, so that we get the next solution.
! % This will automatically reset the heap and trail.
! %
! fail
! ;
! %
! % There are no more solutions.
! % So now we just need to copy the final value
! % of the accumulator from the solutions heap
! % back onto the ordinary heap, and then we can
! % reset the solutions heap pointer.
! %
! % Accumulator := MutVar
! %
! impure get_mutvar(Mutvar, Accumulator1),
! impure partial_deep_copy(SolutionsHeapPtr, Accumulator1,
! Accumulator),
! impure reset_solutions_heap(SolutionsHeapPtr)
! ).
! :- type heap_ptr ---> heap_ptr(c_pointer).
! :- type trail_ptr ---> trail_ptr(c_pointer).
! %
! % Save the state of the Mercury heap and trail registers,
! % for later use in partial_deep_copy/3 and reset_solutions_heap/1.
! %
! :- impure pred get_registers(heap_ptr::out, heap_ptr::out, trail_ptr::out)
! is det.
! :- pragma c_code(get_registers(HeapPtr::out, SolutionsHeapPtr::out,
! TrailPtr::out), will_not_call_mercury,
! "
/* save heap states */
! #ifndef CONSERVATIVE_GC
! HeapPtr = MR_hp;
! SolutionsHeapPtr = MR_sol_hp;
! #else
! HeapPtr = SolutionsHeapPtr = 0;
! #endif
/* save trail state */
! #ifdef MR_USE_TRAIL
! MR_store_ticket(TrailPtr);
! #else
! TrailPtr = 0;
#endif
! ").
+ :- impure pred check_for_floundering(trail_ptr::in) is det.
+ :- pragma c_code(check_for_floundering(TrailPtr::in), [will_not_call_mercury],
+ "
#ifdef MR_USE_TRAIL
/* check for outstanding delayed goals (``floundering'') */
! MR_reset_ticket(TrailPtr, MR_solve);
#endif
! ").
! %
! % Swap the heap with the solutions heap
! %
! :- impure pred swap_heap_and_solutions_heap is det.
! :- pragma c_code(swap_heap_and_solutions_heap,
! will_not_call_mercury,
! "
! #ifndef CONSERVATIVE_GC
! {
! MemoryZone *temp_zone;
! Word *temp_hp;
!
! temp_zone = MR_ENGINE(heap_zone);
! MR_ENGINE(heap_zone) = MR_ENGINE(solutions_heap_zone);
! MR_ENGINE(solutions_heap_zone) = temp_zone;
! temp_hp = MR_hp;
! MR_hp = MR_sol_hp;
! MR_sol_hp = temp_hp;
! }
#endif
! ").
! %
! % partial_deep_copy(SolutionsHeapPtr, OldVal, NewVal):
! % Make a copy of all of the parts of OldVar that occur between
! % SolutionsHeapPtr and the top of the current solutions heap.
! %
! :- impure pred partial_deep_copy(heap_ptr, T, T) is det.
! :- mode partial_deep_copy(in, di, uo) is det.
! :- mode partial_deep_copy(in, mdi, muo) is det.
! :- mode partial_deep_copy(in, in, out) is det.
! :- pragma c_header_code("
! #include ""mercury_deep_copy.h""
! #ifdef CONSERVATIVE_GC
! /* for conservative GC, shallow copies suffice */
! #define MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, \\
! OldVar, NewVal, TypeInfo_for_T) \\
! do { \\
! NewVal = OldVal; \\
! } while (0)
#else
! /*
! ** Note that we need to save/restore the MR_hp register, if it
! ** is transient, before/after calling deep_copy().
! */
! #define MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, \\
! OldVar, NewVal, TypeInfo_for_T) \\
! do { \\
! save_transient_hp(); \\
! NewVal = deep_copy(&OldVal, TypeInfo_for_T, \\
! SolutionsHeapPtr, \\
! MR_ENGINE(solutions_heap_zone)->top); \\
! restore_transient_hp(); \\
! } while (0)
#endif
! ").
! :- pragma c_code(partial_deep_copy(SolutionsHeapPtr::in,
! OldVal::in, NewVal::out), will_not_call_mercury,
! "
! MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, OldVal, NewVal, TypeInfo_for_T);
! ").
! :- pragma c_code(partial_deep_copy(SolutionsHeapPtr::in,
! OldVal::mdi, NewVal::muo), will_not_call_mercury,
! "
! MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, OldVal, NewVal, TypeInfo_for_T);
! ").
! :- pragma c_code(partial_deep_copy(SolutionsHeapPtr::in,
! OldVal::di, NewVal::uo), will_not_call_mercury,
! "
! MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, OldVal, NewVal, TypeInfo_for_T);
! ").
! %
! % reset_solutions_heap(SolutionsHeapPtr):
! % Reset the solutions heap pointer to the specified value,
! % thus deallocating everything allocated on the solutions
! % heap since that value was obtained via get_registers/3.
! %
! :- impure pred reset_solutions_heap(heap_ptr::in) is det.
! :- pragma c_code(reset_solutions_heap(SolutionsHeapPtr::in),
! will_not_call_mercury,
! "
! #ifndef CONSERVATIVE_GC
! MR_sol_hp = SolutionsHeapPtr;
#endif
+ ").
! %-----------------------------------------------------------------------------%
! %%% :- module mutvar.
! %%% :- interface.
! % A non-backtrackably destructively modifiable reference type
! :- type mutvar(T).
! % Create a new mutvar given a term for it to reference.
! :- impure pred new_mutvar(T, mutvar(T)).
! :- mode new_mutvar(in, out) is det.
! :- mode new_mutvar(di, uo) is det.
!
! % Get the value currently referred to by a reference.
! :- impure pred get_mutvar(mutvar(T), T) is det.
! :- mode get_mutvar(in, uo) is det. % XXX this is a work-around
! /*
! XXX `ui' modes don't work yet
! :- mode get_mutvar(in, uo) is det.
! :- mode get_mutvar(ui, uo) is det. % unsafe, but we use it safely
! */
! % destructively modify a reference to refer to a new object.
! :- impure pred set_mutvar(mutvar(T), T) is det.
! :- mode set_mutvar(in, in) is det.
! /*
! XXX `ui' modes don't work yet
! :- pred set_mutvar(ui, di) is det.
! */
! %%% :- implementation.
! % This type is implemented in C.
! :- type mutvar(T) ---> mutvar(c_pointer).
! :- pragma inline(new_mutvar/2).
! :- pragma c_code(new_mutvar(X::in, Ref::out), will_not_call_mercury,
! "
! incr_hp_msg(Ref, 1, MR_PROC_LABEL, ""std_util:mutvar/1"");
! *(Word *) Ref = X;
! ").
! :- pragma c_code(new_mutvar(X::di, Ref::uo), will_not_call_mercury,
! "
! incr_hp_msg(Ref, 1, MR_PROC_LABEL, ""std_util:mutvar/1"");
! *(Word *) Ref = X;
! ").
! :- pragma inline(get_mutvar/2).
! :- pragma c_code(get_mutvar(Ref::in, X::uo), will_not_call_mercury,
! "
! X = *(Word *) Ref;
! ").
! :- pragma inline(set_mutvar/2).
! :- pragma c_code(set_mutvar(Ref::in, X::in), will_not_call_mercury, "
! *(Word *) Ref = X;
! ").
! %%% end_module mutvar.
! %-----------------------------------------------------------------------------%
solutions(Pred, List) :-
builtin_solutions(Pred, UnsortedList),
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3 | -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list