#include #include #include #include namespace autoopt { template struct source { T _value; std::uint64_t _version = 0; source() = default; explicit source(T value) : _value(std::move(value)) {} virtual T& get() { return _value; }; bool set(T value) { if (value == _value) return false; _value = std::move(value); ++_version; return true; } }; template struct transform : source { std::function _func; std::tuple&...> _sources; std::array _versions{}; transform(std::function func, source&... sources) : _func(func), _sources(sources...) { this->_value = std::apply([&](source&... sources) { return _func(sources.get()...); }, _sources); this->_versions = current_versions(); } virtual O& get() override { auto cur_versions = current_versions(); if (_versions == cur_versions) return this->_value; O next = std::apply([&](source&... sources) { return _func(sources.get()...); }, _sources); if (next != this->_value) { this->_value = next; ++this->_version; } return this->_value; } private: std::array current_versions() { return std::apply([&](source&... sources){ return std::array{sources._version...}; }, _sources); } }; template struct sink { source& _upstream; std::uint64_t _version; std::function _cb; void maybe_update() { if (_version != _upstream._version) { _cb(_upstream.get()); _version = _upstream._version; } } }; } // namespace autoopt