Maps



  • Theoretisch würde ich sowas nehmen:

    template<typename key1T, typename key2T>
    struct bimap
    {
            typedef std::vector<std::pair<key1T, key2T>> array_type;
            array_type array;
    
            typename array_type::iterator find(key2T tof)
            {
                    typename array_type::iterator iter = array.begin();
                    for(;iter != array.end();++iter)
                            if(iter->second == tof)
                                    break;
    
                    return iter;
            }
    
            typename array_type::iterator find(key1T tof)
            {
                    typename array_type::iterator iter = array.begin();
                    for(;iter != array.end();++iter)
                            if(iter->first == tof)
                                    break;
    
                    return iter;
            }
    
            key1T& operator[](key2T a)
            {
                    typename array_type::iterator iter;
                    if((iter = find(a)) != array.end())
                            return iter->first;
    
                    array.push_back(std::make_pair(key1T(), a));
                    return array.back().first;
            }
            key2T& operator[](key1T a)
            {
                    typename array_type::iterator iter;
                    if((iter = find(a)) != array.end())
                            return iter->second;
    
                    array.push_back(std::make_pair(a, key2T()));
                    return array.back().second;
            }
    };
    

    Nur ist halt das Problem, dass es nicht reguläre Memberfunktionen wie in einer std::map gibt... ⚠
    ➡ 💡
    Aufgabe für heute gefunden!



  • .. und das es ziemlich langsamer pfusch ist.. 😉



  • daki schrieb:

    .. und das es ziemlich langsamer pfusch ist.. 😉

    Na wenn du das gleich so sagst... machs besser ( :Herausforderung: ) 🤡

    Ich bin soweit fertig (unimplementierte Funktionen sind ja durch das Set verfügbar, und da das nur ein Wrapper um ein Set ist...).

    template<typename leftKeyT, typename rightKeyT>
    class bimap
    {
    public:
    
            typedef std::pair<leftKeyT, rightKeyT> value_type;
            typedef std::set<value_type> array_type;
    
            array_type mSet;///Internal array (set)
    
            typedef leftKeyT left_key_type;
            typedef rightKeyT right_key_type;
    
            typedef typename array_type::iterator iterator;
            typedef typename array_type::const_iterator const_iterator;
            typedef typename array_type::size_type size_type; //Hier können theoretisch noch andere typedefs hin, aber die sind durch das Set verfügbar
    
            iterator find(rightKeyT const& tof)
            {
                    return find(tof);
            }
    
            iterator find(leftKeyT const& tof)
            {
                    return find(tof);
            }
    
            const_iterator find(rightKeyT const& tof) const
            {
                    return std::find_if(mSet.begin(), mSet.end(), [&](value_type const& a){return a.second == tof;});
            }
    
            const_iterator find(leftKeyT const& tof) const
            {
                    return std::find_if(mSet.begin(), mSet.end(), [&](value_type const& a){return a.first == tof;});
            }
    
            leftKeyT& operator[](rightKeyT const& a)
            {
                    return const_cast<leftKeyT&>(insert(a).first->first);
            }
    
            rightKeyT& operator[](leftKeyT const& a)
            {
                    return const_cast<rightKeyT&>(insert(a).first->second);
            }
    
            void clear()
            {
                    mSet.clear();
            }
    
            size_type count(leftKeyT const& lK) const
            {
                    return std::count_if(mSet.mSet.begin(), mSet.end(), [&](std::pair<leftKeyT, rightKeyT> const& p)
                                                                       {
                                                                            return p.first == lK;
                                                                       });
            }
            size_type count(rightKeyT const& rK) const
            {
                    return std::count_if(mSet.mSet.begin(), mSet.end(), [&](std::pair<leftKeyT, rightKeyT> const& p)
                                                                       {
                                                                            return p.second == rK;
                                                                       });
            }
    
            size_type erase(rightkeyT const& lK)
            {
                    size_type rval = count(lK);
                    std::remove_if(mSet.begin(), mSet.end(), [&](value_type const& p){return p.second == lK;});
                    return rval;
            }
    
            size_type erase(leftkeyT const& lK)
            {
                    size_type rval = count(lK);
                    std::remove_if(mSet.begin(), mSet.end(), [&](value_type const& p){return p.first == lK;});
                    return rval;
            }
    
            template<typename keyT>
            std::pair<iterator, bool> insert(keyT const& t)
            {
                    std::pair<iterator, bool> rval(find(t), false);
    
                    if(rval.first != mSet.end())
                            return rval;
    
                    return mSet.insert(std::make_pair(leftKeyT(), t));;
            }
    };
    


  • Hacker schrieb:

    iterator find(rightKeyT const& tof)
            {
                    return std::find_if(mSet.begin(), mSet.end(), [&](value_type const& a){return a.second == tof;});
            }
    
            const_iterator find(rightKeyT const& tof) const
            {
                    return const_cast<bimap*>(this)->find(tof);
            }
    

    Du kannst doch mit einer non-const Instanz eine const-Methode aufrufen.



  • Gugelmoser schrieb:

    Hacker schrieb:

    iterator find(rightKeyT const& tof)
            {
                    return std::find_if(mSet.begin(), mSet.end(), [&](value_type const& a){return a.second == tof;});
            }
    
            const_iterator find(rightKeyT const& tof) const
            {
                    return const_cast<bimap*>(this)->find(tof);
            }
    

    Du kannst doch mit einer non-const Instanz eine const-Methode aufrufen.

    Ja und dann? Findests schöner, oder? Ich bin aber zu faul zum editieren 😃



  • Hacker schrieb:

    Ja und dann? Findests schöner, oder? Ich bin aber zu faul zum editieren 😃

    Ist nicht alles, das keinen const_cast hat, schöner?


  • Mod

    Hacker schrieb:

    Gugelmoser schrieb:

    Hacker schrieb:

    iterator find(rightKeyT const& tof)
            {
                    return std::find_if(mSet.begin(), mSet.end(), [&](value_type const& a){return a.second == tof;});
            }
    
            const_iterator find(rightKeyT const& tof) const
            {
                    return const_cast<bimap*>(this)->find(tof);
            }
    

    Du kannst doch mit einer non-const Instanz eine const-Methode aufrufen.

    Ja und dann? Findests schöner, oder? Ich bin aber zu faul zum editieren 😃

    Die Implementation einer non-const Überladung über die const-Überladung ist trivialerweise korrekt, sofern der Rückgabewert kompatibel ist - das ist eine Frage des Contracts.
    Der umgekehrte Weg funktioniert dagegen nur, falls die non-const Variante das Objekt tatsächlich nicht verändert - ist also von deren Implementation abhängig.
    Preisfrage: Welche Variante koppelt die Funktionen weniger stark und ist folglich vorzuziehen?



  • camper schrieb:

    Der umgekehrte Weg funktioniert dagegen nur, falls die non-const Variante das Objekt tatsächlich nicht verändert - ist also von deren Implementation abhängig.

    Die Bedingungen des umgekehrten Weges sind mir gekannt. Deswegen habe ich es ja auch nicht verändert. Aber wenn ihr darauf besteht 🙄



  • camper schrieb:

    Preisfrage: Welche Variante koppelt die Funktionen weniger stark und ist folglich vorzuziehen?

    Ich würde die Variante ohne const_cast nehmen, aber nur aus dem Grund, weil ich const_cast nicht schön finde. Aber ich bin auf deine Erklärung gespannt, camper. 🙂



  • camper schrieb:

    Preisfrage: Welche Variante koppelt die Funktionen weniger stark und ist folglich vorzuziehen?

    Die Koppelung ist doch vollkomen egal. Es geht um Sicherheit gegenüber Änderungen - und die ist nur bei non-const über const gegeben, folglich ist diese vorzuziehen.

    Gugelmoser schrieb:

    Ich würde die Variante ohne const_cast nehmen, aber nur aus dem Grund, weil ich const_cast nicht schön finde. Aber ich bin auf deine Erklärung gespannt, camper. 🙂

    const_cast ist nicht per-se unschön.


Anmelden zum Antworten