Last active
September 26, 2025 05:16
-
-
Save opsec-ee/fe28a236fae315e6be20f61180fc8be4 to your computer and use it in GitHub Desktop.
Polymorphic Dispatch in C with cJSON
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright (c) 2025 H.Overman <opsec.ee@pm.me> | |
| // JSON Polymorphic Dispatch | |
| // Email: opsec.ee@pm.me | |
| // | |
| // Changelog: | |
| // - Handles actual JSON parsing with minimal overhead | |
| // - Maintains polymorphic dispatch for varied data | |
| // - Zero-copy where possible | |
| // - Computed goto for dispatch | |
| #define _GNU_SOURCE | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <stdint.h> | |
| #include <fcntl.h> | |
| #include <unistd.h> | |
| #include <sys/mman.h> | |
| #include <sys/stat.h> | |
| #include <x86intrin.h> | |
| // Single cache line object | |
| typedef struct __attribute__((aligned(64))) { | |
| double v[7]; // Values extracted from JSON | |
| uint8_t n; // Number of values (1-7) | |
| uint8_t p; // Pattern type (0-3) | |
| uint8_t pad[6]; // Padding to 64 bytes | |
| } Obj; | |
| // Fast JSON number parser - minimal validation | |
| static inline double parse_number(const char **s) { | |
| const char *p = *s; | |
| double val = 0; | |
| int neg = 0; | |
| // Skip whitespace | |
| while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; | |
| // Handle negative | |
| if (*p == '-') { neg = 1; p++; } | |
| // Parse integer part | |
| while (*p >= '0' && *p <= '9') { | |
| val = val * 10 + (*p - '0'); | |
| p++; | |
| } | |
| // Parse decimal | |
| if (*p == '.') { | |
| p++; | |
| double frac = 0.1; | |
| while (*p >= '0' && *p <= '9') { | |
| val += (*p - '0') * frac; | |
| frac *= 0.1; | |
| p++; | |
| } | |
| } | |
| // Handle exponent | |
| if (*p == 'e' || *p == 'E') { | |
| p++; | |
| int exp_neg = 0; | |
| if (*p == '-') { exp_neg = 1; p++; } | |
| else if (*p == '+') p++; | |
| int exp = 0; | |
| while (*p >= '0' && *p <= '9') { | |
| exp = exp * 10 + (*p - '0'); | |
| p++; | |
| } | |
| double mult = 1.0; | |
| while (exp--) mult *= 10.0; | |
| val = exp_neg ? val / mult : val * mult; | |
| } | |
| *s = p; | |
| return neg ? -val : val; | |
| } | |
| // Extract all numbers from a JSON object/array | |
| static inline int extract_numbers(const char *json, double *vals, int max) { | |
| int n = 0; | |
| const char *p = json; | |
| while (*p && n < max) { | |
| // Skip to next number | |
| while (*p && !(*p >= '0' && *p <= '9') && *p != '-' && *p != '.') { | |
| // Skip strings | |
| if (*p == '"') { | |
| p++; | |
| while (*p && *p != '"') { | |
| if (*p == '\\') p++; | |
| p++; | |
| } | |
| } | |
| p++; | |
| } | |
| if (*p && (*p >= '0' && *p <= '9' || *p == '-' || *p == '.')) { | |
| vals[n++] = parse_number(&p); | |
| } | |
| } | |
| return n; | |
| } | |
| // Hash function for type string | |
| static inline uint32_t hash32(const char *s, size_t len) { | |
| uint32_t h = 5381; | |
| for (size_t i = 0; i < len; i++) { | |
| h = ((h << 5) + h) + s[i]; | |
| } | |
| return h; | |
| } | |
| // Parse JSON file into objects | |
| static Obj* parse_json_minimal(const char *filename, size_t *count) { | |
| // Memory map the file | |
| int fd = open(filename, O_RDONLY); | |
| if (fd < 0) return NULL; | |
| struct stat st; | |
| fstat(fd, &st); | |
| char *data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); | |
| if (data == MAP_FAILED) return NULL; | |
| // Quick count of objects (count '{' characters) | |
| *count = 0; | |
| for (size_t i = 0; i < st.st_size; i++) { | |
| if (data[i] == '{') (*count)++; | |
| } | |
| // Allocate aligned object array | |
| Obj *objs = aligned_alloc(64, (*count) * sizeof(Obj)); | |
| memset(objs, 0, (*count) * sizeof(Obj)); | |
| // Parse each object | |
| const char *p = data; | |
| size_t obj_idx = 0; | |
| while (*p && obj_idx < *count) { | |
| // Find start of object | |
| while (*p && *p != '{') p++; | |
| if (!*p) break; | |
| const char *obj_start = p; | |
| p++; // Skip '{' | |
| // Find end of object | |
| int depth = 1; | |
| const char *obj_end = p; | |
| while (*obj_end && depth > 0) { | |
| if (*obj_end == '{') depth++; | |
| else if (*obj_end == '}') depth--; | |
| else if (*obj_end == '"') { | |
| obj_end++; | |
| while (*obj_end && *obj_end != '"') { | |
| if (*obj_end == '\\') obj_end++; | |
| obj_end++; | |
| } | |
| } | |
| obj_end++; | |
| } | |
| // Extract type if present | |
| const char *type_start = strstr(obj_start, "\"type\""); | |
| uint32_t type_hash = 0; | |
| if (type_start && type_start < obj_end) { | |
| type_start = strchr(type_start, ':'); | |
| if (type_start) { | |
| type_start = strchr(type_start, '"'); | |
| if (type_start) { | |
| type_start++; | |
| const char *type_end = strchr(type_start, '"'); | |
| if (type_end) { | |
| type_hash = hash32(type_start, type_end - type_start); | |
| } | |
| } | |
| } | |
| } | |
| // Extract numeric values | |
| objs[obj_idx].n = extract_numbers(obj_start, objs[obj_idx].v, 7); | |
| // Determine pattern based on value count and type | |
| if (objs[obj_idx].n <= 0) objs[obj_idx].n = 1; // At least 1 value | |
| objs[obj_idx].p = (objs[obj_idx].n - 1) & 3; // Pattern 0-3 | |
| obj_idx++; | |
| p = obj_end; | |
| } | |
| munmap(data, st.st_size); | |
| close(fd); | |
| return objs; | |
| } | |
| int main(int argc, char **argv) { | |
| const char *filename = argc > 1 ? argv[1] : "mixed.json"; | |
| size_t iterations = argc > 2 ? atoi(argv[2]) : 10000000; | |
| printf("JSON Polymorphic Dispatch\n"); | |
| printf("File: %s\n", filename); | |
| // Parse JSON | |
| size_t count; | |
| Obj *objs = parse_json_minimal(filename, &count); | |
| if (!objs || count == 0) { | |
| printf("Failed to parse JSON\n"); | |
| return 1; | |
| } | |
| printf("Loaded %zu objects\n", count); | |
| // Show pattern distribution | |
| int patterns[4] = {0}; | |
| for (size_t i = 0; i < count; i++) { | |
| patterns[objs[i].p]++; | |
| } | |
| printf("Patterns: [%d, %d, %d, %d]\n", patterns[0], patterns[1], patterns[2], patterns[3]); | |
| // Warmup | |
| for (size_t i = 0; i < 1000; i++) { | |
| __builtin_prefetch(&objs[i % count], 0, 3); | |
| } | |
| // Labels for computed goto dispatch | |
| static void* dispatch[] = { &&P0, &&P1, &&P2, &&P3 }; | |
| // Benchmark | |
| uint64_t start = __rdtsc(); | |
| double result = 0; | |
| for (size_t i = 0; i < iterations; i++) { | |
| Obj *o = &objs[i % count]; | |
| double x = i * 1.5; | |
| // Prefetch next | |
| __builtin_prefetch(&objs[(i + 8) % count], 0, 1); | |
| // Computed goto dispatch | |
| goto *dispatch[o->p & 3]; | |
| P0: // Single value pattern | |
| result = x + o->v[0] * 1000.0; | |
| goto next; | |
| P1: // Two value pattern | |
| result = x * o->v[0] + o->v[1]; | |
| goto next; | |
| P2: // Three value pattern | |
| result = (x + o->v[0] - o->v[1]) * o->v[2]; | |
| goto next; | |
| P3: // Multi-value pattern | |
| result = x * o->v[0]; | |
| for (int j = 1; j < o->n && j < 7; j++) { | |
| result = result * 0.9 + o->v[j]; | |
| } | |
| next: | |
| asm volatile("" :: "x"(result)); | |
| } | |
| uint64_t cycles = __rdtsc() - start; | |
| printf("\n=== RESULTS ===\n"); | |
| printf("Iterations: %zu\n", iterations); | |
| printf("Cycles/dispatch: %.2f\n", (double)cycles / iterations); | |
| printf("Throughput: %.2f M/sec\n", iterations / (cycles / 2.4e9) / 1e6); | |
| free(objs); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment