package unit; import java.util.*; /** * Models BIRD routing daemon community set operations. * * bird-0003: int_set_union O(N×M) — contains check in union loop * bird-0004: clist_filter O(L×S) — contains check in filter loop * * SLOW: O(N×M) union / O(L×S) filter — linear scan per element * FAST: O(N+M) union / O(L+S) filter — HashSet pre-built from second operand * * CWE-407: nest/a-set.c:394 (union), filter/data.c:421 (filter) */ public class BirdCommunitySetAlgorithmTest { // ------------------------------------------------------------------------- // Slow (defective) — mirrors int_set_contains in loop // ------------------------------------------------------------------------- static class SlowCommunityOps { long scanOps = 0; boolean contains(int[] arr, int val) { for (int v : arr) { scanOps++; if (v == val) return true; } return false; } /** bird-0003: O(N×M) union */ int[] union(int[] l1, int[] l2) { List result = new ArrayList<>(); for (int v : l1) result.add(v); for (int v : l2) { if (!contains(l1, v)) result.add(v); } return result.stream().mapToInt(Integer::intValue).toArray(); } /** bird-0004: O(L×S) filter — keep entries in l1 that are in filterSet */ int[] filter(int[] l1, int[] filterSet) { List result = new ArrayList<>(); for (int v : l1) { if (contains(filterSet, v)) result.add(v); } return result.stream().mapToInt(Integer::intValue).toArray(); } long unionOps(int[] l1, int[] l2) { scanOps = 0; union(l1, l2); return scanOps; } long filterOps(int[] l1, int[] filterSet) { scanOps = 0; filter(l1, filterSet); return scanOps; } } // ------------------------------------------------------------------------- // Fast (fixed) — HashSet from one operand // ------------------------------------------------------------------------- static class FastCommunityOps { long scanOps = 0; int[] union(int[] l1, int[] l2) { Set seen = new HashSet<>(); for (int v : l1) { seen.add(v); scanOps++; } List result = new ArrayList<>(Arrays.stream(l1).boxed().toList()); for (int v : l2) { scanOps++; if (seen.add(v)) result.add(v); } return result.stream().mapToInt(Integer::intValue).toArray(); } int[] filter(int[] l1, int[] filterSet) { Set fs = new HashSet<>(); for (int v : filterSet) { fs.add(v); scanOps++; } List result = new ArrayList<>(); for (int v : l1) { scanOps++; if (fs.contains(v)) result.add(v); } return result.stream().mapToInt(Integer::intValue).toArray(); } long unionOps(int[] l1, int[] l2) { scanOps = 0; union(l1, l2); return scanOps; } long filterOps(int[] l1, int[] filterSet) { scanOps = 0; filter(l1, filterSet); return scanOps; } } static int[] range(int from, int n) { int[] a = new int[n]; for (int i = 0; i < n; i++) a[i] = from + i; return a; } public static void main(String[] args) { SlowCommunityOps slow = new SlowCommunityOps(); FastCommunityOps fast = new FastCommunityOps(); int passed = 0, total = 0; System.out.println("=== bird-0003: int_set_union O(N×M) ==="); int[] sizes = {50, 100, 200, 500}; for (int n : sizes) { int[] l1 = range(0, n); int[] l2 = range(n / 2, n); // partial overlap long s = slow.unionOps(l1, l2); long f = fast.unionOps(l1, l2); double ratio = (double) s / f; total++; boolean ok = s > f && ratio >= 5.0; System.out.printf("N=%3d slow=%8d fast=%5d ratio=%6.1fx %s%n", n, s, f, ratio, ok ? "PASS" : "FAIL"); if (ok) passed++; } System.out.println("=== bird-0004: clist_filter O(L×S) ==="); for (int n : sizes) { int[] l1 = range(0, n); // route's community list int[] filterSet = range(n/4, n/2); // keep middle half long s = slow.filterOps(l1, filterSet); long f = fast.filterOps(l1, filterSet); double ratio = (double) s / f; total++; boolean ok = s > f && ratio >= 3.0; System.out.printf("L=%3d S=%3d slow=%8d fast=%5d ratio=%6.1fx %s%n", n, n/2, s, f, ratio, ok ? "PASS" : "FAIL"); if (ok) passed++; } // Correctness: union contains all unique elements int[] a = range(0, 100), b = range(50, 100); int[] slowUnion = slow.union(a, b); int[] fastUnion = fast.union(a, b); Arrays.sort(slowUnion); Arrays.sort(fastUnion); total++; boolean correct1 = Arrays.equals(slowUnion, fastUnion); System.out.printf("union correctness: %s%n", correct1 ? "PASS" : "FAIL"); if (correct1) passed++; // Correctness: filter returns same kept elements int[] l = range(0, 100), fs = range(20, 60); int[] slowFilter = slow.filter(l, fs); int[] fastFilter = fast.filter(l, fs); Arrays.sort(slowFilter); Arrays.sort(fastFilter); total++; boolean correct2 = Arrays.equals(slowFilter, fastFilter); System.out.printf("filter correctness: %s%n", correct2 ? "PASS" : "FAIL"); if (correct2) passed++; System.out.printf("%n%d/%d PASS%n", passed, total); if (passed < total) System.exit(1); } }