Unable to clone a JSON Array properly using C++ Poco library - c++

I would like to clone json objects.
In order to do the job, I've developped two functions. One for objects and one for arrays.
The method that's clone JSON::Object::Ptr works well.
Here is the code
Poco::JSON::Object::Ptr CJsonHelper::cloneJson(Poco::JSON::Object::Ptr obj)
{
Poco::JSON::Object::Iterator it;
Poco::JSON::Object::Ptr ptr = new Poco::JSON::Object;
// loop and copy
for(it = obj->begin(); it != obj->end(); it++)
ptr->set(it->first, it->second);
return ptr;
}
The method that's clone JSON::Array::Ptr works but when I stringify the object that's contains the array, I got following error :
Can not convert to std::string
Here is the code of the function to clone array that's doesn't work
Poco::JSON::Array::Ptr CJsonHelper::cloneJson(Poco::JSON::Array::Ptr obj)
{
Poco::JSON::Array::Ptr copy = new Poco::JSON::Array;
// loop and copy
for (auto item = obj->begin(); item != obj->end(); ++item)
{
copy->add(item);
}
return copy;
}
The object pass to function is previsoulsy parsed from faile and is valid
{
"items" : [
{
"name" : "object0",
"position" : {
"x" : "700.0",
"y" : "0.0",
"z" : "250.0"
}
}
]
}
In the clonse method if I replace the
copy->add(item);
by
copy->add(item->extract<Poco::JSON::Object::Ptr>());
it's working well but only in this case, I need it to be generic.
I'm sure I've missed something that I don't found because it is working well in clone object method.

I've finally found my mistake !
I've missed a * to go through the auto iterator
copy->add(item);
becomes
copy->add(*item);
I post the updated function if it can help someone
Poco::JSON::Array::Ptr CJsonHelper::cloneJson(Poco::JSON::Array::Ptr obj)
{
Poco::JSON::Array::Ptr copy = new Poco::JSON::Array;
// loop and copy
for (auto item = obj->begin(); item != obj->end(); ++item)
{
copy->add(*item);
}
return copy;
}

Related

Error: no matching function for call to 'std::vector<Movie>::erase(size_t&)'

I am currently learning C++ / making a simple movie database. I use classes and I have a method Delete Movie. Unfortunately, when I try to delete object Movie from a vector database, there's this error.
for (size_t num {}; num < database.size(); ++num)
if ((database.at(num)).getname() == name) {
database.erase(num); // <--- error here
return true;
}
Can someone hopefully tell me, what am I making wrong?
If you need more information, I can send the whole file.
erase accepts iterator as said pptaszni
Replace your for code by this:
auto it = std::remove_if(database.begin(), database.end(), [&name](const Movie& item) -> bool { return item.getname() == name; });
database.erase(it, database.end());
Or change just 1 line (database.erase(num)) like this:
database.erase(database.begin() + num);

I can get objects from a list and copy them, but how do I delete the objects I copied?

I'm trying to find all the processes in the blockedProcess list with the specified event number, copy them into a transferList, and then remove them. Copying and moving the Process objects works fine, but I can't figure out how to remove those Process objects from blockedProcess afterwards.
ProcessQueue findEventFlag(int eventnum)
{
ProcessQueue transferProcess;
Process process;
list<Process>::iterator it;
for (it = blockedProcess.begin(); it != blockedProcess.end(); it++)
{
process = *it;
if (process.getEvent() == eventnum)
{
process.setState("READY");
process.setEvent(-1);
transferProcess.enqueue(process);
}
}
return transferProcess;
}
Building on the comments, try this (which relies on the fact that std::list::erase conveniently returns an iterator to the next item in the list):
ProcessQueue findEventFlag(int eventnum)
{
ProcessQueue transferProcess;
Process process;
list<Process>::iterator it = blockedProcess.begin();
while (it != blockedProcess.end())
{
process = *it;
if (process.getEvent() == eventnum)
{
process.setState("READY");
process.setEvent(-1);
transferProcess.enqueue(process);
it = process.Erase (it);
}
else
it++;
}
return transferProcess;
}
You can also transfer an element from one list to another with std::list::splice which would avoid copying your process object and might therefore be more efficient, something like:
ProcessQueue findEventFlag(int eventnum)
{
ProcessQueue transferProcess;
Process process;
list<Process>::iterator it = blockedProcess.begin();
while (it != blockedProcess.end())
{
process = *it;
list<Process>::iterator next = std::next (it);
if (process.getEvent() == eventnum)
{
process.setState("READY");
process.setEvent(-1);
transferProcess.splice(transferProcess.begin (), blockedProcess, it);
}
it = next;
}
return transferProcess;
}

