accessing value in map of maps - c++

typedef std::vector<UCHAR> RESPONSE_BUFFER;
typedef TimedHashMap<int, RESPONSE_BUFFER*> TimeResponseHashMap;
Inner map prototype has "integer" as key and "pointer to a vector of chars" as mapped value.
TimeResponseHashMap* inner_pending_response_map;
Outer map is a map of maps. it has "integer" as key and "pointer to inner map" as mapped value.
std::map<int, TimeResponseHashMap* > outer_pending_response_map;
I insert like this:
Inner map is a userdefined map, hence it has a different format.
inner_pending_response_map->Insert((int)s16MessageID, &resp_buffer, expirytime);
outer_pending_response_map.insert(make_pair((int)s16SessionID,
inner_pending_response_map));
TimeResponseHashMap provides the user defined interface "Find" to access members of the map.
template <typename Key, typename ElementObject>
THM_ERROR TimedHashMap<Key, ElementObject>::Find(const Key& k, ElementObject& e)
{
typename hash_map<Key, BaseElement_*, dw_hash<Key>, dw_equal_to<Key> >::iterator itr;
try
{
itr = h_->find(k);
} catch ( ... )
{
return E_INTERNAL_ERROR;
}
if ( itr == h_->end() )
{
e = NULL;
return E_ITEM_NOT_FOUND;
}
e = itr->second->e_;
return E_SUCCESS;
}
I have both the keys and now I need to access the "mapped value" of the inner map. The inner map uses the above Find() function to search. I need to pass RESPONSE_BUFFER variable as the second parameter to the Find() function.
I'm trying to extract like this which gives a wrong output:
RESPONSE_BUFFER resp_buffer;
ExtractFragmentResponse(u16Key1, u16Key2, &resp_buffer);
Definition of ExtractFragmentResponse is below:
STATUS
C_THREAD::ExtractFragmentResponse(USHORT u16SessionID, USHORT u16MessageID,
RESPONSE_BUFFER* resp)
{
(((outer_pending_response_map.find(u16SessionID))->second)->Find((int)u16MessageID, resp))
}
resp is not giving me correct data.
How can it be done?

This may not directly answer the question, but it does bring up why the code used is highly faulty and should be broken up into several lines.
STATUS
C_THREAD::ExtractFragmentResponse(USHORT u16SessionID, USHORT u16MessageID,
RESPONSE_BUFFER* resp)
{
(((outer_pending_response_map.find(u16SessionID))->second)->Find((int)u16MessageID, resp))
}
Let's say this did actually "work". There is a major problem with it, regardless. The issue is this:
outer_pending_response_map.find(u16SessionID)
What happens if find doesn't find the entry u16SessionID? You now have been returned outer_pending_response_map.end(). When this return value is used like this:
outer_pending_response_map.end()->second
boom, your dead. That line attempts to use an invalid iterator, which is undefined behavior.
What you should do is this:
std::map<int, TimeResponseHashMap* >::iterator it1 = outer_pending_response_map.find(u16SessionID);
if ( it1 != outer_pending_response_map.end())
(it1->second)->Find((int)u16MessageID, resp);
else
{
// you fill in what happens if the find fails
}
To debug your issue, you can then further break up the lines to ensure what you're getting is valid:
std::map<int, TimeResponseHashMap* >::iterator it1 = outer_pending_response_map.find(u16SessionID);
if ( it1 != outer_pending_response_map.end())
{
TimeResponseHashMap *theMap = it1->second;
theMap->Find((int)u16MessageID, resp);
}
else
{
// you fill in what happens if the find fails
}
The code above saves it1->second to a value (theMap) that you can inspect easily to see if it is correct.

Related

STL map.find returns all the elements

Having a problem with undefined behaviour of STL map defined as follows:
typedef bool (*SNAPSHOT_CALLBACK)(/*Some params here..*/);
typedef std::map<DWORD, SNAPSHOT_CALLBACK> SnapshotsMap;
SnapshotsMap m_mapCallbacks;
insertion:
AddCallback(DWORD snapshotType, SNAPSHOT_CALLBACK callback)
m_mapCallbacks.insert(std::pair<DWORD, SNAPSHOT_CALLBACK>(snapshotType, callback));
and query:
for (auto itr = m_mapCallbacks.find(cpyHeader->hdr); itr != m_mapCallbacks.end(); itr++)
{
itr->second();
}
The problem that I'm having is on a single key search the iterator retrieves both keys that I have inserted.
My logs:
Insert:
Added callback type: 21000b Callback: 615F5AE0
Added callback type: 210136 Callback: 615F5480
Query:
Same iterator loop:
Key to find: 21000b -> FOUND First: 21000b Second: 61da5ae0
Key to find: 21000b -> FOUND First: 210136 Second: 61da5480
for some reason both elements get retrieved and there's no other modifications/thread on this map.
Some help would be much appreciated :)
Query should be
// C++17 if construct
if (auto itr = m_mapCallbacks.find(cpyHeader->hdr); itr != m_mapCallbacks.end())
{
itr->second();
}
or
// pre-C++17 (but C++11 for auto)
auto itr = m_mapCallbacks.find(cpyHeader->hdr);
if (itr != m_mapCallbacks.end())
{
itr->second();
}
Your for iterates from found key until the end (so only (potentially) skips first elements)

check map keys are in set using std::equal or std::all_of

