LeviLamina
Loading...
Searching...
No Matches
Observable.h
1#pragma once
2
3#include <cstdint>
4#include <map>
5#include <memory>
6#include <utility>
7
8#include "mc/platform/brstd/move_only_function.h"
9
10namespace ll::data {
11
12template <class T>
13class Observable {
14public:
15 using Callback = brstd::move_only_function<void(T const&)>;
16 using SubscriptionId = std::uint32_t;
17
18private:
19 struct State {
20 explicit State(T initial) : data(std::move(initial)) {}
21
22 std::map<SubscriptionId, Callback> callbacks;
23 SubscriptionId nextId{};
24 T data;
25 };
26
27 std::shared_ptr<State> state;
28
29public:
30 explicit Observable(T initial) : state(std::make_shared<State>(std::move(initial))) {}
31
32 Observable(Observable const&) = default;
33 Observable& operator=(Observable const&) = default;
34 Observable(Observable&&) noexcept = default;
35 Observable& operator=(Observable&&) noexcept = default;
36
37 [[nodiscard]] T getData() const { return state->data; }
38
39 void setData(T value) {
40 if (state->data == value) {
41 return;
42 }
43 state->data = std::move(value);
44
45 for (auto& [_, callback] : state->callbacks) {
46 callback(state->data);
47 }
48 }
49
50 SubscriptionId subscribe(Callback callback) {
51 if (!callback) {
52 return 0;
53 }
54
55 auto const id = ++state->nextId;
56 state->callbacks.emplace(id, std::move(callback));
57 return id;
58 }
59
60 bool unsubscribe(SubscriptionId id) {
61 if (id == 0) {
62 return false;
63 }
64 return state->callbacks.erase(id) != 0;
65 }
66};
67
68} // namespace ll::data
Definition move_only_function.h:9