Iterate through a vector of objects and find a variable that matches one pulled from a text file

So I have a vector of objects
vector<Module*> moduleVector;
and I need to iterate through it and compare an attribute from the object to another attribute I'm pulling from a text file
I'm using an ifstream and getLine() to store the element that needs to be compared to the object's attribute (fileD is the opened file, markModId is the string variable)
getline(fileD, markModId, ' ');
But I am unsure of how I can refer to the object's attributes in an iterator. So my question is,
how do I compare the attribute from the file to the object using an iterator?
For reference here is my object constructor (id is the attribute I want to compare)
Module::Module(string id, string title, string lecturer, int
courseworkWeight)
{
code = id;
name = title;
lect = lecturer;
cwWeight = courseworkWeight;
exMark = 0; //ex mark initialised as 0
/*
Map to store coursework marks
*/
map<string, float> CWmarks;
//cwMarks.clear(); //cw marks map cleared
//create a map that stores
}
And exMark is the attribute that needs to be added to the object. All attributes in the Module constructor are private.
How do I compare the attribute from the file to the object using an
iterator?
Short answer: Suppose you have an iterator std::vector<Module*>::iterator iter you can access the public members of Module class like:
(*iter)->/*public member*/;
Long answer: First of all, you need a getter for private member id and one setter for exMark, by which you can get the id of each Module and compare to the id from the file and then set its exMark to some value.
std::string getId()const { return code; }
void setExMark(const double newMark) { exMark = newMark; }
If you want to change the first true instance of Module, you can use std::find_if for finding the Module:
std::string idFromFile = "two";
auto Condition = [&idFromFile](Module* element){ return element->getId() == idFromFile; };
auto iter = std::find_if(moduleVector.begin(), moduleVector.end(), Condition);
if(iter != moduleVector.end())
(*iter)->setExMark(10.0); // see this
// ^^^^^^^^^
See a sample code here
For multiple instances you can do:
for(auto iter = moduleVector.begin(); iter != moduleVector.end(); ++iter)
if ( (*iter)->getId() == idFromFile)
(*iter)->setExMark(10.0);
Note: In modern C++ you can use smart pointers, instead of raw pointers, which will delete the objects automatically as it goes out of scope.
Simply dereference the iterator to access its Module* pointer, then you can access the object using operator-> however you want, eg:
for (std::vector<Module*>::iterator iter = moduleVector.begin(), end = moduleVector.end(); iter != end; ++iter)
{
Module *m = *iter;
if (m->code == markModId)
m->exMark = ...;
}
Or, if you are using C++11 or later, let the compiler handle the iterator for you:
for (Module *m : moduleVector)
{
if (m->code == markModId)
m->exMark = ...;
}
Or, use a lambda with one of the standard iteration algorithms, eg:
std::for_each(moduleVector.begin(), moduleVector.end(),
[&](Module *m)
{
if (m->code == markModId)
m->exMark = ...;
}
);
If you are only interested in updating 1 Module, then break the loop when the the desired Module is found:
for (std::vector<Module*>::iterator iter = moduleVector.begin(), end = moduleVector.end(); iter != end; ++iter)
{
Module *m = *iter;
if (m->code == markModId)
{
m->exMark = ...;
break; // <-- add this
}
}
for (Module *m : moduleVector)
{
if (m->code == markModId)
{
m->exMark = ...;
break; // <-- add this
}
}
auto iter = std::find_if(moduleVector.begin(), moduleVector.end(),
[&](Module *m) { return (m->code == markModId); });
if (iter != moduleVector.end())
{
Module *m = *iter;
m->exMark = ...;
}

