interpret/src/pair.c

97 lines
3.0 KiB
C

/** @license 2023 Neil Edelman, distributed under the terms of the
[MIT License](https://opensource.org/licenses/MIT).
A `pair` is `[a, b)` pair of pointers to char.
@std C99 */
#include "pair.h"
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <stdio.h> /* sprintf */
/** @return Constructs `a` and `b` as a pair. */
struct pair pair(const char *const a, const char *const b) {
struct pair p;
p.a = a, p.b = b;
return p;
}
/** Doesn't check if the number is actually in [0, 9].
@return Whether it was able to parse unsigned `p` to `n`. */
int pair_to_natural(const char *s, const char *const e, uint32_t *const n) {
uint32_t accum = 0;
while(s < e) {
unsigned next = accum * 10 + (unsigned)(*s - '0');
if(accum > next) return errno = ERANGE, 0;
accum = next;
s++;
}
return *n = accum, 1;
}
/** `h0` "1" `h1` ":" `m0` "30" `m1` -> 90 `n` @return Valid. */
int pair_colon_to_minutes(const char *h0, const char *const h1,
const char *m0, const char *const m1, uint32_t *const n) {
uint32_t hours, minutes;
return pair_to_natural(h0, h1, &hours) && pair_to_natural(m0, m1, &minutes)
&& minutes < 60 && hours <= UINT32_MAX / 60 - minutes
? (*n = hours * 60 + minutes, 1) : 0;
}
/** `h0` "1" `h1` "." `m0` "5" `m1` -> 90 `n` @return Valid. */
int pair_hours_to_minutes(const char *h0, const char *const h1,
const char *m0, const char *const m1, uint32_t *const n) {
uint32_t hours, minutes;
/* fixme: more precision? */
return pair_to_natural(h0, h1, &hours) && pair_to_natural(m0, m1, &minutes)
&& minutes <= 9 && hours <= UINT32_MAX / 60 - minutes * 6
? (*n = hours * 60 + minutes * 6, 1) : 0;
}
/** @return The content of `x` is the same as `y`. */
int pair_is_equal(struct pair x, struct pair y) {
assert(x.a <= x.b && y.a <= y.b);
if(!x.a) return !y.a;
if(!y.a) return 0;
if(x.b - x.a != y.b - y.a) return 0;
while(x.a < x.b) { if(*x.a != *y.a) return 0; x.a++, y.a++; }
return 1;
}
/** @return Exact match between a pair `x` (start-end pointers) and a string
`y` (null-terminated). */
int pair_is_string(struct pair x, const char *y) {
assert(x.a <= x.b);
if(!x.a) return !y;
if(!y) return 0;
while(x.a < x.b) { if(*x.a != *y || !*y) return 0; x.a++, y++; }
return !*y;
}
/** @return A djb2 <http://www.cse.yorku.ca/~oz/hash.html> hash of `p`. */
uint32_t pair_djb2(struct pair p) {
uint32_t hash = 5381, c;
while(p.a < p.b) {
c = (unsigned char)*p.a++;
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
return hash;
}
/* Maps from substring keywords to indices, default zero. */
static void pairmap_to_string(const struct pair key, const size_t i,
char (*const a)[12]) { (void)key; sprintf(*a, "%zu", i); }
static int pairmap_is_equal(const struct pair a, const struct pair b)
{ return pair_is_equal(a, b); }
static uint32_t pairmap_hash(const struct pair p) { return pair_djb2(p); }
#define TABLE_NAME pairmap
#define TABLE_KEY struct pair
#define TABLE_UINT uint32_t
#define TABLE_VALUE size_t
#define TABLE_DEFAULT 0 /* Default set at zero. */
#define TABLE_TO_STRING
#define TABLE_BODY
#include "../src/table.h"