diff options
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | lib/internal.h | 15 | ||||
-rw-r--r-- | lib/val/ypc_get_float.c | 12 | ||||
-rw-r--r-- | lib/val/ypc_get_int.c | 43 | ||||
-rw-r--r-- | lib/val/ypc_get_size.c | 36 | ||||
-rw-r--r-- | lib/val/ypc_val_parse.c | 15 | ||||
-rw-r--r-- | lib/ypc.h | 77 |
7 files changed, 181 insertions, 20 deletions
diff --git a/Makefile.am b/Makefile.am index b870456..1d2f745 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,6 +33,9 @@ libypc_la_SOURCES=\ lib/val/ypc_add_int.c\ lib/val/ypc_add_raw.c\ lib/val/ypc_add_textn.c\ + lib/val/ypc_get_float.c\ + lib/val/ypc_get_int.c\ + lib/val/ypc_get_size.c\ lib/val/ypc_val_parse.c\ lib/val/ypc_val_resize.c\ lib/ypc_init.c\ diff --git a/lib/internal.h b/lib/internal.h index 2db57ec..36d0863 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -72,6 +72,21 @@ typedef struct iovec ypc_iovec; #define YPC_TCPS_MAXPACKET 4096 +#define YPCT_NULL 0 +#define YPCT_FALSE 1 +#define YPCT_TRUE 2 +#define YPCT_INT8 3 +#define YPCT_INT16 4 +#define YPCT_INT32 5 +#define YPCT_INT64 6 +#define YPCT_FLOAT 7 +#define YPCT_BIN 8 +#define YPCT_TEXT 9 +#define YPCT_ARRAY 10 +#define YPCT_MAP 11 +#define YPCT_CLOSE 12 + + typedef enum { YPCN_CONNECTING, YPCN_TCPS, /* tcps:// handshake */ diff --git a/lib/val/ypc_get_float.c b/lib/val/ypc_get_float.c new file mode 100644 index 0000000..71a029e --- /dev/null +++ b/lib/val/ypc_get_float.c @@ -0,0 +1,12 @@ +#include "../internal.h" +#include "../util/byteswap.h" + +YPC_EXPORT double ypc_get_float(ypc_get g) { + assert(*g.buf == YPCT_FLOAT && "ypc_get_float() used on a non-float value"); + uint64_t u; + double v; + memcpy(&u, g.buf+1, 8); + u = ypc__hn64(u); + memcpy(&v, &u, 8); + return v; +} diff --git a/lib/val/ypc_get_int.c b/lib/val/ypc_get_int.c new file mode 100644 index 0000000..18b23e8 --- /dev/null +++ b/lib/val/ypc_get_int.c @@ -0,0 +1,43 @@ +#include "../internal.h" +#include "../util/byteswap.h" + +YPC_EXPORT int64_t ypc_get_int(ypc_get g) { + /* XXX: Casting from unsigned to signed is UB, so memcpy() instead. */ + switch(*g.buf) { + case YPCT_INT8: + { + int8_t v; + memcpy(&v, g.buf+1, 1); + return v; + } + case YPCT_INT16: + { + uint16_t v; + int16_t i; + memcpy(&v, g.buf+1, 2); + v = ypc__hn16(v); + memcpy(&i, &v, 2); + return i; + } + case YPCT_INT32: + { + uint32_t v; + int32_t i; + memcpy(&v, g.buf+1, 4); + v = ypc__hn32(v); + memcpy(&i, &v, 4); + return i; + } + case YPCT_INT64: + { + uint64_t v; + int64_t i; + memcpy(&v, g.buf+1, 8); + v = ypc__hn64(v); + memcpy(&i, &v, 8); + return i; + } + } + assert(0 && "ypc_get_int() used on a non-integer value"); + return -1; +} diff --git a/lib/val/ypc_get_size.c b/lib/val/ypc_get_size.c new file mode 100644 index 0000000..2fdaa97 --- /dev/null +++ b/lib/val/ypc_get_size.c @@ -0,0 +1,36 @@ +#include "../internal.h" + +YPC_EXPORT size_t ypc_get_size(ypc_get g) { + switch(*g.buf) { + case YPCT_NULL: + case YPCT_FALSE: + case YPCT_TRUE: + case YPCT_CLOSE: + return 1; + case YPCT_INT8: + return 2; + case YPCT_INT16: + return 3; + case YPCT_INT32: + return 5; + case YPCT_INT64: + case YPCT_FLOAT: + return 9; + case YPCT_BIN: + return 4+ypc_get_bin_len(g); + case YPCT_TEXT: + return 2+strlen((const char *)g.buf+1); + case YPCT_ARRAY: + case YPCT_MAP: + { + size_t l = 1; + while(g.buf[l] != YPCT_CLOSE) { + ypc_get v = {g.buf+l}; + l += ypc_get_size(v); + } + return l+1; + } + } + assert(0 && "ypc_get_size() used on an invalid value"); + return 0; +} diff --git a/lib/val/ypc_val_parse.c b/lib/val/ypc_val_parse.c index 223f776..603a01c 100644 --- a/lib/val/ypc_val_parse.c +++ b/lib/val/ypc_val_parse.c @@ -11,21 +11,6 @@ typedef enum { } ypc__parse_state; -#define YPCT_NULL 0 -#define YPCT_FALSE 1 -#define YPCT_TRUE 2 -#define YPCT_INT8 3 -#define YPCT_INT16 4 -#define YPCT_INT32 5 -#define YPCT_INT64 6 -#define YPCT_FLOAT 7 -#define YPCT_BIN 8 -#define YPCT_TEXT 9 -#define YPCT_ARRAY 10 -#define YPCT_MAP 11 -#define YPCT_CLOSE 12 - - static int ypc__parse_endval(ypc_val_parser *p) { p->state = YPCP_TYPE; return p->depth == 0; @@ -24,6 +24,26 @@ typedef struct { uint32_t size, len; } ypc_val; +typedef struct { + const uint8_t *buf; +} ypc_get; + +typedef struct { + const uint8_t *buf; +} ypc_iter; + +typedef enum { + YPC_NULL, + YPC_BOOL, + YPC_INT, + YPC_FLOAT, + YPC_BIN, + YPC_TEXT, + YPC_ARRAY, + YPC_MAP, + YPC_CLOSE +} ypc_type; + #define YPC_NONBLOCK 0x01 #define YPC_RECV 0x02 @@ -72,6 +92,9 @@ YPC_IMPORT int ypc_add_int(ypc_val *, int64_t); YPC_IMPORT int ypc_add_float(ypc_val *, double); YPC_IMPORT int ypc_add_bin(ypc_val *, const uint8_t *, size_t); YPC_IMPORT int ypc_add_textn(ypc_val *, const char *, size_t); +YPC_IMPORT int64_t ypc_get_int(ypc_get); +YPC_IMPORT double ypc_get_float(ypc_get); +YPC_IMPORT size_t ypc_get_size(ypc_get); YPC_IMPORT ypc_msg *ypc_msg_new(const char *, size_t); YPC_IMPORT void ypc_msg_free(ypc_msg *); @@ -99,11 +122,55 @@ YPC_IMPORT void ypc_serv_free(ypc_serv *); /* Smallish stuff that is better suited for inlining */ static inline int ypc_val_init(ypc_val *v, size_t size) { v->buf = NULL; v->len = 0; return ypc_val_resize(v, size ? size : 512); } -static inline int ypc_add_null(ypc_val *v) { return ypc_add_raw(v, (uint8_t *)"\0", 1); } -static inline int ypc_add_bool(ypc_val *v, bool b) { return ypc_add_raw(v, (uint8_t *)(b ? "\2" : "\1"), 1); } +static inline void ypc_val_free(ypc_val *v) { free(v->buf); } +static inline int ypc_add_null(ypc_val *v) { return ypc_add_raw(v, (const uint8_t *)"\0", 1); } +static inline int ypc_add_bool(ypc_val *v, bool b) { return ypc_add_raw(v, (const uint8_t *)(b ? "\2" : "\1"), 1); } static inline int ypc_add_text(ypc_val *v, const char *t) { return ypc_add_textn(v, t, strlen(t)); } -static inline int ypc_add_array(ypc_val *v) { return ypc_add_raw(v, (uint8_t *)"\12", 1); } -static inline int ypc_add_map(ypc_val *v) { return ypc_add_raw(v, (uint8_t *)"\13", 1); } -static inline int ypc_add_close(ypc_val *v) { return ypc_add_raw(v, (uint8_t *)"\14", 1); } +static inline int ypc_add_array(ypc_val *v) { return ypc_add_raw(v, (const uint8_t *)"\12", 1); } +static inline int ypc_add_map(ypc_val *v) { return ypc_add_raw(v, (const uint8_t *)"\13", 1); } +static inline int ypc_add_close(ypc_val *v) { return ypc_add_raw(v, (const uint8_t *)"\14", 1); } +static inline int ypc_add_val(ypc_val *v, ypc_get g) { return ypc_add_raw(v, g.buf, ypc_get_size(g)); } + +static inline ypc_get ypc_val_get(ypc_val *v) { ypc_get g = {v->buf}; return g; } +static inline bool ypc_get_bool(ypc_get g) { return *g.buf == 2; } +static inline const char * ypc_get_text(ypc_get g) { return (const char *)g.buf+1; } +static inline const uint8_t *ypc_get_bin(ypc_get g) { return g.buf+4; } +static inline size_t ypc_get_bin_len(ypc_get g) { return (g.buf[1] << 16) | (g.buf[2] << 8) | g.buf[3]; } +static inline ypc_iter ypc_get_iter(ypc_get g) { ypc_iter i = {g.buf+1}; return i; } +static inline bool ypc_iter_end(ypc_iter i) { return *i.buf == 12; } +static inline ypc_get ypc_iter_next(ypc_iter *i) { ypc_get g = {i->buf}; i->buf += ypc_get_size(g); return g; } + +/* While not very small, this is still a static inline to enable a bunch of + * optimizations. E.g. ypc_get_type(v) == YPC_TEXT should compile down to + * *v->buf == 9, which is much cheaper than a function call. A similar + * optimization is possible when using ypc_get_type() in a switch statement. + */ +static inline ypc_type ypc_get_type(ypc_get *v) { + switch(*v->buf) { + case 0: + return YPC_NULL; + case 1: + case 2: + return YPC_BOOL; + case 3: + case 4: + case 5: + case 6: + return YPC_INT; + case 7: + return YPC_FLOAT; + case 8: + return YPC_BIN; + case 9: + return YPC_TEXT; + case 10: + return YPC_ARRAY; + case 11: + return YPC_MAP; + case 12: + return YPC_CLOSE; + } + return 0; /* Should not happen... */ +} #endif |