summaryrefslogtreecommitdiff
path: root/src/upb_mm.c
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2009-08-24 21:44:22 -0700
committerJoshua Haberman <joshua@reverberate.org>2009-08-24 21:44:22 -0700
commit040f7e6ba2e2282b80f332a031b77d7d34b4fc85 (patch)
tree1d5e273fb9fcca51f6ce299b766ee0a97ee92863 /src/upb_mm.c
parenta223f9af30738cf00c313fabee8de75d04fb9a1a (diff)
Significant memory-management refactoring any Python extension.
Diffstat (limited to 'src/upb_mm.c')
-rw-r--r--src/upb_mm.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/src/upb_mm.c b/src/upb_mm.c
new file mode 100644
index 0000000..853d572
--- /dev/null
+++ b/src/upb_mm.c
@@ -0,0 +1,208 @@
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Joshua Haberman. See LICENSE for details.
+ */
+
+#include "upb_mm.h"
+#include "upb_string.h"
+#include "upb_array.h"
+#include "upb_msg.h"
+
+void upb_msg_destroy(struct upb_msg *msg) {
+ uint32_t i;
+ for(i = 0; i < msg->def->num_fields; i++) {
+ struct upb_msg_fielddef *f = &msg->def->fields[i];
+ if(!upb_msg_isset(msg, f) || !upb_field_ismm(f)) continue;
+ upb_mm_ptrtype type = upb_field_ptrtype(f);
+ union upb_mmptr mmptr = upb_mmptr_read(upb_msg_getptr(msg, f), type);
+ upb_mm_unref(mmptr, type);
+ }
+ 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->len; i++) {
+ union upb_value_ptr p = upb_array_getelementptr(arr, i, arr->fielddef->type);
+ upb_mm_ptrtype type = upb_elem_ptrtype(arr->fielddef);
+ union upb_mmptr mmptr = upb_mmptr_read(p, type);
+ upb_mm_unref(mmptr, type);
+ }
+ }
+ if(arr->size != 0) free(arr->elements._void);
+ free(arr);
+}
+
+static union upb_mmptr upb_mm_newptr(upb_mm_ptrtype type,
+ struct upb_msg_fielddef *f)
+{
+ union upb_mmptr p = {NULL};
+ switch(type) {
+ case UPB_MM_MSG_REF: p.msg = upb_msg_new(f->ref.msg);
+ case UPB_MM_STR_REF: p.str = upb_string_new();
+ case UPB_MM_ARR_REF: p.arr = upb_array_new(f);
+ default: assert(false); break;
+ }
+ return p;
+}
+
+static struct upb_mm_ref *find_or_create_ref(struct upb_mm_ref *fromref,
+ struct upb_mm *mm,
+ union upb_mmptr p, upb_mm_ptrtype type,
+ bool *created)
+{
+ struct upb_mmhead *head = upb_mmhead_addr(p, type);
+ struct upb_mm_ref **ref = &head->refs;
+ while(*ref && (*ref)->mm <= mm) {
+ if((*ref)->mm == mm) {
+ return *ref;
+ *created = false;
+ }
+ ref = &((*ref)->next);
+ }
+ *created = true;
+ struct upb_mm_ref *newref = mm->newref_cb(fromref, p, type);
+ newref->p = p;
+ newref->type = type;
+ newref->mm = mm;
+ newref->next = *ref;
+ *ref = newref;
+ return newref;
+}
+
+struct upb_mm_ref *upb_mm_getref(union upb_mmptr p, upb_mm_ptrtype type,
+ struct upb_mm *mm, bool *created)
+{
+ return find_or_create_ref(NULL, mm, p, type, created);
+}
+
+struct upb_mm_ref *upb_mm_newmsg_ref(struct upb_msgdef *def, struct upb_mm *mm)
+{
+ struct upb_msg *msg = upb_msg_new(def);
+ union upb_mmptr mmptr = {.msg = msg};
+ bool created;
+ struct upb_mm_ref *ref = find_or_create_ref(NULL, mm, mmptr, UPB_MM_MSG_REF, &created);
+ upb_mm_unref(mmptr, UPB_MM_MSG_REF); /* Shouldn't have any counted refs. */
+ assert(created);
+ return ref;
+}
+
+struct upb_mm_ref *upb_mm_getfieldref(struct upb_mm_ref *msgref,
+ struct upb_msg_fielddef *f,
+ bool *refcreated)
+{
+ assert(upb_field_ismm(f));
+ upb_mm_ptrtype ptrtype = upb_field_ptrtype(f);
+ struct upb_msg *msg = msgref->p.msg;
+ union upb_mmptr val;
+ union upb_value_ptr p = upb_msg_getptr(msg, f);
+
+ /* Create the upb value if it doesn't already exist. */
+ if(!upb_msg_isset(msg, f)) {
+ upb_msg_set(msg, f);
+ val = upb_mm_newptr(ptrtype, f);
+ upb_mmptr_write(p, val, ptrtype);
+ } else {
+ val = upb_mmptr_read(p, ptrtype);
+ }
+
+ return find_or_create_ref(msgref, msgref->mm, val, ptrtype, refcreated);
+}
+
+struct upb_mm_ref *upb_mm_getelemref(struct upb_mm_ref *arrref, upb_arraylen_t i,
+ bool *refcreated)
+{
+ struct upb_array *arr = arrref->p.arr;
+ struct upb_msg_fielddef *f = arr->fielddef;
+ assert(upb_elem_ismm(f));
+ assert(i < arr->len);
+ union upb_value_ptr p = upb_array_getelementptr(arr, i, f->type);
+ upb_mm_ptrtype type = upb_elem_ptrtype(f);
+ union upb_mmptr val = upb_mmptr_read(p, type);
+ return find_or_create_ref(arrref, arrref->mm, val, type, refcreated);
+}
+
+void upb_mm_release(struct upb_mm_ref *ref)
+{
+ struct upb_mm_ref **ref_head = (void*)ref->p.msg;
+ struct upb_mm_ref **ref_elem = ref_head;
+ struct upb_mm *mm = ref->mm;
+ while(true) {
+ assert(*ref_elem); /* Client asserts r->mm is in the list. */
+ if((*ref_elem)->mm == mm) {
+ *ref_elem = (*ref_elem)->next; /* Remove from the list. */
+ break;
+ }
+ }
+
+ if(upb_mmhead_norefs(&ref->p.msg->mmhead)) {
+ /* Destroy the dynamic object. */
+ switch(ref->type) {
+ case UPB_MM_MSG_REF:
+ upb_msg_destroy(ref->p.msg);
+ break;
+ case UPB_MM_ARR_REF:
+ upb_array_destroy(ref->p.arr);
+ break;
+ case UPB_MM_STR_REF:
+ upb_string_destroy(ref->p.str);
+ break;
+ default: assert(false); break;
+ }
+ }
+}
+
+void upb_mm_msg_set(struct upb_mm_ref *from_msg_ref, struct upb_mm_ref *to_ref,
+ struct upb_msg_fielddef *f)
+{
+ assert(upb_field_ismm(f));
+ union upb_mmptr fromval = from_msg_ref->p;
+ union upb_mmptr toval = to_ref->p;
+ union upb_value_ptr field_p = upb_msg_getptr(fromval.msg, f);
+ upb_mm_ptrtype type = upb_field_ptrtype(f);
+ if(upb_msg_isset(fromval.msg, f)) {
+ union upb_mmptr existingval = upb_mmptr_read(field_p, type);
+ if(existingval.msg == toval.msg)
+ return; /* Setting to its existing value, do nothing. */
+ upb_mm_unref(existingval, type);
+ }
+ upb_msg_set(fromval.msg, f);
+ upb_mmptr_write(field_p, toval, type);
+ upb_mm_ref(toval, type);
+}
+
+void upb_mm_msgclear(struct upb_mm_ref *from_msg_ref, struct upb_msg_fielddef *f)
+{
+ assert(upb_field_ismm(f));
+ union upb_mmptr fromval = from_msg_ref->p;
+ upb_mm_ptrtype type = upb_field_ptrtype(f);
+ if(upb_msg_isset(fromval.msg, f)) {
+ union upb_value_ptr field_p = upb_msg_getptr(fromval.msg, f);
+ union upb_mmptr existingval = upb_mmptr_read(field_p, type);
+ upb_msg_unset(fromval.msg, f);
+ upb_mm_unref(existingval, type);
+ }
+}
+
+void upb_mm_msgclear_all(struct upb_mm_ref *from)
+{
+ struct upb_msgdef *def = from->p.msg->def;
+ for(uint32_t i = 0; i < def->num_fields; i++) {
+ struct upb_msg_fielddef *f = &def->fields[i];
+ if(!upb_field_ismm(f)) continue;
+ upb_mm_msgclear(from, f);
+ }
+}
+
+void upb_mm_arr_set(struct upb_mm_ref *from, struct upb_mm_ref *to,
+ upb_arraylen_t i, upb_field_type_t type)
+{
+ (void)from;
+ (void)to;
+ (void)i;
+ (void)type;
+}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback