MADARA  3.2.3
VariableNode.cpp
Go to the documentation of this file.
1 
2 #ifndef _MADARA_NO_KARL_
6 #include "VariableExpander.h"
7 
8 
9 #include <string>
10 #include <sstream>
11 
13  const std::string &key,
15 : ComponentNode (context.get_logger ()), key_ (key),
16  context_ (context), key_expansion_necessary_ (false)
17 {
18  // this key requires expansion. We do the compilation and error checking here
19  // as the key shouldn't change, and this allows us to only have to do this
20  // once
21  if (key.find ("{") != key.npos)
22  {
24  "madara::expression::VariableNode: "
25  "Variable %s requires variable expansion.\n",
26  key.c_str ());
27 
29  int num_opens = 0;
30 
31  for (size_t i = 0; i < key.size (); ++i)
32  {
33  if (key[i] == '{')
34  {
35  markers_.push_back (i);
36  ++num_opens;
37  }
38  else if (key[i] == '}')
39  {
40  if (num_opens != 0)
41  {
42  markers_.push_back (i);
43  --num_opens;
44  }
45  else
46  {
47  std::stringstream buffer;
48  buffer << "madara::expression::VariableNode";
49  buffer << ": KARL COMPILE ERROR: matching braces not found in ";
50  buffer << key << "@" << i << "\n";
52  buffer.str ().c_str ());
53 
54  throw KarlException (buffer.str ());
55  }
56  }
57  }
58 
59  if (num_opens > 0)
60  {
61  std::stringstream buffer;
62  buffer << "madara::expression::VariableNode: ";
63  buffer << "KARL COMPILE ERROR: more opening braces than closers in ";
64  buffer << key << "\n";
66  buffer.str ().c_str ());
67 
68  throw KarlException (buffer.str ());
69  }
70  else if (num_opens < 0)
71  {
72  std::stringstream buffer;
73  buffer << "madara::expression::VariableNode: ";
74  buffer << "KARL COMPILE ERROR: more closing braces than openers in ";
75  buffer << key << "\n";
77  buffer.str ().c_str ());
78 
79  throw KarlException (buffer.str ());
80  }
81  }
82  // no variable expansion necessary. Create a hard link to the ref_->
83  // this will save us lots of clock cycles each variable access or
84  // mutation.
85  else
86  {
87  ref_ = context_.get_ref (key);
88  }
89 }
90 
92  size_t opener, size_t & closer) const
93 {
94  size_t i = opener + 1;
95  size_t start = markers_[opener] + 1;
96 
97  std::stringstream builder;
98 
100  "madara::expression::VariableNode:expand_opener: "
101  "key=%s, opener_index=%d, start=%d.\n",
102  key_.c_str (), (int)opener);
103 
104  for (; i < markers_.size (); ++i)
105  {
106  if (key_[markers_[i]] == '{')
107  {
108  // copy before opener (4)
109  if (start < markers_[i])
110  {
111  builder << key_.substr (start, markers_[i] - start);
113  "madara::expression::VariableNode:expand_opener: "
114  "%d-%d{: added %d chars.\n",
115  (int)start, (int)markers_[i], (int)(markers_[i] - start));
116  }
117 
118  size_t sub_opener = i;
119  builder << expand_opener (i, i);
121  "madara::expression::VariableNode:expand_opener: "
122  "get_record(expand_opener()) "
123  "expand_opener(%d, %d).\n",
124  (int)sub_opener, (int)i);
125 
126  // set next start to after [4]{[5]}*[3]
127  start = markers_[i] + 1;
128  }
129  else if (key_[markers_[i]] == '}')
130  {
131  // main action of this function {[2]}
132  closer = i;
133 
134  size_t end = markers_[closer];
135 
136  builder << *context_.get_record (key_.substr (start, end - start));
138  "madara::expression::VariableNode:expand_opener(%d,%d): "
139  "{%d-%d}: added %d chars.\n",
140  (int)opener, (int)closer, (int)start, (int)end, (int)(end-start));
141  break;
142  }
143  }
144 
145  std::string result = builder.str ();
146 
148  "madara::expression::VariableNode:expand_opener(%d,%d): "
149  "return %s\n",
150  (int)opener, (int)closer, result.c_str ());
151 
152  return result;
153 }
154 
157 {
159  {
161  "madara::expression::VariableNode:expand_key: "
162  "Variable %s requires variable expansion"
163  " (%d markers).\n",
164  key_.c_str (), (int)markers_.size ());
165 
166  size_t i = 0;
167  size_t start = 0;
168 
169  // add the first token into a string builder
170  std::stringstream builder;
171 
172  for (; i < markers_.size (); ++i)
173  {
174  if (key_[markers_[i]] == '{')
175  {
176  // copy characters between expansions [1]{
177  if (start < markers_[i])
178  {
179  builder << key_.substr (start, markers_[i] - start);
181  "madara::expression::VariableNode:expand_key: "
182  "%d-%d{: added %d chars.\n",
183  (int)start, (int)markers_[i], (int)(markers_[i] - start));
184  }
185 
186  size_t opener = i;
187  builder << expand_opener (i, i);
189  "madara::expression::VariableNode:expand_key: "
190  "adding results of expand_opener(%d, %d).\n",
191  (int)opener, (int)i);
192 
193  start = markers_[i] + 1;
194  }
195  }
196 
197  // handle characters trailing }[3]
198  if (start < key_.size () && key_.size () - start > 0)
199  {
201  "madara::expression::VariableNode:expand_key: "
202  "substr add from index %d, %d chars.\n",
203  (int)start, (int)key_.size () - start);
204  builder << key_.substr (start, key_.size () - start);
205  }
206 
207  std::string result = builder.str ();
208 
210  "madara::expression::VariableNode:expand_key: "
211  "return %s\n",
212  result.c_str ());
213 
214  return result;
215  }
216  // if there was no need to expand the key, just return
217  // the key
218  else
219  return key_;
220 }
221 
222 
223 void
225 {
226  visitor.visit (*this);
227 }
228 
231 {
232  if (ref_.is_valid())
233  return *ref_.get_record_unsafe();
234  else
235  return context_.get (expand_key ());
236 }
237 
243 {
244  // a variable is one of very few nodes that can change over time and
245  // cannot be pruned
246  can_change = true;
247 
248  // we could call item(), but since it is virtual, it incurs unnecessary
249  // overhead.
250  if (ref_.is_valid())
251  return *ref_.get_record_unsafe();
252  else
253  return context_.get (expand_key ());
254 }
255 
260 {
261  if (ref_.is_valid())
262  return *ref_.get_record_unsafe();
263  else
264  return context_.get (expand_key (), settings);
265 }
266 
267 const std::string &
269 {
270  return key_;
271 }
272 
273 int
277 {
278  int result = 0;
279 
281 
283  "madara::expression::VariableNode::set: "
284  "Attempting to set variable %s to a KnowledgeRecord parameter (%s).\n",
285  key_.c_str (), value.to_string ().c_str ());
286 
287  if (!ref.is_valid())
288  {
289  ref = context_.get_ref (key_, settings);
290  }
291 
292  if (ref.is_valid())
293  {
294  auto record = ref.get_record_unsafe();
295 
296  // notice that we assume the context is locked
297  // check if we have the appropriate write quality
298  if (!settings.always_overwrite && record->write_quality < record->quality)
299  {
300  result = -2;
301  }
302  else
303  {
304  // cheaper to read than write, so check to see if
305  // we actually need to update quality and status
306  if (record->write_quality != record->quality)
307  record->quality = record->write_quality;
308 
310  "madara::expression::VariableNode::set: "
311  "Setting variable %s with KnowledgeRecord assignment operator.\n",
312  key_.c_str ());
313 
314  *record = value;
315 
317  }
318  }
319 
320  return result;
321 }
322 
323 int
326 {
328  "madara::expression::VariableNode::set: "
329  "Attempting to set variable %s to an Integer parameter (%d).\n",
330  key_.c_str (), (int)value);
331 
332  return VariableNode::set (knowledge::KnowledgeRecord (value), settings);
333 }
334 
335 int
338 {
340  "madara::expression::VariableNode::set: "
341  "Attempting to set variable %s to a double parameter (%f).\n",
342  key_.c_str (), value);
343 
344  return VariableNode::set (knowledge::KnowledgeRecord (value), settings);
345 }
346 
347 int
350 {
352  "madara::expression::VariableNode::set: "
353  "Attempting to set variable %s to a string parameter (%s).\n",
354  key_.c_str (), value.c_str ());
355 
356  return VariableNode::set (knowledge::KnowledgeRecord (value), settings);
357 }
358 
362 {
363  if (ref_.is_valid())
364  {
365  auto record = ref_.get_record_unsafe();
366 
367  // notice that we assume the context is locked
368  // check if we have the appropriate write quality
369  if (!settings.always_overwrite && record->write_quality < record->quality)
370  return *record;
371 
372  // cheaper to read than write, so check to see if
373  // we actually need to update quality and status
374  if (record->write_quality != record->quality)
375  record->quality = record->write_quality;
376 
377  --(*record);
378 
379  std::string expanded_key(expand_key());
381 
382  return *record;
383  }
384  else
385  return context_.dec (expand_key(), settings);
386 }
387 
391 {
392  if (ref_.is_valid())
393  {
394  auto record = ref_.get_record_unsafe();
395 
396  // notice that we assume the context is locked
397  // check if we have the appropriate write quality
398  if (!settings.always_overwrite && record->write_quality < record->quality)
399  return *record;
400 
401  // cheaper to read than write, so check to see if
402  // we actually need to update quality and status
403  if (record->write_quality != record->quality)
404  record->quality = record->write_quality;
405 
406  ++(*record);
407 
408  std::string expanded_key(expand_key());
410 
411  return *record;
412  }
413  else
414  return context_.inc (expand_key(), settings);
415 }
416 
417 #endif // _MADARA_NO_KARL_
This class encapsulates an entry in a KnowledgeBase.
madara::knowledge::KnowledgeRecord dec(const madara::knowledge::KnowledgeUpdateSettings &settings=knowledge::KnowledgeUpdateSettings())
Atomically decrement the variable.
uint32_t quality
priority of the update
madara::knowledge::ThreadSafeContext & context_
Definition: VariableNode.h:111
virtual madara::knowledge::KnowledgeRecord evaluate(const madara::knowledge::KnowledgeUpdateSettings &settings)
Evaluates the node and its children.
void mark_and_signal(VariableReference ref, const KnowledgeUpdateSettings &settings=KnowledgeUpdateSettings())
method for marking a record modified and signaling changes
madara::knowledge::VariableReference ref_
Definition: VariableNode.h:109
KnowledgeRecord * get_record_unsafe(void) const
Returns a pointer to the variable&#39;s KnowledgeRecord Do not use this pointer unless you&#39;ve locked the ...
virtual madara::knowledge::KnowledgeRecord prune(bool &can_change)
Prune the tree of unnecessary nodes.
logger::Logger * logger_
handle the context
Definition: ComponentNode.h:97
This class stores variables and their values for use by any entity needing state information in a thr...
Optimized reference to a variable within the knowledge base.
bool is_valid(void) const
Checks to see if the variable reference has been initialized.
const std::string key_
Key for retrieving value of this variable.
Definition: VariableNode.h:108
std::vector< size_t > markers_
Definition: VariableNode.h:116
static struct madara::knowledge::tags::string_t string
madara::knowledge::KnowledgeRecord dec(const std::string &key, const KnowledgeUpdateSettings &settings=KnowledgeUpdateSettings())
Atomically decrements the value of the variable.
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.
An abstract base class defines a simple abstract implementation of an expression tree node...
Definition: ComponentNode.h:36
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:91
VariableReference get_ref(const std::string &key, const KnowledgeReferenceSettings &settings=KnowledgeReferenceSettings())
Atomically returns a reference to the variable.
std::string expand_opener(size_t opener, size_t &closer) const
madara::knowledge::KnowledgeRecord inc(const madara::knowledge::KnowledgeUpdateSettings &settings=knowledge::KnowledgeUpdateSettings())
Atomically increment the variable.
An exception for unrecoverable KaRL compilation issues.
Definition: KarlException.h:18
bool always_overwrite
Toggle for always overwriting records, regardless of quality, clock values, etc.
virtual madara::knowledge::KnowledgeRecord item(void) const
Return the item stored in the node.
KnowledgeRecord * get_record(const std::string &key, const KnowledgeReferenceSettings &settings=KnowledgeReferenceSettings())
Retrieves a knowledge record from the key.
Settings for applying knowledge updates.
virtual void visit(const LeafNode &node)=0
Visit a LeafNode.
madara::knowledge::KnowledgeRecord get(const std::string &key, const KnowledgeReferenceSettings &settings=KnowledgeReferenceSettings()) const
Atomically returns the value of a variable.
std::string to_string(const std::string &delimiter=", ") const
converts the value to a string.
std::string expand_key(void) const
Expands the key (if necessary).
bool key_expansion_necessary_
Expansion necessary.
Definition: VariableNode.h:114
madara::knowledge::KnowledgeRecord inc(const std::string &key, const KnowledgeUpdateSettings &settings=KnowledgeUpdateSettings())
Atomically increments the value of the variable.