6
6
#include < stdint.h>
7
7
#include < unordered_map>
8
8
#include < mutex>
9
+ #include < shared_mutex>
9
10
#include < sstream>
10
11
11
12
#include " behaviortree_cpp/basic_types.h"
12
13
#include " behaviortree_cpp/utils/safe_any.hpp"
13
14
#include " behaviortree_cpp/exceptions.h"
15
+ #include " behaviortree_cpp/utils/locked_reference.hpp"
14
16
15
17
namespace BT
16
18
{
19
+
20
+ using AnyReadRef = LockedConstRef<Any>;
21
+ using AnyWriteRef = LockedRef<Any>;
22
+
17
23
/* *
18
24
* @brief The Blackboard is the mechanism used by BehaviorTrees to exchange
19
25
* typed data.
20
26
*/
21
27
class Blackboard
22
28
{
29
+
23
30
public:
24
31
typedef std::shared_ptr<Blackboard> Ptr;
25
32
@@ -29,6 +36,21 @@ class Blackboard
29
36
{}
30
37
31
38
public:
39
+
40
+ struct Entry
41
+ {
42
+ Any value;
43
+ PortInfo port_info;
44
+ std::shared_mutex entry_mutex;
45
+
46
+ Entry (const PortInfo& info) : port_info(info)
47
+ {}
48
+
49
+ Entry (Any&& other_any, const PortInfo& info) :
50
+ value (std::move(other_any)), port_info(info)
51
+ {}
52
+ };
53
+
32
54
/* * Use this static method to create an instance of the BlackBoard
33
55
* to share among all your NodeTrees.
34
56
*/
@@ -39,13 +61,7 @@ class Blackboard
39
61
40
62
virtual ~Blackboard () = default ;
41
63
42
- /* *
43
- * @brief The method getAny allow the user to access directly the type
44
- * erased value.
45
- *
46
- * @return the pointer or nullptr if it fails.
47
- */
48
- const Any* getAny (const std::string& key) const
64
+ const Entry* getEntry (const std::string& key) const
49
65
{
50
66
std::unique_lock<std::mutex> lock (mutex_);
51
67
// search first if this port was remapped
@@ -56,19 +72,49 @@ class Blackboard
56
72
auto remapping_it = internal_to_external_.find (key);
57
73
if (remapping_it != internal_to_external_.end ())
58
74
{
59
- return parent->getAny (remapping_it->second );
75
+ return parent->getEntry (remapping_it->second );
60
76
}
61
77
}
62
78
}
63
79
auto it = storage_.find (key);
64
- return (it == storage_.end ()) ? nullptr : &( it->second .value );
80
+ return (it == storage_.end ()) ? nullptr : it->second .get ( );
65
81
}
66
82
67
- Any* getAny (const std::string& key)
83
+ Entry* getEntry (const std::string& key)
68
84
{
69
85
// "Avoid Duplication in const and Non-const Member Function,"
70
86
// on p. 23, in Item 3 "Use const whenever possible," in Effective C++, 3d ed
71
- return const_cast <Any*>( static_cast <const Blackboard &>(*this ).getAny (key));
87
+ return const_cast <Entry*>( static_cast <const Blackboard &>(*this ).getEntry (key));
88
+ }
89
+
90
+ AnyReadRef getAnyRead (const std::string& key) const
91
+ {
92
+ if (auto entry = getEntry (key))
93
+ {
94
+ return AnyReadRef (&entry->value , const_cast <std::shared_mutex*>(&entry->entry_mutex ));
95
+ }
96
+ return {};
97
+ }
98
+
99
+ AnyWriteRef getAnyWrite (const std::string& key)
100
+ {
101
+ if (auto entry = getEntry (key))
102
+ {
103
+ return AnyWriteRef (&entry->value , &entry->entry_mutex );
104
+ }
105
+ return {};
106
+ }
107
+
108
+ [[deprecated(" Use getAnyRead instead" )]]
109
+ const Any* getAny (const std::string& key) const
110
+ {
111
+ return getAnyRead (key).get ();
112
+ }
113
+
114
+ [[deprecated(" Use getAnyWrite instead" )]]
115
+ Any* getAny (const std::string& key)
116
+ {
117
+ return getAnyWrite (key).get ();
72
118
}
73
119
74
120
/* * Return true if the entry with the given key was found.
@@ -77,12 +123,12 @@ class Blackboard
77
123
template <typename T>
78
124
bool get (const std::string& key, T& value) const
79
125
{
80
- const Any* val = getAny (key);
81
- if (val)
126
+ if (auto any_ref = getAnyRead (key))
82
127
{
83
- value = val->cast <T>();
128
+ value = any_ref.get ()->cast <T>();
129
+ return true ;
84
130
}
85
- return ( bool )val ;
131
+ return false ;
86
132
}
87
133
88
134
/* *
@@ -91,10 +137,9 @@ class Blackboard
91
137
template <typename T>
92
138
T get (const std::string& key) const
93
139
{
94
- const Any* val = getAny (key);
95
- if (val)
140
+ if (auto any_ref = getAnyRead (key))
96
141
{
97
- return val ->cast <T>();
142
+ return any_ref. get () ->cast <T>();
98
143
}
99
144
else
100
145
{
@@ -106,7 +151,6 @@ class Blackboard
106
151
template <typename T>
107
152
void set (const std::string& key, const T& value)
108
153
{
109
- std::unique_lock lock_entry (entry_mutex_);
110
154
std::unique_lock lock (mutex_);
111
155
112
156
// search first if this port was remapped.
@@ -133,19 +177,21 @@ class Blackboard
133
177
if (std::is_constructible<StringView, T>::value)
134
178
{
135
179
PortInfo new_port (PortDirection::INOUT, typeid (std::string), {});
136
- storage_.emplace (key, Entry (Any (value), new_port));
180
+ storage_.emplace (key, std::make_unique< Entry> (Any (value), new_port));
137
181
}
138
182
else
139
183
{
140
184
PortInfo new_port (PortDirection::INOUT, typeid (T), {});
141
- storage_.emplace (key, Entry (Any (value), new_port));
185
+ storage_.emplace (key, std::make_unique< Entry> (Any (value), new_port));
142
186
}
143
187
}
144
188
else
145
189
{
146
190
// this is not the first time we set this entry, we need to check
147
191
// if the type is the same or not.
148
- Entry& entry = it->second ;
192
+ Entry& entry = *it->second ;
193
+ std::scoped_lock lock (entry.entry_mutex );
194
+
149
195
Any& previous_any = entry.value ;
150
196
const PortInfo& port_info = entry.port_info ;
151
197
@@ -209,30 +255,9 @@ class Blackboard
209
255
storage_.clear ();
210
256
}
211
257
212
- // Lock this mutex before using get() and getAny() and unlock it while you have
213
- // done using the value.
214
- std::recursive_mutex& entryMutex () const
215
- {
216
- return entry_mutex_;
217
- }
218
-
219
258
private:
220
- struct Entry
221
- {
222
- Any value;
223
- PortInfo port_info;
224
-
225
- Entry (const PortInfo& info) : port_info(info)
226
- {}
227
-
228
- Entry (Any&& other_any, const PortInfo& info) :
229
- value (std::move(other_any)), port_info(info)
230
- {}
231
- };
232
-
233
259
mutable std::mutex mutex_;
234
- mutable std::recursive_mutex entry_mutex_;
235
- std::unordered_map<std::string, Entry> storage_;
260
+ std::unordered_map<std::string, std::unique_ptr<Entry>> storage_;
236
261
std::weak_ptr<Blackboard> parent_bb_;
237
262
std::unordered_map<std::string, std::string> internal_to_external_;
238
263
0 commit comments