update json api and docs

This commit is contained in:
Martin Schröder 2016-01-11 09:39:05 +01:00
parent e4828f4e3a
commit 6e7300536a
8 changed files with 170 additions and 34 deletions

140
README.md
View file

@ -8,6 +8,12 @@ The blobs are packed in platform independent format so you can use blobpack to
pack data on one platform and then unpack it on a different one regardless of
it's endianness.
Blobpack shall be used strictly for serialization and deserialization of
arbitrary structured data. Supporting runtime representation of data with
support for modifying/inserting fields shall not be supported to keep library
simple and fast. You may keep readonly represetation of data as blobs but you
should not attempt to use blobs for storing values that change.
Data Types
-------------
@ -15,18 +21,43 @@ Blobpack API shall be agnostic of actual packing implementation and shall
present the user with ability to pack following types:
- int: [ 9223372036854775807, +9223372036854775807 ] range
- float: double precision float
- real: double precision float
- string: an array of characters with 0 at the end
- array: an aggregation of any number of fields of any type
- table: an aggregation of any number of fields where each element is a pair of string and any other type
- table: an aggregation of any number of fields where each element is a pair of
string and any other type
Internally the types shall be packed to balance quick unpacking with space efficiency.
Internally the types shall be packed to balance quick unpacking with space
efficiency.
The format is intentionally made to include length even on fixed length types
like integers to simplify and speed up packing and unpacking. Some
optimizations can of course be done to the packing format, but at current time
such optimizations are deemed to be unnecessary because the gains are marginal.
JSON Support
------------
All blobs shall be exportable and importable to and from JSON. Binary data
shall be encoded as base64 strings.
The mapping between blobpack types and json types is as follows:
+-----------------------------+
| blobpack | JSON |
+-----------------------------+
| BLOB_FIELD_BINARY | base64 |
| BLOB_FIELD_STRING | string |
| BLOB_FIELD_INT8 | number |
| BLOB_FIELD_INT16 | number |
| BLOB_FIELD_INT32 | number |
| BLOB_FIELD_INT64 | number |
| BLOB_FIELD_FLOAT32 | number |
| BLOB_FIELD_FLOAT64 | number |
| BLOB_FIELD_ARRAY | array |
| BLOB_FIELD_TABLE | object |
+-----------------------------+
Validation
----------
@ -58,6 +89,10 @@ point numbers for the sake of performance.
Note: the performance hit of casting numbers to long long is marginal enough
even on mips, to be ignored completely for the sake of a clean api.
Note nr2: even though currently smallest size of number in blobpack is 4 byte
(32 bit), we still pack small integers as int8 inside a 4 byte memory area
because the packing format may be altered in the future to be more efficient.
Blobpack packs fields into a blob buffer. Each field has a 4 byte
header containing attribyte type and length of the whole field including
both header and data. If NAME bit is set then the next two bytes are the length
@ -79,11 +114,10 @@ The header consists of 4 bytes which have this layout:
- e: reserved
- t: type of the field (see below)
- s: size of whole field (header+name+data)
- s: size of whole field (header+data)
Type can be one of the following:
BLOB_FIELD_ROOT: this is root element. For historical reasons it is has type of 0
BLOB_FIELD_ARRAY: this element can only contain unnamed elements
BLOB_FIELD_TABLE: this element can contain named elements
BLOB_FIELD_BINARY: a binary blob. We don't care about content (never included in json!)
@ -106,9 +140,99 @@ elements.
API Reference
-------------
//! Initializes a blob_buf structure. Optionally takes memory area to be copied into the buffer which must represent a valid blob buf.
void blob_buf_init(struct blob_buf *buf, const char *data, size_t size);
//! Initializes a blob_buf structure. Optionally takes memory area to be
//! copied into the buffer which must represent a valid blob buf.
//! if data is NULL and size is > 0 then the library shall create an empty
//! memory area of the size "size" to avoid allocating more memory until the
//! contents of the blob no longer can fit inside this memory area.
void blob_init(struct blob_buf *buf, const char *data, size_t size);
//! deletes memroy associated with this buffer
void blob_free(struct blob *buf);
//! Resets header but does not deallocate any memory.
void blob_reset(struct blob *buf);
//! Resizes the buffer. Can only be used to increase size.
bool blob_resize(struct blob *buf, int newsize);
//! returns the full size of the buffer memory including padding
static inline size_t blob_size(struct blob *self){ return blob_field_raw_pad_len(blob_head(self)); }
//! puts a string into the blob buffer
struct blob_field *blob_put_string(struct blob *self, const char *str);
Array/Table functions
---------------------
The following functions open a new nested element and return a "tag" to this element which can be used later to close the element.
//! opens an array element
blob_offset_t blob_open_array(struct blob *buf);
//! closes an array element
void blob_close_array(struct blob *buf, blob_offset_t);
//! opens an table element
blob_offset_t blob_open_table(struct blob *buf);
//! closes an table element
void blob_close_table(struct blob *buf, blob_offset_t);
Write Functions
---------------
Writing to the buffer is always done at the end of the buffer. Functionality to
insert elements has been intentionally left out. Reading is done by reading
elements directly from a blob field to which they belong (all elements always
belong to a field, top level elements belong to root field which can be
retreived using blob\_head(buffer);
//! write a boolean into the buffer
struct blob_field *blob_put_bool(struct blob *buf, bool val);
//! write a string into the buffer
struct blob_field *blob_put_string(struct blob *buf, const char *str);
//! write binary data into the buffer
struct blob_field *blob_put_binary(struct blob *buf, const char *data, size_t size);
//! write a number into the buffer
struct blob_field *blob_put_int(struct blob *buf, long long val);
//! write a real into the buffer
struct blob_field *blob_put_real(struct blob *buf, double value);
//! write a raw attribute into the buffer
struct blob_field *blob_put_attr(struct blob *buf, struct blob_field *attr);
//! print out the whole buffer
void blob_dump(struct blob *self);
Reading/Writing JSON
--------------------
//! allocate a string and return it filled with json representation
char *blob_to_json(struct blob *buf);
//! convert json element to blob_field and write it to the blob
bool blob_put_json(struct blob *buf, const char *json);
Debugging
---------
//! dump blob buffer contents to console using detailed info.
Packing data
------------

15
blob.h
View file

@ -106,11 +106,22 @@ struct blob_field *blob_put_u64(struct blob *buf, uint64_t val);
#define blob_put_i64 blob_put_u64
*/
//! write a boolean into the buffer
struct blob_field *blob_put_bool(struct blob *buf, bool val);
struct blob_field *blob_put_int(struct blob *buf, long long val);
struct blob_field *blob_put_float(struct blob *buf, double value);
//! write a string into the buffer
struct blob_field *blob_put_string(struct blob *buf, const char *str);
//! write binary data into the buffer
struct blob_field *blob_put_binary(struct blob *buf, const void *data, unsigned int size);
//! write a number into the buffer
struct blob_field *blob_put_int(struct blob *buf, long long val);
//! write a real into the buffer
struct blob_field *blob_put_real(struct blob *buf, double value);
//! write a raw attribute into the buffer
struct blob_field *blob_put_attr(struct blob *buf, struct blob_field *attr);
//! print out the whole buffer

View file

@ -205,7 +205,7 @@ long long blob_field_get_int(const struct blob_field *self){
return 0;
}
double blob_field_get_float(const struct blob_field *self){
double blob_field_get_real(const struct blob_field *self){
int type = blob_field_type(self);
switch(type){
case BLOB_FIELD_INT8: return blob_field_get_i8(self);

View file

@ -40,7 +40,7 @@ uint32_t blob_field_raw_pad_len(const struct blob_field *attr);
bool blob_field_get_bool(const struct blob_field *self);
long long int blob_field_get_int(const struct blob_field *self);
double blob_field_get_float(const struct blob_field *self);
double blob_field_get_real(const struct blob_field *self);
const char *blob_field_get_string(const struct blob_field *self);
/*

View file

@ -20,7 +20,7 @@
#include <json-c/json.h>
typedef const char *(*blob_json_format_t)(void *priv, struct blob_field *attr);
/*
bool blob_put_json_object(struct blob *b, json_object *obj)
{
json_object_object_foreach(obj, key, val) {
@ -88,13 +88,6 @@ static bool __blob_add_json(struct blob *b, json_object *obj)
return false;
ret = blob_put_json_element(b, obj);
/*
if (json_object_get_type(obj) == json_type_object){
ret = blob_put_json_object(b, obj);
} else {
ret = blob_put_json_array(b, json_object_get_array(obj));
}
*/
json_object_put(obj);
return ret;
}
@ -106,7 +99,7 @@ bool blob_put_json_from_file(struct blob *b, const char *file){
bool blob_put_json_from_string(struct blob *b, const char *str){
return __blob_add_json(b, json_tokener_parse(str));
}
*/
struct strbuf {
int len;
int pos;
@ -335,24 +328,28 @@ char *blob_format_json_with_cb(struct blob_field *attr, bool list, blob_json_for
return s.buf;
}
char *blob_format_json(struct blob_field *attr, bool list){
return blob_format_json_with_cb(attr, list, NULL, NULL, -1);
char *blob_field_to_json(struct blob_field *attr){
return blob_format_json_with_cb(attr, false, NULL, NULL, -1);
}
char *blob_format_json_indent(struct blob_field *attr, bool list, int indent){
return blob_format_json_with_cb(attr, list, NULL, NULL, indent);
char *blob_field_to_json_pretty(struct blob_field *attr){
return blob_format_json_with_cb(attr, false, NULL, NULL, 1);
}
static void _blob_field_dump_json(struct blob_field *self, int indent){
assert(self);
char *json = blob_format_json_indent(self, true, indent);
char *json = NULL;
if(indent == 1)
json = blob_field_to_json(self);
else
json = blob_field_to_json_pretty(self);
printf("%s\n", json);
free(json);
}
void blob_field_dump_json(struct blob_field *self){
assert(self);
_blob_field_dump_json(self, -1);
_blob_field_dump_json(self, 0);
}
void blob_field_dump_json_pretty(struct blob_field *self){

View file

@ -20,18 +20,23 @@ struct json_object;
#include <stdbool.h>
#include "blob.h"
/*
bool blob_put_json_object(struct blob *b, struct json_object *obj);
bool blob_put_json_element(struct blob *b, struct json_object *obj);
bool blob_put_json_from_string(struct blob *b, const char *str);
bool blob_put_json_from_file(struct blob *b, const char *file);
char *blob_format_json(struct blob_field *attr, bool list);
char *blob_format_json_indent(struct blob_field *attr, bool list, int indent);
*/
void blob_field_dump_json(struct blob_field *self);
void blob_field_dump_json_pretty(struct blob_field *self);
static inline void blob_dump_json(struct blob *self){ blob_field_dump_json(blob_head(self)); }
char *blob_field_to_json(struct blob_field *self);
static inline char *blob_to_json(struct blob *self){ return blob_field_to_json(blob_head(self)); }
bool blob_put_json(struct blob *self, const char *json);
#endif

View file

@ -43,7 +43,7 @@ static void dump_attr_data(struct blob_field *data, int indent, int next_indent)
break;
case BLOB_FIELD_FLOAT32:
case BLOB_FIELD_FLOAT64:
indent_printf(indent, "%Le\n", (long double) blob_field_get_float(data));
indent_printf(indent, "%Le\n", (long double) blob_field_get_real(data));
break;
case BLOB_FIELD_TABLE:
case BLOB_FIELD_ARRAY:
@ -157,7 +157,7 @@ int main(int argc, char **argv)
blob_dump(&buf);
dump_message(&buf);
char *json = blob_format_json(blob_head(&buf), false);
char *json = blob_to_json(&buf);
printf("json: %s\n", json);
free(json);
const char *sig = "{sv}s[{si}]";
@ -183,7 +183,7 @@ int main(int argc, char **argv)
// test the normal encoder/decoder
blob_reset(&buf);
clock_gettime(CLOCK_MONOTONIC, &start);
blob_put_json_from_string(&buf, json);
blob_put_json(&buf, json);
clock_gettime(CLOCK_MONOTONIC, &end);
printf("encode jsconc: %s\n", json);
printf("time taken %lums\n", (end.tv_nsec - start.tv_nsec) / 1000);

View file

@ -490,8 +490,7 @@ int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, const char
#define Buffer_AppendCharUnchecked(__enc, __chr) \
*((__enc)->offset++) = __chr; \
FASTCALL_ATTR INLINE_PREFIX void FASTCALL_MSVC strreverse(char* begin, char* end)
{
static void strreverse(char* begin, char* end){
char aux;
while (end > begin)
aux = *end, *end-- = *begin, *begin++ = aux;