From 14624e34d82468773516a4ff3eb3a4d6bc030658 Mon Sep 17 00:00:00 2001
From: Joshua Haberman <joshua@reverberate.org>
Date: Sun, 1 Mar 2009 14:01:29 -0800
Subject: [PATCH] Added the first iteration of pbstruct.

---
 pbstruct.c |  11 ++++++
 pbstruct.h | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+)
 create mode 100644 pbstruct.c
 create mode 100644 pbstruct.h

diff --git a/pbstruct.c b/pbstruct.c
new file mode 100644
index 0000000000..97e0a9f840
--- /dev/null
+++ b/pbstruct.c
@@ -0,0 +1,11 @@
+/*
+ * pbstream - a stream-oriented implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Joshua Haberman.  See LICENSE for details.
+ */
+
+#include <stddef.h>
+#include "pbstruct.h"
+
+#define alignof(t) offsetof(struct { char c; t x; }, x)
+
diff --git a/pbstruct.h b/pbstruct.h
new file mode 100644
index 0000000000..9b12ce3d41
--- /dev/null
+++ b/pbstruct.h
@@ -0,0 +1,100 @@
+/*
+ * pbstream - a stream-oriented implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Joshua Haberman.  See LICENSE for details.
+ *
+ * pbstruct is an efficient, compact, self-describing format for storing
+ * pb messages in-memory.  It can be used when parsing a protobuf into
+ * a structure is desired, but both the parsing and emitting modules can
+ * be used without ever using pbstruct.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum pbstruct_type {
+  PBSTRUCT_TYPE_DOUBLE = 1,
+  PBSTRUCT_TYPE_FLOAT = 2,
+  PBSTRUCT_TYPE_INT32 = 3,
+  PBSTRUCT_TYPE_UINT32 = 4,
+  PBSTRUCT_TYPE_INT64 = 5,
+  PBSTRUCT_TYPE_UINT64 = 6,
+  PBSTRUCT_TYPE_BOOL = 7,
+
+  /* For these types, the main struct contains a pointer to the real data. */
+  PBSTRUCT_TYPE_BYTES = 8,
+  PBSTRUCT_TYPE_STRING = 9,
+  PBSTRUCT_TYPE_SUBSTRUCT = 10,
+
+  /* The array types are just like the primitive types, except the main struct
+   * contains a pointer to an array of the primitive type. */
+  PBSTRUCT_ARRAY = 16,  /* Not itself a real type. */
+  PBSTRUCT_TYPE_DOUBLE_ARRAY    = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_DOUBLE,
+  PBSTRUCT_TYPE_FLOAT_ARRAY     = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_FLOAT,
+  PBSTRUCT_TYPE_INT32_ARRAY     = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_INT32,
+  PBSTRUCT_TYPE_UINT32_ARRAY    = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_UINT32,
+  PBSTRUCT_TYPE_INT64_ARRAY     = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_INT64,
+  PBSTRUCT_TYPE_UINT64_ARRAY    = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_UINT64,
+  PBSTRUCT_TYPE_BOOL_ARRAY      = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_BOOL,
+  PBSTRUCT_TYPE_BYTES_ARRAY     = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_BYTES,
+  PBSTRUCT_TYPE_STRING_ARRAY    = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_STRING,
+  PBSTRUCT_TYPE_SUBSTRUCT_ARRAY = PBSTRUCT_ARRAY | PBSTRUCT_TYPE_SUBSTRUCT,
+} pbstruct_type_t;
+
+struct pbstruct_field {
+  char *name;
+  pbstruct_type_t type;
+  ptrdiff_t byte_offset;
+  ptrdiff_t isset_byte_offset;
+  uint8_t isset_byte_mask;
+};
+
+struct pbstruct_delimited {
+  size_t len;
+  char data[];
+};
+
+struct pbstruct_definition {
+  char *name;
+  size_t struct_size;
+  int num_fields;
+  int num_required_fields;
+  struct pbstruct_field fields[];
+};
+
+struct pbstruct {
+  struct pbstruct_definition *definition;
+  uint8_t data[];
+};
+
+struct pbstruct* pbstruct_new(struct pbstruct_definition *definition);
+/* Deletes any sub-structs also. */
+struct pbstruct* pbstruct_delete(struct pbstruct_definition *definition);
+
+bool pbstruct_is_set(struct pbstruct *s, struct pbstruct_field *f) {
+  return s->data[f->isset_byte_offset] & f->isset_byte_mask;
+}
+
+/* These do no existence checks or type checks. */
+#define DEFINE_GETTERS(ctype, name) \
+  ctype pbstruct_get_ ## name(struct pbstruct *s, struct pbstruct_field *f) { \
+    /* TODO: make sure the compiler knows this is an aligned access. */ \
+    return *(ctype*)(s->data + f->byte_offset); \
+  } \
+  ctype *pbstruct_get_ ## name ## _array(struct pbstruct *s, \
+                                         struct pbstruct_field *f) { \
+    /* TODO: make sure the compiler knows this is an aligned access. */ \
+    return *(ctype**)(s->data + f->byte_offset); \
+  }
+
+DEFINE_GETTERS(double,   double);
+DEFINE_GETTERS(float,    float);
+DEFINE_GETTERS(int32_t,  int32);
+DEFINE_GETTERS(int64_t,  int64);
+DEFINE_GETTERS(uint32_t, uint32);
+DEFINE_GETTERS(uint64_t, uint64);
+DEFINE_GETTERS(bool,     bool);
+DEFINE_GETTERS(struct pbstruct_delimited*, bytes);
+DEFINE_GETTERS(struct pbstruct_delimited*, string);
+DEFINE_GETTERS(struct pbstruct*, substruct);
+