4 // scm_reverse_x without the checks
6 fast_reverse_x (SCM lst, SCM tail)
8 while (!scm_is_null (lst))
10 SCM n = scm_cdr (lst);
11 scm_set_cdr_x (lst, tail);
18 // copy the spine of lst not including tail, appending newtail
21 partial_list_copy (SCM lst, SCM tail, SCM newtail)
24 for (; !scm_is_eq (lst, tail); lst = scm_cdr (lst))
25 p = scm_cons (scm_car (lst), p);
26 return fast_reverse_x (p, newtail);
30 assq_tail (SCM key, SCM alist, SCM based_on = SCM_EOL)
32 for (SCM p = alist; !scm_is_eq (p, based_on); p = scm_cdr (p))
34 if (scm_is_eq (scm_caar (p), key))
41 assv_tail (SCM key, SCM alist, SCM based_on = SCM_EOL)
43 for (SCM p = alist; !scm_is_eq (p, based_on); p = scm_cdr (p))
45 if (scm_is_true (scm_eqv_p (scm_caar (p), key)))
52 assoc_tail (SCM key, SCM alist, SCM based_on = SCM_EOL)
55 return assq_tail (key, alist, based_on);
56 if (scm_is_number (key) || scm_is_true (scm_char_p (key)))
57 return assv_tail (key, alist, based_on);
58 for (SCM p = alist; !scm_is_eq (p, based_on); p = scm_cdr (p))
60 if (ly_is_equal (scm_caar (p), key))
66 // Like assq, but removes the found element destructively
67 SCM assq_pop_x (SCM key, SCM *alist)
69 for (SCM p = *alist; scm_is_pair (p); p = *(alist = SCM_CDRLOC (p)))
71 if (scm_is_eq (scm_caar (p), key))
81 Drop key from the list alist..alist_end.
84 evict_from_alist (SCM key, SCM alist, SCM alist_end)
86 SCM p = assoc_tail (key, alist, alist_end);
89 return partial_list_copy (alist, p, scm_cdr (p));
93 // This is the same as
94 // nested_property_alist (SCM_EOL, prop_path, value) but faster
96 nested_create_alist (SCM prop_path, SCM value)
98 if (scm_is_null (prop_path))
100 return scm_acons (scm_car (prop_path),
101 nested_create_alist (scm_cdr (prop_path), value),
106 PROP_PATH should be big-to-small ordering
109 // Take the given alist and replace the given nested property with the
110 // given value. Multiple overrides of the same property path are not
111 // coalesced for efficiency reasons: they are considered rare enough
112 // to not be worth the cost of detecting them. When sublists are
113 // modified, however, we remove the original sublist and copy the
114 // spine before it. The cost for finding the sublist has already been
117 // A typical use case for this routine is applying (possibly nested)
118 // tweaks to a grob property list.
121 nested_property_alist (SCM alist, SCM prop_path, SCM value)
123 // replacement moves to the front.
124 SCM key = scm_car (prop_path);
125 SCM rest = scm_cdr (prop_path);
126 if (scm_is_pair (rest))
128 SCM where = assoc_tail (key, alist);
130 if (scm_is_false (where))
131 return scm_acons (key, nested_create_alist (rest, value), alist);
132 return scm_acons (key, nested_property_alist (scm_cdar (where),
135 partial_list_copy (alist, where, scm_cdr (where)));
137 // Outcommented code would coalesce multiple overrides of the same
140 SCM where = assq_tail (alist, key);
141 if (scm_is_true (where))
142 return scm_acons (key, value,
143 partial_list_copy (alist, where, scm_cdr (where)));
145 return scm_acons (key, value, alist);
149 nested_property (SCM alist, SCM prop_path, SCM fallback)
151 for (; scm_is_pair (prop_path); prop_path = scm_cdr (prop_path))
153 SCM tail = assoc_tail (scm_car (prop_path), alist);
154 if (scm_is_false (tail))
156 alist = scm_cdar (tail);
162 set_nested_property (Grob *me, SCM big_to_small, SCM value)
164 SCM alist = me->get_property (scm_car (big_to_small));
166 alist = nested_property_alist (alist, scm_cdr (big_to_small), value);
168 me->set_property (scm_car (big_to_small), alist);
171 // This converts an alist with nested overrides in it to a proper
172 // alist. The number of nested overrides is known in advance,
173 // everything up to the last nested override is copied, the tail is
176 // The first nalist index has to be a symbol since the conversion
177 // relies on eq? comparisons, uses some special non-symbol values for
178 // special purposes, and does validity checking indexed by symbols.
179 // Subindexing can be done with equal?-comparable indexes, however.
182 nalist_to_alist (SCM nalist, int nested)
186 SCM copied = SCM_EOL;
187 SCM partials = SCM_EOL;
188 // partials is a alist of partial overrides
191 SCM elt = scm_car (nalist);
192 nalist = scm_cdr (nalist);
193 SCM key = scm_car (elt);
194 if (!scm_is_symbol (key))
196 if (scm_is_bool (key))
198 if (scm_is_false (key))
203 if (scm_is_pair (key))
204 // nested override: record for key in partial
206 SCM pair = scm_sloppy_assq (scm_car (key), partials);
207 if (scm_is_false (pair))
208 partials = scm_acons (scm_car (key), scm_list_1 (elt),
211 scm_set_cdr_x (pair, scm_cons (elt, scm_cdr (pair)));
214 assert (scm_is_symbol (key));
215 // plain override: apply any known corresponding partials
216 SCM pair = assq_pop_x (key, &partials);
217 if (scm_is_true (pair))
219 SCM value = scm_cdr (elt);
220 for (SCM pp = scm_cdr (pair); scm_is_pair (pp); pp = scm_cdr (pp))
221 value = nested_property_alist (value, scm_cdaar (pp), scm_cdar (pp));
222 copied = scm_acons (key, value, copied);
225 copied = scm_cons (elt, copied);
227 // Now need to work off the remaining partials. All of them are
228 // unique, so we can push them to `copied' after resolving without
229 // losing information.
231 for (;scm_is_pair (partials); partials = scm_cdr (partials))
233 SCM pair = scm_car (partials);
234 SCM key = scm_car (pair);
235 SCM elt = scm_sloppy_assq (key, nalist);
237 if (scm_is_true (elt))
238 value = scm_cdr (elt);
240 for (SCM pp = scm_cdr (pair); scm_is_pair (pp); pp = scm_cdr (pp))
241 value = nested_property_alist (value, scm_cdaar (pp), scm_cdar (pp));
243 copied = scm_acons (key, value, copied);
245 return fast_reverse_x (copied, nalist);
249 // Alternative approach: don't unfold those partial overrides while
250 // they are part of contexts but instead use a special accessor for
251 // subproperties in the grob. Not used or tested for now.
254 nassq_ref (SCM key, SCM nalist, SCM fallback)
256 SCM partials = SCM_EOL;
257 // partials is list of partial overrides for the given property
258 for (SCM p = nalist; scm_is_pair (p); p = scm_cdr (p))
260 SCM elt = scm_car (p);
261 SCM pkey = scm_car (elt);
262 if (scm_is_pair (pkey))
264 if (scm_is_eq (scm_car (pkey), key))
265 partials = scm_cons (elt, partials);
267 else if (scm_is_eq (pkey, key))
269 SCM value = scm_cdr (elt);
270 for (; scm_is_pair (partials); partials = scm_cdr (partials))
272 value = nested_property_alist (value, scm_cdaar (partials),
273 scm_cdar (partials));
278 if (scm_is_pair (partials))
280 // Bit of a quandary here: we have only subproperty overrides
281 // but no main property. Could be a programming error, but we
282 // instead override an empty list.
283 SCM value = nested_create_alist (scm_cdaar (partials), scm_cdar (partials));
284 partials = scm_cdr (partials);
285 for (; scm_is_pair (partials); partials = scm_cdr (partials))
286 value = nested_property_alist (value, scm_cdaar (partials),
287 scm_cdar (partials));
290 return SCM_UNBNDP (fallback) ? SCM_EOL : fallback;
293 // Also needed for this approach to make sense: an accessor for true
296 nassq_nested_ref (SCM key, SCM subpath, SCM nalist, SCM fallback);