summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2014-08-18 14:08:28 +0200
committerYorhel <git@yorhel.nl>2014-08-18 14:08:28 +0200
commit8d5116d0480148d5cb7ca136c60da06347628782 (patch)
treecf903420e4b44c023d52b65b1d1ffcf92b7916df
parente2566325af7c77f7621639a6d5fca8b2a3bb914e (diff)
Add functions for reading YPC values
These functions are fast, simple, and very unsafe if used incorrectly or with invalid data. Again totally untested.
-rw-r--r--Makefile.am3
-rw-r--r--lib/internal.h15
-rw-r--r--lib/val/ypc_get_float.c12
-rw-r--r--lib/val/ypc_get_int.c43
-rw-r--r--lib/val/ypc_get_size.c36
-rw-r--r--lib/val/ypc_val_parse.c15
-rw-r--r--lib/ypc.h77
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;
diff --git a/lib/ypc.h b/lib/ypc.h
index 17bc5a2..ee71df5 100644
--- a/lib/ypc.h
+++ b/lib/ypc.h
@@ -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