parent
c241976485
commit
7dd113baa8
2 changed files with 357 additions and 0 deletions
@ -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); |
||||
} |
||||
|
@ -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 |
Loading…
Reference in new issue