/** @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 #include #include /** @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 anything. @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; } 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; } 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; } /** djb2 */ 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; }