Skip to content

Instantly share code, notes, and snippets.

@michael-grunder
Created November 29, 2023 04:15
Show Gist options
  • Save michael-grunder/b9429a0fc9560e176841b1f3ba1bf659 to your computer and use it in GitHub Desktop.
Save michael-grunder/b9429a0fc9560e176841b1f3ba1bf659 to your computer and use it in GitHub Desktop.
Toy program to convert uint8_t strings into uint8_t values.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <locale.h>
#define MAX_DIGITS 3
#define TABLE_SIZE 3750194
struct numbers {
char *ptr;
uint8_t *dgt;
};
uint8_t *g_lookup;
long long ustime(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000 + tv.tv_usec;
}
void printTiming(const char *what, long long n, long long tm) {
double sec = tm / 1000000.00, psec = n / sec;
printf("Executed %lld '%s' calls in %f sec (%'lu/sec)\n",
n, what, sec, (unsigned long)psec);
}
static void *zcalloc(size_t n) {
void *ptr;
ptr = calloc(1, n);
if (ptr == NULL) {
fprintf(stderr, "Error: Failed to allocate %zu bytes\n", n);
exit(1);
}
return ptr;
}
static size_t countDigits(uint8_t n) {
if (n >= 100)
return 3;
else if (n >= 10)
return 2;
else
return 1;
}
struct numbers createNumbers(size_t n) {
struct numbers res = {0};
res.ptr = zcalloc(3 * n + 1);
res.dgt = zcalloc(sizeof(*res.dgt) * n);
if (res.ptr == NULL || res.dgt == NULL)
abort();
char *ptr = res.ptr;
for (size_t i = 0; i < n; i++) {
uint8_t rng = rand() % 256;
res.dgt[i] = sprintf(ptr, "%u", rng);
ptr += res.dgt[i];
}
return res;
}
void freeNumbers(struct numbers *nums) {
if (nums == NULL)
return;
free(nums->ptr);
free(nums->dgt);
}
typedef union {
struct {
uint32_t v24: 24;
uint8_t unused;
} v24;
uint16_t v16;
uint8_t v8;
} vli;
#ifdef SAFE
static inline size_t calcIndexValue(char *num, size_t len) {
vli aux = {0};
if (len == 3) {
memcpy(&aux, num, sizeof(aux));
return aux.v24.v24;
} else if (len == 2) {
memcpy(&aux, num, 2);
return aux.v16;
} else {
memcpy(&aux, num, 1);
return aux.v8;
}
}
#else
static inline size_t calcIndexValue(char *num, size_t len) {
vli aux;
// We are assuming we can always copy sizeof(aux) bytes
memcpy(&aux, num, sizeof(aux));
if (len == 3) {
return aux.v24.v24;
} else if (len == 2) {
return aux.v16;
} else {
return aux.v8;
}
}
#endif
static inline uint8_t parse_u8(char *num, size_t len) {
return g_lookup[calcIndexValue(num, len)];
}
void initLookup(void) {
g_lookup = calloc(TABLE_SIZE, sizeof(*g_lookup));
for (uint16_t i = 0; i < 256; i++) {
size_t len, idx;
char buf[24];
len = snprintf(buf, sizeof(buf), "%u", i);
idx = calcIndexValue(buf, len);
g_lookup[idx] = i;
}
}
void getIndexes(void) {
for (uint16_t i = 0; i < 256; i++) {
size_t len, idx;
char buf[24];
len = snprintf(buf, sizeof(buf), "%u", i);
idx = calcIndexValue(buf, len);
printf("%zu : %s\n", idx, buf);
}
}
static void validateConversion(size_t n, char *num, size_t len) {
char tmp[24] = {0};
uint8_t chk_val, alg_val;
memcpy(tmp, num, len);
alg_val = parse_u8(num, len);
chk_val = atoi(tmp);
if (alg_val != chk_val) {
fprintf(stderr, "Error: [%zu] %u doesn't match expected %u for input '%s'\n",
n, alg_val, chk_val, tmp);
exit(1);
}
// fprintf(stderr, "OK: '%s' -> %u\n", tmp, alg_val);
}
int main(int argc, const char **argv) {
size_t count, total = 0;
struct numbers nums;
uint8_t val;
char *ptr;
initLookup();
srand(ustime());
setlocale(LC_NUMERIC, "");
count = argc > 1 ? atoi(argv[1]) : 10000000;
if (count < 1) {
fprintf(stderr, "Error: Must generate at least one number\n");
exit(1);
}
printf("Generating %zu random uint8_t values...", count);
nums = createNumbers(count);
printf("done\n");
ptr = nums.ptr;
long long t1 = ustime();
for (size_t i = 0; i < count; i++) {
val = parse_u8(ptr, nums.dgt[i]);
#if VERIFY
validateConversion(i, ptr, nums.dgt[i]);
#endif
total += val;
ptr += nums.dgt[i];
}
long long t2 = ustime();
// So we don't optimize away the conversions
printf("Total value of all numbers: %zu\n", total);
printTiming("CALLS", count, t2 - t1);
freeNumbers(&nums);
free(g_lookup);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment