0

In this question, it is answered how a vector can be copied into a repeated field by using fMessage.mutable_samples() = {fData.begin(), fData.end()}; ( and the other direction works too ).

But how about a partial copy? Would the below work?

std::copy(
  fData.begin() + 3, fData.end() - 2,
  fMessage.mutable_samples()->begin() + 3
);

In this scenario fMessage has already allocated elements in the samples field, and std::copy would overwrite the items already present in fMessage.

Dávid Tóth
  • 2,788
  • 1
  • 21
  • 46

3 Answers3

2

Inspect API of RepeatedField.

IMO you should use this:

fMessage.mutable_samples()->Add(fData.begin() + 3, fData.end() - 2);
// or
fMessage.mutable_samples()->Assign(fData.begin() + 3, fData.end() - 2);
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • So the way I understand `Assign` overwrites the first `std::distance(fData.begin() + 3, fData.end() -2)` elements with the contents in `fData`, right? Is there a usecase for when the Assign should start from `fMessage.mutable_samples()->begin() + 3` ? Should `(fMessage.mutable_samples() + 3)->Assign(fData.begin() + 3, fData.end() - 2);` work? – Dávid Tóth Mar 15 '22 at 12:27
  • I tested it out and my suggestion doesn't work, and unfortunately using `Assign` reduces the size of the repeated field to the given range, and that is not desired behaviour – Dávid Tóth Mar 15 '22 at 12:45
  • Meanwhile I took the liberty of adding an answer based on yours to the linked question. https://stackoverflow.com/a/71482580/1467600 If you'd like I already mentioned you but if you'd like I can delete my answer so you can post yours. – Dávid Tóth Mar 15 '22 at 13:02
1

If samples are primitive types, e.g. int32, double, you can use the Add method to append a range of items the end of samples:

fMessage.mutable_samples()->Add(fData.begin() + 3, fData.end() - 2);

If samples are string or message type, and you're using protobuf 3.16 or latter, then you're lucky, and you can use the solutions mentioned above.

However, if your protobuf is older than 3.16, you have to do it in a loop to add a range of items of string or message type:

for (auto iter = fData.begin() + 3; iter != fData.end() - 2; ++iter)
    *(fMessage.add_samples()) = *iter;
for_stack
  • 21,012
  • 4
  • 35
  • 48
  • Thank you for your input! What I was asking for is actually a way to modify already allocated data. I will update my question to reflect that. – Dávid Tóth Mar 15 '22 at 12:29
0

I created a program to test this, and it seems that using std::copy works!

syntax = "proto3";

message messagetest{
    repeated float samples = 6;
}
#include <iostream>
#include <vector>

#include "message.pb.h"

int main(){
  std::vector<float> fData(10);
  messagetest fMessage;
  std::generate(fData.begin(),fData.end(),[&fMessage](){
    static float num = 0.0;
    num += 1.0;
    fMessage.add_samples(0.0);
    return num;
  });
  for(const float& f : fData)
     std::cout << "[" << f << "]";
  std::cout << std::endl;
  
  std::copy(
    fData.begin() + 3, fData.end() - 2,
    fMessage.mutable_samples()->begin() + 3
  );
  
  for(const float& f : fMessage.samples())
     std::cout << "[" << f << "]";
  std::cout << std::endl;
  
  
  return 0;
}

output:

[1][2][3][4][5][6][7][8][9][10]
[0][0][0][4][5][6][7][8][0][0]
Dávid Tóth
  • 2,788
  • 1
  • 21
  • 46