I have a blob whose format is something like:
(id1,key1,value1)(id2,key2,value2)....
where id is a uint32_t
, and key and value are null-terminated strings. I am looking for an iterator-like interface that will extract records from the blob.
This is what I have come up with:
typedef struct blob_ {
uint32_t size; // length of the buffer
char buf[];
}blob;
typedef struct record_ {
uint32_t id; // id
char *key; // pointer to key in the blob
char *value; // pointer to value in the blob
char *next; // pointer to where the next record starts
} record;
static record
get_next_obj(const char* begin, const char* end)
{
record obj;
if (begin == end) {
obj.id = 0;
obj.key = NULL;
obj.value = NULL;
obj._next = NULL;
} else {
memcpy(&obj.id, begin, sizeof(uint32_t));
begin += sizeof(uint32_t);
obj.key = begin;
while(begin < end && *begin != '\0')
++begin;
++begin;
obj.value = begin;
while(begin < end && *begin != '\0')
++begin;
++begin;
obj.next = begin;
}
return obj;
}
record
blob_list_next(const blob *data, const record *prev)
{
const char *begin, *end;
begin = prev->next;
end = data->buf + data->size;
return get_next_obj(begin, end);
}
record
blob_list_begin(const blob *data)
{
const char *begin, *end;
begin = data->buf;
end = data->buf + data->size;
return get_next_obj(begin, end);
}
record
blob_list_end(const blob *data)
{
record obj;
obj.id = 0;
obj.key = NULL;
obj.value = NULL;
obj.next = NULL;
return obj;
}
Then the API will be accessed with something like this:
record obj;
record obj_end;
// comp is a comparison operator of two record objects
for (obj = blob_list_begin(data), obj_end = blob_list_end(data);
comp(obj, obj_end) == false; obj = blob_list_next(data, &obj)) {
// access the obj
}
I used return-by-value semantics because I wanted to avoid calling malloc()
. There will be a maximum of 4096 records in a tuple.