Very rough (doesn't even compile) pbstruct.

pull/13171/head
Joshua Haberman 16 years ago
parent a714989094
commit 3c515a6ce9
  1. 101
      pbstruct.c
  2. 114
      pbstruct.h

@ -10,6 +10,25 @@
#define alignof(t) offsetof(struct { char c; t x; }, x)
#define ALIGN_UP(p, t) (alignof(t) + ((p - 1) & ~(alignof(t) - 1)))
void pbstruct_init(struct pbstruct *s, struct pbstruct_definition *d)
{
/* "set" flags start as unset, dynamic pointers start as NULL. */
memset(s, 0, d->struct_size);
s->definition = d;
}
pbstruct *pbstruct_new(struct pbstruct_defintion *d, struct pballoc *a)
{
pbstruct *s = a->realloc(NULL, d->struct_size, d->user_data);
pbstruct_init(s, d);
}
void pbstruct_free(struct pbstruct *s, struct pballoc *a, bool free_substructs)
{
pbstruct_free_all_fields(s, free_substructs);
a->free(s, s->user_data);
}
bool pbstruct_is_set(struct pbstruct *s, struct pbstruct_field *f)
{
return s->data[f->isset_byte_offset] & f->isset_byte_mask;
@ -25,6 +44,88 @@ void pbstruct_set(struct pbstruct *s, struct pbstruct_field *f)
s->data[f->isset_byte_offset] |= f->isset_byte_mask;
}
void pbstruct_unset_all(struct pbstruct *s)
{
for(int i = 0; i < s->definition->num_fields; i++)
pbstruct_unset(s, &s->definition->fields[i]);
}
void pbstruct_resize_str(struct pbstruct *s, struct pbstruct_field *f,
size_t len, struct pballoc *a)
{
assert(f->type & PBSTRUCT_DELIMITED);
size_t size = next_pow2(len);
struct pbstruct_dynamic **dyn = (struct pbstruct_dynamic**)get_addr(s, f);
if(!*dyn || (*dyn)->size < size) {
size_t old_len = *dyn ? (*dyn)->len : 0;
*dyn = a->realloc(*dyn, size*type_size, s->definition->user_data);
(*dyn)->size = size;
(*dyn)->len = len;
}
}
size_t pbstruct_append_array(struct pbstruct *s, struct pbstruct_field *f,
struct pballoc *a)
{
assert(f->type & PBSTRUCT_ARRAY);
struct pbstruct_dynamic **dyn = (struct pbstruct_dynamic**)get_addr(s, f);
size_t new_len, new_size;
if(!*dyn) {
new_len = 1;
new_size = 4; /* Initial size. */
} else {
new_len = (*dyn)->len + 1;
new_size = next_pow2(new_len);
}
*dyn = a->realloc(*dyn, ARRSIZE(f->type, new_size), s->defintion->user_data);
memset(ARRADDR(*dyn, f->type, new_len-1), 0, SIZE(f->type));
}
void pbstruct_clear_array(struct pbstruct *s, struct pbstruct_field *f,
struct pballoc *a, bool free_substructs)
{
assert(f->type & PBSTRUCT_ARRAY);
struct pbstruct_dynamic *dyn = *(struct pbstruct_dynamic**)get_addr(s, f);
if(dyn) {
if((f->type & PBSTRUCT_DELIMITED) || free_substructs) {
for(int i = 0; i < dyn->len; i++)
FREE(ARRADDR(dyn, f->type, i), a, s->definition->user_data);
}
dyn->size = 0;
}
}
/* Resizes a delimited field (string or bytes) string that is within an array.
* The array must already be large enough that str_offset is a valid member. */
void pbstruct_resize_arraystr(struct pbstruct *s, struct pbstruct_field *f,
size_t str_offset, size_t len, struct pballoc *a)
{
}
/* Like pbstruct_append_array, but appends a string of the specified length. */
size_t pbstruct_append_arraystr(struct pbstruct *s, struct pbstruct_field *f,
size_t len, struct pballoc *a)
{
}
void pbstruct_free_field(struct pbstruct *s, struct pbstruct_field *f,
bool free_substructs)
{
pbstruct_clear_array(s, f, free_substructs);
struct pbstruct_dynamic **dyn = (struct pbstruct_dynamic**)get_addr(s, f);
if(*dyn) {
FREE(*dyn, s);
*dyn = NULL;
}
}
void pbstruct_free_all_fields(struct pbstruct *s, bool free_substructs)
{
for(int i = 0; i < s->definition->num_fields; i++)
pbstruct_free_field(s, &s->definition->fields[i]);
}
#define DEFINE_GETTERS(ctype, name) \
ctype *pbstruct_get_ ## name(struct pbstruct *s, struct pbstruct_field *f) { \
return (ctype*)(s->data + f->byte_offset); \

@ -39,6 +39,14 @@
* This proto will take N times more memory if structures are by value than if
* they are by reference. To avoid such bad cases, submessages are by
* reference.
*
* Ownership semantics:
* - Each pbstruct absolutely owns any data allocated for its arrays or
* strings. If you want a copy of this data that will outlive the struct,
* you must copy it out.
* - Each pbstruct optionally owns any data allocated for substructs, based
* on whether you pass the free_substructs parameter to any of several
* functions.
*/
#ifndef PBSTRUCT_H_
@ -52,24 +60,25 @@ extern "C" {
#endif
typedef enum pbstruct_type {
PBSTRUCT_TYPE_DOUBLE = 0,
PBSTRUCT_TYPE_FLOAT = 1,
PBSTRUCT_TYPE_INT32 = 2,
PBSTRUCT_TYPE_UINT32 = 3,
PBSTRUCT_TYPE_INT64 = 4,
PBSTRUCT_TYPE_UINT64 = 5,
PBSTRUCT_TYPE_BOOL = 6,
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,
/* Main struct contains a pointer to a pbstruct. */
PBSTRUCT_TYPE_SUBSTRUCT = 7,
PBSTRUCT_TYPE_SUBSTRUCT = 8,
/* Main struct contains a pointer to a pbstruct_delimited. */
PBSTRUCT_DELIMITED = 8, /* Not itself a real type. */
PBSTRUCT_TYPE_BYTES = PBSTRUCT_DELIMITED | 1,
PBSTRUCT_TYPE_STRING = PBSTRUCT_DELIMITED | 2,
PBSTRUCT_DYNAMIC = 16,
PBSTRUCT_TYPE_BYTES = PBSTRUCT_DYNAMIC | 1,
PBSTRUCT_TYPE_STRING = PBSTRUCT_DYNAMIC | 2,
/* The main struct contains a pointer to a pbstruct_array, for which each
* element is identical to the non-array form. */
PBSTRUCT_ARRAY = 16, /* Not itself a real type. */
PBSTRUCT_ARRAY = PBSTRUCT_DYNAMIC | 32, /* 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,
@ -90,13 +99,9 @@ struct pbstruct_field {
uint8_t isset_byte_mask;
};
struct pbstruct_delimited {
size_t len; /* Measured in bytes. */
uint8_t data[];
};
struct pbstruct_array {
size_t len; /* Measured in elements. */
struct pbstruct_dynamic {
size_t len; /* Number of present elements (bytes for string/bytes). */
size_t size; /* Total size in present elements. */
uint8_t data[];
};
@ -113,17 +118,74 @@ struct pbstruct {
uint8_t data[]; /* layout is described by definition. */
};
/* Initializes everything to unset. */
void pbstruct_init(struct pbstruct *s, struct pbstruct_definition *definition);
struct pballoc {
void *(*realloc)(void *ptr, size_t size, void *user_data);
void (*free)(void *ptr, void *user_data);
};
/* Initializes everything to unset, with no dynamic memory alocated. */
void pbstruct_init(struct pbstruct *s, struct pbstruct_definition *d);
pbstruct *pbstruct_new(struct pbstruct_defintion *d, struct pballoc *a);
/* Frees the struct itself and any dynamic string or array data, and substructs
* also if free_substructs is true. */
void pbstruct_free(struct pbstruct *s, struct pballoc *a, bool free_substructs);
/* For setting, clearing, and testing the "set" flag for each field.
* Clearing the "set" flag does not free any dynamically allocated
* storage -- it will be reused again if the field becomes set again. */
bool pbstruct_is_set(struct pbstruct *s, struct pbstruct_field *f);
/* Doesn't check whether the field is holding allocated memory, and will leak
* the memory if it is. */
void pbstruct_unset(struct pbstruct *s, struct pbstruct_field *f);
void pbstruct_unset_all(struct pbstruct *s);
void pbstruct_set(struct pbstruct *s, struct pbstruct_field *f);
/* These do no existence checks or type checks. */
/* Resizes the given string field to len, triggering a realloc() if
* necessary. Never reallocs() the string to be shorter. */
void pbstruct_resize_str(struct pbstruct *s, struct pbstruct_field *f,
size_t len, struct pballoc *a);
/* Appends an element to the given array field, triggering a realloc() if
* necessary. Returns the offset of the new array element. */
size_t pbstruct_append_array(struct pbstruct *s, struct pbstruct_field *f,
struct pballoc *a);
/* Sets the size of the given array field to zero, but does not free the
* array itself (call pbstruct_free_field() for that). Does free any
* strings that were in the array (for string arrays), and any substructs
* if free_substructs is true. Does not affect the "set" flag (if the
* field was previously set, it will remain set, but as zero elements long). */
void pbstruct_clear_array(struct pbstruct *s, struct pbstruct_field *f,
struct pballoc *a, bool free_substructs);
/* Resizes a delimited field (string or bytes) string that is within an array.
* The array must already be large enough that str_offset is a valid member. */
void pbstruct_resize_arraystr(struct pbstruct *s, struct pbstruct_field *f,
size_t str_offset, size_t len, struct pballoc *a);
/* Like pbstruct_append_array, but appends a string of the specified length. */
size_t pbstruct_append_arraystr(struct pbstruct *s, struct pbstruct_field *f,
size_t len, struct pballoc *a);
/* Clears all data associated with f (like pbstruct_clear_array()), but also
* frees all underlying storage. For string array fields, also frees the
* individual strings. Clears the "set" flag since it is an error for an
* array field to be set if it has no dynamic data allocated. */
void pbstruct_free_field(struct pbstruct *s, struct pbstruct_field *f,
bool free_substructs);
void pbstruct_free_all_fields(struct pbstruct *s, bool free_substructs);
/* These do no existence checks, bounds checks, or type checks. */
#define DECLARE_GETTERS(ctype, name) \
ctype *pbstruct_get_ ## name(struct pbstruct *s, struct pbstruct_field *f);
ctype pbstruct_get_ ## name(struct pbstruct *s, \
struct pbstruct_field *f); \
ctype *pbstruct_get_ ## name ## _ptr(struct pbstruct *s, \
struct pbstruct_field *f); \
ctype pbstruct_get_ ## name ## _array(struct pbstruct *s, \
struct pbstruct_field *f, \
int i); \
ctype *pbstruct_get_ ## name ## _array_ptr(struct pbstruct *s, \
struct pbstruct_field *f, \
int i); \
DECLARE_GETTERS(double, double)
DECLARE_GETTERS(float, float)
@ -132,9 +194,9 @@ DECLARE_GETTERS(int64_t, int64)
DECLARE_GETTERS(uint32_t, uint32)
DECLARE_GETTERS(uint64_t, uint64)
DECLARE_GETTERS(bool, bool)
DECLARE_GETTERS(struct pbstruct*, substruct)
DECLARE_GETTERS(struct pbstruct_delimited*, bytes)
DECLARE_GETTERS(struct pbstruct_delimited*, string)
DECLARE_GETTERS(struct pbstruct*, substruct)
#ifdef __cplusplus
} /* extern "C" */

Loading…
Cancel
Save