diff --git a/Makefile b/Makefile index d7b67a1059..0fd7f65cd9 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ clean: # The core library (src/libupb.a) SRC=src/upb.c src/upb_parse.c src/upb_table.c src/upb_def.c src/upb_data.c \ - descriptor/descriptor.c + descriptor/descriptor.c src/upb_text.c # Override the optimization level for upb_def.o, because it is not in the # critical path but gets very large when -O3 is used. src/upb_def.o: src/upb_def.c diff --git a/src/upb_data.c b/src/upb_data.c index b654facad1..0f58556fa6 100644 --- a/src/upb_data.c +++ b/src/upb_data.c @@ -8,10 +8,6 @@ #include "upb_data.h" #include "upb_def.h" -INLINE void data_init(upb_data *d, int flags) { - d->v = flags; -} - static uint32_t round_up_to_pow2(uint32_t v) { /* cf. http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */ @@ -25,6 +21,28 @@ static uint32_t round_up_to_pow2(uint32_t v) return v; } +/* upb_data *******************************************************************/ + +static void data_elem_unref(void *d, struct upb_fielddef *f) { + if(f->type == UPB_TYPE(MESSAGE) || f->type == UPB_TYPE(GROUP)) { + upb_msg_unref((upb_msg*)d, upb_downcast_msgdef(f->def)); + } else if(f->type == UPB_TYPE(STRING) || f->type == UPB_TYPE(BYTES)) { + upb_string_unref((upb_string*)d); + } +} + +static void data_unref(void *d, struct upb_fielddef *f) { + if(upb_isarray(f)) { + upb_array_unref((upb_array*)d, f); + } else { + data_elem_unref(d, f); + } +} + +INLINE void data_init(upb_data *d, int flags) { + d->v = flags; +} + static void check_not_frozen(upb_data *d) { // On one hand I am reluctant to put abort() calls in a low-level library // that are enabled in a production build. On the other hand, this is a bug @@ -50,6 +68,9 @@ static void string_set_bytesize(upb_string *s, upb_strlen_t newsize) { } } + +/* upb_string *******************************************************************/ + upb_string *upb_string_new() { upb_string *s = malloc(sizeof(upb_refcounted_string)); data_init(&s->common.base, UPB_DATA_HEAPALLOCATED | UPB_DATA_REFCOUNTED); @@ -76,6 +97,43 @@ void upb_string_resize(upb_string *s, upb_strlen_t byte_len) { s->common.byte_len = byte_len; } +upb_string *upb_strreadfile(const char *filename) { + FILE *f = fopen(filename, "rb"); + if(!f) return false; + if(fseek(f, 0, SEEK_END) != 0) goto error; + long size = ftell(f); + if(size < 0) goto error; + if(fseek(f, 0, SEEK_SET) != 0) goto error; + upb_string *s = upb_string_new(); + char *buf = upb_string_getrwbuf(s, size); + if(fread(buf, size, 1, f) != 1) goto error; + fclose(f); + return s; + +error: + fclose(f); + return NULL; +} + + +/* upb_array ******************************************************************/ + +// ONLY handles refcounted arrays for the moment. +void _upb_array_free(upb_array *a, struct upb_fielddef *f) +{ + if(upb_elem_ismm(f)) { + for(upb_arraylen_t i = 0; i < a->refcounted.size; i++) { + union upb_value_ptr p = _upb_array_getptr(a, f, i); + data_elem_unref(p._void, f); + } + } + if(a->refcounted.size != 0) free(a->common.elements._void); + free(a); +} + + +/* upb_msg ********************************************************************/ + upb_msg *upb_msg_new(struct upb_msgdef *md) { upb_msg *msg = malloc(md->size); memset(msg, 0, md->size); @@ -83,28 +141,16 @@ upb_msg *upb_msg_new(struct upb_msgdef *md) { return msg; } -#if 0 -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)); +// ONLY handles refcounted messages for the moment. +void _upb_msg_free(upb_msg *msg, struct upb_msgdef *md) +{ + for(int i = 0; i < md->num_fields; i++) { + struct upb_fielddef *f = &md->fields[i]; + union upb_value_ptr p = _upb_msg_getptr(msg, f); + if(!upb_field_ismm(f) || !p._void) continue; + data_unref(p._void, f); } - upb_def_unref(UPB_UPCAST(msg->def)); + upb_def_unref(UPB_UPCAST(md)); 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); -} -#endif diff --git a/src/upb_data.h b/src/upb_data.h index 471272f2a6..e5980cecfa 100644 --- a/src/upb_data.h +++ b/src/upb_data.h @@ -378,12 +378,29 @@ typedef struct type ## _array { \ // empty. Caller owns one ref on it. upb_array *upb_array_new(void); -INLINE union upb_value upb_array_get(upb_array *a, struct upb_fielddef *f, - int elem) { +// INTERNAL-ONLY: +// Frees the given message and releases references on members. +void _upb_array_free(upb_array *a, struct upb_fielddef *f); + +// INTERNAL-ONLY: +// Returns a pointer to the given elem. +INLINE union upb_value_ptr _upb_array_getptr(upb_array *a, + struct upb_fielddef *f, int elem) { assert(elem < upb_array_len(a)); size_t type_size = upb_type_info[f->type].size; union upb_value_ptr p = {._void = &a->common.elements.uint8[elem * type_size]}; - return upb_value_read(p, f->type); + return p; +} + +INLINE union upb_value upb_array_get(upb_array *a, struct upb_fielddef *f, + int elem) { + return upb_value_read(_upb_array_getptr(a, f, elem), f->type); +} + +// 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) { + if(_upb_data_unref(&a->common.base)) _upb_array_free(a, f); } #if 0 @@ -392,10 +409,6 @@ INLINE union upb_value upb_array_get(upb_array *a, struct upb_fielddef *f, // were incompatible with src's. INLINE upb_array *upb_array_getref(upb_array *src, int ref_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. @@ -429,20 +442,33 @@ struct upb_msg { // Creates a new msg of the given type. upb_msg *upb_msg_new(struct upb_msgdef *md); +// INTERNAL-ONLY: +// Frees the given message and releases references on members. +void _upb_msg_free(upb_msg *msg, struct upb_msgdef *md); + +// INTERNAL-ONLY: +// Returns a pointer to the given field. +INLINE union upb_value_ptr _upb_msg_getptr(upb_msg *msg, struct upb_fielddef *f) { + union upb_value_ptr p = {._void = &msg->data[f->byte_offset]}; + return p; +} + +// Releases a references on msg. +INLINE void upb_msg_unref(upb_msg *msg, struct upb_msgdef *md) { + if(_upb_data_unref(&msg->base)) _upb_msg_free(msg, md); +} + // Tests whether the given field is explicitly set, or whether it will return // a default. INLINE bool upb_msg_has(upb_msg *msg, struct upb_fielddef *f) { return msg->data[f->field_index/8] % (1 << (f->field_index % 8)); } -void upb_msg_unref(upb_msg *msg, struct upb_msgdef *md); - // Returns the current value if set, or the default value if not set, of the // specified field. The caller does *not* own a ref. INLINE union upb_value upb_msg_get(upb_msg *msg, struct upb_fielddef *f) { if(upb_msg_has(msg, f)) { - union upb_value_ptr p = {._void = &msg->data[f->byte_offset]}; - return upb_value_read(p, f->type); + return upb_value_read(_upb_msg_getptr(msg, f), f->type); } else { return f->default_value; } diff --git a/src/upb_text.c b/src/upb_text.c index 103468cf81..17efa9f24c 100644 --- a/src/upb_text.c +++ b/src/upb_text.c @@ -7,9 +7,7 @@ #include #include "descriptor.h" #include "upb_text.h" -#include "upb_string.h" -#include "upb_msg.h" -#include "upb_array.h" +#include "upb_data.h" void upb_text_printval(upb_field_type_t type, union upb_value val, FILE *file) { @@ -51,7 +49,7 @@ static void print_indent(struct upb_text_printer *p, FILE *stream) } void upb_text_printfield(struct upb_text_printer *p, - struct upb_string *name, + upb_string *name, upb_field_type_t valtype, union upb_value val, FILE *stream) { @@ -65,7 +63,7 @@ void upb_text_printfield(struct upb_text_printer *p, } void upb_text_push(struct upb_text_printer *p, - struct upb_string *submsg_type, + upb_string *submsg_type, FILE *stream) { print_indent(p, stream); @@ -82,49 +80,48 @@ void upb_text_pop(struct upb_text_printer *p, fprintf(stream, "}\n"); } -static void printval(struct upb_text_printer *printer, union upb_value_ptr p, +static void printval(struct upb_text_printer *printer, union upb_value v, struct upb_fielddef *f, FILE *stream); -static void printmsg(struct upb_text_printer *printer, struct upb_msg *msg, - FILE *stream) +static void printmsg(struct upb_text_printer *printer, + upb_msg *msg, struct upb_msgdef *md, FILE *stream) { - struct upb_msgdef *m = msg->def; - for(upb_field_count_t i = 0; i < m->num_fields; i++) { - struct upb_fielddef *f = &m->fields[i]; - if(!upb_msg_isset(msg, f)) continue; - union upb_value_ptr p = upb_msg_getptr(msg, f); + for(upb_field_count_t i = 0; i < md->num_fields; i++) { + struct upb_fielddef *f = &md->fields[i]; + if(!upb_msg_has(msg, f)) continue; + union upb_value v = upb_msg_get(msg, f); if(upb_isarray(f)) { - struct upb_array *arr = *p.arr; - for(uint32_t j = 0; j < arr->len; j++) { - union upb_value_ptr elem_p = upb_array_getelementptr(arr, j); - printval(printer, elem_p, f, stream); + upb_array *arr = v.arr; + for(uint32_t j = 0; j < upb_array_len(arr); j++) { + union upb_value elem = upb_array_get(arr, f, j); + printval(printer, elem, f, stream); } } else { - printval(printer, p, f, stream); + printval(printer, v, f, stream); } } } -static void printval(struct upb_text_printer *printer, union upb_value_ptr p, +static void printval(struct upb_text_printer *printer, union upb_value v, struct upb_fielddef *f, FILE *stream) { if(upb_issubmsg(f)) { upb_text_push(printer, f->name, stream); - printmsg(printer, *p.msg, stream); + printmsg(printer, v.msg, upb_downcast_msgdef(f->def), stream); upb_text_pop(printer, stream); } else { - upb_text_printfield(printer, f->name, f->type, - upb_value_read(p, f->type), stream); + upb_text_printfield(printer, f->name, f->type, v, stream); } } -void upb_msg_print(struct upb_msg *msg, bool single_line, FILE *stream) +void upb_msg_print(upb_msg *msg, struct upb_msgdef *md, bool single_line, + FILE *stream) { struct upb_text_printer printer; upb_text_printer_init(&printer, single_line); - printmsg(&printer, msg, stream); + printmsg(&printer, msg, md, stream); }