[array] Replace std::sort with internal sort_r_simple std::sort instantiates several internal STL helpers (__introsort_loop, __insertion_sort, __adjust_heap, __heap_select, __unguarded_linear_insert) as weak symbols in the std:: namespace. These leaked into libharfbuzz.so for every distinct (T, Compar) pair, polluting the public ABI surface. Route hb_array_t::qsort(Compar) through our existing templated sort_r_simple instead. The comparator is still inlined into the sort body (sort_r_simple has been comparator-templated since 05762b2fac). Drop the bool-returning comparator overload in favor of a single int-sign convention; convert the call sites added during the std::sort migration back to int-sign comparators. Step 1 of two: this restores ABI hygiene at the cost of typed- element swap (sort_r_simple swaps byte-by-byte). A follow-up will introduce a typed sort to recover that perf. Tested: 240/240 tests pass; nm -D libharfbuzz.so shows zero remaining _ZSt sort weak symbols. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
diff --git a/src/hb-array.hh b/src/hb-array.hh index 2799d84..fafaf00 100644 --- a/src/hb-array.hh +++ b/src/hb-array.hh
@@ -32,8 +32,6 @@ #include "hb-iter.hh" #include "hb-null.hh" -#include <algorithm> - template <typename Type> struct hb_sorted_array_t; @@ -227,22 +225,16 @@ hb_qsort (arrayZ, length, this->get_item_size (), cmp); return hb_sorted_array_t<Type> (*this); } - /* std::sort wants a strict-weak `a < b` boolean, but our other - * qsort overload (and most existing call sites) follow the C - * qsort convention of returning negative / zero / positive ints. - * Adapt to either via overload resolution: bool passes through; - * any other arithmetic return type is treated as the int signed - * comparator. */ - template <typename T> static bool _qsort_lt (T v) { return v < 0; } - static bool _qsort_lt (bool v) { return v; } + /* Comparator follows the C qsort convention: returns + * negative / zero / positive int. */ template <typename Compar> hb_sorted_array_t<Type> qsort (Compar compar) { if (likely (length)) - std::sort (arrayZ, arrayZ + length, - [&] (const Type &a, const Type &b) - { return _qsort_lt (compar (a, b)); }); + sort_r_simple (arrayZ, length, sizeof (Type), + [&] (const void *a, const void *b) + { return compar (*(const Type *) a, *(const Type *) b); }); return hb_sorted_array_t<Type> (*this); } @@ -251,7 +243,7 @@ hb_enable_if (std::is_move_assignable<T>::value)> hb_sorted_array_t<Type> _qsort (hb_priority<1>) { - return qsort ([] (const Type &a, const Type &b) { return Type::cmp (&a, &b) < 0; }); + return qsort ([] (const Type &a, const Type &b) { return Type::cmp (&a, &b); }); } hb_sorted_array_t<Type> _qsort (hb_priority<0>) {
diff --git a/src/hb-cairo-utils.cc b/src/hb-cairo-utils.cc index f4edc9b..d0888d4 100644 --- a/src/hb-cairo-utils.cc +++ b/src/hb-cairo-utils.cc
@@ -579,7 +579,7 @@ hb_array_t<hb_color_stop_t> (stops, len) .qsort ([] (const hb_color_stop_t &a, const hb_color_stop_t &b) { - return a.offset < b.offset; + return (a.offset > b.offset) - (a.offset < b.offset); }); cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
diff --git a/src/hb-face-builder.cc b/src/hb-face-builder.cc index d62bd96..579ef27 100644 --- a/src/hb-face-builder.cc +++ b/src/hb-face-builder.cc
@@ -181,7 +181,7 @@ // Not much to do... } sorted_tags.qsort ([] (const hb_tag_t &a, const hb_tag_t &b) { - return a < b; + return (a > b) - (a < b); }); auto array = sorted_tags.as_array ().sub_array (start_offset, table_count);
diff --git a/src/hb-gpu-draw.cc b/src/hb-gpu-draw.cc index ea47532..a05996e 100644 --- a/src/hb-gpu-draw.cc +++ b/src/hb-gpu-draw.cc
@@ -579,11 +579,13 @@ unsigned count = s.hband_curve_counts.arrayZ[b]; s.hband_curves.as_array ().sub_array (off, count) .qsort ([infos] (const unsigned &a, const unsigned &b) { - return infos[a].max_x > infos[b].max_x; + auto av = infos[a].max_x, bv = infos[b].max_x; + return (av < bv) - (av > bv); }); s.hband_curves_asc.as_array ().sub_array (off, count) .qsort ([infos] (const unsigned &a, const unsigned &b) { - return infos[a].min_x < infos[b].min_x; + auto av = infos[a].min_x, bv = infos[b].min_x; + return (av > bv) - (av < bv); }); } @@ -593,11 +595,13 @@ unsigned count = s.vband_curve_counts.arrayZ[b]; s.vband_curves.as_array ().sub_array (off, count) .qsort ([infos] (const unsigned &a, const unsigned &b) { - return infos[a].max_y > infos[b].max_y; + auto av = infos[a].max_y, bv = infos[b].max_y; + return (av < bv) - (av > bv); }); s.vband_curves_asc.as_array ().sub_array (off, count) .qsort ([infos] (const unsigned &a, const unsigned &b) { - return infos[a].min_y < infos[b].min_y; + auto av = infos[a].min_y, bv = infos[b].min_y; + return (av > bv) - (av < bv); }); }
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh index 3741f13..5aa97ca 100644 --- a/src/hb-ot-post-table.hh +++ b/src/hb-ot-post-table.hh
@@ -197,7 +197,7 @@ auto thiz = this; hb_array_t<uint16_t> (gids, count) .qsort ([thiz] (const uint16_t &a, const uint16_t &b) { - return thiz->find_glyph_name (a).cmp (thiz->find_glyph_name (b)) > 0; + return thiz->find_glyph_name (a).cmp (thiz->find_glyph_name (b)); }); if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
diff --git a/src/hb-paint.cc b/src/hb-paint.cc index 4565635..e272ec3 100644 --- a/src/hb-paint.cc +++ b/src/hb-paint.cc
@@ -939,7 +939,7 @@ hb_array_t<hb_color_stop_t> (stops, len) .qsort ([] (const hb_color_stop_t &a, const hb_color_stop_t &b) { - return a.offset < b.offset; + return (a.offset > b.offset) - (a.offset < b.offset); }); float mn = stops[0].offset, mx = stops[0].offset;
diff --git a/src/hb-vector-paint-pdf.cc b/src/hb-vector-paint-pdf.cc index 64b52e4..1acf72f 100644 --- a/src/hb-vector-paint-pdf.cc +++ b/src/hb-vector-paint-pdf.cc
@@ -892,7 +892,7 @@ /* Sort by offset. */ paint->color_stops_scratch.as_array ().qsort ( [] (const hb_color_stop_t &a, const hb_color_stop_t &b) - { return a.offset < b.offset; }); + { return (a.offset > b.offset) - (a.offset < b.offset); }); if (count == 2) { @@ -1342,7 +1342,7 @@ hb_vector_t<hb_color_stop_t> &stops = paint->color_stops_scratch; stops.as_array ().qsort ( [] (const hb_color_stop_t &a, const hb_color_stop_t &b) - { return a.offset < b.offset; }); + { return (a.offset > b.offset) - (a.offset < b.offset); }); hb_paint_extend_t extend = hb_color_line_get_extend (color_line);