+size_t
+scm_prepare_fluids (size_t n, SCM *fluids, SCM *values)
+{
+ size_t j;
+
+ /* Ensure that there are no duplicates in the fluids set -- an N^2 operation,
+ but N will usually be small, so perhaps that's OK. */
+ for (j = n; j--;)
+ {
+ size_t i;
+
+ if (SCM_UNLIKELY (!IS_FLUID (fluids[j])))
+ scm_wrong_type_arg ("with-fluids", 0, fluids[j]);
+
+ for (i = j; i--;)
+ if (scm_is_eq (fluids[i], fluids[j]))
+ {
+ values[i] = values[j]; /* later bindings win */
+ n--;
+ fluids[j] = fluids[n];
+ values[j] = values[n];
+ break;
+ }
+ }
+
+ return n;
+}
+
+void
+scm_swap_fluids (size_t n, SCM *fluids, SCM *values, SCM dynstate)
+{
+ SCM fluid_vector;
+ size_t i, max = 0;
+
+ fluid_vector = DYNAMIC_STATE_FLUIDS (dynstate);
+
+ /* We could cache the max in the with-fluids, but that would take more mem,
+ and we're touching all the fluids anyway, so this per-swap traversal should
+ be OK. */
+ for (i = 0; i < n; i++)
+ {
+ size_t num = FLUID_NUM (fluids[i]);
+ max = (max > num) ? max : num;
+ }
+
+ if (SCM_UNLIKELY (max >= SCM_SIMPLE_VECTOR_LENGTH (fluid_vector)))
+ {
+ /* Lazily grow the current thread's dynamic state. */
+ grow_dynamic_state (dynstate);
+
+ fluid_vector = DYNAMIC_STATE_FLUIDS (dynstate);
+ }
+
+ /* Bind the fluids. Order doesn't matter, as all fluids are distinct. */
+ for (i = 0; i < n; i++)
+ {
+ size_t fluid_num;
+ SCM x;
+
+ fluid_num = FLUID_NUM (fluids[i]);
+ x = SCM_SIMPLE_VECTOR_REF (fluid_vector, fluid_num);
+ SCM_SIMPLE_VECTOR_SET (fluid_vector, fluid_num, values[i]);
+ values[i] = x;
+ }
+}
+