Best waty to code repeated varint with known size

520 views
Skip to first unread message

cptkoolbeenz

unread,
Aug 16, 2014, 1:19:45 AM8/16/14
to nan...@googlegroups.com
Petteri-
Thank you for making this very nice implementation of protobuf.  I need to encode a repeated sint32 with a known number of sint32s.
The code below seems to work, but would this be the best/most efficient method?
Thanks,
-c



bool write_repeatedsint32(pb_ostream_t *stream, const pb_field_t *field, int32_t* data, const uint8_t length)
{
    uint32_t i
= 0;
   
bool error = 0;
    pb_ostream_t sizestream
= {0};
   
   
if (!pb_encode_tag(stream, PB_WT_STRING, 2))
       
return false;
   
   
   
for(i=0; i < length; i++){
        error
|= pb_encode_svarint(&sizestream, data[i]);
   
}
   
   
if (!pb_encode_varint(stream, sizestream.bytes_written))
   
return false;
   
   
for(i=0; i < length; i++){
        error
|= pb_encode_svarint(stream, data[i]);
   
}
   
     
return error;
}


Petteri Aimonen

unread,
Aug 16, 2014, 1:32:55 AM8/16/14
to nan...@googlegroups.com
Hi,

> Thank you for making this very nice implementation of protobuf. I need to
> encode a repeated sint32 with a known number of sint32s.
> The code below seems to work, but would this be the best/most efficient
> method?

Pretty much. It is not really possible to avoid the separate sizing
pass currently in nanopb.

You can also achieve the same functionality without callbacks by doing:
> repeated int32 myfield = 1 [(nanopb).type = FT_POINTER];
and
> MyMessage.myfield_count = length;
> MyMessage.myfield = data;

Efficiency etc. will be the same, just less code to write.

--
Petteri

cptkoolbeenz

unread,
Aug 16, 2014, 1:38:08 AM8/16/14
to nan...@googlegroups.com
Thanks for such a fast response!
-c

cptkoolbeenz

unread,
Aug 19, 2014, 6:48:20 PM8/19/14
to nan...@googlegroups.com
Hi Petteri
I would like to try your suggestion above...

When you mention

repeated int32 myfield = 1 [(nanopb).type = FT_POINTER];
I assume you mean to put this as my field definition in the .proto file, correct?

Then I should specify the length and data as you suggest in my code before calling encode, right?

MyMessage.myfield_count = length;
MyMessage.myfield = data;

Thanks,
Chris

Petteri Aimonen

unread,
Aug 20, 2014, 10:10:29 AM8/20/14
to nan...@googlegroups.com
Hi,

> When you mention
> repeated int32 myfield = 1 [(nanopb).type = FT_POINTER];
> I assume you mean to put this as my field definition in the .proto file,
> correct?

Yeah. Or if you use a separate .options file, you can put there as:
MyMessage.myfield type:FT_POINTER

> Then I should specify the length and data as you suggest in my code before
> calling encode, right?
> MyMessage.myfield_count = length;
> MyMessage.myfield = data;

Yeah.

--
Petteri

cptkoolbeenz

unread,
Aug 20, 2014, 3:15:45 PM8/20/14
to nan...@googlegroups.com
Thanks Petteri
That worked very nicely!  I expected decoding to work just as easily, but apparently I need to enable malloc support?  I thought since the sizes were defined, malloc would not be needed...
Chris

Petteri Aimonen

unread,
Aug 21, 2014, 10:02:52 AM8/21/14
to nan...@googlegroups.com
Hi,

> That worked very nicely! I expected decoding to work just as easily, but
> apparently I need to enable malloc support? I thought since the sizes were
> defined, malloc would not be needed...

Ah well, it's not really safe to do that for decoding, because it would
try to reallocate the array. Use your original callback way if you need
decoding.

--
Petteri

cptkoolbeenz

unread,
Aug 21, 2014, 11:22:46 AM8/21/14
to nan...@googlegroups.com
No problem!
I have a variable in my structure like:

pb_bytes_array_t **IPAddr;

Where the length of the intended array would be 4.

Should I be using the script PB_BYTES_ARRAY_T to fill the variable?
Otherwise the bytes array only has one element:

struct _pb_bytes_array_t {
    size_t size
;
    uint8_t bytes
[1];
};

Could you show how to use your two PB_BYTES_ARRAY_T scripts?

Thanks!
Chris

Petteri Aimonen

unread,
Aug 21, 2014, 12:23:32 PM8/21/14
to nan...@googlegroups.com
Hi,

> I have a variable in my structure like:
> pb_bytes_array_t **IPAddr;
>
> Where the length of the intended array would be 4.

If you know the size, put it in .options or .proto
(max_size:4 for the length of the bytes contents, max_count:4 for the
number of bytes entries). Then you will get easier to fill variable.

But if you need variable-length variable-count, do this:

// N is number of entries, M is length of each entry.
msg->IPAddr = malloc(sizeof(void*) * N);
msg->IPAddr[0] = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(M))
msg->IPAddr[0]->size = M;
memcpy(&msg->IPAddr[0]->bytes, &mydata, M);
.. same for IPAddr[1] etc. ...

> Otherwise the bytes array only has one element:

This technique is known as a variable length array member.
It (ab)uses the C property that you can index past an array, and relies
on the user to allocate necessary space.

--
Petteri

cptkoolbeenz

unread,
Aug 21, 2014, 12:40:20 PM8/21/14
to nan...@googlegroups.com
Excellent!  Thanks for such great help and through explanations!
I will (try to) stop bothering you now... :)
-c

cptkoolbeenz

unread,
Aug 21, 2014, 12:41:52 PM8/21/14
to nan...@googlegroups.com
thorough*
Reply all
Reply to author
Forward
0 new messages