MADARA  3.1.8
VariableNode.cpp
Go to the documentation of this file.
1 
2 #ifndef _MADARA_NO_KARL_
6 
7 
8 #include <string>
9 #include <sstream>
10 
12  const std::string &key,
14 : ComponentNode (context.get_logger ()), key_ (key), record_ (0),
15  context_ (context), key_expansion_necessary_ (false)
16 {
17  // this key requires expansion. We do the compilation and error checking here
18  // as the key shouldn't change, and this allows us to only have to do this
19  // once
20  if (key.find ("{") != key.npos)
21  {
23  "Variable %s requires variable expansion.\n",
24  key.c_str ());
25 
27  int num_opens = 0;
28 
29  for (size_t i = 0; i < key.size (); ++i)
30  {
31  if (key[i] == '{')
32  {
33  markers_.push_back (i);
34  ++num_opens;
35  }
36  else if (key[i] == '}')
37  {
38  if (num_opens != 0)
39  {
40  markers_.push_back (i);
41  --num_opens;
42  }
43  else
44  {
46  "KARL COMPILE ERROR: " \
47  "Expanded variable name has a leading closing brace "
48  "instead of opening closing brace at %d\n",
49  (int)i);
50 
51  exit (-1);
52  }
53  }
54  }
55 
56  if (num_opens > 0)
57  {
59  "KARL COMPILE ERROR: " \
60  "Variable name has more opening braces than closing in %s\n",
61  key.c_str ());
62 
63  exit (-1);
64  }
65  else if (num_opens < 0)
66  {
68  "KARL COMPILE ERROR: " \
69  "Variable name has more closing braces than opening in %s\n",
70  key.c_str ());
71  exit (-1);
72  }
73  }
74  // no variable expansion necessary. Create a hard link to the record_->
75  // this will save us lots of clock cycles each variable access or
76  // mutation.
77  else
78  {
79  record_ = context_.get_record (key);
80  }
81 }
82 
84 {
85  // do not clean up record_. Let the context clean that up.
86 }
87 
89  size_t opener, size_t & closer) const
90 {
91  size_t i = opener + 1;
92  size_t start = markers_[opener] + 1;
93 
94  std::stringstream builder;
95 
97  "VariableNode:expand_opener: key=%s, opener_index=%d, start=%d.\n",
98  key_.c_str (), (int)opener);
99 
100  for (; i < markers_.size (); ++i)
101  {
102  if (key_[markers_[i]] == '{')
103  {
104  // copy before opener (4)
105  if (start < markers_[i])
106  {
107  builder << key_.substr (start, markers_[i] - start);
109  "VariableNode:expand_opener: %d-%d{: added %d chars.\n",
110  (int)start, (int)markers_[i], (int)(markers_[i] - start));
111  }
112 
113  size_t sub_opener = i;
114  builder << expand_opener (i, i);
116  "VariableNode:expand_opener: get_record(expand_opener()) "
117  "expand_opener(%d, %d).\n",
118  (int)sub_opener, (int)i);
119 
120  // set next start to after [4]{[5]}*[3]
121  start = markers_[i] + 1;
122  }
123  else if (key_[markers_[i]] == '}')
124  {
125  // main action of this function {[2]}
126  closer = i;
127 
128  size_t end = markers_[closer];
129 
130  builder << *context_.get_record (key_.substr (start, end - start));
132  "VariableNode:expand_opener(%d,%d): {%d-%d}: added %d chars.\n",
133  (int)opener, (int)closer, (int)start, (int)end, (int)(end-start));
134  break;
135  }
136  }
137 
138  std::string result = builder.str ();
139 
141  "VariableNode:expand_opener(%d,%d): return %s\n",
142  (int)opener, (int)closer, result.c_str ());
143 
144  return result;
145 }
146 
149 {
151  {
153  "VariableNode:expand_key: Variable %s requires variable expansion"
154  " (%d markers).\n",
155  key_.c_str (), (int)markers_.size ());
156 
157  size_t i = 0;
158  size_t start = 0;
159 
160  // add the first token into a string builder
161  std::stringstream builder;
162 
163  for (; i < markers_.size (); ++i)
164  {
165  if (key_[markers_[i]] == '{')
166  {
167  // copy characters between expansions [1]{
168  if (start < markers_[i])
169  {
170  builder << key_.substr (start, markers_[i] - start);
172  "VariableNode:expand_key: %d-%d{: added %d chars.\n",
173  (int)start, (int)markers_[i], (int)(markers_[i] - start));
174  }
175 
176  size_t opener = i;
177  builder << expand_opener (i, i);
179  "VariableNode:expand_key: adding results of "
180  "expand_opener(%d, %d).\n",
181  (int)opener, (int)i);
182 
183  start = markers_[i] + 1;
184  }
185  }
186 
187  // handle characters trailing }[3]
188  if (start < key_.size () && key_.size () - start > 0)
189  {
191  "VariableNode:expand_key: substr add from index %d, %d chars.\n",
192  (int)start, (int)key_.size () - start);
193  builder << key_.substr (start, key_.size () - start);
194  }
195 
196  std::string result = builder.str ();
197 
199  "VariableNode:expand_key: return %s\n",
200  result.c_str ());
201 
202  return result;
203  }
204  // if there was no need to expand the key, just return
205  // the key
206  else
207  return key_;
208 }
209 
210 
211 void
213 {
214  visitor.visit (*this);
215 }
216 
219 {
220  if (record_)
221  return *record_;
222  else
223  return context_.get (expand_key ());
224 }
225 
231 {
232  // a variable is one of very few nodes that can change over time and
233  // cannot be pruned
234  can_change = true;
235 
236  // we could call item(), but since it is virtual, it incurs unnecessary
237  // overhead.
238  if (record_)
239  return *record_;
240  else
241  return context_.get (expand_key ());
242 }
243 
248  const madara::knowledge::KnowledgeUpdateSettings & /*settings*/)
249 {
250  // we could call item(), but since it is virtual, it incurs unnecessary
251  // overhead.
252  if (record_)
253  return *record_;
254  else
255  return context_.get (expand_key ());
256 }
257 
258 const std::string &
260 {
261  return key_;
262 }
263 
264 int
268 {
269  int result = 0;
270 
272 
274  "VariableNode::set: "
275  "Attempting to set variable %s to a KnowledgeRecord parameter (%s).\n",
276  key_.c_str (), value.to_string ().c_str ());
277 
278  if (!record)
279  {
280  record = context_.get_record (this->expand_key ());
281  }
282 
283  if (record)
284  {
285  // notice that we assume the context is locked
286  // check if we have the appropriate write quality
287  if (!settings.always_overwrite && record->write_quality < record->quality)
288  {
289  result = -2;
290  }
291  else
292  {
293  // cheaper to read than write, so check to see if
294  // we actually need to update quality and status
295  if (record->write_quality != record->quality)
296  record->quality = record->write_quality;
297 
299  "VariableNode::set: "
300  "Setting variable %s with KnowledgeRecord assignment operator.\n",
301  key_.c_str ());
302 
303  *record = value;
304 
305  std::string expanded_key(expand_key());
306  context_.mark_and_signal (expanded_key.c_str (), record);
307  }
308  }
309 
310  return result;
311 }
312 
313 int
316 {
318  "VariableNode::set: "
319  "Attempting to set variable %s to an Integer parameter (%d).\n",
320  key_.c_str (), (int)value);
321 
322  if (record_)
323  {
324  // notice that we assume the context is locked
325  // check if we have the appropriate write quality
327  return -2;
328 
329  // cheaper to read than write, so check to see if
330  // we actually need to update quality and status
333 
334  record_->set_value (value);
335 
336  std::string expanded_key(expand_key());
337  context_.mark_and_signal (expanded_key.c_str(), record_);
338 
339  return 0;
340  }
341  else
342  return context_.set (expand_key (), value, settings);
343 }
344 
345 int
348 {
350  "VariableNode::set: "
351  "Attempting to set variable %s to a double parameter (%f).\n",
352  key_.c_str (), value);
353 
354  if (record_)
355  {
356  // notice that we assume the context is locked
357  // check if we have the appropriate write quality
359  return -2;
360 
361  // cheaper to read than write, so check to see if
362  // we actually need to update quality and status
365 
366  record_->set_value (value);
367 
368  std::string expanded_key(expand_key());
369  context_.mark_and_signal (expanded_key.c_str(), record_);
370 
371  return 0;
372  }
373  else
374  return context_.set (expand_key (), value, settings);
375 }
376 
377 int
380 {
382  "VariableNode::set: "
383  "Attempting to set variable %s to a string parameter (%s).\n",
384  key_.c_str (), value.c_str ());
385 
386  if (record_)
387  {
388  // notice that we assume the context is locked
389  // check if we have the appropriate write quality
391  return -2;
392 
393  // cheaper to read than write, so check to see if
394  // we actually need to update quality and status
397 
398  record_->set_value (value);
399 
400  std::string expanded_key(expand_key());
401  context_.mark_and_signal (expanded_key.c_str(), record_);
402 
403  return 0;
404  }
405  else
406  return context_.set (expand_key (), value, settings);
407 }
408 
412 {
413  if (record_)
414  {
415  // notice that we assume the context is locked
416  // check if we have the appropriate write quality
418  return *record_;
419 
420  // cheaper to read than write, so check to see if
421  // we actually need to update quality and status
424 
425  --(*record_);
426 
427  std::string expanded_key(expand_key());
428  context_.mark_and_signal (expanded_key.c_str(), record_);
429 
430  return *record_;
431  }
432  else
433  return context_.dec (expand_key (), settings);
434 }
435 
439 {
440  if (record_)
441  {
442  // notice that we assume the context is locked
443  // check if we have the appropriate write quality
445  return *record_;
446 
447  // cheaper to read than write, so check to see if
448  // we actually need to update quality and status
451 
452  ++(*record_);
453 
454  std::string expanded_key(expand_key());
455  context_.mark_and_signal (expanded_key.c_str(), record_);
456 
457  return *record_;
458  }
459  else
460  return context_.inc (expand_key (), settings);
461 }
462 
463 #endif // _MADARA_NO_KARL_
This class encapsulates an entry in a KnowledgeBase.
madara::knowledge::KnowledgeRecord dec(const std::string &key, const KnowledgeUpdateSettings &settings=KnowledgeUpdateSettings())
Atomically decrements the value of the variable.
madara::knowledge::KnowledgeRecord dec(const madara::knowledge::KnowledgeUpdateSettings &settings=knowledge::KnowledgeUpdateSettings())
Atomically decrement the variable.
int set(const std::string &key, T &&value, const KnowledgeUpdateSettings &settings=KnowledgeUpdateSettings())
Atomically sets the value of a variable to the specific record.
madara::knowledge::KnowledgeRecord get(const std::string &key, const KnowledgeReferenceSettings &settings=KnowledgeReferenceSettings()) const
Atomically returns the value of a variable.
uint32_t quality
priority of the update
madara::knowledge::ThreadSafeContext & context_
Definition: VariableNode.h:114
virtual madara::knowledge::KnowledgeRecord evaluate(const madara::knowledge::KnowledgeUpdateSettings &settings)
Evaluates the node and its children.
madara::knowledge::KnowledgeRecord * record_
Definition: VariableNode.h:112
virtual madara::knowledge::KnowledgeRecord prune(bool &can_change)
Prune the tree of unnecessary nodes.
logger::Logger * logger_
handle the context
Definition: ComponentNode.h:96
This class stores variables and their values for use by any entity needing state information in a thr...
const std::string key_
Key for retrieving value of this variable.
Definition: VariableNode.h:111
std::vector< size_t > markers_
Definition: VariableNode.h:119
void set_value(const KnowledgeRecord &new_value)
Sets the value from another KnowledgeRecord, does not copy clock and write_quality.
const std::string & key(void) const
Return the variable key.
#define madara_logger_ptr_log(logger, level,...)
Fast version of the madara::logger::log method for Logger pointers.
Definition: Logger.h:32
int set(const madara::knowledge::KnowledgeRecord::Integer &value, const madara::knowledge::KnowledgeUpdateSettings &settings=knowledge::KnowledgeUpdateSettings())
Sets the value stored in the node.
virtual void accept(Visitor &visitor) const
Define the accept() operation used for the Visitor pattern.
madara::knowledge::KnowledgeRecord inc(const std::string &key, const KnowledgeUpdateSettings &settings=KnowledgeUpdateSettings())
Atomically increments the value of the variable.
An abstract base class defines a simple abstract implementation of an expression tree node...
Definition: ComponentNode.h:35
VariableNode(const std::string &key, madara::knowledge::ThreadSafeContext &context)
Ctor.
Abstract base class for all visitors to all classes that derive from ComponentNode.
Definition: Visitor.h:90
std::string expand_opener(size_t opener, size_t &closer) const
static constexpr struct madara::knowledge::tags::string_t string
madara::knowledge::KnowledgeRecord inc(const madara::knowledge::KnowledgeUpdateSettings &settings=knowledge::KnowledgeUpdateSettings())
Atomically increment the variable.
bool always_overwrite
Toggle for always overwriting records, regardless of quality, clock values, etc.
KnowledgeRecord * get_record(const std::string &key, const KnowledgeReferenceSettings &settings=KnowledgeReferenceSettings())
Retrieves a knowledge record from the key.
virtual madara::knowledge::KnowledgeRecord item(void) const
Return the item stored in the node.
uint32_t write_quality
write priority for any local updates
Settings for applying knowledge updates.
virtual void visit(const LeafNode &node)=0
Visit a LeafNode.
virtual ~VariableNode(void)
Dtor.
std::string to_string(const std::string &delimiter=", ") const
converts the value to a string.
void mark_and_signal(const char *name, knowledge::KnowledgeRecord *record, const KnowledgeUpdateSettings &settings=KnowledgeUpdateSettings())
method for marking a record modified and signaling changes
std::string expand_key(void) const
Expands the key (if necessary).
bool key_expansion_necessary_
Expansion necessary.
Definition: VariableNode.h:117