java-topology/defects/raylib/unit/RaylibGlyphIndexTest.java
russell@unturf.com 9934133dcf whitepaper: 312 sites / 151 ecosystems — wave2+3 defect tables and PDF rebuild
Add 88 new defect entries to HIGH and MEDIUM tables:
  HIGH: mysql-0001/0002, mariadb-0001, redis-0001/0002, valkey-0001/0002, openvpn-0001,
        vlc-0001, prometheus-0001, otel-collector-0001, cockroachdb-0001..0004,
        tidb-0001..0008, kubernetes-0001/0002, go-0001, kotlin-0002, scala-0001,
        allegro5-0001, sdl2-0001, grafana-0001, clickhouse-0001, duckdb-0001,
        mongodb-0001, envoy-0001, istio-0001, cilium-0001, linkerd2-0001,
        linux-0001/0002/0003, tor-0002/0003, curl-0001, julia-0001, lua-0001,
        perl5-0001, nats-0001, spring-0003/0004, tomcat-0001, onos-0002, odl-0002

  MEDIUM: helm-0001, mariadb-0002, openssl-0001/0002, memcached-0001,
          cassandra-0001..0004, flink-0001, storm-0001/0002, zookeeper-0001..0003,
          pip-0001, gradle-0001, nginx-0001, haproxy-0001, caddy-0001, varnish-0001,
          ffmpeg-0001, gstreamer-0001, raylib-0001, love2d-0001, php-0001/0002,
          r-source-0001, cpython-0002, ruby-0001, rabbitmq-0003/0004, activemq-0001,
          ovs-0001, onos-0003, odl-0002, jetty-0001

PDF: 976K
2026-03-27 15:23:43 -04:00

120 lines
4.1 KiB
Java

package unit;
import java.util.Arrays;
/**
* RaylibGlyphIndexTest — CWE-407 raylib-0001
*
* Models GetGlyphIndex(Font font, int codepoint):
* slow() = O(n) linear scan of glyphs array (current defect)
* fast() = O(log n) binary search on sorted glyphs array (patch)
*
* Assert: slowOps > fastOps * Nx at N=2048 glyphs.
*/
public class RaylibGlyphIndexTest {
// Simulates font.glyphs[i].value — codepoint stored per glyph slot
static int[] buildGlyphs(int n) {
int[] glyphs = new int[n];
// Mimic a Unicode font: codepoints spread across BMP
// Start at 0x20 (space), stride by 1 — typical Latin+extended range
for (int i = 0; i < n; i++) {
glyphs[i] = 0x20 + i;
}
return glyphs;
}
static long linearOps;
static long binaryOps;
/**
* slow: O(n) linear scan — exact translation of raylib GetGlyphIndex
* SUPPORT_UNORDERED_CHARSET branch.
*/
static int getGlyphIndexSlow(int[] glyphs, int codepoint) {
int index = 0;
int fallbackIndex = 0;
for (int i = 0; i < glyphs.length; i++) {
linearOps++;
if (glyphs[i] == 63) fallbackIndex = i; // '?' fallback
if (glyphs[i] == codepoint) {
index = i;
break;
}
}
if (index == 0 && glyphs[0] != codepoint) index = fallbackIndex;
return index;
}
/**
* fast: O(log n) binary search — patch approach, requires sorted glyphs.
*/
static int getGlyphIndexFast(int[] glyphs, int codepoint) {
int lo = 0, hi = glyphs.length - 1;
while (lo <= hi) {
binaryOps++;
int mid = lo + (hi - lo) / 2;
if (glyphs[mid] == codepoint) return mid;
else if (glyphs[mid] < codepoint) lo = mid + 1;
else hi = mid - 1;
}
// Fallback to '?' (codepoint 63) — also binary search
return getGlyphIndexFast(glyphs, 63);
}
public static void main(String[] args) {
final int N = 2048; // font.glyphCount
final int NX = 10; // minimum required speedup factor
final int TRIALS = 1000; // number of lookups to accumulate ops
int[] glyphs = buildGlyphs(N);
// Sorted by construction — binary search is valid
// Worst-case codepoint: the last glyph (maximizes linear scan ops)
int worstCaseCodepoint = glyphs[N - 1];
linearOps = 0;
binaryOps = 0;
for (int t = 0; t < TRIALS; t++) {
getGlyphIndexSlow(glyphs, worstCaseCodepoint);
}
long slowOps = linearOps;
for (int t = 0; t < TRIALS; t++) {
getGlyphIndexFast(glyphs, worstCaseCodepoint);
}
long fastOps = binaryOps;
// Correctness check
int slowIdx = getGlyphIndexSlow(glyphs, worstCaseCodepoint);
int fastIdx = getGlyphIndexFast(glyphs, worstCaseCodepoint);
boolean correctnessOk = (slowIdx == fastIdx);
boolean speedupOk = slowOps > fastOps * NX;
System.out.printf("N=%d glyphs, worst-case codepoint=0x%X%n", N, worstCaseCodepoint);
System.out.printf("slow (linear) ops over %d trials: %d%n", TRIALS, slowOps);
System.out.printf("fast (binary) ops over %d trials: %d%n", TRIALS, fastOps);
System.out.printf("speedup ratio: %.1fx (required >%dx)%n",
(double) slowOps / fastOps, NX);
System.out.printf("index match: slow=%d fast=%d%n", slowIdx, fastIdx);
int passed = 0, total = 2;
if (correctnessOk) {
System.out.println("1/2 PASS correctness: slow and fast return same index");
passed++;
} else {
System.out.printf("1/2 FAIL correctness: slow=%d fast=%d%n", slowIdx, fastIdx);
}
if (speedupOk) {
System.out.printf("2/2 PASS speedup: %d > %d * %d%n", slowOps, fastOps, NX);
passed++;
} else {
System.out.printf("2/2 FAIL speedup: %d not > %d * %d%n", slowOps, fastOps, NX);
}
System.out.printf("%d/%d PASS%n", passed, total);
if (passed < total) System.exit(1);
}
}