[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);