diff options
| author | Federico Angelilli <code@fedang.net> | 2024-06-05 02:29:45 +0200 |
|---|---|---|
| committer | Federico Angelilli <code@fedang.net> | 2024-06-05 02:29:45 +0200 |
| commit | c3d59b49767602ef2e53cd93f0f963e981af6cdd (patch) | |
| tree | 028ed86f73428c48f7118f916d6d12b9b5c019a3 /any_sexp.h | |
| parent | 286d597683ee3fe6fbeed44ffcf362bccb701b03 (diff) | |
Add no boxing option for any_sexp
Diffstat (limited to 'any_sexp.h')
| -rw-r--r-- | any_sexp.h | 138 |
1 files changed, 111 insertions, 27 deletions
@@ -5,29 +5,48 @@ #include <stddef.h> #include <stdbool.h> -#define ANY_SEXP_NIL (any_sexp_t)NULL -#define ANY_SEXP_ERROR (any_sexp_t)UINTPTR_MAX - -#ifdef ANY_SEXP_NO_TAGGING -typedef struct { +typedef enum { + ANY_SEXP_TAG_ERROR = 0xf, + ANY_SEXP_TAG_NIL = 0, + ANY_SEXP_TAG_CONS = 1 << 0, + ANY_SEXP_TAG_SYMBOL = 1 << 1, + ANY_SEXP_TAG_QUOTE = 1 << 2, +} any_sexp_tag_t; + +#ifdef ANY_SEXP_NO_BOXING + +typedef struct any_sexp { + any_sexp_tag_t tag; + union { + struct any_sexp_cons *cons; + char *symbol; + struct any_sexp *quote; + }; } any_sexp_t; +#define ANY_SEXP_NIL ((any_sexp_t){ ANY_SEXP_TAG_NIL }) +#define ANY_SEXP_ERROR ((any_sexp_t){ ANY_SEXP_TAG_ERROR }) + +#define ANY_SEXP_GET_TAG(sexp) ((sexp).tag) + #else typedef void *any_sexp_t; +#define ANY_SEXP_NIL (any_sexp_t)NULL +#define ANY_SEXP_ERROR (any_sexp_t)UINTPTR_MAX #define ANY_SEXP_UNTAG(sexp) (any_sexp_t)((uintptr_t)(sexp) & 0x0fffffffffffffff) #define ANY_SEXP_TAG(sexp, tag) (any_sexp_t)((uintptr_t)(sexp) | ((uintptr_t)tag << 60)) #define ANY_SEXP_GET_TAG(sexp) (((uintptr_t)(sexp) >> 60) & 0xf) - -#define ANY_SEXP_TAG_ERROR 0xf -#define ANY_SEXP_TAG_NIL 0 -#define ANY_SEXP_TAG_CONS (1 << 0) -#define ANY_SEXP_TAG_SYMBOL (1 << 1) -#define ANY_SEXP_TAG_QUOTE (1 << 2) #endif -typedef struct { +#define ANY_SEXP_IS_TAG(sexp, tag) (ANY_SEXP_GET_TAG(sexp) == (tag)) +#define ANY_SEXP_IS_ERROR(sexp) (ANY_SEXP_IS_TAG(sexp, ANY_SEXP_TAG_ERROR)) +#define ANY_SEXP_IS_NIL(sexp) (ANY_SEXP_IS_TAG(sexp, ANY_SEXP_TAG_NIL)) +#define ANY_SEXP_IS_CONS(sexp) (ANY_SEXP_IS_TAG(sexp, ANY_SEXP_TAG_CONS)) +#define ANY_SEXP_IS_QUOTE(sexp) (ANY_SEXP_IS_TAG(sexp, ANY_SEXP_TAG_QUOTE)) + +typedef struct any_sexp_cons { any_sexp_t car; any_sexp_t cdr; } any_sexp_cons_t; @@ -130,7 +149,15 @@ static any_sexp_t any_sexp_parser_symbol(any_sexp_parser_t *parser) memcpy(sym, parser->source + cursor, length); sym[length] = '\0'; +#ifndef ANY_SEXP_NO_BOXING return ANY_SEXP_TAG(sym, ANY_SEXP_TAG_SYMBOL); +#else + any_sexp_t sexp = { + .tag = ANY_SEXP_TAG_SYMBOL, + .symbol = sym, + }; + return sexp; +#endif } static any_sexp_t any_sexp_parser_quote(any_sexp_parser_t *parser) @@ -139,8 +166,18 @@ static any_sexp_t any_sexp_parser_quote(any_sexp_parser_t *parser) parser->cursor++; any_sexp_t *quote = ANY_SEXP_MALLOC(sizeof(any_sexp_t)); + if (quote == NULL) return ANY_SEXP_ERROR; *quote = any_sexp_parser_next(parser); + +#ifndef ANY_SEXP_NO_BOXING return (any_sexp_t )ANY_SEXP_TAG(quote, ANY_SEXP_TAG_QUOTE); +#else + any_sexp_t sexp = { + .tag = ANY_SEXP_TAG_QUOTE, + .quote = quote, + }; + return sexp; +#endif } any_sexp_t any_sexp_parser_next(any_sexp_parser_t *parser) @@ -168,7 +205,7 @@ any_sexp_t any_sexp_parser_next(any_sexp_parser_t *parser) any_sexp_t sub = any_sexp_parser_next(parser); sexp = any_sexp_cons(sub, sexp); // reversed - if (sub == ANY_SEXP_ERROR || sexp == ANY_SEXP_NIL) { + if (ANY_SEXP_IS_ERROR(sub) || ANY_SEXP_IS_ERROR(sexp)) { any_sexp_free(sexp); return ANY_SEXP_ERROR; } @@ -183,55 +220,84 @@ any_sexp_t any_sexp_parser_next(any_sexp_parser_t *parser) any_sexp_t any_sexp_cons(any_sexp_t car, any_sexp_t cdr) { any_sexp_cons_t *cons = ANY_SEXP_MALLOC(sizeof(any_sexp_cons_t)); + if (cons == NULL) return ANY_SEXP_ERROR; + cons->car = car; cons->cdr = cdr; + +#ifndef ANY_SEXP_NO_BOXING return ANY_SEXP_TAG(cons, ANY_SEXP_TAG_CONS); +#else + any_sexp_t sexp = { + .tag = ANY_SEXP_TAG_CONS, + .cons = cons, + }; + return sexp; +#endif } any_sexp_t any_sexp_car(any_sexp_t sexp) { - if (ANY_SEXP_GET_TAG(sexp) != ANY_SEXP_TAG_CONS) + if (!ANY_SEXP_IS_CONS(sexp)) return ANY_SEXP_ERROR; +#ifndef ANY_SEXP_NO_BOXING any_sexp_cons_t *cons = (any_sexp_cons_t *)ANY_SEXP_UNTAG(sexp); return cons->car; +#else + return sexp.cons->car; +#endif } any_sexp_t any_sexp_cdr(any_sexp_t sexp) { - if (ANY_SEXP_GET_TAG(sexp) != ANY_SEXP_TAG_CONS) + if (!ANY_SEXP_IS_CONS(sexp)) return ANY_SEXP_ERROR; +#ifndef ANY_SEXP_NO_BOXING any_sexp_cons_t *cons = (any_sexp_cons_t *)ANY_SEXP_UNTAG(sexp); return cons->cdr; +#else + return sexp.cons->cdr; +#endif } any_sexp_t any_sexp_reverse(any_sexp_t sexp) { - if (sexp == ANY_SEXP_NIL) + if (ANY_SEXP_IS_NIL(sexp)) return sexp; - if (ANY_SEXP_GET_TAG(sexp) != ANY_SEXP_TAG_CONS) + if (!ANY_SEXP_IS_CONS(sexp)) return ANY_SEXP_ERROR; +#ifndef ANY_SEXP_NO_BOXING any_sexp_cons_t *cons = (any_sexp_cons_t *)ANY_SEXP_UNTAG(sexp); any_sexp_t prev = ANY_SEXP_NIL, next = ANY_SEXP_NIL; while (cons != NULL) { - - if (cons->cdr != ANY_SEXP_NIL && ANY_SEXP_GET_TAG(cons->cdr) != ANY_SEXP_TAG_CONS) + if (!ANY_SEXP_IS_NIL(cons) && !ANY_SEXP_IS_CONS(cons)) return ANY_SEXP_ERROR; next = (any_sexp_cons_t *)ANY_SEXP_UNTAG(cons->cdr); - cons->cdr = prev == ANY_SEXP_NIL - ? ANY_SEXP_NIL - : ANY_SEXP_TAG(prev, ANY_SEXP_TAG_CONS); - - prev = cons; + cons->cdr = prev; + prev = ANY_SEXP_TAG(cons, ANY_SEXP_TAG_CONS); cons = next; } +#else + any_sexp_t cons = sexp, prev = ANY_SEXP_NIL, next = ANY_SEXP_NIL; + + while (cons.cons != NULL) { + if (!ANY_SEXP_IS_NIL(cons) && !ANY_SEXP_IS_CONS(cons)) + return ANY_SEXP_ERROR; + + memcpy(&next, &cons.cons->cdr, sizeof(any_sexp_t)); + memcpy(&cons.cons->cdr, &prev, sizeof(any_sexp_t)); + memcpy(&prev, &cons, sizeof(any_sexp_t)); + memcpy(&cons, &next, sizeof(any_sexp_t)); + } +#endif - return ANY_SEXP_TAG(prev, ANY_SEXP_TAG_CONS); + return prev; } void any_sexp_print(any_sexp_t sexp) @@ -247,21 +313,29 @@ void any_sexp_print(any_sexp_t sexp) case ANY_SEXP_TAG_CONS: putchar('('); - while (sexp != ANY_SEXP_NIL && sexp != ANY_SEXP_ERROR) { + while (!ANY_SEXP_IS_NIL(sexp) && !ANY_SEXP_IS_ERROR(sexp)) { any_sexp_print(any_sexp_car(sexp)); sexp = any_sexp_cdr(sexp); - if (sexp != ANY_SEXP_NIL) putchar(' '); + if (!ANY_SEXP_IS_NIL(sexp)) putchar(' '); } putchar(')'); break; case ANY_SEXP_TAG_SYMBOL: +#ifndef ANY_SEXP_NO_BOXING printf("%s", (char *)ANY_SEXP_UNTAG(sexp)); +#else + printf("%s", sexp.symbol); +#endif break; case ANY_SEXP_TAG_QUOTE: putchar('\''); +#ifndef ANY_SEXP_NO_BOXING any_sexp_print(*(any_sexp_t *)ANY_SEXP_UNTAG(sexp)); +#else + any_sexp_print(*sexp.quote); +#endif break; } } @@ -276,16 +350,26 @@ void any_sexp_free(any_sexp_t sexp) case ANY_SEXP_TAG_CONS: any_sexp_free(any_sexp_car(sexp)); any_sexp_free(any_sexp_cdr(sexp)); +#ifndef ANY_SEXP_NO_BOXING ANY_SEXP_FREE(ANY_SEXP_UNTAG(sexp)); +#endif break; case ANY_SEXP_TAG_SYMBOL: +#ifndef ANY_SEXP_NO_BOXING ANY_SEXP_FREE(ANY_SEXP_UNTAG(sexp)); +#else + ANY_SEXP_FREE(sexp.symbol); +#endif break; case ANY_SEXP_TAG_QUOTE: +#ifndef ANY_SEXP_NO_BOXING any_sexp_free(*(any_sexp_t *)ANY_SEXP_UNTAG(sexp)); ANY_SEXP_FREE(ANY_SEXP_UNTAG(sexp)); +#else + any_sexp_free(*sexp.quote); +#endif break; } } |
