#pragma once #include #include #include #include "Atomic.h" template > T operator ++(T& value, int) { return std::exchange(value, static_cast(value < T{} || value >= Mod ? static_cast(0) : static_cast(value) + 1)); } template > T operator --(T& value, int) { return std::exchange(value, static_cast(value <= T{} || value >= static_cast(Mod) - 1 ? static_cast(Mod) - 1 : static_cast(value) - 1)); } template >(T::__state_enum_max)> class state_machine { using under = std::underlying_type_t; using ftype = void(CRT::*)(T); atomic_t m_value; template static inline ftype transition_map(std::integer_sequence, T state) { // Constantly initialized list of functions static constexpr ftype map[Size]{&CRT::template transition(Ind)>...}; // Unsafe table lookup (TODO) return map[static_cast(state)]; } // "Convert" variable argument to template argument static inline ftype transition_get(T state) { return transition_map(std::make_index_sequence(), state); } public: constexpr state_machine() : m_value{T{}} { } constexpr state_machine(T state) : m_value{state} { } // Get current state T state_get() const { return m_value; } // Unconditionally set state void state_set(T state) { T _old = m_value.exchange(state); if (_old != state) { (static_cast(this)->*transition_get(state))(_old); } } // Conditionally set state (optimized) explicit_bool_t state_test_and_set(T expected, T state) { if (m_value == expected && m_value.compare_and_swap_test(expected, state)) { (static_cast(this)->*transition_get(state))(expected); return true; } return false; } // Conditionally set state (list version) explicit_bool_t state_test_and_set(std::initializer_list expected, T state) { T _old; if (m_value.atomic_op([&](T& value) { for (T x : expected) { if (value == x) { _old = std::exchange(value, state); return true; } } return false; })) { (static_cast(this)->*transition_get(state))(_old); return true; } return false; } // Unconditionally set next state void state_next() { T _old, state = m_value.op_fetch([&](T& value) { _old = value++; }); (static_cast(this)->*transition_get(state))(_old); } // Unconditionally set previous state void state_prev() { T _old, state = m_value.op_fetch([&](T& value) { _old = value--; }); (static_cast(this)->*transition_get(state))(_old); } // Get number of states static constexpr std::size_t size() { return Size; } }; //enum class test_state //{ // on, // off, // la, // // __state_enum_max // 3 //}; // //struct test_machine final : state_machine //{ // template // void transition(test_state old_state); // // void on() // { // state_set(test_state::on); // } // // void off() // { // state_set(test_state::off); // } // // void test() // { // state_next(); // } //}; // //template <> //void test_machine::transition(test_state) //{ // LOG_SUCCESS(GENERAL, "ON"); //} // //template <> //void test_machine::transition(test_state) //{ // LOG_SUCCESS(GENERAL, "OFF"); //} // // //template <> //void test_machine::transition(test_state) //{ // on(); // off(); // test(); //} enum class event_result { skip, handled }; class events_queue { std::deque> m_queue; public: /*template events_queue& operator += (event &evt) { evt.set_queue(this); return *this; } */ void invoke(std::function function) { m_queue.push_back(function); } void flush() { while (!m_queue.empty()) { std::function function = m_queue.front(); function(); m_queue.pop_front(); } } }; template class event { using func_t = std::function; using entry_t = typename std::list::iterator; std::list handlers; events_queue& m_queue; public: event(events_queue* queue = nullptr) : m_queue(*queue) { } void invoke(AT... args) { m_queue.invoke(std::bind([&](AT... eargs) { for (auto &&handler : handlers) { if (handler(eargs...) == event_result::handled) break; } }, args...)); } void operator()(AT... args) { invoke(args...); } entry_t bind(func_t func) { handlers.push_front(func); return handlers.begin(); } template entry_t bind(T *caller, event_result(T::*callback)(AT...)) { return bind([=](AT... args) { return (caller->*callback)(args...); }); } template entry_t bind(T *caller, void(T::*callback)(AT...)) { return bind([=](AT... args) { (caller->*callback)(args...); return event_result::skip; }); } void unbind(entry_t entry) { handlers.erase(entry); } entry_t operator +=(func_t func) { return bind(func); } void operator -=(entry_t what) { return unbind(what); } }; template<> class event { using func_t = std::function; using entry_t = std::list::iterator; std::list m_listeners; events_queue* m_queue; void invoke_listeners() { for (auto &&listener : m_listeners) { if (listener() == event_result::handled) break; } } public: event(events_queue* queue = nullptr) : m_queue(queue) { } void invoke() { if (m_queue) m_queue->invoke([=]() { invoke_listeners(); }); else invoke_listeners(); } void operator()() { invoke(); } entry_t bind(func_t func) { m_listeners.push_front(func); return m_listeners.begin(); } template entry_t bind(T *caller, event_result(T::*callback)()) { return bind([=]() { return (caller->*callback)(); }); } template entry_t bind(T *caller, void(T::*callback)()) { return bind([=]() { (caller->*callback)(); return event_result::skip; }); } void unbind(entry_t what) { m_listeners.erase(what); } entry_t operator +=(func_t func) { return bind(func); } void operator -=(entry_t what) { return unbind(what); } }; class event_binder_t { template class binder_impl_t { event_binder_t *m_binder; event *m_event; public: binder_impl_t(event_binder_t *binder, event *evt) : m_binder(binder) , m_event(evt) { } }; public: template binder_impl_t operator()(event& evt) const { return{ this, &evt }; } }; template class combined_data; template class local_data { public: using type = T; protected: type m_data; void set(type value) { m_data = value; } type get() const { return m_data; } bool equals(T value) const { return get() == value; } bool invoke_event(type value) { return false; } friend combined_data; }; template class combined_data { public: using type = T; protected: local_data m_local_data; std::function m_invoke_event_function; std::function m_get_function; bool invoke_event(type value) { if (m_invoke_event_function) { m_invoke_event_function(value); return true; } return false; } void set(type value) { m_local_data.set(value); } type get() const { if (m_get_function) { return m_get_function(); } return m_local_data.get(); } type get_local() const { return m_local_data.get(); } bool equals(T value) const { return get_local() == value; } public: void invoke_event_function(std::function function) { m_invoke_event_function = function; } void get_function(std::function function) { m_get_function = function; } }; template> class data_event : public base_type_ { public: using type = T; using base_type = base_type_; protected: event_result dochange(type new_value) { auto old_value = get(); base_type::set(new_value); onchanged(old_value); return event_result::handled; } public: event onchange; event onchanged; data_event(events_queue *queue = nullptr) : onchange(queue) , onchanged(queue) { onchange.bind(this, &data_event::dochange); base_type::set({}); } type get() const { return base_type::get(); } type operator()() const { return get(); } void change(type value, bool use_custom_invoke_event = true) { if (!base_type::equals(value)) { if (!use_custom_invoke_event || !base_type::invoke_event(value)) { onchange(value); } } } operator const type() const { return get(); } operator type() { return get(); } data_event& operator = (type value) { change(value); return *this; } template auto operator + (aType value) const { return get() + value; } template auto operator - (aType value) const { return get() - value; } template auto operator * (aType value) const { return get() * value; } template auto operator / (aType value) const { return get() / value; } template auto operator % (aType value) const { return get() % value; } template auto operator & (aType value) const { return get() & value; } template auto operator | (aType value) const { return get() | value; } template auto operator ^ (aType value) const { return get() ^ value; } template data_event& operator += (aType value) { return *this = get() + value; } template data_event& operator -= (aType value) { return *this = get() - value; } template data_event& operator *= (aType value) { return *this = get() * value; } template data_event& operator /= (aType value) { return *this = get() / value; } template data_event& operator %= (aType value) { return *this = get() % value; } template data_event& operator &= (aType value) { return *this = get() & value; } template data_event& operator |= (aType value) { return *this = get() | value; } template data_event& operator ^= (aType value) { return *this = get() ^ value; } data_event& operator ++() { type value = get(); return *this = ++value; } type operator ++(int) { type value = get(); type result = value; *this = value++; return result; } data_event& operator --() { type value = get(); return *this = --value; } type operator --(int) { type value = get(); type result = value; *this = value--; return result; } }; struct with_event_binder { event_binder_t event_binder; }; struct test_obj { void test(int) { event i; auto it = i.bind(this, &test_obj::test); i(5); i.unbind(it); i(6); } };