Hey guys,

With this defintion:

sss.hpp

#include <fstream>
#include <string>
#include <map>

namespace sss {

    using namespace std;

    class node {
    public:
        multimap<string, string>  values;
        multimap<string, node>    children;

        string &value(const string name, int index = 0);
        node &child(const string name, int index = 0);
        //...
    };

    typedef pair<string, string> value;
    typedef pair<string, node>   child;

    typedef multimap<string, string>::iterator valueiterator;
    typedef multimap<string, node>::iterator   childiterator;
}

and this implementation:

sss.cpp

#include <iostream>
#include <fstream>
#include <map>
#include <string>

#include "sss.hpp"

using namespace std;
using sss::node;
using sss::valueiterator;
using sss::childiterator;

string& node::value(const string name,int index) {
    valueiterator it = values.find(name);
    try {
        int i;
        if (it == values.end()) throw 0;
        for (i = 0; i<index; i++) {
            it++;
            if (it == values.end()) throw 0;
        }
    } catch (int e) {
        it = values.insert(sss::value(name,string()));
    }
    return it->second;
}

node& node::child(const string name,int index) {
    childiterator it = children.find(name);
    try {
        int i;
        if (it == children.end()) throw 0;
        for (i = 0; i<index; i++) {
            it++;
            if (it == children.end()) throw 0;
        }
    } catch (int e) {
        it = children.insert(sss::child(name, node()));
    }
    return it->second;
}

How would I merge these two functions? They have so much it common! It seemed redundant... Is there a way with templates and/or with a function that has the shared code?

Thanks in advance,

Sorry for those semi-gotos. Here are equivalent function without lazy-programmerness.

string& node::value(const string name, int index) {
    using sss::value;

    valueiterator it = values.find(name);
    if (it == values.end()) {
        it = values.insert(value(name,string()));
        return it->second;
    }


    for (int i = 0; i < index; i++) {
        it++;
        if (it == values.end()) {
            it = values.insert(value(name,string()));
            return it->second;
        }
    }

    return it->second;
}


node& node::child(const string name, int index) {
    using sss::child;

    childiterator it = children.find(name);
    if (it == children.end()) {
        it = children.insert(child(name, node()));
        return it->second;
    }

    for (int i = 0; i < index; i++) {
        it++;
        if (it == children.end()) {
            it = children.insert(child(name, node()));
            return it->second;
        }
    }

    return it->second;
}

PS:
In C I'd do something like this:

#define nodeOrValue(returnType, type, plural, myIterator, insertType)\
returnType node::type(const string name, int index) {\
using sss::type;\
myIterator it = plural.find(name);\
    if (it == plural.end()) {\
        it = plural.insert(type(name, insertType()));\
        return it->second;\
    }\
    for (int i = 0; i < index; i++) {\
        it++;\
        if (it == plural.end()) {\
            it = plural.insert(type(name, insertType()));\
            return it->second;\
        }\
    }\
    return it->second;\
}

nodeOrValue(string&, value, values, valueiterator, string);
nodeOrValue(node&, child, children, childiterator, node);

So, considering this is (SPARTA!) C++, how should I do it? ;)

This compiles, but there's got to be a better way. It's probably not generally worth it in this case.

#include <fstream>
#include <string>
#include <map>

namespace sss {

    using namespace std;

    class node {
    public:
        multimap<string, string>  values;
        multimap<string, node>    children;
    };

    typedef pair<string, string> value;
    typedef pair<string, node>   child;
    typedef multimap<string, string>::iterator valueiterator;
    typedef multimap<string, node>::iterator   childiterator;

    template <typename Container, typename ReturnType>
    ReturnType&
    insert (Container& con, std::string  name,
            int index, ReturnType retType) { // retType just used for type
        typename Container::iterator it = con.find (name);
        try {
            int i;
            if (it == con.end()) throw 0;
            for (i = 0; i < index; i++) {
                if (++it == con.end()) throw 0;
            }
        } catch (int e) {
            it = con.insert(
                    std::pair <std::string, ReturnType>
                              (name, ReturnType()));
        }
        return it->second;
    }
}

int main() {
    sss::node n;
    std::string str;
    std::string& strRef = sss::insert (n.values, "aaa", 1, str);
    sss::node& nodeRef = sss::insert (n.children, "bbb", 1, n);
}

How would I merge these two functions? They have so much it common! It seemed redundant... Is there a way with templates and/or with a function that has the shared code?

Templates could be an option I think, but isn't overloading a good one ?

It's so simple: you need the third member function (may be protected or private): search. It's exactly what you are trying to do in both functions inside so strange try block (no need in exceptions to control a simple found/not found condition).

This article has been dead for over six months. Start a new discussion instead.