summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2009-12-21 12:52:35 -0800
committerJoshua Haberman <joshua@reverberate.org>2009-12-21 12:52:35 -0800
commit7dd113baa80af735073ce7131e46c66a6b69d01f (patch)
tree2e9ec98224355e0b05d123c0c0987f6e20e5725f
parentc2419764856e5666bfa9e3c1b87de29ec93babe1 (diff)
Added upb_data.*, left out of last commit.
-rw-r--r--src/upb_data.c78
-rw-r--r--src/upb_data.h279
2 files changed, 357 insertions, 0 deletions
diff --git a/src/upb_data.c b/src/upb_data.c
new file mode 100644
index 0000000..66e9885
--- /dev/null
+++ b/src/upb_data.c
@@ -0,0 +1,78 @@
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Joshua Haberman. See LICENSE for details.
+ */
+
+#include "upb_data.h"
+
+static uint32_t round_up_to_pow2(uint32_t v)
+{
+ /* cf. http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+ return v;
+}
+
+upb_string *upb_string_new() {
+ upb_string *s = malloc(sizeof(*s));
+ s->byte_size = 0;
+ s->byte_len = 0;
+ s->ptr = NULL;
+ s->is_heap_allocated = true;
+ s->is_frozen = false;
+ return s;
+}
+
+static void _upb_string_free(upb_string *s)
+{
+ if(s->byte_size != 0) free(s->ptr);
+ free(s);
+}
+
+INLINE upb_string *upb_string_getref(upb_string *s, upb_flags_t ref_flags) {
+ if((ref_flags == UPB_REF_FROZEN && !s->is_frozen && s
+ upb_atomic_read((void*)(s + 1)) > 1) ||
+ (ref_flags == UPB_REF_MUTABLE && s->is_frozen &&
+}
+
+char *upb_string_getrwbuf(upb_string *s, upb_strlen_t byte_len)
+{
+ if(s->byte_size < byte_len) {
+ // Need to resize.
+ s->byte_size = round_up_to_pow2(byte_len);
+ s->ptr = realloc(s->ptr, s->byte_size);
+ }
+ s->byte_len = byte_len;
+ return s->ptr;
+}
+
+void upb_msg_destroy(struct upb_msg *msg) {
+ for(upb_field_count_t i = 0; i < msg->def->num_fields; i++) {
+ struct upb_fielddef *f = &msg->def->fields[i];
+ if(!upb_msg_isset(msg, f) || !upb_field_ismm(f)) continue;
+ upb_mm_destroy(upb_msg_getptr(msg, f), upb_field_ptrtype(f));
+ }
+ upb_def_unref(UPB_UPCAST(msg->def));
+ free(msg);
+}
+
+void upb_array_destroy(struct upb_array *arr)
+{
+ if(upb_elem_ismm(arr->fielddef)) {
+ upb_arraylen_t i;
+ /* Unref elements. */
+ for(i = 0; i < arr->size; i++) {
+ union upb_value_ptr p = upb_array_getelementptr(arr, i);
+ upb_mm_destroy(p, upb_elem_ptrtype(arr->fielddef));
+ }
+ }
+ if(arr->size != 0) free(arr->elements._void);
+ free(arr);
+}
+
diff --git a/src/upb_data.h b/src/upb_data.h
new file mode 100644
index 0000000..a15cb35
--- /dev/null
+++ b/src/upb_data.h
@@ -0,0 +1,279 @@
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Joshua Haberman. See LICENSE for details.
+ *
+ * This file defines the in-memory format for messages, arrays, and strings
+ * (which are the three dynamically-allocated structures that make up all
+ * protobufs). */
+
+#ifndef UPB_DATA_H
+#define UPB_DATA_H
+
+#include <string.h>
+#include "upb.h"
+#include "upb_def.h"
+
+// Set if the object itself was allocated with malloc() and should be freed
+// with free(). This flag would be false if the object was allocated on the
+// stack or is data from the static segment of an object file. Note that this
+// flag does not apply to the data being referenced by a string or array.
+//
+// If this flag is false, UPB_FLAG_HAS_REFCOUNT must be false also; there is
+// no sense refcounting something that does not need to be freed.
+#define UPB_FLAG_IS_HEAP_ALLOCATED (1<<2)
+
+// Set if the object is frozen against modification. While an object is
+// frozen, it is suitable for concurrent access. Note that this flag alone is
+// not a sufficient mechanism for preventing any kind of writes to the object's
+// memory, because the object could still have a refcount and/or reflist.
+#define UPB_FLAG_IS_FROZEN (1<<3)
+
+// Set if the object has an embedded refcount.
+#define UPB_FLAG_HAS_REFCOUNT (1<<4)
+
+// Specifies the type of ref that is requested based on the kind of access the
+// caller needs to the object.
+enum upb_ref_flags {
+ // Use when the client plans to perform read-only access to the object, and
+ // only in one thread at a time. This imposes the least requirements on the
+ // object; it can be either frozen or not. As a result, requesting a
+ // reference of this type never performs a copy unless the object has no
+ // refcount.
+ UPB_REF_THREADUNSAFE_READONLY = 0,
+
+ // Use when the client plans to perform read-only access, but from multiple
+ // threads concurrently. This will force the object to eagerly perform any
+ // parsing that may have been lazily deferred, and will force a copy if the
+ // object is not current frozen and there are any other referents (who expect
+ // the object to stay writable).
+ //
+ // Asking for a reference of this type is equivalent to:
+ // x = getref(y, UPB_REF_THREADUNSAFE_READONLY);
+ // x = freeze(x);
+ // ...except it is more efficient.
+ UPB_REF_FROZEN = 1,
+
+ // Use when the client plans to perform read/write access. As a result, the
+ // reference will not be thread-safe for concurrent reading *or* writing; the
+ // object must be externally synchronized if it is being accessed from more
+ // than one thread. This will force a copy if the object is not currently
+ // frozen and there are any other referents (who expect the object to stay
+ // safe for unsynchronized reads).
+ //
+ // Asking for a reference of this type is equivalent to:
+ // x = getref(y, UPB_REF_THREADUNSAFE_READONLY);
+ // x = thaw(x);
+ // ...except it is more efficient.
+ UPB_REF_MUTABLE = 2
+}
+
+typedef uint8_t upb_flags_t;
+struct upb_mmhead {};
+
+/* upb_string *****************************************************************/
+
+typedef uint32_t upb_strlen_t;
+
+// The members of this struct are private. Access should only be through the
+// associated functions.
+typedef struct upb_string {
+ unsigned int byte_size:29; // How many bytes we own, 0 if we don't own.
+ bool is_heap_allocated:1;
+ bool is_frozen:1;
+ // TODO. At the moment, all dynamically allocated strings have refcounts.
+ bool has_refcount:1;
+ upb_strlen_t byte_len;
+ // We expect the data to be 8-bit clean (uint8_t), but char* is such an
+ // ingrained convention that we follow it.
+ char *ptr;
+} upb_string;
+
+typedef struct {
+ upb_string s;
+ upb_atomic_refcount_t refcount;
+} upb_refcounted_string;
+
+// Returns a newly constructed string, which starts out empty. Caller owns one
+// ref on it.
+upb_string *upb_string_new(void);
+
+// Returns a string to which caller owns a ref, and contains the same contents
+// as src. The returned value may be a copy of src, if the requested flags
+// were incompatible with src's.
+INLINE upb_string *upb_string_getref(upb_string *_s, upb_flags_t ref_flags) {
+ upb_refcount_string *s = _s;
+ if((ref_flags == UPB_REF_FROZEN && !s->is_frozen) ||
+ (ref_flags == UPB_REF_MUTABLE && s->is_frozen) ||
+ !s->has_refcount) {
+ // Copy should always be refcounted. Should be frozen iff a frozen ref was req.
+ return upb_strdup(s, flags);
+ }
+ // Take a ref on the existing object.
+ if(s->is_frozen) upb_atomic_ref(s->refcount);
+ else s->refcount.val++;
+ return s;
+}
+
+// The caller releases a ref on src, which it must previously have owned a ref
+// on.
+INLINE void upb_string_unref(upb_string *s) {
+ void *refcount = s + 1;
+ if(s->is_frozen) {
+}
+
+// Returns a buffer to which the caller may write. The string is resized to
+// byte_len (which may or may not trigger a reallocation). The src string must
+// not be frozen otherwise the program will assert-fail or abort().
+char *upb_string_getrwbuf(upb_string *s, upb_strlen_t byte_len);
+
+// Returns a buffer that the caller may use to read the current contents of
+// the string. The number of bytes available is upb_strlen(s).
+INLINE const char *upb_string_getrobuf(upb_string *s) {
+ return s->ptr;
+}
+
+// Returns the current length of the string.
+INLINE size_t upb_strlen(upb_string *s) {
+ return s->byte_len;
+}
+
+/* upb_string library functions ***********************************************/
+
+// Named like their <string.h> counterparts, these are all safe against buffer
+// overflow. These only use the public upb_string interface.
+
+// More efficient than upb_strcmp if all you need is to test equality.
+INLINE bool upb_streql(upb_string *s1, upb_string *s2) {
+ upb_strlen_t len = upb_strlen(s1);
+ if(len != upb_strlen(s2)) {
+ return false;
+ } else {
+ return memcmp(upb_string_getrobuf(s1), upb_string_getrobuf(s2), len) == 0;
+ }
+}
+
+INLINE int upb_strcmp(upb_string *s1, upb_string *s2) {
+ upb_strlen_t common_length = UPB_MIN(upb_strlen(s1), upb_strlen(s2));
+ int common_diff = memcmp(upb_string_getrobuf(s1), upb_string_getrobuf(s2),
+ common_length);
+ return common_diff ==
+ 0 ? ((int)upb_strlen(s1) - (int)upb_strlen(s2)) : common_diff;
+}
+
+INLINE void upb_strcpy(upb_string *dest, upb_string *src) {
+ upb_strlen_t src_len = upb_strlen(src);
+ memcpy(upb_string_getrwbuf(dest, src_len), upb_string_getrobuf(src), src_len);
+}
+
+// Reads an entire file into a newly-allocated string (caller owns one ref).
+upb_string *upb_strreadfile(const char *filename);
+
+// Typedef for a read-only string that is allocated statically or on the stack.
+// Initialize with the given macro, which must resolve to a const char*. You
+// must not dynamically allocate this type.
+typedef upb_string upb_static_string;
+#define UPB_STRLIT(str) {sizeof(str), false, true, false, 0, str}
+
+// Allows using upb_strings in printf, ie:
+// upb_string str = UPB_STRLIT("Hello, World!\n");
+// printf("String is: " UPB_STRFMT, UPB_STRARG(str)); */
+#define UPB_STRARG(str) (str)->byte_len, (str)->ptr
+#define UPB_STRFMT "%.*s"
+
+/* upb_array ******************************************************************/
+
+typedef uint32_t upb_arraylen_t;
+
+// The members of this struct are private. Access should only be through the
+// associated functions.
+typedef struct {
+ unsigned int size:29; // How many bytes we own, 0 if we don't own.
+ bool is_heap_allocated:1;
+ bool is_frozen:1;
+ bool has_refcount:1;
+ upb_arraylen_t len;
+ union upb_value_ptr *elements;
+} upb_array;
+
+#define UPB_DEFINE_MSG_ARRAY(type) \
+typedef struct type ## array { \
+ unsigned int size:29; \
+ bool is_heap_allocated:1; \
+ bool is_frozen:1;\
+ bool has_refcount:1;\
+ upb_arraylen_t len;\
+ type **elements; \
+} type ## array; \
+
+#define UPB_MSG_ARRAY(type) struct type ## array
+
+// Constructs a newly-allocated array, which starts out empty. Caller owns one
+// ref on it.
+upb_array *upb_array_new(void);
+
+// Returns an array to which caller owns a ref, and contains the same contents
+// as src. The returned value may be a copy of src, if the requested flags
+// were incompatible with src's.
+INLINE upb_array *upb_array_getref(upb_array *src, upb_flags_t flags);
+
+// The caller releases a ref on the given array, which it must previously have
+// owned a ref on.
+INLINE void upb_array_unref(upb_array *a, struct upb_fielddef *f);
+
+// Sets the given element in the array to val. The current length of the array
+// must be greater than elem. If the field type is dynamic, the array will
+// take a ref on val and release a ref on what was previously in the array.
+INLINE void upb_array_set(upb_array *a, struct upb_fielddef *f, int elem,
+ union upb_value val);
+
+// Note that the caller does *not* own a ref on the returned value.
+INLINE union upb_value upb_array_get(upb_array *a, struct upb_fielddef *f,
+ int elem);
+INLINE union upb_value upb_array_getmutable(upb_array *a,
+ struct upb_fielddef *f, int elem,
+ union upb_value val);
+
+// Note that array_append will attempt to take a reference on the given value,
+// so to avoid a copy use append_default and get.
+INLINE void upb_array_append(upb_array *a, struct upb_fielddef *f,
+ union upb_value val);
+INLINE void upb_array_append_default(upb_array *a, struct upb_fielddef *f,
+ union upb_value val);
+
+// Returns the current number of elements in the array.
+INLINE size_t upb_array_len(upb_array *a) {
+ return a->len;
+}
+
+/* upb_msg ********************************************************************/
+
+typedef struct {
+ uint8_t data[1];
+} upb_msg;
+
+// Creates a new msg of the given type.
+upb_msg *upb_msg_new(struct upb_msgdef *md);
+
+void upb_msg_unref(upb_msg *msg, struct upb_msgdef *md);
+
+// Tests whether the given field is explicitly set, or whether it will return
+// a default.
+bool upb_msg_isset(upb_msg *msg, struct upb_fielddef *f);
+
+// Returns the current value if set, or the default value if not set, of the
+// specified field. The mutable version will first replace the value with a
+// mutable copy if it is not already mutable.
+union upb_value upb_msg_get(upb_msg *msg, struct upb_fielddef *f);
+union upb_value upb_msg_getmutable(upb_msg *msg, struct upb_fielddef *f);
+
+// Sets the given field to the given value. The msg will take a ref on val,
+// and will drop a ref on whatever was there before.
+void upb_msg_set(upb_msg *msg, struct upb_fielddef *f, union upb_value val);
+
+void upb_msg_clear(upb_msg *msg, struct upb_msgdef *md);
+
+void upb_msg_parsestr(upb_msg *msg, struct upb_msgdef *md, upb_string *data,
+ struct upb_status *status);
+
+#endif
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback