I'm developing network protocol. I have a lot of non-polimorphic structures. I need to pass input structure to packet with its id(unique number of structure) and serialize it to byte array to send.
And deserialize it the same: receive byte array, get structure id, and deserialize bytes as this structure.
How?
Example with comments:
// Internal structure, cannot be edited
struct FirstProcedureParams {
std::string some_string;
int some_integer;
};
// Also cannot be edited
struct SecondProcedureParams {
std::vector<int> some_vector;
std::map<int, int> some_map;
};
// My class to serialize and deserialize packet data to send to client or server.
class CallProcedurePacket : public BasePacket {
public:
void Serialize(uint8_t** bytes, size_t* length) override;
void Deserialize(const uint8_t* bytes, size_t length) override;
public:
int procedure_id; // for example, 1 - FirstProcedureParams, 2 - SecondProcedureParams.
// there is must be parameters for concrete procedure id.
};
void CallProcedurePacket::Serialize(uint8_t** bytes, size_t* length) {
// Some stuff..
writer.Write(procedure_id);
// How can I write dynamic parameters structure
// If it is not polymorphic and it hasn't method like Serialize?
// In this example only 2 structures: FirstProcedureParams and SecondProcedureParams.
// But in real code I have more than 15 structures.
}
void CallProcedurePacket::Deserialize(const uint8_t* bytes, size_t length) {
// Some stuff..
reader.Read(procedure_id);
// I need to get FirstProcedureParams if procedure_id equal 1
// or SecondProcedureParams if procedure_id equal 2.
}
// -----------------------------
// Example of using CallProcedurePacket:
void SomeSendFunction() {
FirstProcedureParams params;
params.some_string = "some string";
params.some_integer = 789;
CallProcedurePacket call_procedure_packet;
call_procedure_packet.procedure_id = 1;
call_procedure_packet.params = params; // what type should be `params` field? how can I write FirstProcedureParams to it?
SendPacket(call_procedure_packet);
}
void SomeSendFunction2() {
SecondProcedureParams params;
params.some_vector = { 1, 2, 3 };
params.some_map = {
{ 1, 5 },
{ 7, 9 }
};
CallProcedurePacket call_procedure_packet;
call_procedure_packet.procedure_id = 2;
call_procedure_packet.params = params; // params field should accept SecondProcedureParams too.
SendPacket(call_procedure_packet);
}
// And reading..
void SomeReceiveFunction() {
CallProcedurePacket call_procedure_packet = ReceivePacket();
if (call_procedure_packet.procedure_id == 1) {
FirstProcedureParams params;
// somehow get the params.
procedure(params.some_string, params.some_integer);
}
else if (call_procedure_packet.procedure_id == 2) {
SecondProcedureParams params;
// some usage of params.
}
}
I have a list of objects of the same class.
This class contains an attribute I want to use.
I would like to get a list of all these attributes in one line. Is this possible?
Here is a small example: I just want a list of all the colors.
It is important that I return directly a list of these attributes, without the normal forEach statement.
void main() {
List<Car> listOfCars = [
Car('blue'),
Car('green'),
Car('yellow'),
];
}
//List<String> listOfColors = listOfCars[all].color;
class Car{
String color;
Car(this.color);
}
You can use the map function to achieve this
List<String> listOfColors = listOfCars.map((car) => car.color).toList();
print(listOfColors);
Just check out this code below:
void main() {
List<Car> listOfCars = [
Car('blue'),
Car('green'),
Car('yellow'),
];
List<String> stringList = List();
// This is where you get the single car object and then you add it the list of string
for (int i = 0; i < listOfCars.length; i++) {
stringList.add(listOfCars[i].color);
}
// this is the desired out put i have just printed your list :
print('This is the string length : ' + stringList.length.toString());
for (int i = 0; i < stringList.length; i++) {
print('This is the string list :' + stringList[i]);
}
}
class Car {
final String color;
Car(this.color);
}
Blow is the output :
This is the string length : 3
This is the string list :blue
This is the string list :green
This is the string list :yellow
Consider the following example for which my source is
Json::Value root;
root["id"]=0;
Json::Value text;
text["first"]="i";
text["second"]="love";
text["third"]="you";
root["text"]=text;
root["type"]="test";
root["begin"]=1;
root["end"]=1;
Json::StyledWriter writer;
string strJson=writer.write(root);
cout<<"JSON WriteTest" << endl << strJson <<endl;
I thought I'd write the json fields in the order of the lines. Instead the result is:
JSON WriteTest
{
"begin" : 1,
"end" : 1,
"id" : 0,
"text" : {
"first" : "i",
"second" : "love",
"third" : "you"
},
"type" : "test"
}
I want json format is
JSON WriteTest
{
"id" : 0,
"text" : {
"first" : "i",
"second" : "love",
"third" : "you"
},
"type" : "test"
"begin" : 1,
"end" : 1,
}
How can I write a Json order?
No, I don't think you can. JsonCpp keeps its values in a std::map<CZString, Value>, which is always sorted by the CZString comparison. So it doesn't know the original order you added items.
This is my workaround to a get an ordered json output from jsoncpp
Json::Value root;
root["*1*id"]=0;
Json::Value text;
text["*1*first"]="i";
text["*2*second"]="love";
text["*3*third"]="you";
root["*2*text"]=text;
root["*3*type"]="test";
root["*4*begin"]=1;
root["*5*end"]=1;
Json::StyledWriter writer;
string resultString=writer.write(root);
resultString=ReplaceAll(resultString,"*1*", "");
resultString=ReplaceAll(resultString,"*2*", "");
resultString=ReplaceAll(resultString,"*3*", "");
resultString=ReplaceAll(resultString,"*4*", "");
resultString=ReplaceAll(resultString,"*5*", "");
cout<<"JSON WriteTest" << endl << resultString <<endl;
with RepleceAll function defined as this
std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
}
return str;
}
I have a way can solve your problem. Would you like to try? My solution is that you use boost/property_tree/json_parser.hpp, the output is what format you want! About There is my code:
#include <boost/property_tree/json_parser.hpp>
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
boost::property_tree::ptree parser, child;
parser.put("id", 0);
child.put("first", "i");
child.put("second", "love");
child.put("third", "you");
parser.put_child("text", child);
parser.put("type", "test");
parser.put("begin", 1);
parser.put("end", 1);
stringstream ss;
boost::property_tree::json_parser::write_json(ss, parser);
cout << ss.str() << endl;
return 0;
}
Before run the codes, you should install boost 1.57. The codes run well in gcc 4.7, boost 1.57.The output is { "id" : 0, "text" : { "first" : "i", "second" : "love", "third" : "you" }, "type" : "test" "begin" : 1, "end" : 1, }. About boost::property_tree::ptree, you can click here. It used list<pair<key, ptree>> for saving data. So it saved unordered data, unless you called list.sort(). I hope this can help you.
As mentioned by The Dark, JsonCpp keeps its values in a std::map<CZString, Value>, which is always sorted by the CZString comparison, without keeping track neither of the original order in which you added the items nor the desired order in the output.
But you can use this "hidden feature" in your benefit. I mean, you just need that the keys in the desired order follow the "natural" order of CZString. I have a method in my JSONCPP wrapper classes that do this. The quick'n'dirty code, converted to simple function, would be something like this:
std::string sortedStr(Json::Value & value, std::vector<std::string> sortKeys)
{
Json::Value sortedValue; // The JSON object to store the new (sorted) hash
char newKey[60]; // I use C expressions, modify to C++ if you like
// Build new sortedValue
int i = 0;
for (auto & key : sortKeys) {
sprintf(newKey, "SORTEDKEY:%03d-%s", i++, key.c_str());
sortedValue[newKey] = value[key];
}
// Write to string, should be sorted on primary keys
Json::StyledWriter w;
std::string result = w.write(sortedValue);
// Remove aux. tags from primary keys
std::size_t pos = 0;
while ((pos = result.find("SORTEDKEY:", pos)) != std::string::npos) {
result.erase(pos, 14);
}
return result;
}
To use it, just call:
std::string sortedObjStr = sortedValue(myValue, {"first", "second", "third", "fourth"});
Note that:
I use this for relatively small objects (configuration data).
I use the "tag" SORTEDKEY, since this is not going to appear anywhere in my data. Modify according to your needs.
I do not check that the keys used do exist. You can add this check.
You can use this also to generate a restricted, ordered subset of your original object.
The key-value pairs in an object will always be sorted. Json arrays are not sorted, they consists of a series of values without keys.
Objects, as named collections (arrays) of key-value pairs within brackets, in an array, will retain their positions, e.g.
{
"adressen" : [
{
"start" : {
"ID" : 1,
"key" : "2352KJ25",
"lat" : 52.157225922529967,
"lon" : 4.5298663828345527
}
},
{
"eind" : {
"ID" : 2,
"key" : "2352KJ25",
"lat" : 52.157225922529967,
"lon" : 4.5298663828345527
}
}
}
ID, key, lat, lon are sorted, but start and eind are in their original positions.
So, at least your first, second, third could have been
Json::Value text(Json::arrayValue);
text.append("I");
text.append("love");
text.append("you");
No need for the tags first, second and third!
Maybe this helps you to find a workaround.
I'm not that good in English, that's why my Question is probably wrong. But I have a problem and I don't know how to solve it or if it's even possible to do.
I have 2 Structs defined:
typedef struct
{
UINT16 ScriptNumber;
std::string ScriptText;
} StepStruct;
typedef struct
{
std::string SequenceName;
std::string DisplayName;
StepStruct SequenceSteps;
} SequenceStruct;
As you can see, the first Struct is a Member of the second struct. So I want both structs to by dynamical. So I created 2 Dynamic Arrays from the Type StepStruct and 1 dynamic Array from the Type SequenceStruct.
The two dynamical Arrays for of the Type StepStructs are defined as follows:
StepStruct gsFirstSkript[] =
{
{ 1 , "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
StepStruct gsSecondSkript[] =
{
{ 48, "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
Those to Structs are of the Type StepStruct. Now I want to do the Same with a SequenceStruct Type, but I want to assign the two Arrays I already have to it under the Struct Member SequenceSteps. I mean this as follows:
SequenceStruct gsSequenceList[] =
{
{ "FirstScript", "Test One", gsFirstSkript},
{ "SecondScript", "Test Two", gsSecondSkript}
}
If I now want to Read the Member gsSequenceList, I can not access any information under the SequenceSteps Index of it! What means, that the Data is not copied! I tried it with Pointers
but had no success.
UINT16 lTestVal = gsSequenceList[0].SequenceSteps[2].ScriptNumber;
So Can I mangage that this works, and lTestVal contains the Value 45?
typedef struct
{
std::string SequenceName;
std::string DisplayName;
StepStruct* SequenceSteps;
} SequenceStruct;
This will allow the code to compile and the test fragment you've shown will work.
However this will not copy the data. If you change gsFristSkript it will change in gsSequenceList as well. If you want to make a copy of the data you can either do that explicitly, have a constructor or just use vector<>.
Here's the solution with vector:
#include <vector>
...
typedef struct{
std::string SequenceName;
std::string DisplayName;
vector<StepStruct> SequenceSteps;
} SequenceStruct;
vector<StepStruct> gsFirstSkript =
{
{ 1 , "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
vector<StepStruct> gsSecondSkript =
{
{ 48, "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
SequenceStruct gsSequenceList[] =
{
{ "FirstScript", "Test One", gsFirstSkript},
{ "SecondScript", "Test Two", gsSecondSkript}
}
I need to understand and modify a sample code. I am stuck at some point and couldn't find any solution. Here is the code:
void foo(std::istream& input)
{
using boost::property_tree::ptree;
ptree pt;
boost::property_tree::read_json(input, pt);
BOOST_FOREACH(ptree::value_type &node, pt.get_child("some_nodes"))
{
std::string id;
unsigned int number1;
bool flag1;
bool flag2;
id = node.second.get<std::string>("id");
number1 = node.second.get<unsigned int>("number1");
flag1 = node.second.get<bool>("flag1");
flag2 = node.second.get<bool>("flag2");
}
}
Can somebody please tell me what does 'second' mean here ?
Here is the JSON example that the program reads:
{
"some_nodes" :
[
{
"id" : "vader",
"number1" : "1024",
"flag1" : "false",
"flag2" : "true",
},
{
"id" : "anakin",
"number1" : "4096",
"flag1" : "true",
"flag2" : "true",
}
]
}
One more question, I also get the following error when I try to compile the code. What does this mean, how can I solve it?
Invalid arguments '
Candidates are:
boost::foreach_detail_::foreach_reference<#0,#1>::type deref(const boost::foreach_detail_::auto_any_base &, boost::foreach_detail_::type2type<#0,#1> *)
'
Thanks a lot.
ptree::value_type is defined this way:
typedef std::pair< const Key, self_type > value_type;
so it's simply an std::pair.
The root node of your JSON is the array "some_nodes".
When you iterate your property tree you are iterating through all "some_nodes" children.
first field is the key (implicit in this case since you are iterating all the root child nodes). I suppose in your case node.first is always "some_nodes".
second is the value (a child node of the key: another ptree). In this case at each iteration second is the i-th unnamed object of your array.