|
|
|
@ -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" */ |
|
|
|
|