hop-2012/experiments/cmsg/sexp.h

163 lines
4.3 KiB
C

/* Copyright 2010, 2011, 2012 Tony Garnock-Jones <tonygarnockjones@gmail.com>.
*
* This file is part of Hop.
*
* Hop is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hop is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Hop. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef cmsg_sexp_h
#define cmsg_sexp_h
typedef struct sexp_data_t_ {
refcount_t refcount;
cmsg_bytes_t data;
} sexp_data_t;
typedef enum sexp_type_t_ {
SEXP_BYTES,
SEXP_SLICE,
SEXP_DISPLAY_HINT,
SEXP_PAIR
} sexp_type_t;
typedef struct sexp_t_ {
refcount_t refcount;
sexp_type_t kind;
union {
cmsg_bytes_t bytes;
struct {
sexp_data_t *data;
size_t offset;
size_t length;
} slice;
struct {
struct sexp_t_ *head;
struct sexp_t_ *tail;
} pair; /* and display-hint */
} data;
} sexp_t;
extern sexp_t *sexp_empty_bytes;
extern void init_sexp(void);
extern void done_sexp(void);
extern sexp_t *sexp_incref(sexp_t *x);
extern sexp_t *sexp_decref(sexp_t *x);
extern void sexp_data_destructor(sexp_data_t *data);
extern void sexp_destructor(sexp_t *x);
extern sexp_data_t *sexp_data_copy(cmsg_bytes_t body, size_t offset, size_t length);
extern sexp_data_t *sexp_data_alias(cmsg_bytes_t body);
extern sexp_t *sexp_cstring(char const *str);
extern sexp_t *sexp_bytes(cmsg_bytes_t bytes);
extern sexp_t *sexp_slice(sexp_data_t *data, size_t offset, size_t length);
extern sexp_t *sexp_display_hint(sexp_t *hint, sexp_t *body);
extern sexp_t *sexp_cons(sexp_t *head, sexp_t *tail);
static inline int sexp_simple_stringp(sexp_t *x) {
return (x != NULL) && ((x->kind == SEXP_BYTES) || (x->kind == SEXP_SLICE));
}
static inline int sexp_stringp(sexp_t *x) {
return sexp_simple_stringp(x) || ((x != NULL) && (x->kind == SEXP_DISPLAY_HINT));
}
static inline int sexp_pairp(sexp_t *x) {
return (x != NULL) && (x->kind == SEXP_PAIR);
}
extern cmsg_bytes_t sexp_data(sexp_t *x);
extern int sexp_cmp(sexp_t *a, sexp_t *b);
static inline sexp_t *sexp_head(sexp_t *x) {
assert(x->kind == SEXP_PAIR);
return x->data.pair.head;
}
static inline sexp_t *sexp_tail(sexp_t *x) {
assert(x->kind == SEXP_PAIR);
return x->data.pair.tail;
}
static inline sexp_t *sexp_hint(sexp_t *x) {
assert(x->kind == SEXP_DISPLAY_HINT);
return x->data.pair.head;
}
static inline sexp_t *sexp_body(sexp_t *x) {
assert(x->kind == SEXP_DISPLAY_HINT);
return x->data.pair.tail;
}
#define sexp_setter_(settername,fieldname) \
static inline sexp_t *settername(sexp_t *x, sexp_t *y) { \
sexp_t *old; \
assert(x->kind == SEXP_PAIR); \
INCREF(y); \
old = x->data.pair.fieldname; \
x->data.pair.fieldname = y; \
DECREF(old, sexp_destructor); \
return x; \
}
sexp_setter_(sexp_sethead, head)
sexp_setter_(sexp_settail, tail)
static inline sexp_t *sexp_push(sexp_t *oldstack, sexp_t *val) {
sexp_t *newstack = INCREF(sexp_cons(val, oldstack));
DECREF(oldstack, sexp_destructor);
return newstack;
}
static inline sexp_t *sexp_pop(sexp_t *oldstack, sexp_t **valp) {
sexp_t *nextstack = INCREF(sexp_tail(oldstack));
sexp_t *val = INCREF(sexp_head(oldstack));
DECREF(oldstack, sexp_destructor);
UNGRAB(val);
if (valp != NULL) {
*valp = val;
}
return nextstack;
}
static inline int sexp_pseudo_pop(sexp_t **px) {
*px = sexp_tail(*px);
return sexp_pairp(*px);
}
static inline sexp_t *sexp_listtail(sexp_t *list, size_t dropcount) {
while (dropcount) {
list = sexp_tail(list);
dropcount--;
}
return list;
}
static inline sexp_t *sexp_listref(sexp_t *list, size_t index) {
return sexp_head(sexp_listtail(list, index));
}
extern sexp_t *sexp_assoc(sexp_t *list, cmsg_bytes_t key);
extern size_t sexp_length(sexp_t *list);
extern sexp_t *sexp_new_queue(void);
extern int sexp_queue_emptyp(sexp_t *q);
extern void sexp_queue_pushback(sexp_t *q, sexp_t *x);
extern void sexp_enqueue(sexp_t *q, sexp_t *x);
extern sexp_t *sexp_dequeue(sexp_t *q);
#endif