Recursive insert of a chain into memory fails

This meight be a long question but i hope someone can help me figuring out whats going wrong.
I am inserting a JSON Object into already allocated Memory with my own Datatype which basically holds a Union with Data and a ptrdiff_t to the next Datatype in 8bit steps.
template <typename T>
class BaseType
{
public:
BaseType();
explicit BaseType(T& t);
explicit BaseType(const T& t);
~BaseType();
inline void setNext(const ptrdiff_t& next);
inline std::ptrdiff_t getNext();
inline void setData(T& t);
inline void setData(const T& t);
inline T getData() const;
protected:
union DataUnion
{
T data;
::std::ptrdiff_t size;
DataUnion()
{
memset(this, 0, sizeof(DataUnion));
} //init with 0
explicit DataUnion(T& t);
explicit DataUnion(const T& t);
} m_data;
long long m_next;
};
The implementation is streight so nothing special happes there just setting/getting the values of the definition. (i'll skip the impl. here)
So here starts the code where something goes wrong:
std::pair<void*, void*> Page::insertObject(const rapidjson::GenericValue<rapidjson::UTF8<>>& value,
BaseType<size_t>* last)
{
//return ptr to the first element
void* l_ret = nullptr;
//prev element ptr
BaseType<size_t>* l_prev = last;
//position pointer
void* l_pos = nullptr;
//get the members
for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it)
{
switch (it->value.GetType())
{
case rapidjson::kNullType:
LOG_WARN << "null type: " << it->name.GetString();
continue;
case rapidjson::kFalseType:
case rapidjson::kTrueType:
{
l_pos = find(sizeof(BaseType<bool>));
void* l_new = new (l_pos) BaseType<bool>(it->value.GetBool());
if (l_prev != nullptr)
l_prev->setNext(dist(l_prev, l_new));
}
break;
case rapidjson::kObjectType:
{
//pos for the obj id
//and insert the ID of the obj
l_pos = find(sizeof(BaseType<size_t>));
std::string name = it->name.GetString();
void* l_new = new (l_pos) BaseType<size_t>(common::FNVHash()(name));
if (l_prev != nullptr)
l_prev->setNext(dist(l_prev, l_new));
//TODO something strange happens here!
// pass the objid Object to the insertobj!
// now recursive insert the obj
// the second contains the last element inserted
// l_pos current contains the last inserted element and get set to the
// last element of the obj we insert
l_pos = (insertObject(it->value, reinterpret_cast<BaseType<size_t>*>(l_new)).second);
}
break;
case rapidjson::kArrayType:
{//skip this at the moment till the bug is fixed
}
break;
case rapidjson::kStringType:
{
// find pos where the string fits
// somehow we get here sometimes and it does not fit!
// which cant be since we lock the whole page
l_pos = find(sizeof(StringType) + strlen(it->value.GetString()));
//add the String Type at the pos of the FreeType
auto* l_new = new (l_pos) StringType(it->value.GetString());
if (l_prev != nullptr)
l_prev->setNext(dist(l_prev, l_new));
}
break;
case rapidjson::kNumberType:
{
//doesnt matter since long long and double are equal on x64
//find pos where the string fits
l_pos = find(sizeof(BaseType<long long>));
void* l_new;
if (it->value.IsInt())
{
//insert INT
l_new = new (l_pos) BaseType<long long>(it->value.GetInt64());
}
else
{
//INSERT DOUBLE
l_new = new (l_pos) BaseType<double>(it->value.GetDouble());
}
if (l_prev != nullptr)
l_prev->setNext(dist(l_prev, l_new));
}
break;
default:
LOG_WARN << "Unknown member Type: " << it->name.GetString() << ":" << it->value.GetType();
continue;
}
//so first element is set now, store it to return it.
if(l_ret == nullptr)
{
l_ret = l_pos;
}
//prev is the l_pos now so cast it to this;
l_prev = reinterpret_cast<BaseType<size_t>*>(l_pos);
}
//if we get here its in!
return{ l_ret, l_pos };
}
I am starting to insert like this:
auto firstElementPos = insertObject(value.MemberBegin()->value, nullptr).first;
While value.MemberBegin()->value is Object to be inserted and ->name holds the Name of the object. In the case below its Person and everything between {}.
The problem is, if i insert a JSON Object which has one Object inside like so:
"Person":
{
"age":25,
"double": 23.23,
"boolean": true,
"double2": 23.23,
"firstInnerObj":{
"innerDoub": 12.12
}
}
It works properly and i can reproduce the Object. But if i have more inner objects like so:
"Person":
{
"age":25,
"double": 23.23,
"boolean": true,
"double2": 23.23,
"firstInnerObj":{
"innerDoub": 12.12
},
"secondInnerObj":{
"secInnerDoub": 12.12
}
}
It fails and i lose data so i think that my recursion goes wrong but i dont see why. If you need any more informations let me know. Meight take a look here and the client here.
The test.json need to contain a json object like above. And the find only need to contain {"oid__":2} to get the second object that was inserted.
I could track the issue down to the Point where i recreate the Object recursively in the code. Some of the Nextpointers seem to be incorrect:
void* Page::buildObject(const size_t& hash, void* start, rapidjson::Value& l_obj,
rapidjson::MemoryPoolAllocator<>& aloc)
{
//get the meta information of the object type
//to build it
auto& l_metaIdx = meta::MetaIndex::getInstance();
//get the meta dataset
auto& l_meta = l_metaIdx[hash];
//now we are already in an object here with l_obj!
auto l_ptr = start;
for (auto it = l_meta->begin(); it != l_meta->end(); ++it)
{
//create the name value
rapidjson::Value l_name(it->name.c_str(), it->name.length(), aloc);
//create the value we are going to add
rapidjson::Value l_value;
//now start building it up again
switch (it->type)
{
case meta::OBJECT:
{
auto l_data = static_cast<BaseType<size_t>*>(l_ptr);
//get the hash to optain the metadata
auto l_hash = l_data->getData();
//set to object and create the inner object
l_value.SetObject();
//get the start pointer which is the "next" element
//and call recursive
l_ptr = static_cast<BaseType<size_t>*>(buildObject(l_hash,
(reinterpret_cast<char*>(l_data) + l_data->getNext()), l_value, aloc));
}
break;
case meta::ARRAY:
{
l_value.SetArray();
auto l_data = static_cast<ArrayType*>(l_ptr);
//get the hash to optain the metadata
auto l_size = l_data->size();
l_ptr = buildArray(l_size, static_cast<char*>(l_ptr) + l_data->getNext(), l_value, aloc);
}
break;
case meta::INT:
{
//create the data
auto l_data = static_cast<BaseType<long long>*>(l_ptr);
//with length attribute it's faster ;)
l_value = l_data->getData();
}
break;
case meta::DOUBLE:
{
//create the data
auto l_data = static_cast<BaseType<double>*>(l_ptr);
//with length attribute it's faster ;)
l_value = l_data->getData();
}
break;
case meta::STRING:
{
//create the data
auto l_data = static_cast<StringType*>(l_ptr);
//with length attribute it's faster
l_value.SetString(l_data->getString()->c_str(), l_data->getString()->length(), aloc);
}
break;
case meta::BOOL:
{
//create the data
auto l_data = static_cast<BaseType<bool>*>(l_ptr);
l_value = l_data->getData();
}
break;
default:
break;
}
l_obj.AddMember(l_name, l_value, aloc);
//update the lptr
l_ptr = static_cast<char*>(l_ptr) + static_cast<BaseType<size_t>*>(l_ptr)->getNext();
}
//return the l_ptr which current shows to the next lement. //see line above
return l_ptr;
}
After houers and houres of debugging i found the small issue which causes this. The method which builds up the Object after it was inserted returns a pointer to the actuall last element->next which was inserted and after the switch case i did call the ->next again which causes a loss of data because it scipped one element in the single chained list.
The Fix to this is to put the line
l_ptr = static_cast<char*>(l_ptr) + static_cast<BaseType<size_t>*>(l_ptr)->getNext();
Only into the switch cases where it is not an Object or Array. Fix Commit This actually also gave me the fix for an Issue with inserting Array.
Of cause the real issue could not know someone here who did not took a deep look into the code but i still want to show the fix here. Thanks to #sehe who helped alot with figuring out whats going wrong here.