I'm new to C++ and predicates but I'm running into a problem. I'm trying to check if all keys in an unordered_map exist in a set or even keys in another map with different value type for that matter.
Essentially, [key in set_ for key in map_.keys()] OR [key in map2_ for key in map1_.keys()] in python.
one approach is the following:
for( auto itr = map_.begin(); itr != map_.end(); ++itr ) {
if( set_.find( itr->first ) == set_.end() ) return false;
}
But I want to use std::all_of or std::equal to achieve the same. Here's what I have so far:
some_function() {
//set_ and map_ in scope
areEqual = std::equal( map_.begin(), map_.end(), set_,
[]( auto itr ){ return set_.find( itr->first ) != set_.end(); } );
}
compiler complains that set_ is out of scope in return set_.find(...)...
I also tried
class checker {
public:
bool operator()( map_itr itr )
{ return set_.find( itr->first ) != set_.end(); }
};
but ran into the same problem.
Any help or pointers is greatly appreciated :)
Lambdas can't access variables declared in its scope by default. In order to access your set_ variable from the lambda function, you should capture it in the lambda function.
The capture list is defined between the [] characters at the beginning of the lambda function.
In this case, I would use [&] which captures all objects from the scope by reference, including your set_ variable.
some_function() {
areEqual = std::equal( map_.begin(), map_.end(), set_,
[&]( auto itr ){ return set_.find( itr->first ) != set_.end(); } );
}
You should read the Lambda expressions page on cppreference for further information.

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 = ...;
}

rapidjson - recursively change key value with nested field

I have a Json record with nested object and object arrays, the keys in those field contain spaces, I want to change all spaces to _, so I have to iterate all keys in the json object.
My idea is to write a depth first search to iterate all nested keys using ConstMemberIterator, my question is how can I change the key by given its iterator?
The example below represents my idea:
void DFSReplaceSpaceInKeys(Value::ConstMemberIterator& itr) {
// Replace space in nested key
std::string s(itr->name.GetString());
std::replace(s.begin(), s.end(), ' ', '_');
// set new string to key
itr->name.SetString(s, ?.GetAllocator()); // <----- How can I get the document allocator?
std::cout << "new key: " << itr->name.GetString() << std::endl;
// recursive call in DFS
if (itr->value.GetType() == Type::kObjectType) {
DFSReplaceSpaceInKeys(itr->value.GetObject().MemberBegin());
}
}
A Json record example:
{
"a": {"b": [{"c": [...]}, {...}]
}
You can pass an allocator as parameter. I also think you should better pass Value& to represent a node.
void DFSReplaceSpaceInKeys(Value& value, Value::AllocatorType& allocator) {
if (value.IsObject()) {
for (Value::ConstMemberIterator itr = value.MemberBegin(); itr != MemberEnd(); ++itr)
{
// Modify itr->name here...
DFSReplaceSpaceInKeys(itr->value, allocator);
}
}
else if (value.IsArray()) {
for (Value::ConstIterator itr = value.Begin(); itr != value.End(); ++itr)
DFSReplaceSpaceInKeys(*itr, allocator);
}
}
// ...
Document d;
DFSReplaceSpaceInKeys(d, d.GetAllocator());
If you only need to do the task as mentioned, you may just use the SAX API, which can be easier and faster. Check capitalize example.
rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
auto news_obj= news_info["news_feature"].GetObject();
auto title_keyword = news_obj.FindMember ("title_keyword");
if (title_keyword != news_obj.MemberEnd()) {
title_keyword->name.SetString ("title_keywords", allocator);
}

Cocos2D X: How to check if a key exists for a plist file?

I am using the following code to read data from plist for my game:
int levelNum = SOME_VALUE_FROM_OUTSIDE;
ValueMap mapFile = FileUtils::getInstance()->getValueMapFromFile("LevelDetails.plist");
std::string strLevel = std::to_string(levelNum);
ValueMap mapLevel = mapFile.at(strLevel).asValueMap();
LevelDetails.plist is a plist with dictionary as root. The problem is there can be occasions where there is no key named levelNum / strLevel. So I have to check if the key exists before I run this line:
ValueMap mapLevel = mapFile.at(strLevel).asValueMap(); //Throws exception occasionally
So what is the proper way to check if a key named levelNum / strLevel exists or not?
Because ValueMap is a std::unordered_map, you can use the methods from that class:
if (mapFile.count(strLevel).count() > 0) {
ValueMap mapLevel = mapFile.at(strLevel).asValueMap();
}
Declaration of ValueMap in cocos2d-x is:
typedef std::unordered_map<std::string, Value> ValueMap;
You could also use the find method which will return an iterator to the key-element pair or a past-the-end iterator if the key isn't found.
auto it = mapFile.find(strLevel);
if (it != mapFile.end()) {
it->first; //key
it->second; //element
}
else {
//key not found
}
I came across this question for a similar reason and think I have found an appropriate solution, using cocos2d-x-3.11.1 (should also be applicable for older versions).
if( mapFile.at(strLevel).getType() != Value::Type::NONE ){
//OR if( mapFile[strLevel].getType() != Value::Type::NONE ) {
//if reached here then the 'key exists', thus perform desired line.
ValueMap mapLevel = mapFile.at(strLevel).asValueMap();
}
You could also check against a specific type defined in "CCValue.h" such as:
Value::Type::MAP
What we use is this:
string fullPath = cocos2d::FileUtils::getInstance()->fullPathForFilename("file.plist");
auto dataFromPlist = cocos2d::FileUtils::getInstance()->getValueMapFromFile(fullPath);
if (!dataFromPlist["key1"].isNull())
{
auto map = dataFromPlist["key1"].asValueMap();
//Do something else
}