6 static SCM break_criterion;
8 set_break_subsititution (SCM criterion)
10 break_criterion = criterion;
14 Perform the substitution for a single grob.
17 substitute_grob (Grob *sc)
19 if (SCM_INUMP (break_criterion))
21 Item * i = dynamic_cast<Item*> (sc);
22 Direction d = to_dir (break_criterion);
23 if (i && i->break_status_dir () != d)
25 Item *br = i->find_prebroken_piece (d);
26 return (br) ? br->self_scm () : SCM_UNDEFINED;
32 = dynamic_cast<System*> (unsmob_grob (break_criterion));
33 if (sc->get_system () != line)
35 sc = sc->find_broken_piece (line);
39 /* now: !sc || (sc && sc->get_system () == line) */
43 /* now: sc && sc->get_system () == line */
45 return sc->self_scm();
48 We don't return SCM_UNDEFINED for
49 suicided grobs, for two reasons
51 - it doesn't work (strange disappearing objects)
53 - it forces us to mark the parents of a grob, leading to
54 a huge recursion in the GC routine.
58 This was introduced in 1.3.49 as a measure to prevent
59 programming errors. It looks rather expensive (?).
63 benchmark , document when (what kind of programming
66 if (sc->common_refpoint (line, X_AXIS)
67 && sc->common_refpoint (line, Y_AXIS))
69 return sc->self_scm ();
74 return sc->self_scm();
80 Do break substitution in S, using CRITERION. Return new value.
81 CRITERION is either a SMOB pointer to the desired line, or a number
82 representing the break direction. Do not modify SRC.
84 It is rather tightly coded, since it takes a lot of time; it is
85 one of the top functions in the profile.
87 We don't pass break_criterion as a parameter, since it is
88 `constant', but takes up stack space.
90 It would be nice if we could do this in-place partially. We now
91 generate a lot of garbage.
94 do_break_substitution (SCM src)
98 if (unsmob_grob (src))
100 return substitute_grob (unsmob_grob (src));
102 else if (gh_vector_p (src))
104 int l = SCM_VECTOR_LENGTH (src);
105 SCM nv = scm_c_make_vector (l, SCM_UNDEFINED);
107 for (int i =0 ; i< l ; i++)
109 SCM si = gh_int2scm (i);
110 scm_vector_set_x (nv, si, do_break_substitution (scm_vector_ref (src, si)));
113 else if (ly_pair_p (src))
116 UGH! breaks on circular lists.
118 SCM newcar = do_break_substitution (ly_car (src));
119 SCM oldcdr = ly_cdr (src);
121 if (newcar == SCM_UNDEFINED
122 && (gh_pair_p (oldcdr) || oldcdr == SCM_EOL))
125 This is tail-recursion, ie.
127 return do_break_substution (cdr);
129 We don't want to rely on the compiler to do this. Without
130 tail-recursion, this easily crashes with a stack overflow. */
135 return scm_cons (newcar, do_break_substitution (oldcdr));
145 Perform substitution on GROB_LIST using a constant amount of stack.
148 substitute_grob_list (SCM grob_list)
153 for (SCM s = grob_list; gh_pair_p (s); s = gh_cdr (s))
155 SCM n= substitute_grob (unsmob_grob (gh_car (s)));
157 if (n != SCM_UNDEFINED)
159 *tail = gh_cons (n, SCM_EOL);
160 tail = SCM_CDRLOC(*tail);
171 Although the substitution can be written as
173 property_alist = do_substitution (other_property_alist),
175 we have a special function here: we want to invoke a special
176 function for lists of grobs. These can be very long for large
177 orchestral scores (eg. 1M elements). do_break_substitution() can
178 recurse many levels, taking lots of stack space.
180 This becomes a problem if lily is linked against guile with
181 pthreads. pthreads impose small limits on the stack size.
184 substitute_mutable_property_alist (SCM alist)
187 grob_list_p = scm_c_eval_string ("grob-list?");
191 for (SCM s = alist; gh_pair_p (s); s = gh_cdr (s))
193 SCM sym = gh_caar(s);
194 SCM val = gh_cdar(s);
195 SCM type = scm_object_property (sym, ly_symbol2scm ("backend-type?"));
197 if (type == grob_list_p)
198 val = substitute_grob_list (val);
200 val = do_break_substitution (val);
202 *tail = gh_cons (gh_cons (sym, val), SCM_EOL);
203 tail = SCM_CDRLOC (*tail);