I have a protobuf such as:
message TestWordOne {
uint32 word = 1;
}
message TestWordTwo {
repeated TestWordOne words = 1;
}
message TestMessage {
oneof payload {
TestWordTwo test_data = 1;
<some more stuff here>
}
}
Now, I can serialize in such a way:
TestMessage sentMessage;
TestMessage recvMessage;
TestWordTwo* data_test(new TestWordTwo);
for (int i=0; i<5; i++)
{
TestWordOne* oneWord = data_test->add_words();
oneWord->set_word(i);
}
Then serialize it with outputstream
sentMessage.SerializeToOstream(&outputStream)
However, I when I
recvMessage.ParseFromIstream(&outputStream)
I have no idea on how to get words from recVMessage, one by one. Any tips?
I tried using Descriptor and Reflection, but all available examples do not specify on how to proceed in my case.
It's easy to find in *.pb.h:
for (int i=0; i<5; i++) {
const TestWordOne& oneWord = data_test->words(i);
TestWordOne* oneWordMutable = data_test->mutable_words(i);
}
Related
I have problems with comparing strings.
I receive from mqtt a number of messages, I want to store the latest value for each topic (key)
I have shown the pertinent parts of my sketch.
#define MAX_SENSORS 6
// table of topic and value
char sensor_data[MAX_SENSORS][2][20];
initialize table
void init() {
....
for (int i=0;i<MAX_SENSORS;i++) // initialize table
{
strcpy(sensor_data[i][0],"?");
strcpy(sensor_data[i][1],"");
}
}
Message received here
void callback(char* topic, byte* b_payload, unsigned int length) {
// Convert byte* b_payload to string
for (int i = 0; i < length; i++) {
payload[i]=(char)b_payload[i];
};
payload[length]='\0';
for (int i = 0; i < MAX_SENSORS; i++)
{
Why does this (desparate debug) not work?
if (sensor_data[i][0]=="?") {
Serial.print("*");
}
Original
if (sensor_data[i][0]==topic) { // Slot matching topic found
strcpy(sensor_data[i][1],payload);
Serial.printf(" Slot %d",i);
break;
} else if (sensor_data[i][0]=="?") { // Empty slot found, store topic here
strcpy(sensor_data[i][0],topic);
strcpy(sensor_data[i][1],payload);
Serial.printf(" New %d",i);
break;
}
}
Serial.println();
}
It all probably originates because I'm confused between strings and char arrays?
edit
The assignment
strcpy(sensor_data[i][0],topic);
strcpy(sensor_data[i][1],payload);
seem to assign
concat(topic,payload) to sensor_data[i][0].
It all probably originates because I'm confused between strings and
char arrays?
Seems like it. C-strings (char* and char[]) are not comparable with ==, arduino's String class is. Either convert the left side of the comparison to String or use strcmp to compare the strings.
if (String(sensor_data[i][0])=="?") {
if (strcmp(sensor_data[i][0], "?") == 0) {
I am tasked with writing a program to maintain the representation of a simple network(weighted directed graph) and compute the best path between two given nodes upon request.
Currently, I am attempting to write a function to compute the simplest between two nodes, however, when attempting to run my program, I get two specific error
Severity Code Description Project File Line Suppression State
Error C3863 array type 'bool [openNode]' is not assignable P 127
and
Severity Code Description Project File Line Suppression State
Error C3863 array type 'int [openNode]' is not assignable
I am unable to debug since these two primary errors are not allowing my program to run. Is there any particular reason for these errors?
Thanks in advance!
This is the node structure defined in Graph.h
struct GraphNode
{
char ID;
std::string name;
int inNodes = 0;
int outNodes = 0;
std::vector<std::pair<GraphNode*, int>> connection;
int connections = 0;
};
And here is the particular code that causes the errors.
#include "Graph.h"
std::vector<GraphNode*> _graph;
int openNode = 0;
//Obligatory constructor
void Graph()
{
}
void shortestPath(char fromNode, char toNode)
{
bool known[openNode];
int distance[openNode];
GraphNode* previous[openNode];
int numbChecked = 0;
for (int i = 0; i < openNode; i++)
{
known[i] = false;
distance[i] = 999999;
previous[i] = nullptr;
}
distance[findNode(fromNode)] = 0;
while (numbChecked < openNode)
{
int smallestUnknown = 9999999;
int locationOfSmall = 0;
for (int i = 0; i < openNode; i++)
{
if (known[i] == false && distance[i] < smallestUnknown)
{
smallestUnknown = distance[i];
locationOfSmall = i;
}
}
if (distance[locationOfSmall] == 0)
{
previous[locationOfSmall] = nullptr;
}
known[locationOfSmall] = true;
numbChecked++;
if (_graph[locationOfSmall]->outNodes > 0)
{
for (int i = 0; i < _graph[locationOfSmall]->outNodes; i++)
{
int newDistanceLocation = findNode(_graph[locationOfSmall]->connection[i].first->ID);
if (known[newDistanceLocation] == false && (distance[locationOfSmall] + _graph[locationOfSmall]->connection[i].second) < distance[newDistanceLocation])
{
distance[newDistanceLocation] = distance[locationOfSmall] + _graph[locationOfSmall]->connection[i].second;
previous[newDistanceLocation] = _graph[locationOfSmall];
}
}
}
}
int destination = findNode(toNode);
std::string output;
std::string charTransfer;
charTransfer = toNode;
output = charTransfer;
while (previous[destination] != nullptr)
{
destination = findNode(previous[destination]->ID);
charTransfer = _graph[destination]->ID;
output = charTransfer + "->" + output;
}
if (_graph[destination]->ID != fromNode)
{
std::cout << "The nodes are not connected." << std::endl;
}
else
{
std::cout << "The path is: " << output << std::endl;
std::cout << "The distance is: " << distance[findNode(toNode)] << std::endl;
}
}
Any change suggestions would be much appreciated!
You have invalid code at the beginning of your shortestPath function:
bool known[openNode];
int distance[openNode];
GraphNode* previous[openNode];
You cannot use variables to create arrays on the stack (which is what you are trying to do there), because the compiler doesn't know the value of openNode at compile time (which is needed to determine the stack size).
Why don't you use a vector, like:
std::vector<bool> known(openNode, false);
std::vector<int> distance(openNode, 999999);
std::vector<GraphNode*> previous(openNode, nullptr);
Using this method makes the for loop below obsolete aswell.
Visual Studio is telling me that this for loop isn't correct.
Error Messages are:
type bool unexpected
ok is undeclared identifier
missing ; before }
infos:
-recordset.Select return a long -MoveNext a bool
for (size_t i = 0, bool ok = recordset.Select(Adress::getSQLStatement() + "Where A05.recid = %ld", i); ok; ok = recordset.MoveNext(), i++) {
at(i).Save(recordset);
}
It's as StenSoft said. But you can define an anonymous structure in the loops first statement, and initialize that.
#include <iostream>
using namespace std;
int main() {
for (struct {size_t i; bool ok;} s = {0, true}; s.ok; ++s.i) {
s.ok = s.i < 10;
cout << s.i;
}
return 0;
}
But IMHO, while it works, it's more trouble than it's worth. Better restructure you code.
First off, you can of course rewrite your loop like so:
{
bool ok = recordset.Select(...);
for (std::size_t i = 0; ok; ok = recordset.MoveNext(), ++i)
{
/* ... */
}
}
But the meta lesson here is that almost all loops are for-loops, and when you think your structure is different, think again. There's probably a rewrite in terms of for-loops that makes your logic clearer. Your present code doesn't distinguish an initial error from a "no more records" error later. With the new code, that's now explicitly possible:
if (bool ok = recordset.select(...))
{
for (std::size_t i = 0; ok; ok = recordset.MoveNext(), ++i) { /* ... */ }
}
else
{
// handle initial error
}
I would probably even get rid of the redundant ok variable:
if (recordset.select(...))
{
for (std::size_t i = 0; ; ++i)
{
/* ... */
if (!recordset.MoveNext()) break;
}
}
else
{
// handle initial error
}
Given an enum:
enum AnEnum { Foo, Bar, Bash, Baz };
Can you iterate over each of these enums using Qt's foreach loop?
This code doesn't compile (not that I expected it to...)
foreach(AnEnum enum, AnEnum)
{
// do nothing
}
If it is moced into a QMetaEnum than you can iterate over it like this:
QMetaEnum e = ...;
for (int i = 0; i < e.keyCount(); i++)
{
const char* s = e.key(i); // enum name as string
int v = e.value(i); // enum index
...
}
http://qt-project.org/doc/qt-4.8/qmetaenum.html
Example using QNetworkReply which is a QMetaEnum:
QNetworkReply::NetworkError error;
error = fetchStuff();
if (error != QNetworkReply::NoError) {
QString errorValue;
QMetaObject meta = QNetworkReply::staticMetaObject;
for (int i=0; i < meta.enumeratorCount(); ++i) {
QMetaEnum m = meta.enumerator(i);
if (m.name() == QLatin1String("NetworkError")) {
errorValue = QLatin1String(m.valueToKey(error));
break;
}
}
QMessageBox box(QMessageBox::Information, "Failed to fetch",
"Fetching stuff failed with error '%1`").arg(errorValue),
QMessageBox::Ok);
box.exec();
return 1;
}
foreach in Qt is definitely just for Qt containers. It is stated in the docs here.
There is a much simpler version for retrieving the QMetaEnum object (Qt 5.5 and above):
QMetaEnum e = QMetaEnum::fromType<QLocale::Country>();
QStringList countryList;
for (int k = 0; k < e.keyCount(); k++)
{
QLocale::Country country = (QLocale::Country) e.value(k);
countryList.push_back(QLocale::countryToString(country));
}
I have the below protocol buffer. Note that StockStatic is a repeated field.
message ServiceResponse
{
enum Type
{
REQUEST_FAILED = 1;
STOCK_STATIC_SNAPSHOT = 2;
}
message StockStaticSnapshot
{
repeated StockStatic stock_static = 1;
}
required Type type = 1;
optional StockStaticSnapshot stock_static_snapshot = 2;
}
message StockStatic
{
optional string sector = 1;
optional string subsector = 2;
}
I am filling out the StockStatic fields while iterating through a vector.
ServiceResponse.set_type(ServiceResponse_Type_STOCK_STATIC_SNAPSHOT);
ServiceResponse_StockStaticSnapshot stockStaticSnapshot;
for (vector<stockStaticInfo>::iterator it = m_staticStocks.begin(); it!= m_staticStocks.end(); ++it)
{
StockStatic* pStockStaticEntity = stockStaticSnapshot.add_stock_static();
SetStockStaticProtoFields(*it, pStockStaticEntity); // sets sector and subsector field to pStockStaticEntity by reading the fields using (*it)
}
But the above code is right only if StockStatic was an optional field and not a repeated field. My questions is what line of code am i missing to make it a repeated field?
No, you're doing the right thing.
Here's a snippet of my protocol buffer (details omitted for brevity):
message DemandSummary
{
required uint32 solutionIndex = 1;
required uint32 demandID = 2;
}
message ComputeResponse
{
repeated DemandSummary solutionInfo = 3;
}
...and the C++ to fill up ComputeResponse::solutionInfo:
ComputeResponse response;
for ( int i = 0; i < demList.size(); ++i ) {
DemandSummary* summary = response.add_solutioninfo();
summary->set_solutionindex(solutionID);
summary->set_demandid(demList[i].toUInt());
}
response.solutionInfo now contains demList.size() elements.
Here the c++ sample code but may not efficient:
message MyArray
{
repeated uint64 my_data = 1;
}
//Copy
std::array<unsigned long long, 5> test={1,1,2,3,5};
mynamespace::MyArray pbvar;
auto *dst_ptr = keys.my_data();
google::protobuf::RepeatedField<google::protobuf::uint64> field{test.begin(), test.end()};
dst_ptr->CopyFrom(field);
//Output
for (auto it : pbvar.my_data())
std::cout<<it<<" ";
std::cout<<std::endl;
Another way of accomplishing the same thing:
message SearchResponse {
message Result {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
repeated Result result = 1;
}