From: David Kastrup Date: Tue, 14 May 2013 10:00:08 +0000 (+0200) Subject: Issue 3365: Create and use uniquify function for removing duplicate Grobs X-Git-Tag: release/2.17.19-1~8^2~11 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=db8b07bb2323afd6fd8b0d9cfc48241f31e870a8;p=lilypond.git Issue 3365: Create and use uniquify function for removing duplicate Grobs As opposed to the previous code, this retains the original order, making results independent from GUILE's memory allocation algorithms. --- diff --git a/lily/accidental-placement.cc b/lily/accidental-placement.cc index 1f2a943045..b7a41c0266 100644 --- a/lily/accidental-placement.cc +++ b/lily/accidental-placement.cc @@ -342,9 +342,8 @@ extract_heads_and_stems (vector const &apes) for (vsize i = ret.size (); i--;) if (Grob *s = Rhythmic_head::get_stem (ret[i])) ret.push_back (s); - - vector_sort (ret, less ()); - uniq (ret); + + uniquify (ret); return ret; } diff --git a/lily/grob-array.cc b/lily/grob-array.cc index 62d071cee1..d0cf111068 100644 --- a/lily/grob-array.cc +++ b/lily/grob-array.cc @@ -98,8 +98,7 @@ Grob_array::remove_duplicates () { assert (!ordered_); - vector_sort (grobs_, less ()); - ::uniq (grobs_); + uniquify (grobs_); } bool diff --git a/lily/grob.cc b/lily/grob.cc index a6b862e04e..43828310a7 100644 --- a/lily/grob.cc +++ b/lily/grob.cc @@ -972,3 +972,50 @@ Grob::check_cross_staff (Grob *commony) return false; } +static +bool +indirect_less (Grob **a, Grob **b) +{ + // Use original order as tie breaker. That gives us a stable sort + // at the lower price tag of an unstable one, and we want a stable + // sort in order to reliably retain the first instance of a grob + // pointer. + return *a < *b || (*a == *b && a < b); +} + +static +bool +indirect_eq (Grob **a, Grob **b) +{ + return *a == *b; +} + +static +bool +direct_less (Grob **a, Grob **b) +{ + return a < b; +} + +// uniquify uniquifies on the memory addresses of the Grobs, but then +// uses the original order. This makes results independent from the +// memory allocation of Grobs. + +void +uniquify (vector & grobs) +{ + vector vec (grobs.size ()); + for (vsize i = 0; i < grobs.size (); i++) + vec[i] = &grobs[i]; + vector_sort (vec, indirect_less); + vec.erase (unique (vec.begin (), vec.end (), indirect_eq), vec.end ()); + vector_sort (vec, direct_less); + + // Since the output is a sorted copy of the input with some elements + // removed, we can fill in the vector in-place if we do it starting + // from the front. + for (vsize i = 0; i < vec.size (); i++) + grobs[i] = *vec[i]; + grobs.erase (grobs.begin () + vec.size (), grobs.end ()); + return; +} diff --git a/lily/include/grob.hh b/lily/include/grob.hh index 70c9c0a94e..bc4071eb04 100644 --- a/lily/include/grob.hh +++ b/lily/include/grob.hh @@ -176,6 +176,9 @@ DECLARE_UNSMOB (Grob, grob); Spanner *unsmob_spanner (SCM); Item *unsmob_item (SCM); +/* unification */ +void uniquify (vector &); + /* refpoints */ Grob *common_refpoint_of_list (SCM elt_list, Grob *, Axis a); Grob *common_refpoint_of_array (vector const &, Grob *, Axis a); diff --git a/lily/system.cc b/lily/system.cc index b2e0d53a88..1ec46fbaf6 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -548,8 +548,7 @@ System::post_processing () anyway. */ vector all_elts_sorted (all_elements_->array ()); - vector_sort (all_elts_sorted, std::less ()); - uniq (all_elts_sorted); + uniquify (all_elts_sorted); this->get_stencil (); for (vsize i = all_elts_sorted.size (); i--;) {