summaryrefslogtreecommitdiff
path: root/src/utils/timed_events.hpp
blob: fa0fc5014c590e38f905d7af0ab48bb4b7535324 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pragma once

#include <functional>
#include <string>
#include <chrono>
#include <vector>

using namespace std::literals::chrono_literals;

namespace utils {
static constexpr std::chrono::milliseconds no_timeout = std::chrono::milliseconds(-1);
}

class TimedEventsManager;

/**
 * A callback with an associated date.
 */

class TimedEvent
{
  friend class TimedEventsManager;
public:
  /**
   * An event the occurs only once, at the given time_point
   */
  explicit TimedEvent(std::chrono::steady_clock::time_point&& time_point,
                      std::function<void()> callback, std::string name="");
  explicit TimedEvent(std::chrono::milliseconds&& duration,
                      std::function<void()> callback, std::string name="");

  explicit TimedEvent(TimedEvent&&) = default;
  TimedEvent& operator=(TimedEvent&&) = default;
  ~TimedEvent() = default;

  TimedEvent(const TimedEvent&) = delete;
  TimedEvent& operator=(const TimedEvent&) = delete;

  /**
   * Whether or not this event happens after the other one.
   */
  bool is_after(const TimedEvent& other) const;
  bool is_after(const std::chrono::steady_clock::time_point& time_point) const;
  /**
   * Return the duration difference between now and the event time point.
   * If the difference would be negative (i.e. the event is expired), the
   * returned value is 0 instead. The value cannot then be negative.
   */
  std::chrono::milliseconds get_timeout() const;
  void execute() const;
  const std::string& get_name() const;

private:
  /**
   * The next time point at which the event is executed.
   */
  std::chrono::steady_clock::time_point time_point;
  /**
   * The function to execute.
   */
  std::function<void()> callback;
  /**
   * Whether or not this events repeats itself until it is destroyed.
   */
  bool repeat;
  /**
   * This value is added to the time_point each time the event is executed,
   * if repeat is true. Otherwise it is ignored.
   */
  std::chrono::milliseconds repeat_delay;
  /**
   * A name that is used to identify that event. If you want to find your
   * event (for example if you want to cancel it), the name should be
   * unique.
   */
  std::string name;
};

/**
 * A class managing a list of TimedEvents.
 * They are sorted, new events can be added, removed, fetch, etc.
 */

class TimedEventsManager
{
public:
  ~TimedEventsManager() = default;

  TimedEventsManager(const TimedEventsManager&) = delete;
  TimedEventsManager(TimedEventsManager&&) = delete;
  TimedEventsManager& operator=(const TimedEventsManager&) = delete;
  TimedEventsManager& operator=(TimedEventsManager&&) = delete;

  /**
   * Return the unique instance of this class
   */
  static TimedEventsManager& instance();
  /**
   * Add an event to the list of managed events. The list is sorted after
   * this call.
   */
  void add_event(TimedEvent&& event);
  /**
   * Returns the duration, in milliseconds, between now and the next
   * available event. If the event is already expired (the duration is
   * negative), 0 is returned instead (as in “it's not too late, execute it
   * now”)
   * Returns a negative value if no event is available.
   */
  std::chrono::milliseconds get_timeout() const;
  /**
   * Execute all the expired events (if their expiration time is exactly
   * now, or before now). The event is then removed from the list. If the
   * event does repeat, its expiration time is updated and it is reinserted
   * in the list at the correct position.
   * Returns the number of executed events.
   */
  std::size_t execute_expired_events();
  /**
   * Remove (and thus cancel) all the timed events with the given name.
   * Returns the number of canceled events.
   */
  std::size_t cancel(const std::string& name);
  /**
   * Return the number of managed events.
   */
  std::size_t size() const;
  /**
   * Return a pointer to the first event with the given name. If none
   * is found, returns nullptr.
   */
  const TimedEvent* find_event(const std::string& name) const;

private:
  std::vector<TimedEvent> events;
  explicit TimedEventsManager() = default;
};