std::map<string, int> MapStringToInt; MapStringToInt[ "one" ] = 1; MapStringToInt[ "two" ] = 2; MapStringToInt[ "three" ] = 3; int value = MapStringToInt[ "one" ]; assert( value == 1 );
std::map<string, int> MapStringToInt; for(std::map<string, int>::const_iterator it = MapStringToInt.begin(); it != MapStringToInt.end(); it++) { const string&text = it->first; int value = it->second; //... }
typedef std::map<string, int> MapStringToInt_t; MapStringToInt_t MapStringToInt; for(MapStringToInt_t::const_iterator it = MapStringToInt.begin(); it != MapStringToInt.end(); it++) { ... }
MapStringToInt_t MapStringToInt; MapStringToInt_t::const_iterator it = MapStringToInt.find("four"); if (it == MapStringToInt.end() ) { puts(" element not found "); }
For stored objects that are pointers, we may however return an null pointer. STL does not support this, but in VISH we are using a convention that does. For readonly access we overload the () operator, and derive out own class that implements this feature. In particular, reference counted objects (see Reference Pointers ) are used frequently as mapped objects, so we may return a NullPtr() when objects are not found.
struct MapStringToValuePtr : map<string, RefPtr<Value> > { RefPtr<Value> operator()(const string&s) const { const_iterator it = find(s); if (it == end() ) return NullPtr() return it->second; } };
MapStringToValuePtr myMap; myMap[ "one" ] = new Value(1); myMap[ "two" ] = new Value(2); myMap[ "three" ] = new Value(3); if (RefPtr<Value> Four = myMap("four") ) { //... yes, entry "four" was found ... }
The recommended solution is to provide methods to wrap the required functionality of the STL object.
Therefore we need to hide the maps, and iterators, within one compilation unit (i.e. a shared library). It is fine to have maps in a header file, but they must not be accessed from the outside. An object's header file .hpp with a class definition (including the Windows API statement) therefore looks like this:
class MY_API MapStringToValuePtr { typedef map<string, RefPtr<Value> > MapStringToValuePtr_t; MapStringToValuePtr_t myMap; public: ~MapStringToValuePtr(); RefPtr<Value> operator[](const string&s); RefPtr<Value> operator()(const string&s) const; };
MapStringToValuePtr::~MapStringToValuePtr() {} RefPtr<Value> MapStringToValuePtr::operator[](const string&s) { return myMap[ s ]; } RefPtr<Value> MapStringToValuePtr::operator()(const string&s) const { MapStringToValuePtr_t::const_iterator it = find(s); if (it == end() ) return NullPtr() return it->second; }
The iteration over all elements of a map (or general STL container) also needs to be capsuled, which is done by introducing abstract iterator objects in the class:
class MY_API MapStringToValuePtr { typedef map<string, RefPtr<Value> > MapStringToValuePtr_t; MapStringToValuePtr_t myMap; public: ~MapStringToValuePtr(); struct iterator { virtual ~iterator() = 0; bool apply(const string&key, const RefPtr<Value>&value) = 0; }; int iterate(iterator&it); };
int MapStringToValuePtr::iterate(iterator&IteratorObject) { int Count = 0; for(MapStringToValuePtr_t::iterator it = myMap.begin(); it != myMap.end(); it++) { if (!IteratorObject.apply( it->first, it->second) ) break; Count++; } return Count; }
Upon usage, the user needs to define a class to be derived for iteration, with the abstract member function apply() to be overloaded. Such a class may well be defined just locally within a function, a not very much known C++ feature:
void myfunction(MapStringToValuePtr&MyMap) { struct It : MapStringToValuePtr::iterator { bool apply(const string&key, const RefPtr<Value>&value) { //... do something with key and value ... return true; } }; It MyLocalIterator; MyMap.iterate( MyLocalIterator ); }
Note that additional arguments can be passed to the iterator object as data members:
void myfunction(MapStringToValuePtr&MyMap, int param) { struct It : MapStringToValuePtr::iterator { int param; bool apply(const string&key, const RefPtr<Value>&value) { //... do something with param, key and value ... return true; } }; It MyLocalIterator; MyLocalIterator.param = param; MyMap.iterate( MyLocalIterator ); }
string myfunction(MapStringToValuePtr&MyMap, int param) { struct It : MapStringToValuePtr::iterator { int param; string output; bool apply(const string&key, const RefPtr<Value>&value) { // //... do something with param, key and value ... // like concatenating all keys that have a value // if (value) output += key; return true; } }; It MyLocalIterator; MyLocalIterator.param = param; MyMap.iterate( MyLocalIterator ); return MyLocalIterator.output; }