Skip to content

File param-ref.hpp

File List > epiworld > param-ref.hpp

Go to the documentation of this file

#ifndef EPIWORLD_PARAM_REF_HPP
#define EPIWORLD_PARAM_REF_HPP

struct ParamId {
    size_t idx;
};

inline uint32_t new_param_layout_id()
{
    static std::atomic< uint32_t > counter{0u};
    uint32_t id = ++counter;
    while (id == 0u)
        id = ++counter;
    return id;
}

class ParamRef {
private:
    std::string pname;

    // (layout id << 32) | position; 0 means not resolved.
    mutable std::atomic< uint64_t > cache{0u};

public:

    explicit ParamRef(std::string name) : pname(std::move(name)) {};

    ParamRef(const ParamRef & other) :
        pname(other.pname),
        cache(other.cache.load(std::memory_order_relaxed)) {};

    ParamRef & operator=(const ParamRef & other)
    {
        pname = other.pname;
        cache.store(
            other.cache.load(std::memory_order_relaxed),
            std::memory_order_relaxed
        );
        return *this;
    };

    const std::string & name() const { return pname; };

    template< typename TModel >
    ParamId id(const TModel & model) const
    {
        const uint32_t layout = model.get_param_layout_id();
        const uint64_t c = cache.load(std::memory_order_relaxed);
        if (static_cast< uint32_t >(c >> 32) == layout)
            return ParamId{static_cast< size_t >(c & 0xffffffffu)};

        ParamId res = model.get_param_id(pname);
        if (res.idx > 0xffffffffu)
            return res;

        cache.store(
            (static_cast< uint64_t >(layout) << 32) |
                static_cast< uint64_t >(res.idx),
            std::memory_order_relaxed
        );
        return res;
    };

    template< typename TModel >
    epiworld_double operator()(const TModel & model) const
    {
        return model.par_at(id(model));
    };

};

#endif