File README.md changed (mode: 100644) (index e7702ef..90e68bd) |
1 |
|
## dynamo
|
|
2 |
|
|
|
3 |
|
![doc header](https://s3-us-west-2.amazonaws.com/mod-resources/mod-header.svg) |
|
|
1 |
|
# dynamo |
|
2 |
|
|
|
3 |
|
Dispatch work to agents. |
|
4 |
|
|
|
5 |
|
## Interface |
|
6 |
|
``` |
|
7 |
|
#pragma once |
|
8 |
|
|
|
9 |
|
#include <functional> |
|
10 |
|
#include <memory> |
|
11 |
|
|
|
12 |
|
namespace om636 { |
|
13 |
|
namespace control { |
|
14 |
|
|
|
15 |
|
template <typename... T> |
|
16 |
|
class Batch { |
|
17 |
|
public: |
|
18 |
|
typedef std::function<void(T...)> function_type; |
|
19 |
|
typedef std::shared_ptr<function_type> agent_type; |
|
20 |
|
typedef agent_type listener_type; |
|
21 |
|
|
|
22 |
|
virtual ~Batch() = default; |
|
23 |
|
virtual agent_type hook(function_type) = 0; |
|
24 |
|
virtual agent_type hook_once(function_type) = 0; |
|
25 |
|
virtual void invoke(T...) = 0; |
|
26 |
|
}; |
|
27 |
|
|
|
28 |
|
template <typename... T> |
|
29 |
|
std::shared_ptr<Batch<T...>> make_queue(); |
|
30 |
|
|
|
31 |
|
template <typename... T> |
|
32 |
|
std::shared_ptr<Batch<T...>> make_stack(); |
|
33 |
|
|
|
34 |
|
} // control |
|
35 |
|
} // om636 |
|
36 |
|
|
|
37 |
|
``` |
|
38 |
|
|
|
39 |
|
## Example |
|
40 |
|
``` |
|
41 |
|
#include <tmp/src/test.h> |
|
42 |
|
|
|
43 |
|
#include <lib/dynamo/src/impl/batch.h> |
|
44 |
|
#include <lib/dynamo/src/interface.h> |
|
45 |
|
|
|
46 |
|
int main() |
|
47 |
|
{ |
|
48 |
|
auto b = om636::control::make_queue<int>(); |
|
49 |
|
|
|
50 |
|
int sum{ 0 }; |
|
51 |
|
|
|
52 |
|
auto q = b->hook([&](int i) { sum += i; }); |
|
53 |
|
auto p = b->hook([&](int i) { sum *= i; }); |
|
54 |
|
b->invoke(5); |
|
55 |
|
ASSERT(sum == 25); |
|
56 |
|
return 0; |
|
57 |
|
} |
|
58 |
|
|
|
59 |
|
``` |
|
60 |
|
|
|
61 |
|
### Dependencies |
|
62 |
|
|
|
63 |
|
Dynamo uses Circuit for thread syncronization |
|
64 |
|
|
|
65 |
|
### Plan |
|
66 |
|
|
|
67 |
|
Instead of copy and insert elements inside of invok, push the elements one by one as they get traversed (obviosly don't add elements that are dead)... |
|
68 |
|
|
|
69 |
|
![doc header](https://s3-us-west-2.amazonaws.com/mod-resources/mod-header.svg) |
File src/agent.hxx deleted (index 5f3dde8..0000000) |
1 |
|
namespace om636 { |
|
2 |
|
namespace control { |
|
3 |
|
|
|
4 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
5 |
|
// Agent |
|
6 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
7 |
|
template <typename T> |
|
8 |
|
Agent<T>::Agent(callback_type callback) |
|
9 |
|
: m_callback(callback) |
|
10 |
|
{ |
|
11 |
|
} |
|
12 |
|
|
|
13 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
14 |
|
template <typename T> |
|
15 |
|
void Agent<T>::invoke() |
|
16 |
|
{ |
|
17 |
|
ASSERT(!is_dead()); |
|
18 |
|
m_callback(); |
|
19 |
|
} |
|
20 |
|
|
|
21 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
22 |
|
template <typename T> |
|
23 |
|
template <typename V> |
|
24 |
|
void Agent<T>::invoke(V v) |
|
25 |
|
{ |
|
26 |
|
ASSERT(!is_dead()); |
|
27 |
|
m_callback(v); |
|
28 |
|
} |
|
29 |
|
|
|
30 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
31 |
|
template <typename T> |
|
32 |
|
template <typename V, typename W> |
|
33 |
|
void Agent<T>::invoke(V v, W w) |
|
34 |
|
{ |
|
35 |
|
ASSERT(!is_dead()); |
|
36 |
|
m_callback(v, w); |
|
37 |
|
} |
|
38 |
|
|
|
39 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
40 |
|
template <typename T> |
|
41 |
|
void Agent<T>::kill_invoke() |
|
42 |
|
{ |
|
43 |
|
ASSERT(!is_dead()); |
|
44 |
|
callback_type temp(m_callback); |
|
45 |
|
kill(); |
|
46 |
|
temp(); |
|
47 |
|
} |
|
48 |
|
|
|
49 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
50 |
|
template <typename T> |
|
51 |
|
template <typename V> |
|
52 |
|
void Agent<T>::kill_invoke(V v) |
|
53 |
|
{ |
|
54 |
|
ASSERT(!is_dead()); |
|
55 |
|
callback_type temp(m_callback); |
|
56 |
|
kill(); |
|
57 |
|
temp(v); |
|
58 |
|
} |
|
59 |
|
|
|
60 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
61 |
|
template <typename T> |
|
62 |
|
template <typename V, typename W> |
|
63 |
|
void Agent<T>::kill_invoke(V v, W w) |
|
64 |
|
{ |
|
65 |
|
ASSERT(!is_dead()); |
|
66 |
|
callback_type temp(m_callback); |
|
67 |
|
kill(); |
|
68 |
|
temp(v, w); |
|
69 |
|
} |
|
70 |
|
|
|
71 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
72 |
|
template <typename T> |
|
73 |
|
void Agent<T>::kill() |
|
74 |
|
{ |
|
75 |
|
m_callback = callback_type(); |
|
76 |
|
} |
|
77 |
|
|
|
78 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
79 |
|
template <typename T> |
|
80 |
|
bool Agent<T>::is_dead() |
|
81 |
|
{ |
|
82 |
|
return !m_callback; |
|
83 |
|
} |
|
84 |
|
|
|
85 |
|
} //control |
|
86 |
|
} // om636 |
|
File src/batch.h deleted (index 648807c..0000000) |
1 |
|
#ifndef BATCH_H__iFZqmDoIwhGaYO3df4xe5LCQXrbBvj |
|
2 |
|
#define BATCH_H__iFZqmDoIwhGaYO3df4xe5LCQXrbBvj |
|
3 |
|
|
|
4 |
|
#include <algorithm> |
|
5 |
|
#include <map> |
|
6 |
|
#include <memory> |
|
7 |
|
#include <vector> |
|
8 |
|
|
|
9 |
|
#include "agent.h" |
|
10 |
|
|
|
11 |
|
namespace om636 { |
|
12 |
|
namespace control { |
|
13 |
|
template <typename T> |
|
14 |
|
class Batch { |
|
15 |
|
public: |
|
16 |
|
typedef T callback_type; |
|
17 |
|
typedef Agent<callback_type> agent_type; |
|
18 |
|
typedef std::weak_ptr<agent_type> pointer_type; |
|
19 |
|
typedef std::shared_ptr<agent_type> listener_type; |
|
20 |
|
typedef std::vector<pointer_type> batch_type; |
|
21 |
|
|
|
22 |
|
Batch() = default; |
|
23 |
|
virtual ~Batch() = default; |
|
24 |
|
Batch(const Batch&) = delete; |
|
25 |
|
Batch& operator=(const Batch&) = delete; |
|
26 |
|
|
|
27 |
|
listener_type hook(callback_type); |
|
28 |
|
void unhook(); |
|
29 |
|
|
|
30 |
|
template <class ... V> |
|
31 |
|
void traverse(V ...); |
|
32 |
|
|
|
33 |
|
template <class ... V> |
|
34 |
|
void traverse_destructive(V ...); |
|
35 |
|
|
|
36 |
|
batch_type& elements(); |
|
37 |
|
const batch_type& elements() const; |
|
38 |
|
|
|
39 |
|
void merge_added_elements(); |
|
40 |
|
|
|
41 |
|
private: |
|
42 |
|
batch_type m_elements; |
|
43 |
|
batch_type m_elements_add; |
|
44 |
|
}; |
|
45 |
|
|
|
46 |
|
namespace utils { |
|
47 |
|
|
|
48 |
|
template <typename T, typename ... V> |
|
49 |
|
void process_and_kill(T&, V...); |
|
50 |
|
|
|
51 |
|
template <typename T, typename ... V> |
|
52 |
|
void process(T&, V...); |
|
53 |
|
|
|
54 |
|
template <typename T> |
|
55 |
|
void kill_all(T&); |
|
56 |
|
} |
|
57 |
|
|
|
58 |
|
} //control |
|
59 |
|
} // om636 |
|
60 |
|
|
|
61 |
|
#include "batch.hxx" |
|
62 |
|
|
|
63 |
|
#endif |
|
File src/batch.hxx deleted (index 49fe368..0000000) |
1 |
|
namespace om636 { |
|
2 |
|
namespace control { |
|
3 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
4 |
|
template <typename T> |
|
5 |
|
auto Batch<T>::hook(callback_type c) -> listener_type |
|
6 |
|
{ |
|
7 |
|
listener_type agent(std::make_shared<agent_type>(c)); |
|
8 |
|
m_elements_add.push_back(agent); |
|
9 |
|
return agent; |
|
10 |
|
} |
|
11 |
|
|
|
12 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
13 |
|
template <typename T> |
|
14 |
|
void Batch<T>::unhook() |
|
15 |
|
{ |
|
16 |
|
utils::kill_all(elements()); |
|
17 |
|
utils::kill_all(m_elements_add); |
|
18 |
|
} |
|
19 |
|
|
|
20 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
21 |
|
template <typename T> |
|
22 |
|
template <class ... V> |
|
23 |
|
void Batch<T>::traverse(V ... arg) |
|
24 |
|
{ |
|
25 |
|
merge_added_elements(); |
|
26 |
|
|
|
27 |
|
utils::process(elements(), arg ... ); |
|
28 |
|
} |
|
29 |
|
|
|
30 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
31 |
|
template <typename T> |
|
32 |
|
template <class ... V> |
|
33 |
|
void Batch<T>::traverse_destructive(V ... arg) |
|
34 |
|
{ |
|
35 |
|
merge_added_elements(); |
|
36 |
|
|
|
37 |
|
utils::process_and_kill(elements(), arg ...); |
|
38 |
|
} |
|
39 |
|
|
|
40 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
41 |
|
template <typename T> |
|
42 |
|
auto Batch<T>::elements() -> batch_type& |
|
43 |
|
{ |
|
44 |
|
return m_elements; |
|
45 |
|
} |
|
46 |
|
|
|
47 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
48 |
|
template <typename T> |
|
49 |
|
auto Batch<T>::elements() const -> const batch_type& |
|
50 |
|
{ |
|
51 |
|
return m_elements; |
|
52 |
|
} |
|
53 |
|
|
|
54 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
55 |
|
template <typename T> |
|
56 |
|
void Batch<T>::merge_added_elements() |
|
57 |
|
{ |
|
58 |
|
elements().insert(elements().end(), m_elements_add.begin(), m_elements_add.end()); |
|
59 |
|
m_elements_add.clear(); |
|
60 |
|
} |
|
61 |
|
|
|
62 |
|
namespace utils { |
|
63 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
64 |
|
template <typename T, typename ... V> |
|
65 |
|
void process(T& elements, V ... v) |
|
66 |
|
{ |
|
67 |
|
T copy(elements); |
|
68 |
|
for_each(copy.begin(), copy.end(), [&](typename T::value_type p) { |
|
69 |
|
auto s(p.lock()); |
|
70 |
|
if (s && !s->is_dead()) |
|
71 |
|
s->invoke(v ...); |
|
72 |
|
//else |
|
73 |
|
//elements.erase(p); |
|
74 |
|
}); |
|
75 |
|
} |
|
76 |
|
|
|
77 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
78 |
|
template <typename T, typename ... V> |
|
79 |
|
void process_and_kill(T& elements, V ... v) |
|
80 |
|
{ |
|
81 |
|
T copy(elements); |
|
82 |
|
for_each(copy.begin(), copy.end(), [&](typename T::value_type p) { |
|
83 |
|
auto s(p.lock()); |
|
84 |
|
if (s && !s->is_dead()) |
|
85 |
|
s->kill_invoke(v ...); |
|
86 |
|
}); |
|
87 |
|
elements.clear(); |
|
88 |
|
} |
|
89 |
|
|
|
90 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
91 |
|
template <typename T> |
|
92 |
|
void kill_all(T& elements) |
|
93 |
|
{ |
|
94 |
|
for_each(elements.begin(), elements.end(), [](typename T::value_type p) { |
|
95 |
|
auto s(p.lock()); |
|
96 |
|
if (s) { |
|
97 |
|
s->kill(); |
|
98 |
|
} |
|
99 |
|
}); |
|
100 |
|
elements.clear(); |
|
101 |
|
} |
|
102 |
|
} // utils |
|
103 |
|
} // control |
|
104 |
|
} // om636 |
|
File src/impl/batch.h added (mode: 100644) (index 0000000..fe6e79f) |
|
1 |
|
#pragma once |
|
2 |
|
|
|
3 |
|
#include <algorithm> |
|
4 |
|
#include <memory> |
|
5 |
|
#include <vector> |
|
6 |
|
|
|
7 |
|
#include <lib/circuit/src/impl/circuit_host.h> |
|
8 |
|
#include <lib/circuit/src/impl/queue.h> |
|
9 |
|
#include <lib/circuit/src/impl/stack.h> |
|
10 |
|
|
|
11 |
|
#include "../interface.h" |
|
12 |
|
|
|
13 |
|
namespace om636 { |
|
14 |
|
namespace control { |
|
15 |
|
|
|
16 |
|
template <template <typename> typename P, typename... T> |
|
17 |
|
class BatchImpl : public Batch<T...> { |
|
18 |
|
public: |
|
19 |
|
typedef Batch<T...> base_type; |
|
20 |
|
using typename base_type::agent_type; |
|
21 |
|
using typename base_type::function_type; |
|
22 |
|
|
|
23 |
|
~BatchImpl() override = default; |
|
24 |
|
agent_type hook(function_type) override; |
|
25 |
|
agent_type hook_once(function_type) override; |
|
26 |
|
void invoke(T...) override; |
|
27 |
|
|
|
28 |
|
typedef std::weak_ptr<typename agent_type::element_type> pointer_type; |
|
29 |
|
typedef std::tuple<pointer_type, bool> tuple_type; |
|
30 |
|
typedef circuit::CircuitHost<tuple_type, P> batch_type; |
|
31 |
|
batch_type& impl_ref(); |
|
32 |
|
const batch_type& impl_ref() const; |
|
33 |
|
|
|
34 |
|
private: |
|
35 |
|
template <typename U> |
|
36 |
|
void invoke(U, T...); |
|
37 |
|
|
|
38 |
|
batch_type m_impl; |
|
39 |
|
}; |
|
40 |
|
|
|
41 |
|
} //control |
|
42 |
|
} // om636 |
|
43 |
|
|
|
44 |
|
#include "batch.hxx" |
File src/impl/batch.hxx added (mode: 100644) (index 0000000..877b294) |
|
1 |
|
namespace om636 { |
|
2 |
|
namespace control { |
|
3 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
4 |
|
template <template <typename> typename P, typename... T> |
|
5 |
|
auto BatchImpl<P, T...>::hook(function_type callback) -> agent_type |
|
6 |
|
{ |
|
7 |
|
using namespace std; |
|
8 |
|
auto agent(make_shared<function_type>(callback)); |
|
9 |
|
impl_ref().push(make_tuple<pointer_type, bool>(agent, true)); |
|
10 |
|
return agent; |
|
11 |
|
} |
|
12 |
|
|
|
13 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
14 |
|
template <template <typename> typename P, typename... T> |
|
15 |
|
auto BatchImpl<P, T...>::hook_once(function_type callback) -> agent_type |
|
16 |
|
{ |
|
17 |
|
using namespace std; |
|
18 |
|
auto agent(make_shared<function_type>(callback)); |
|
19 |
|
impl_ref().push(make_tuple<pointer_type, bool>(agent, false)); |
|
20 |
|
return agent; |
|
21 |
|
} |
|
22 |
|
|
|
23 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
24 |
|
template <template <typename> typename P, typename... T> |
|
25 |
|
void BatchImpl<P, T...>::invoke(T... arg) |
|
26 |
|
{ |
|
27 |
|
using namespace std; |
|
28 |
|
batch_type traverse; |
|
29 |
|
traverse.swap(impl_ref()); |
|
30 |
|
tuple_type agent; |
|
31 |
|
while (traverse.check_pop(agent)) { |
|
32 |
|
agent_type s(get<0>(agent).lock()); |
|
33 |
|
if (s) { |
|
34 |
|
(*s)(arg...); |
|
35 |
|
} |
|
36 |
|
s = get<0>(agent).lock(); |
|
37 |
|
if (s && get<1>(agent)) { |
|
38 |
|
impl_ref().push(move(agent)); |
|
39 |
|
} |
|
40 |
|
} |
|
41 |
|
} |
|
42 |
|
|
|
43 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
44 |
|
template <template <typename> typename P, typename... T> |
|
45 |
|
auto BatchImpl<P, T...>::impl_ref() -> batch_type& |
|
46 |
|
{ |
|
47 |
|
return m_impl; |
|
48 |
|
} |
|
49 |
|
|
|
50 |
|
///////////////////////////////////////////////////////////////////////////////////// |
|
51 |
|
template <template <typename> typename P, typename... T> |
|
52 |
|
auto BatchImpl<P, T...>::impl_ref() const -> const batch_type& |
|
53 |
|
{ |
|
54 |
|
return m_impl; |
|
55 |
|
} |
|
56 |
|
|
|
57 |
|
template <typename... T> |
|
58 |
|
std::shared_ptr<Batch<T...>> make_queue() |
|
59 |
|
{ |
|
60 |
|
return std::make_shared<BatchImpl<om636::circuit::QueuePolicy, T...>>(); |
|
61 |
|
} |
|
62 |
|
|
|
63 |
|
template <typename... T> |
|
64 |
|
std::shared_ptr<Batch<T...>> make_stack() |
|
65 |
|
{ |
|
66 |
|
return std::make_shared<BatchImpl<om636::circuit::StackPolicy, T...>>(); |
|
67 |
|
} |
|
68 |
|
} // control |
|
69 |
|
} // om636 |
File test/lib/circuit/src/impl/circuit_host.h added (mode: 100644) (index 0000000..375f033) |
|
1 |
|
#pragma once |
|
2 |
|
|
|
3 |
|
#include <condition_variable> |
|
4 |
|
#include <mutex> |
|
5 |
|
#include <thread> |
|
6 |
|
|
|
7 |
|
#include "../interface.h" |
|
8 |
|
|
|
9 |
|
namespace om636 { |
|
10 |
|
namespace circuit { |
|
11 |
|
|
|
12 |
|
template <typename T, template <typename> class U> |
|
13 |
|
struct CircuitHost |
|
14 |
|
: Circuit<T>, |
|
15 |
|
U<T> { |
|
16 |
|
typedef Circuit<T> base_type; |
|
17 |
|
using typename base_type::value_type; |
|
18 |
|
|
|
19 |
|
CircuitHost() = default; |
|
20 |
|
CircuitHost(const CircuitHost&); |
|
21 |
|
CircuitHost(CircuitHost&&); |
|
22 |
|
CircuitHost& operator=(CircuitHost); |
|
23 |
|
|
|
24 |
|
void swap(CircuitHost&); |
|
25 |
|
bool empty() const; |
|
26 |
|
bool is_locked() const; |
|
27 |
|
|
|
28 |
|
~CircuitHost() override = default; |
|
29 |
|
void push(value_type&&) override; |
|
30 |
|
bool check_pop(value_type&) override; |
|
31 |
|
void wait_pop(value_type&) override; |
|
32 |
|
CircuitHost* clone() const override; |
|
33 |
|
|
|
34 |
|
private: |
|
35 |
|
typedef U<T> policy_type; |
|
36 |
|
typedef std::lock_guard<std::mutex> lock_type; |
|
37 |
|
typedef std::mutex mutex_type; |
|
38 |
|
|
|
39 |
|
mutable mutex_type m_mutex; |
|
40 |
|
std::condition_variable m_condition; |
|
41 |
|
}; |
|
42 |
|
|
|
43 |
|
} // circuit |
|
44 |
|
} // om636 |
|
45 |
|
|
|
46 |
|
#include "circuit_host.hxx" |
File test/lib/circuit/src/impl/circuit_host.hxx added (mode: 100644) (index 0000000..fdf9742) |
|
1 |
|
namespace om636 { |
|
2 |
|
namespace circuit { |
|
3 |
|
|
|
4 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
5 |
|
template <typename T, template <typename> class U> |
|
6 |
|
CircuitHost<T, U>::CircuitHost(const CircuitHost& rhs) |
|
7 |
|
{ |
|
8 |
|
typedef std::unique_lock<mutex_type> lock_type; |
|
9 |
|
|
|
10 |
|
lock_type left_lock(m_mutex, std::defer_lock); |
|
11 |
|
lock_type right_lock(rhs.m_mutex, std::defer_lock); |
|
12 |
|
std::lock(left_lock, right_lock); |
|
13 |
|
|
|
14 |
|
policy_type::on_copy(*this, rhs); |
|
15 |
|
} |
|
16 |
|
|
|
17 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
18 |
|
template <typename T, template <typename> class U> |
|
19 |
|
CircuitHost<T, U>::CircuitHost(CircuitHost&& rhs) |
|
20 |
|
{ |
|
21 |
|
lock_type lock(m_mutex); |
|
22 |
|
policy_type::on_init(*this, rhs); |
|
23 |
|
} |
|
24 |
|
|
|
25 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
26 |
|
template <typename T, template <typename> class U> |
|
27 |
|
CircuitHost<T, U>& CircuitHost<T, U>::operator=(CircuitHost rhs) |
|
28 |
|
{ |
|
29 |
|
swap(rhs); |
|
30 |
|
return *this; |
|
31 |
|
} |
|
32 |
|
|
|
33 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
34 |
|
template <typename T, template <typename> class U> |
|
35 |
|
void CircuitHost<T, U>::swap(CircuitHost& rhs) |
|
36 |
|
{ |
|
37 |
|
if (this == &rhs) |
|
38 |
|
return; |
|
39 |
|
|
|
40 |
|
typedef std::unique_lock<mutex_type> lock_type; |
|
41 |
|
|
|
42 |
|
lock_type left_lock(m_mutex, std::defer_lock); |
|
43 |
|
lock_type right_lock(rhs.m_mutex, std::defer_lock); |
|
44 |
|
std::lock(left_lock, right_lock); |
|
45 |
|
|
|
46 |
|
policy_type::on_swap(*this, rhs); |
|
47 |
|
} |
|
48 |
|
|
|
49 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
50 |
|
template <typename T, template <typename> class U> |
|
51 |
|
bool CircuitHost<T, U>::empty() const |
|
52 |
|
{ |
|
53 |
|
lock_type lock(m_mutex); |
|
54 |
|
return policy_type::on_empty(*this); |
|
55 |
|
} |
|
56 |
|
|
|
57 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
58 |
|
template <typename T, template <typename> class U> |
|
59 |
|
bool CircuitHost<T, U>::is_locked() const |
|
60 |
|
{ |
|
61 |
|
bool result(false); |
|
62 |
|
std::thread([this, &result]() { |
|
63 |
|
result = m_mutex.try_lock(); |
|
64 |
|
if (result) { |
|
65 |
|
m_mutex.unlock(); |
|
66 |
|
} |
|
67 |
|
}).join(); |
|
68 |
|
return !result; |
|
69 |
|
} |
|
70 |
|
|
|
71 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
72 |
|
template <typename T, template <typename> class U> |
|
73 |
|
void CircuitHost<T, U>::push(value_type&& v) |
|
74 |
|
{ |
|
75 |
|
lock_type lock(m_mutex); |
|
76 |
|
|
|
77 |
|
policy_type::on_push(*this, std::move(v)); |
|
78 |
|
m_condition.notify_one(); |
|
79 |
|
} |
|
80 |
|
|
|
81 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
82 |
|
template <typename T, template <typename> class U> |
|
83 |
|
bool CircuitHost<T, U>::check_pop(value_type& value) |
|
84 |
|
{ |
|
85 |
|
lock_type lock(m_mutex); |
|
86 |
|
|
|
87 |
|
if (policy_type::on_empty(*this)) |
|
88 |
|
return false; |
|
89 |
|
|
|
90 |
|
policy_type::on_pop(*this, value); |
|
91 |
|
return true; |
|
92 |
|
} |
|
93 |
|
|
|
94 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
95 |
|
template <typename T, template <typename> class U> |
|
96 |
|
void CircuitHost<T, U>::wait_pop(value_type& value) |
|
97 |
|
{ |
|
98 |
|
std::unique_lock<std::mutex> lock(m_mutex); |
|
99 |
|
m_condition.wait(lock, [this] { return !policy_type::on_empty(*this); }); |
|
100 |
|
policy_type::on_pop(*this, value); |
|
101 |
|
} |
|
102 |
|
|
|
103 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
104 |
|
template <typename T, template <typename> class U> |
|
105 |
|
auto CircuitHost<T, U>::clone() const -> CircuitHost* |
|
106 |
|
{ |
|
107 |
|
return new CircuitHost(*this); |
|
108 |
|
} |
|
109 |
|
|
|
110 |
|
} // circuit |
|
111 |
|
} // om636 |
File test/lib/circuit/src/impl/queue.h added (mode: 100644) (index 0000000..b4aaa20) |
|
1 |
|
#pragma once |
|
2 |
|
|
|
3 |
|
#include <queue> |
|
4 |
|
|
|
5 |
|
namespace om636 { |
|
6 |
|
namespace circuit { |
|
7 |
|
|
|
8 |
|
template <typename T> |
|
9 |
|
struct QueuePolicy { |
|
10 |
|
typedef T value_type; |
|
11 |
|
|
|
12 |
|
template <class U> |
|
13 |
|
static void on_init(U& lhs, U&& rhs) |
|
14 |
|
{ |
|
15 |
|
ASSERT(lhs.is_locked()); |
|
16 |
|
ASSERT(rhs.is_locked()); |
|
17 |
|
lhs.m_queue = std::move(rhs.m_queue); |
|
18 |
|
} |
|
19 |
|
|
|
20 |
|
template <class U> |
|
21 |
|
static void on_copy(U& lhs, const U& rhs) |
|
22 |
|
{ |
|
23 |
|
ASSERT(lhs.is_locked()); |
|
24 |
|
ASSERT(rhs.is_locked()); |
|
25 |
|
lhs.m_queue = rhs.m_queue; |
|
26 |
|
} |
|
27 |
|
|
|
28 |
|
template <class U> |
|
29 |
|
static void on_swap(U& lhs, U& rhs) |
|
30 |
|
{ |
|
31 |
|
ASSERT(lhs.is_locked()); |
|
32 |
|
ASSERT(rhs.is_locked()); |
|
33 |
|
lhs.m_queue.swap(rhs.m_queue); |
|
34 |
|
} |
|
35 |
|
|
|
36 |
|
template <class U> |
|
37 |
|
static void on_pop(U& lhs, value_type& v) |
|
38 |
|
{ |
|
39 |
|
ASSERT(lhs.is_locked()); |
|
40 |
|
v = std::move(lhs.m_queue.front()); |
|
41 |
|
lhs.m_queue.pop(); |
|
42 |
|
} |
|
43 |
|
|
|
44 |
|
template <class U> |
|
45 |
|
static void on_push(U& lhs, value_type&& v) |
|
46 |
|
{ |
|
47 |
|
ASSERT(lhs.is_locked()); |
|
48 |
|
lhs.m_queue.push(std::move(v)); |
|
49 |
|
} |
|
50 |
|
|
|
51 |
|
template <class U> |
|
52 |
|
static bool on_empty(U& h) |
|
53 |
|
{ |
|
54 |
|
ASSERT(h.is_locked()); |
|
55 |
|
return h.m_queue.empty(); |
|
56 |
|
} |
|
57 |
|
|
|
58 |
|
private: |
|
59 |
|
std::queue<value_type> m_queue; |
|
60 |
|
}; |
|
61 |
|
|
|
62 |
|
} // circuit |
|
63 |
|
} // om636 |
File test/lib/circuit/src/impl/stack.h added (mode: 100644) (index 0000000..20c2f4c) |
|
1 |
|
#pragma once |
|
2 |
|
|
|
3 |
|
#include <stack> |
|
4 |
|
|
|
5 |
|
namespace om636 { |
|
6 |
|
namespace circuit { |
|
7 |
|
|
|
8 |
|
template <typename T> |
|
9 |
|
struct StackPolicy { |
|
10 |
|
typedef T value_type; |
|
11 |
|
|
|
12 |
|
template <class U> |
|
13 |
|
static void on_copy(U& lhs, const U& rhs) |
|
14 |
|
{ |
|
15 |
|
ASSERT(lhs.is_locked()); |
|
16 |
|
ASSERT(rhs.is_locked()); |
|
17 |
|
lhs.m_stack = rhs.m_stack; |
|
18 |
|
} |
|
19 |
|
|
|
20 |
|
template <class U> |
|
21 |
|
static void on_init(U& lhs, U&& rhs) |
|
22 |
|
{ |
|
23 |
|
ASSERT(lhs.is_locked()); |
|
24 |
|
ASSERT(rhs.is_locked()); |
|
25 |
|
lhs.m_stack = std::move(rhs.m_stack); |
|
26 |
|
} |
|
27 |
|
|
|
28 |
|
template <class U> |
|
29 |
|
static void on_swap(U& lhs, U& rhs) |
|
30 |
|
{ |
|
31 |
|
ASSERT(lhs.is_locked()); |
|
32 |
|
ASSERT(rhs.is_locked()); |
|
33 |
|
lhs.m_stack.swap(rhs.m_stack); |
|
34 |
|
} |
|
35 |
|
|
|
36 |
|
template <class U> |
|
37 |
|
static void on_pop(U& lhs, value_type& v) |
|
38 |
|
{ |
|
39 |
|
ASSERT(lhs.is_locked()); |
|
40 |
|
v = std::move(lhs.m_stack.top()); |
|
41 |
|
lhs.m_stack.pop(); |
|
42 |
|
} |
|
43 |
|
|
|
44 |
|
template <class U> |
|
45 |
|
static void on_push(U& lhs, value_type&& v) |
|
46 |
|
{ |
|
47 |
|
ASSERT(lhs.is_locked()); |
|
48 |
|
lhs.m_stack.push(std::move(v)); |
|
49 |
|
} |
|
50 |
|
|
|
51 |
|
template <class U> |
|
52 |
|
static bool on_empty(U& h) |
|
53 |
|
{ |
|
54 |
|
ASSERT(h.is_locked()); |
|
55 |
|
return h.m_stack.empty(); |
|
56 |
|
} |
|
57 |
|
|
|
58 |
|
private: |
|
59 |
|
std::stack<value_type> m_stack; |
|
60 |
|
}; |
|
61 |
|
|
|
62 |
|
} // circuit |
|
63 |
|
} // om636 |
File test/src/batch.h changed (mode: 100644) (index d597c61..47cff77) |
|
1 |
|
#include <lib/circuit/src/impl/queue.h> |
|
2 |
|
|
|
3 |
|
using namespace om636::control; |
1 |
4 |
using namespace om636; |
using namespace om636; |
2 |
5 |
using namespace std; |
using namespace std; |
|
6 |
|
using namespace om636::circuit; |
3 |
7 |
|
|
4 |
|
typedef std::function<void()> callback_type; |
|
5 |
|
typedef control::Batch<callback_type> batch_type; |
|
6 |
|
|
|
7 |
|
void check_traverse_with_arg() |
|
|
8 |
|
void check_unhook_while_traverse() |
8 |
9 |
{ |
{ |
9 |
|
typedef function<void(int)> callback_type; |
|
10 |
|
typedef control::Batch<callback_type> batch_type; |
|
|
10 |
|
BatchImpl<QueuePolicy> batch; |
|
11 |
|
unsigned passed(0); |
11 |
12 |
|
|
12 |
|
unsigned test_passed(0); |
|
|
13 |
|
typename BatchImpl<QueuePolicy>::listener_type temp(batch.hook([&]() { |
|
14 |
|
++passed; |
|
15 |
|
temp.reset(); |
|
16 |
|
})); |
|
17 |
|
|
|
18 |
|
batch.invoke(); |
|
19 |
|
batch.invoke(); |
|
20 |
|
|
|
21 |
|
ASSERT(passed == 1) |
|
22 |
|
(passed); |
|
23 |
|
} |
|
24 |
|
|
|
25 |
|
void dead_agent_removal() |
|
26 |
|
{ |
|
27 |
|
typedef BatchImpl<QueuePolicy, int> batch_type; |
13 |
28 |
batch_type batch; |
batch_type batch; |
|
29 |
|
batch.hook([](int) {}); |
|
30 |
|
batch.invoke(9); |
|
31 |
|
|
|
32 |
|
ASSERT(batch.impl_ref().empty() && "dead agent removal"); |
|
33 |
|
} |
14 |
34 |
|
|
|
35 |
|
void check_traverse_with_arg() |
|
36 |
|
{ |
|
37 |
|
BatchImpl<QueuePolicy, int> batch; |
|
38 |
|
int v = 0; |
15 |
39 |
auto p(batch.hook([&](int i) { |
auto p(batch.hook([&](int i) { |
16 |
|
ASSERT(i == 99); |
|
17 |
|
++test_passed; |
|
|
40 |
|
v = i; |
18 |
41 |
})); |
})); |
19 |
42 |
|
|
20 |
|
batch.traverse(99); |
|
|
43 |
|
batch.invoke(99); |
21 |
44 |
|
|
22 |
|
ASSERT(test_passed == 1); |
|
23 |
|
FOOTER; |
|
|
45 |
|
ASSERT(v == 99); |
24 |
46 |
} |
} |
25 |
47 |
|
|
26 |
48 |
void check_traverse_with_args() |
void check_traverse_with_args() |
27 |
49 |
{ |
{ |
28 |
|
typedef function<void(int, int)> callback_type; |
|
29 |
|
typedef control::Batch<callback_type> batch_type; |
|
|
50 |
|
typedef BatchImpl<QueuePolicy, int, int> batch_type; |
30 |
51 |
|
|
31 |
52 |
unsigned test_passed(0); |
unsigned test_passed(0); |
32 |
53 |
batch_type batch; |
batch_type batch; |
|
... |
... |
void check_traverse_with_args() |
37 |
58 |
++test_passed; |
++test_passed; |
38 |
59 |
})); |
})); |
39 |
60 |
|
|
40 |
|
batch.traverse(99, 3); |
|
|
61 |
|
batch.invoke(99, 3); |
41 |
62 |
|
|
42 |
63 |
ASSERT(test_passed == 1); |
ASSERT(test_passed == 1); |
43 |
|
FOOTER; |
|
44 |
64 |
} |
} |
45 |
65 |
|
|
46 |
66 |
void check_traverse_while_traverse() |
void check_traverse_while_traverse() |
47 |
67 |
{ |
{ |
48 |
|
batch_type batch; |
|
|
68 |
|
BatchImpl<QueuePolicy> batch; |
49 |
69 |
unsigned passed(0); |
unsigned passed(0); |
50 |
70 |
|
|
51 |
71 |
auto p(batch.hook([&]() { |
auto p(batch.hook([&]() { |
52 |
72 |
++passed; |
++passed; |
53 |
|
batch.traverse(); |
|
|
73 |
|
batch.invoke(); |
54 |
74 |
})); |
})); |
55 |
75 |
|
|
56 |
|
batch.traverse(); |
|
|
76 |
|
batch.invoke(); |
57 |
77 |
|
|
58 |
78 |
ASSERT(passed == 1); |
ASSERT(passed == 1); |
59 |
|
FOOTER; |
|
60 |
79 |
} |
} |
61 |
80 |
|
|
62 |
81 |
void check_traverse() |
void check_traverse() |
63 |
82 |
{ |
{ |
64 |
|
batch_type batch; |
|
|
83 |
|
BatchImpl<QueuePolicy> batch; |
65 |
84 |
unsigned passed(0); |
unsigned passed(0); |
66 |
85 |
|
|
67 |
86 |
auto temp(batch.hook([&]() { |
auto temp(batch.hook([&]() { |
68 |
87 |
++passed; |
++passed; |
69 |
88 |
})); |
})); |
70 |
89 |
|
|
71 |
|
batch.traverse(); |
|
72 |
|
batch.traverse(); |
|
|
90 |
|
batch.invoke(); |
|
91 |
|
batch.invoke(); |
73 |
92 |
|
|
74 |
93 |
ASSERT(passed == 2); |
ASSERT(passed == 2); |
75 |
|
FOOTER; |
|
76 |
|
} |
|
|
94 |
|
} |
File test/src/main.cpp changed (mode: 100644) (index 6e4b832..59f5bb6) |
3 |
3 |
|
|
4 |
4 |
#include <tmp/src/test.h> |
#include <tmp/src/test.h> |
5 |
5 |
|
|
6 |
|
#include <lib/dynamo/src/batch.h> |
|
|
6 |
|
#include <lib/dynamo/src/impl/batch.h> |
7 |
7 |
|
|
8 |
8 |
#include "batch.h" |
#include "batch.h" |
9 |
9 |
|
|
10 |
10 |
int main(int argc, const char* argv[]) |
int main(int argc, const char* argv[]) |
11 |
11 |
{ |
{ |
12 |
12 |
check_traverse(); |
check_traverse(); |
13 |
|
//check_traverse_while_traverse(); |
|
|
13 |
|
check_unhook_while_traverse(); |
|
14 |
|
check_traverse_while_traverse(); |
14 |
15 |
check_traverse_with_arg(); |
check_traverse_with_arg(); |
15 |
16 |
check_traverse_with_args(); |
check_traverse_with_args(); |
16 |
|
|
|
|
17 |
|
dead_agent_removal(); |
17 |
18 |
return 0; |
return 0; |
18 |
|
} |
|
|
19 |
|
} |