/*
- Simultaneous_music-iterator.cc -- implement Simultaneous_music_iterator
+ This file is part of LilyPond, the GNU music typesetter.
- source file of the GNU LilyPond music typesetter
+ Copyright (C) 1997--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
- (c) 1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+ LilyPond is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ LilyPond is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "translator-group.hh"
-#include "debug.hh"
#include "simultaneous-music-iterator.hh"
-#include "music-list.hh"
-#include "killing-cons.tcc"
-
+#include "music.hh"
+#include "context.hh"
+#include "warn.hh"
+#include "context-def.hh"
Simultaneous_music_iterator::Simultaneous_music_iterator ()
{
- separate_contexts_b_ = false;
+ create_separate_contexts_ = false;
+ children_list_ = SCM_EOL;
}
-Simultaneous_music_iterator::Simultaneous_music_iterator (Simultaneous_music_iterator const& src)
- : Music_iterator (src)
+void
+Simultaneous_music_iterator::derived_mark () const
{
- separate_contexts_b_ = src.separate_contexts_b_;
- for (Cons<Music_iterator> *p = src.children_p_list_.head_; p; p = p->next_)
- {
- Music_iterator *i = p->car_;
- children_p_list_.append (new Killing_cons<Music_iterator> (i->clone (), 0));
- }
+ scm_gc_mark (children_list_);
}
-Simultaneous_music_iterator::~Simultaneous_music_iterator ()
+void
+Simultaneous_music_iterator::derived_substitute (Context *f, Context *t)
{
- children_p_list_.junk ();
-}
-
-SCM
-Simultaneous_music_iterator::get_music (Moment m)const
-{
- SCM s = SCM_EOL;
- for (Cons<Music_iterator> *p = children_p_list_.head_; p; p = p->next_)
- {
- s = gh_append2 (p->car_->get_music (m), s);
- }
- return s;
+ for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
+ unsmob<Music_iterator> (scm_car (s))->substitute_outlet (f, t);
}
void
Simultaneous_music_iterator::construct_children ()
{
int j = 0;
- Music_sequence const *sim = dynamic_cast<Music_sequence const*> (music_l ());
- SCM i = sim->music_list ();
- for (; gh_pair_p (i); i = ly_cdr (i), j++)
+ SCM i = get_music ()->get_property ("elements");
+
+ children_list_ = SCM_EOL;
+ SCM *tail = &children_list_;
+ for (; scm_is_pair (i); i = scm_cdr (i), j++)
{
- Music *mus = unsmob_music (ly_car (i));
- Music_iterator * mi = static_get_iterator_p (mus);
+ Music *mus = unsmob<Music> (scm_car (i));
+
+ SCM scm_iter = get_static_get_iterator (mus);
+ Music_iterator *mi = unsmob<Music_iterator> (scm_iter);
+
+ /* if create_separate_contexts_ is set, create a new context with the
+ number number as name */
- /* if separate_contexts_b_ is set, create a new context with the
- number number as name */
-
- Translator_group * t = (j && separate_contexts_b_)
- ? report_to_l ()->find_create_translator_l (report_to_l ()->type_str_,
- to_str (j))
- : report_to_l ();
+ SCM name = ly_symbol2scm (get_outlet ()->context_name ().c_str ());
+ Context *c = (j && create_separate_contexts_)
+ ? get_outlet ()->find_create_context (name, ::to_string (j), SCM_EOL)
+ : get_outlet ();
- if (!t)
- t = report_to_l ();
+ if (!c)
+ c = get_outlet ();
- mi->init_translator (mus, t);
+ mi->init_context (mus, c);
mi->construct_children ();
-
- if (mi->ok ())
- {
- children_p_list_.append (new Killing_cons<Music_iterator> (mi,0));
- }
+
+ if (mi->ok ())
+ {
+ *tail = scm_cons (scm_iter, *tail);
+ tail = SCM_CDRLOC (*tail);
+ }
else
- delete mi;
+ mi->quit ();
}
}
+// If we have some iterators with definite next moment and no of them
+// remain after processing, we take the iterators with indefinite next
+// moment along. That makes sure that no Lyric_combine_music_iterator
+// will outstay its welcome (issue 2010).
void
Simultaneous_music_iterator::process (Moment until)
{
- for (Cons<Music_iterator> **pp = &children_p_list_.head_; *pp;)
+ SCM *proc = &children_list_;
+ bool finite = !pending_moment ().main_part_.is_infinity ();
+ while (scm_is_pair (*proc))
{
- Music_iterator * i = (*pp)->car_;
- if (i->pending_moment () == until)
- {
- i->process (until);
- }
+ Music_iterator *i = unsmob<Music_iterator> (scm_car (*proc));
+ if (i->run_always () || i->pending_moment () == until)
+ i->process (until);
if (!i->ok ())
- delete children_p_list_.remove_cons (pp);
+ {
+ i->quit ();
+ *proc = scm_cdr (*proc);
+ }
else
- pp = & (*pp)->next_;
+ {
+ proc = SCM_CDRLOC (*proc);
+ }
}
-}
-
-void
-Simultaneous_music_iterator::skip (Moment until)
-{
- for (Cons<Music_iterator> **pp = &children_p_list_.head_; *pp;)
+ // If there were definite-ended iterators and all of them died, take
+ // the rest of the iterators along with them. They have
+ // likely lost their reference iterators. Basing this on the actual
+ // music contexts is not reliable since something like
+ // \new Voice = blah {
+ // << \context Voice = blah { c4 d }
+ // \addlyrics { oh no }
+ // >> e f
+ // }
+ // cannot wait for the death of context blah before ending the
+ // simultaneous iterator.
+ if (finite && pending_moment ().main_part_.is_infinity ())
{
- Music_iterator * i = (*pp)->car_;
- if (i->pending_moment () <= until)
- {
- i->skip (until);
- }
- if (!i->ok ())
- delete children_p_list_.remove_cons (pp);
- else
- pp = & (*pp)->next_;
+ for (SCM p = children_list_; scm_is_pair (p); p = scm_cdr (p))
+ unsmob<Music_iterator> (scm_car (p))->quit ();
+ children_list_ = SCM_EOL;
}
}
{
Moment next;
next.set_infinite (1);
-
- for (Cons<Music_iterator> *p = children_p_list_.head_; p; p = p->next_)
- next = next <? p->car_->pending_moment () ;
- return next;
-}
+ for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
+ {
+ Music_iterator *it = unsmob<Music_iterator> (scm_car (s));
+ next = min (next, it->pending_moment ());
+ }
+ return next;
+}
bool
Simultaneous_music_iterator::ok () const
{
- return children_p_list_.head_;
+ for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
+ {
+ Music_iterator *it = unsmob<Music_iterator> (scm_car (s));
+ if (it->ok ())
+ return true;
+ }
+ return false;
}
-Music_iterator*
-Simultaneous_music_iterator::try_music_in_children (Music *m) const
+bool
+Simultaneous_music_iterator::run_always () const
{
- Music_iterator * b=0;
- for (Cons<Music_iterator> *p = children_p_list_.head_; !b && p; p = p->next_)
- b =p->car_->try_music (m);
- return b;
+ for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
+ {
+ Music_iterator *it = unsmob<Music_iterator> (scm_car (s));
+ if (it->run_always ())
+ return true;
+ }
+ return false;
}
-
+void
+Simultaneous_music_iterator::do_quit ()
+{
+ for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
+ unsmob<Music_iterator> (scm_car (s))->quit ();
+}
IMPLEMENT_CTOR_CALLBACK (Simultaneous_music_iterator);