I'm trying to read a JSON formatted file which is nested with the BOOST library in C++.
I tried a couple of things, browsed through many questions in this forum, but I couldn't find anything really similar, or that would work.
the json file im looking at has the following structure
{
"ABC": {
"FF:[10.0,20.0]": {
"GHG:[-2.5,-2.0]": {
"value": 1.1176470518112183,
"error": 0.013857235087295462
},
"GHG:[1.566,2.0]": {
"value": 0.9958805441856384,
"error": 0.027176504445043704
}
},
"FF:[30.0,50.0]": {
"GHG:[-2.5,-2.0]": {
"value": 1.1176470518112183,
"error": 0.013857235087295462
},
"GHG:[2.0,2.5]": {
"value": 1.0464363098144531,
"error": 0.061588554028766326
}
}
},
"ZXY": {
"FF:[10.0,20.0]": {
"GHG:[-2.5,-2.0]": {
"value": 1.1176470518112183,
"error": 0.013857235087295462
},
"GHG:[1.566,2.0]": {
"value": 0.9958805441856384,
"error": 0.027176504445043704
}
},
"FF:[30.0,50.0]": {
"GHG:[-2.5,-2.0]": {
"value": 1.1176470518112183,
"error": 0.013857235087295462
},
"GHG:[2.0,2.5]": {
"value": 1.0464363098144531,
"error": 0.061588554028766326
}
}
}
}
i was trying to use the BOOST_FOREACH method as is described here:
http://www.ce.unipr.it/people/medici/boost_ptree.html
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/foreach.hpp>
#include <iostream>
namespace pt = boost::property_tree;
pt::ptree tree;
int main() {
pt::read_json("bla.json", tree);
BOOST_FOREACH( pt::ptree::value_type const&v, tree.get_child("ABC") ) {
const std::string & key = v.first;
const pt::ptree & subtree = v.second;
//const pt::ptree & subsubtree = v.second;
std::cout << key << std::endl;
if(subtree.empty()) {
std::cout << "subtree empty" << std::endl;
} else {
std::cout << "subtree not empty" << std::endl;
BOOST_FOREACH( pt::ptree::value_type const&sv, subtree.get_child(key) ) {
const std::string & subkey = sv.first; // key
const pt::ptree & subsubtree = sv.second; // value (or a subnode)
if(subsubtree.empty()) {
std::cout << "subsubtree empty" << std::endl;
} else {
std::cout << "subsubtree not empty" << std::endl;
std::cout << subsubtree.data() << std::endl;
}
}
}
}
return 0;
}
but i always get an error that there's no such node:
terminate called after throwing an instance of 'boost::wrapexcept<boost::property_tree::ptree_bad_path>'
what(): No such node (FF:[10.0,20.0])
Aborted
i'm pretty sure this is not a hard problem, but i'm kind of a newbie with c++ and i really appreciate any help!
Finally, I got it that your get_child usage is not correct! Just pass the tree to range-based for.
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/foreach.hpp>
#include <iostream>
namespace pt = boost::property_tree;
pt::ptree tree;
int main() {
pt::read_json("bla.json", tree);
for(auto&& v : tree.get_child("ABC")) {
const std::string & key = v.first; // key
const pt::ptree & subtree = v.second; // value (or a subnode)
//const pt::ptree & subsubtree = v.second; // value (or a subnode)
std::cout << key << std::endl;
if(subtree.empty()) {
// This is a key:value
// use subtree.data() as string value or subtree.get_value<T>()
std::cout << "subtree empty" << std::endl;
} else {
// This is a subtree
// use subtree as child
std::cout << "subtree not empty" << std::endl;
for(auto&& sv : subtree/*.get_child(pt::path(key, '\0'))*/) {
[[maybe_unused]]const std::string & subkey = sv.first; // key
const pt::ptree & subsubtree = sv.second; // value (or a subnode)
std::cout << subkey << std::endl;
if(subsubtree.empty()) {
std::cout << "subsubtree empty" << std::endl;
} else {
std::cout << "subsubtree not empty" << std::endl;
std::cout << subsubtree.data() << std::endl;
for(auto&& ssv: subsubtree) {
[[maybe_unused]]const std::string & subsubkey = ssv.first; // key
const pt::ptree & subsubsubtree = ssv.second; // value (or a subnode)
std::cout << subsubkey << std::endl;
if(subsubsubtree.empty()) {
std::cout << "subsubsubtree empty" << std::endl;
if (auto subsubsubtree_v = subsubsubtree.get_value_optional<double>()) {
std::cout << subsubsubtree_v.get() << std::endl;
}
}
else {
std::cout << "subsubtree not empty" << std::endl;
std::cout << subsubtree.data() << std::endl;
}
}
}
}
}
}
return 0;
}
https://wandbox.org/permlink/uRub7N5VeZ9WrDKd
Related
hey I have class containing
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
using namespace std;
struct student
{
std::string ID;
std::string Name;
std::vector<std::string> friends;
};
And main function contains
int main() {
vector<student> List_Students = { { "d123", "Jacob", {"e321"} }, { "e321", "Abo", {"d123", "e456"} }, { "e456","Mark",{} } };
for (auto& s : List_Students)
{
cout << s.ID << "\t" << s.Name;
for (auto& f : s.friends)
{
cout << " " << f << " ";
}
cout << endl;
}
}
this yields output as expected
output:
d123 Jacob e321
e321 Abo d123 e456
e456 Mark
my question is how can I compare the vector of friends with IDs so that so that after it shows friends it shows their names with it. Expected output:
d123 Jacob e321 (Abo)
e321 Abo d123 (Jacob) e456 (Mark)
e456 Mark (No friends)
quite new to c++ any help would be appreciated thank you
You can use the standard std::find_if() algorithm, eg
...
#include <algorithm>
...
int main() {
vector<student> List_Students = {
{ "d123", "Jacob", {"e321"} },
{ "e321", "Abo", {"d123", "e456"} },
{ "e456", "Mark", {} }
};
for (auto& s : List_Students)
{
cout << s.ID << "\t" << s.Name;
if (s.friends.empty())
{
cout << " (No friends)";
}
else
{
for (auto& f : s.friends)
{
cout << " " << f << " ";
auto iter = find_if(List_Students.begin(), List_Students.end(),
[&](const student &s2){ return s2.ID == f; }
);
if (iter != List_Students.end())
{
cout << "(" << iter->Name << ") ";
}
}
}
cout << endl;
}
}
Or, like #Ch3steR said in comments, you can store the names in a std::map:
...
#include <map>
#include <utility>
...
int main() {
vector<student> List_Students = {
{ "d123", "Jacob", {"e321"} },
{ "e321", "Abo", {"d123", "e456"} },
{ "e456", "Mark", {} }
};
map<string, string> names;
for (auto& s : List_Students)
{
names.insert(make_pair(s.ID, s.Name));
}
for (auto& s : List_Students)
{
cout << s.ID << "\t" << s.Name;
if (s.friends.empty())
{
cout << " (No friends)";
}
else
{
for (auto& f : s.friends)
{
cout << " " << f << " (" << names[f] << ") ";
}
}
cout << endl;
}
}
Alternatively:
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct student
{
string Name;
vector<string> friends;
};
int main() {
map<string, student> List_Students = {
{ "d123", { "Jacob", {"e321"} } },
{ "e321", { "Abo", {"d123", "e456"} } },
{ "e456", { "Mark", {} } }
};
for (auto& elem : List_Students)
{
auto &s = elem.second;
cout << elem.first << "\t" << s.Name;
if (s.friends.empty())
{
cout << " (No friends)";
}
else
{
for (auto& f : s.friends)
{
cout << " " << f << " (" << List_Students[f].Name << ") ";
}
}
cout << endl;
}
}
I'm new to json and trying to use nlohmann library and I'm quite stuck.
config.json file looks like this
{
"Version": 1.1,
"Size": 1024,
"integer": 600,
"Map": [{"0": "india"}, {"1": "usa"}, {"2": "china"}, {"2": "japan"}],
"name": "xxx",
}
I want to get the value of ["Map"]["1"] where "1" is a runtime entity. I have tried several ways but none of them is working.
std::string strRwFilePath = std::string(CONFIG_PATH) + "config.json";
std::ifstream RwFile(strRwFilePath);
if (RwFile.fail())
{
std::cout << "[ReadFileContents]RwFile doesnt exist" << std::endl;
}
else
{
// parsing input
RwFile >> conf_json;
if(!(conf_json.empty()))
{
//METHOD 1
for (auto it = conf_json["Map"].begin(); it != conf_json["Map"].end(); ++it)
{
std::cout << it.key() << " | " << it.value() << "\n";
std::string keyy = std::to_string(m_iRegionType);
std::string tempKey = it.key(); //ERROR- [json.exception.invalid_iterator.207] cannot use key() for non-object iterators
std::cout << "for loop: tempKey:" << tempKey << " \n";
if(!strcmp(tempKey.c_str(),(std::to_string(m_iRegionType)).c_str()))
{
std::cout << "SUCCESS 222" << std::endl;
break;
}
else
{
std::cout << "FAILURE 222" << std::endl;
}
}
//METHOD 2
for(auto& element : conf_json["Map"].items())
{
std::cout << element.key() << " | " << element.value() << "\n";
m_iRegionType = 2;
std::string keyy = std::to_string(m_iRegionType);
std::string tempKey = element.key(); //ERROR: [json.exception.type_error.302] type must be string, but is object
if(!strcmp(tempKey.c_str(),(std::to_string(m_iRegionType)).c_str()))
{
std::cout << "SUCCESS 333" << std::endl;
break;
}
else
{
std::cout << "FAILURE 333" << std::endl;
}
}
//METHOD 3
std::string strTempKey = std::to_string(m_iRegionType);
if(!conf_json["Map"][strTempKey.c_str()].is_null())
{
std::string strName = conf_json["Map"][strTempKey.c_str()]; //ERROR: [json.exception.type_error.305] cannot use operator[] with a string argument with array
std::cout << "key found. RegionName: " << strName << '\n';
}
else
{
std::cout << "key not found" << std::endl;
}
//METHOD 4
// create a JSON object
std::string strKey = "/Map/" + std::to_string(m_iRegionType);
// call find
auto it_two = conf_json.find(strKey.c_str());
if(true == (it_two != conf_json.end()))
{
std::cout << "Region key was found. RegionBucketName: " << *it_two << '\n';
std::string strRegionName = conf_json["Map"][m_iRegionType];
std::string strRegionName2 = *it_two;
std::cout << "strRegionName: " << strRegionName << '\n';
std::cout << "strRegionName2: " << strRegionName2 << '\n';
}
else
{
//getting this as OUTPUT even though key is available
std::cout << "invalid region type, key not available m_iRegionType: " << m_iRegionType << std::endl;
}
}
else
{
std::cout << "[ReadFileContents]Read Write Json object is empty" << std::endl;
}
}
I have also tried using the small json structure where I am not able to access the value using the runtime key.
json j =
{
{"integer", 1},
{"floating", 42.23},
{"string", "hello world"},
{"boolean", true},
{"object", {{"key1", 1}, {"key2", 2}}},
{"array", {1, 2, 3}}
};
int avail4 = j.value("/integer"_json_pointer, 444);
std::cout << "avail4 : " << avail4 << std::endl; //OUTPUT- avial4 : 1
int avail5 = j.value("/object/key2"_json_pointer, 555);
std::cout << "avail5 : " << avail5 << std::endl; //OUTPUT- avial5 : 2
auto strKey3 = "/object/key2";
int avail6 = j.value(strKey3, 666);
std::cout << "avail6 : " << avail6 << std::endl; //OUTPUT- avial6 : 666
Could any one help me.
You can't use ["Map"]["1"] to find the inner array objects. You need iterator through the array
A code example may like this:
#include <nlohmann/json.hpp>
#include <iostream>
// for convenience
using json = nlohmann::json;
int main() {
json j = R"(
{
"Version": 1.1,
"Size": 1024,
"integer": 600,
"Map": [{
"0": "india"
}, {
"1": "usa"
}, {
"2": "china"
}, {
"2": "japan"
}],
"name": "xxx"
}
)"_json;
for (const auto& ele : j["Map"]) {
if (ele.contains("1")) {
std::cout << ele["1"] << std::endl;
}
}
}
Output:
usa
Demo
I'm trying to interpret the output of FasterRCNN in C++ and I'm fighting with the GenericDict type.
My code is as follows:
#include <opencv4/opencv2/opencv.hpp>
#include <opencv4/opencv2/shape.hpp>
#include <opencv4/opencv2/imgcodecs.hpp>
#include <opencv4/opencv2/highgui.hpp>
#include <opencv4/opencv2/imgproc.hpp>
#include <opencv4/opencv2/core/utility.hpp>
#include <opencv4/opencv2/core/mat.hpp>
#include <c10/cuda/CUDAStream.h>
#include <torch/csrc/autograd/grad_mode.h>
#include <torch/csrc/api/include/torch/torch.h>
#include <torch/script.h>
#include <torchvision/vision.h>
#include <torchvision/nms.h>
#include <iostream>
#include <memory>
#include <string>
int main(int argc, const char* argv[])
{
if (argc != 3)
{
printf("usage: %s <path-to-exported-script-module> <image_to_test>\n",argv[0]);
return -1;
}
std::string module_filename = argv[1];
std::string image_file = argv[2];
try
{
cv::Mat input_img = cv::imread(image_file, cv::IMREAD_GRAYSCALE);
torch::autograd::AutoGradMode guard(false);
// Deserialize the ScriptModule from a file using torch::jit::load().
torch::jit::script::Module module = torch::jit::load(module_filename);
assert(module.buffers().size() > 0);
module.eval();
// Assume that the entire model is on the same device.
// We just put input to this device.
auto device = (*std::begin(module.buffers())).device();
const int height = input_img.rows;
const int width = input_img.cols;
const int channels = 1;
auto input = torch::from_blob(input_img.data, {height, width, channels}, torch::kUInt8);
// HWC to CHW
// input = input.to(device, torch::kFloat).permute({2, 0, 1}).contiguous();
input = input.to(device, torch::kFloat).permute({2, 0, 1}).contiguous();
// run the network
std::vector<at::Tensor> inputs;
inputs.push_back(input);
auto output = module.forward({inputs});
if (device.is_cuda())
c10::cuda::getCurrentCUDAStream().synchronize();
std::cout << "output: " << output << std::endl;
auto outputs = output.toTuple()->elements();
std::cout << "outputs: " << outputs << std::endl;
for( auto& elem : outputs )
{
std::cout << "elem: " << elem << std::endl;
if( elem.isGenericDict() )
{
std::cout << "elem is generic dict: " << elem << std::endl;
c10::Dict<c10::IValue, c10::IValue> dict = elem.toGenericDict();
auto elem_vector_0 = dict.at(c10::IValue("scores")).toIntVector();
auto elem_vector_1 = dict.at(c10::IValue("boxes")).toIntVector();
auto elem_vector_2 = dict.at(c10::IValue("labels")).toIntVector();
for( auto& ee0 : elem_vector_0 )
{
std::cout << "elem_vector_0" << ee0 << std::endl;
}
for( auto& ee0 : elem_vector_1 )
{
std::cout << "elem_vector_1" << ee0 << std::endl;
}
for( auto& ee0 : elem_vector_2 )
{
std::cout << "elem_vector_2" << ee0 << std::endl;
}
}
}
cv::namedWindow("Display Image", cv::WINDOW_AUTOSIZE );
cv::imshow("Display Image", input_img);
cv::waitKey(0);
}
catch(const c10::Error& e)
{
std::cerr << e.what() << std::endl;
return -1;
}
catch(const cv::Exception& e)
{
std::cerr << e.what() << std::endl;
return -1;
}
catch(const std::exception& e)
{
std::cerr << e.what() << std::endl;
return -1;
}
catch(...)
{
std::cerr << "Unknown error" << std::endl;
return -1;
}
std::cout << "ok\n";
return 0;
}
and the output is:
(base) fstrati#fstrati-desktop:~/libtorch_shared_cuda_10.1/load_and_run_model/Release$ ./load_and_run_model ./torch_script_v0.2.pt test_img.png
[W faster_rcnn.py:95] Warning: RCNN always returns a (Losses, Detections) tuple in scripting (function )
output: ({}, [{boxes: [ CPUFloatType{0,4} ], labels: [ CPULongType{0} ], scores: [ CPUFloatType{0} ]}])
outputs: {} [{boxes: [ CPUFloatType{0,4} ], labels: [ CPULongType{0} ], scores: [ CPUFloatType{0} ]}]
elem: {}
elem is generic dict: {}
Argument passed to at() was not in the map.
I'm struggling to find a way to extract the boxes, labels and scores from the dictionary
GenericDict.
This map is strange, I cannot iterate on it and I cannot access first and second types...
with it->first it->second
Any ideas ?
Thanks in advance
I think the following method can resolve the main problem here,
output = module.forward(inputs);
auto detections = output.toTuple()->elements().at(1).toList().get(0).toGenericDict();
std::cout << ">>> detections labels: " << detections.at("labels") << std::endl;
std::cout << ">>> detections boxes: " << detections.at("boxes") << std::endl;
std::cout << ">>> detections scores: " << detections.at("scores") << std::endl;
Besides, I've added an executable file https://github.com/zhiqwang/yolov5-rt-stack/tree/master/deployment/libtorch to show how libtorch works.
"A": "1"
"A.B": "2"
"A.C": "3"
How to get the value of A.B if i iterate through the ptree it works. if i try
to get value of pt.get_child("A\.B").get_value<std::string>(). i get the following exception
terminate called after throwing an instance of boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::property_tree::ptree_bad_path> >'
what(): No such node
please find the complete code below
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <iostream>
#include <string>
#include <iterator>
using boost::property_tree::ptree;
/* Indent Json Output */
std::string indent(int level) {
std::string s;
for (int i = 0; i < level; i++) s += " ";
return s;
}
/* Print tree in json format */
void printTree(ptree & pt, int level) {
if (pt.empty()) {
std::cerr << "\"" << pt.data() << "\"";
} else {
if (level) std::cerr << std::endl;
std::cerr << indent(level) << "{" << std::endl;
for (ptree::iterator pos = pt.begin(); pos != pt.end();) {
std::cerr << indent(level + 1) << "\"" << pos-> first << "\": ";
printTree(pos->second, level + 1);
++pos;
if (pos != pt.end()) {
std::cerr << ",";
}
std::cerr << std::endl;
}
std::cerr << indent(level) << " }";
}
return;
}
int main()
{
ptree pt;
read_ini("sample.ini", pt);
printTree(pt, 0);
std::cout << pt.get_child("A.B").get_value<std::string>() << std::endl; //tries to resolve A.B to two nodes
std::cout << pt.get_child("A\\.B").get_value<std::string>() << std::endl; //error
}
sample.ini
A=1
A.B=2
A.C=3
You can use alternative path delimiters, but it's a bit tricky and not very well documented.
You have to temporarily specify an alternative path separator:
Live On Coliru
#include <boost/property_tree/ini_parser.hpp>
#include <iostream>
using boost::property_tree::ptree;
int main() {
ptree pt;
pt.put("a.b", "first");
pt.put(ptree::path_type("a|complicated.name", '|'), "second");
write_ini(std::cout, pt);
}
Prints
[a]
b=first
complicated.name=second
I am sharing a boost::interprocess::vector across two processes, using a boost::interprocess::named_mutex and boost::interprocess::named_condition.
The reader begins first, obtaining the mutex and waiting for data to be written. The writer obtains the mutex, begins writing but it hangs on the line where it updates the shared vector.
If I run the program I get the following output:
Reader trying to get mutex
Reader waiting for data
Writer attempting to get mutex
Writer got mutex. Number of items to write: 2
Writing value: 1
The writer has two items to insert in the vector, but for some reason it stops after inserting the first and just hangs.
This is the code for the writer (full code further below):
void write(const std::vector<T>& items)
{
std::cout << "Writer attempting to get mutex" << std::endl;
scoped_lock<named_mutex> lock(*mutex);
{
std::cout << "Writer got mutex. Number of items to write: " << items.size() << std::endl;
for(const auto& item : items)
{
std::cout << "Writing value: " << item << std::endl;
vec->push_back(item); // <--------------------------- HANGS HERE -----
}
std::cout << "Writer notifying reader" << std::endl;
cond_empty->notify_all();
}
std::cout << "Writer finished" << std::endl;
}
This is the full code (should be able to copy, paste and run):
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
#include <string>
#include <cstdlib> //std::system
#include <iostream>
#include <memory>
using namespace boost::interprocess;
template<typename T>
struct MySharedData
{
using ShmemAllocator = allocator<T, managed_shared_memory::segment_manager>;
using MyVector = vector<T, ShmemAllocator>;
MySharedData(const bool isConsumer, const std::string& sharedMemoryName, const std::string& blockName, const int numBytes) : shared_memory_name(sharedMemoryName), block_name(blockName)
{
is_consumer = isConsumer;
segment.reset(new managed_shared_memory(open_or_create, sharedMemoryName.c_str(), numBytes));
const ShmemAllocator alloc_inst(segment->get_segment_manager());
vec = segment->find_or_construct<MyVector>(blockName.c_str())(alloc_inst);
cond_empty.reset(new named_condition(open_or_create, sharedMemoryName.c_str()));
mutex.reset(new named_mutex(open_or_create, sharedMemoryName.c_str()));
}
~MySharedData()
{
if(is_consumer)
{
segment->destroy<MyVector>(block_name.c_str());
}
}
void write(const std::vector<T>& items)
{
std::cout << "Writer attempting to get mutex" << std::endl;
scoped_lock<named_mutex> lock(*mutex);
{
std::cout << "Writer got mutex. Number of items to write: " << items.size() << std::endl;
for(const auto& item : items)
{
std::cout << "Writing value: " << item << std::endl;
vec->push_back(item); // <--------------------------- HANGS HERE -----
}
std::cout << "Writer notifying reader" << std::endl;
cond_empty->notify_all();
}
std::cout << "Writer finished" << std::endl;
}
std::vector<T> read()
{
std::vector<T> toReturn;
bool continue_trying = true;
while(continue_trying)
{
std::cout << "Reader trying to get mutex" << std::endl;
scoped_lock<named_mutex> lock(*mutex);
{
if(nullptr != vec )
{
if(vec->empty())
{
std::cout << "Reader waiting for data" << std::endl;
cond_empty->wait(lock);
std::cout << "Reader notified of data" << std::endl;
}
for(auto& t : *vec)
{
std::cout << "Reading: " << t << std::endl;
toReturn.push_back(t);
}
continue_trying = false;
}
else
{
std::cout << "No data to read from shared memory: " << shared_memory_name << " block: " << block_name << std::endl;
continue_trying = false;
}
}
}
std::cout << "Reader finished" << std::endl;
return toReturn;
}
std::unique_ptr<named_mutex> mutex{nullptr};
MyVector* vec{nullptr};
std::unique_ptr<managed_shared_memory> segment{nullptr};
std::unique_ptr<named_condition> cond_empty;
bool is_consumer{false};
std::string shared_memory_name;
std::string block_name;
};
void parent()
{
MySharedData<int> msd1(false, "a", "b", 100000);
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
msd1.write(vec);
}
void child()
{
MySharedData<int> msd2(true, "a", "b", 100000);
std::vector<int> x = msd2.read();
}
int main()
{
shared_memory_object::remove("a");
shared_memory_object::remove("b");
shared_memory_object::remove("c");
shared_memory_object::remove("d");
named_mutex::remove("a");
named_mutex::remove("b");
named_mutex::remove("c");
named_mutex::remove("d");
named_condition::remove("a");
named_condition::remove("b");
named_condition::remove("c");
named_condition::remove("d");
// The below code spawns the parent method off to a separate process
pid_t pid = fork();
if(pid == 0)
{
//child();
parent();
}
else if(pid > 0)
{
//parent();
child();
}
std::cout << "FINISHED" << std::endl;
}