1 properties-cpp {#mainpage}
4 process-cpp is a simple header-only implementation of properties and
5 signals. It is meant to be used for developing low-level system
6 services. Its main features include:
8 - Thread-safe signal invocation and observer mgmt.
9 - The ability to dispatch signal invocations via arbitrary event loops.
10 - Typed properties with an in-place update mechanism that avoids unneccessary deep copies.
11 - Well tested and documented.
13 A Textfield With an Observable Cursor Position
14 ----------------------------------------------
21 void move_cursor_to(int new_position)
23 cursor_position.set(new_position);
26 core::Property<int> cursor_position;
30 TEST(Property, cursor_position_changes_are_transported_correctly)
36 // Setup a connection to the cursor position property
37 tf.cursor_position.changed().connect(
38 [&position](int value)
44 tf.move_cursor_to(22);
46 // Check that the correct value has propagated
47 EXPECT_EQ(22, position);
51 Integrating With Arbitrary Event Loops/Reactor Implementations
52 --------------------------------------------------------------
58 typedef std::function<void()> Handler;
62 stop_requested = true;
67 while (!stop_requested)
69 std::unique_lock<std::mutex> ul(guard);
70 wait_condition.wait_for(
72 std::chrono::milliseconds{500},
73 [this]() { return handlers.size() > 0; });
75 while (handlers.size() > 0)
83 void dispatch(const Handler& h)
85 std::lock_guard<std::mutex> lg(guard);
89 bool stop_requested = false;
90 std::queue<Handler> handlers;
92 std::condition_variable wait_condition;
96 TEST(Signal, installing_a_custom_dispatcher_ensures_invocation_on_correct_thread)
98 // We instantiate an event loop and run it on a different thread than the main one.
100 std::thread dispatcher_thread{[&dispatcher]() { dispatcher.run(); }};
101 std::thread::id dispatcher_thread_id = dispatcher_thread.get_id();
103 // The signal that we want to dispatch via the event loop.
104 core::Signal<int, double> s;
106 static const int expected_invocation_count = 10000;
108 // Setup the connection. For each invocation we check that the id of the
109 // thread the handler is being called upon equals the thread that the
110 // event loop is running upon.
111 auto connection = s.connect(
112 [&dispatcher, dispatcher_thread_id](int value, double d)
114 EXPECT_EQ(dispatcher_thread_id,
115 std::this_thread::get_id());
117 std::cout << d << std::endl;
119 if (value == expected_invocation_count)
123 // Route the connection via the dispatcher
124 connection.dispatch_via(
126 &EventLoop::dispatch,
127 std::ref(dispatcher),
128 std::placeholders::_1));
130 // Invoke the signal from the main thread.
131 for (unsigned int i = 1; i <= expected_invocation_count; i++)
134 if (dispatcher_thread.joinable())
135 dispatcher_thread.join();