fritzone / miso

Micro Signal/Slot implementetation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Connect with unique objects

vainamon opened this issue · comments

Hello!
Thanks for the useful nice little tool.
Consider the following example:

class other_class
{
public:
    other_class() = default;
    other_class(int v) : nr(v) {}

    void clicked()
    {
    	xil_printf("clicked:");
    }

    void clicked_again(int v)
    {
    	xil_printf("clicked_again:");
    }


private:

    int nr = 23;
};

class my_class
{
public:

    my_class(int f) : mf(f) {}

    void some_method()
    {
        emit click();
    }

    miso::signal<> click;
    int mf = 0;

};

int main() {
    my_class src(56);
    my_class src2(5656);

    other_class dst(4);
    other_class dst2(100500);

    miso::connect(src.click, std::bind(&other_class::clicked, dst));
    miso::connect(src2.click, std::bind(&other_class::clicked, dst2));

    src.some_method();

    return 0;
}

Slot clicked() will be called twice, which is unexpected, but is not surprise - because of static nature of SHT in connect_i function. For solve this I replace static SHT sh to

static std::unordered_map<std::string, SHT> sh_hash;    

auto sh_key = typeid(T).name() + std::string(typeid(FT).name()) + static_cast<std::ostringstream&>(
                        std::ostringstream().flush() << reinterpret_cast<void*>(&sholders)
                      ).str();

SHT &sh = sh_hash[sh_key];

But there is another problem if objects dynamically and repeatedly created, connected, emitted and destroyed: sh_hash would not be cleared and would be overfull sometime. That is why I changed connect_i function to:

        template<class T, class FT, class SHT>
        void connect_i(T &&f, std::vector<common_slot_base *> &sholders, bool active = true) {
            static std::unordered_map<std::string, SHT> sh_hash;
            
            auto sh_key = typeid(T).name() + std::string(typeid(FT).name()) + static_cast<std::ostringstream&>(
                        std::ostringstream().flush() << reinterpret_cast<void*>(&sholders)
                      ).str();

            SHT &sh = sh_hash[sh_key];

            func_and_bool<FT> fb{std::make_shared<FT>(std::forward<T>(f)), active, reinterpret_cast<void *>(&f)};
            bool already_in = false;
            bool active_status = active;
            
            std::for_each(sh.slots.begin(), sh.slots.end(),
                          [&](func_and_bool<FT> &s) { if (s.addr == fb.addr){s.active = active; already_in = true;} active_status |= s.active; });
            
            if (active_status) {
                if (!already_in) sh.slots.emplace_back(fb);
                if (std::find(sholders.begin(), sholders.end(), static_cast<common_slot_base *>(&sh)) == sholders.end()) {
                    sholders.push_back(&sh);
                }
            } else {
                remove(sholders.begin(), sholders.end(), static_cast<common_slot_base *>(&sh));
                sh_hash.erase(sh_key);
            }
        }

That's all.

Hi,

Thanks for taking time to fix this issue, indeed the problem you have reported is a valid and serious one. I would be happy to have it fixed, so, in case you would open a pull request, I would be happy to have it merged back, and considering the amount of code you have wrote for this, I'd be happy to add you as a project developer too if you want this, using the motto: "more eyes see more!"!

Cheers, f.

Ok, I would open a pull request. And of course these changes must be reviewed and tested by someone else. I think there's no need for add me as a project developer - I'll plan to use miso in my projects and if there's another issues, then I'll be definitely let you know.