Timeout and Interval events
This commit is contained in:
		
							
								
								
									
										141
									
								
								src/dawn/event/CustomEvent.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/dawn/event/CustomEvent.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
			
		||||
// Copyright (c) 2023 Dominic Masters
 | 
			
		||||
// 
 | 
			
		||||
// This software is released under the MIT License.
 | 
			
		||||
// https://opensource.org/licenses/MIT
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "dawnlibs.hpp"
 | 
			
		||||
 | 
			
		||||
namespace Dawn {
 | 
			
		||||
  enum class CustomEventResult {
 | 
			
		||||
    NOTHING,
 | 
			
		||||
    REMOVE,
 | 
			
		||||
    INVOKE,
 | 
			
		||||
    INVOKE_AND_REMOVE
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  template<
 | 
			
		||||
    typename InternalData,
 | 
			
		||||
    typename InternalListenerData,
 | 
			
		||||
    typename ListenerArgument,
 | 
			
		||||
    typename ...InvokeArgs
 | 
			
		||||
  >
 | 
			
		||||
  class CustomEvent {
 | 
			
		||||
    private:
 | 
			
		||||
      int32_t nextId = 0;
 | 
			
		||||
      std::unordered_map<
 | 
			
		||||
        int32_t,
 | 
			
		||||
        std::pair<InternalListenerData, std::function<void(InvokeArgs...)>>
 | 
			
		||||
      > listeners;
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
      InternalData internalData;
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Custom event filter. Decides whether or not the event should be emitted
 | 
			
		||||
       * to the listener.
 | 
			
		||||
       * 
 | 
			
		||||
       * @param listenerData Data for this listener.
 | 
			
		||||
       * @param args The arguments to pass to the listeners.
 | 
			
		||||
       * @return The result of the filter.
 | 
			
		||||
       */
 | 
			
		||||
      virtual enum CustomEventResult shouldEmit(
 | 
			
		||||
        const InternalListenerData &listenerData,
 | 
			
		||||
        const InvokeArgs... args
 | 
			
		||||
      ) = 0;
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Transform the arguments for listener data when the listener is first
 | 
			
		||||
       * subscribed.
 | 
			
		||||
       * 
 | 
			
		||||
       * @param argument The argument to transform.
 | 
			
		||||
       * @return The transformed argument into an internal data format.
 | 
			
		||||
       */
 | 
			
		||||
      virtual InternalListenerData transformData(
 | 
			
		||||
        const ListenerArgument &argument
 | 
			
		||||
      ) = 0;
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Transform the data for listener data after the event has been emitted.
 | 
			
		||||
       * 
 | 
			
		||||
       * @param internalData The internal data to transform.
 | 
			
		||||
       * @return Updated/Transformed internal data.
 | 
			
		||||
       */
 | 
			
		||||
      virtual InternalListenerData transformDataAfterEmit(
 | 
			
		||||
        const InternalListenerData &internalData
 | 
			
		||||
      ) {
 | 
			
		||||
        return internalData;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
      /**
 | 
			
		||||
       * Emits the event.
 | 
			
		||||
       * @param args The arguments to pass to the listeners.
 | 
			
		||||
       */
 | 
			
		||||
      void emit(InvokeArgs... args) {
 | 
			
		||||
        auto copy = listeners;
 | 
			
		||||
        for(auto &pair : copy) {
 | 
			
		||||
          // Check emit test.
 | 
			
		||||
          auto result = this->shouldEmit(
 | 
			
		||||
            pair.second.first,
 | 
			
		||||
            args...
 | 
			
		||||
          );
 | 
			
		||||
          if(
 | 
			
		||||
            result == CustomEventResult::INVOKE ||
 | 
			
		||||
            result == CustomEventResult::INVOKE_AND_REMOVE
 | 
			
		||||
          ) {
 | 
			
		||||
            pair.second.second(args...);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if(
 | 
			
		||||
            result == CustomEventResult::REMOVE || 
 | 
			
		||||
            result == CustomEventResult::INVOKE_AND_REMOVE
 | 
			
		||||
          ) {
 | 
			
		||||
            listeners.erase(pair.first);
 | 
			
		||||
            continue;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if(
 | 
			
		||||
            result == CustomEventResult::INVOKE ||
 | 
			
		||||
            result == CustomEventResult::INVOKE_AND_REMOVE
 | 
			
		||||
          ) {
 | 
			
		||||
            // Update the internal data.
 | 
			
		||||
            listeners[pair.first].first = transformDataAfterEmit(
 | 
			
		||||
              pair.second.first
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Listens to the event.
 | 
			
		||||
       * 
 | 
			
		||||
       * @param data Listener data to use.
 | 
			
		||||
       * @param listener The listener to add.
 | 
			
		||||
       * @returns A function that can be called to remove the listener.
 | 
			
		||||
       */
 | 
			
		||||
      std::function<void()> listen(
 | 
			
		||||
        const ListenerArgument &data,
 | 
			
		||||
        const std::function<void(InvokeArgs...)> listener
 | 
			
		||||
      ) {
 | 
			
		||||
        int32_t id = nextId++;
 | 
			
		||||
 | 
			
		||||
        auto pair = std::make_pair(
 | 
			
		||||
          transformData(data),
 | 
			
		||||
          listener
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        listeners[id] = pair;
 | 
			
		||||
        return [this, id]() {
 | 
			
		||||
          listeners.erase(id);
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Destroys the custom event.
 | 
			
		||||
       */
 | 
			
		||||
      virtual ~CustomEvent() {
 | 
			
		||||
        listeners.clear();
 | 
			
		||||
      }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
@@ -37,7 +37,9 @@ namespace Dawn {
 | 
			
		||||
       * @param listener The listener to add.
 | 
			
		||||
       * @returns A function that can be called to remove the listener.
 | 
			
		||||
       */
 | 
			
		||||
      std::function<void()> listen(const std::function<void(A...)> listener) {
 | 
			
		||||
      std::function<void()> listen(
 | 
			
		||||
        const std::function<void(A...)> listener
 | 
			
		||||
      ) {
 | 
			
		||||
        int32_t id = nextId++;
 | 
			
		||||
        listeners[id] = listener;
 | 
			
		||||
        return [this, id]() {
 | 
			
		||||
@@ -46,8 +48,7 @@ namespace Dawn {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Removes a listener from the event.
 | 
			
		||||
       * @param id The id of the listener to remove.
 | 
			
		||||
       * Destroys the event.
 | 
			
		||||
       */
 | 
			
		||||
      virtual ~Event() {
 | 
			
		||||
        listeners.clear();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user