GOF Composite Design Pattern CompositeObject::Remove Recursive Implementation in C++

This is the part of question from my question asked in codereview website:
GOF Composite Design Pattern Implementation Using Modern C++
The post has complete information/implementation about it but here I am posting this question to understand about the following information:
How to implement CompositeEquipment::Remove?.
Based on my understanding, it should do recursive search in all composite object in which client has invoked and recursively all its child objects which can also be of composite type. Just to illustrate from above implementation, if client write the as cabinet->Remove(bus); it would not remove bus object as it is the child of chassis object. This seems to be incorrect to me. However I am not able to implement the CompositeEquipment::Remove in such a way that it searches recursively if child objects themselves are of composite.
So far I have came of with the following implementation which just searches the composite objects which client has involved for Remove method.
//To find out whether items are in the composite objects
class Name_Equal {
private:
Equipment::EquipmentSmartPtr val;
public:
Name_Equal(const Equipment::EquipmentSmartPtr& v) :val(v) { }
bool operator()(const Equipment::EquipmentSmartPtr& x) const {
return (x->Name() == val->Name());
}
};
void CompositeEquipment::Remove(EquipmentSmartPtr entry) {
find_equipment(_equipment, entry);
}
void CompositeEquipment::find_equipment(std::vector<EquipmentSmartPtr>& vec,
EquipmentSmartPtr& entry){
Name_Equal eq(entry);
auto itrpos = std::find_if(std::begin(vec), std::end(vec), eq);
if (itrpos != std::end(vec)) {
vec.erase(itrpos);
}
}
Kindly let me know in case any additional information or complete code needs to post here as well.
There are two options:
Provide a virtual function Remove in the base class and make it a noop implementation. Then add a few more lines to CompositeEquipment::find_equipment.
void CompositeEquipment::find_equipment(std::vector<EquipmentSmartPtr>& vec,
EquipmentSmartPtr& entry){
Name_Equal eq(entry);
auto itrpos = std::find_if(std::begin(vec), std::end(vec), eq);
if (itrpos != std::end(vec)) {
vec.erase(itrpos);
} else {
for ( EquipmentSmartPtr sptr : vec )
{
sptr->Remove(entry);
}
}
}
Use dynamic_cast to determine whether an item of the composite is a composite also. If so, call Remove on it. I prefer this option.
void CompositeEquipment::find_equipment(std::vector<EquipmentSmartPtr>& vec,
EquipmentSmartPtr& entry){
Name_Equal eq(entry);
auto itrpos = std::find_if(std::begin(vec), std::end(vec), eq);
if (itrpos != std::end(vec)) {
vec.erase(itrpos);
} else {
for ( EquipmentSmartPtr sptr : vec )
{
Equipment* ptr = dynamic_cast<Equipment*>(sptr.get());
if ( ptr )
{
ptr->Remove(entry);
}
}
}
}
A bit about names... find_equipment seems a strange name for the function. I would put the whole thing in Remove.
void CompositeEquipment::Remove(EquipmentSmartPtr& entry){
std::vector<EquipmentSmartPtr>& vec = _equipment;
Name_Equal eq(entry);
auto itrpos = std::find_if(std::begin(vec), std::end(vec), eq);
if (itrpos != std::end(vec)) {
vec.erase(itrpos);
} else {
for ( EquipmentSmartPtr sptr : vec )
{
Equipment* ptr = dynamic_cast<Equipment*>(sptr.get());
if ( ptr )
{
ptr->Remove(entry);
}
}
}
}