MemoryID.cpp
Go to the documentation of this file.
1 #include "MemoryID.h"
2 
3 #include <forward_list>
4 
5 #include <boost/algorithm/string.hpp>
6 
7 #include <SimoxUtility/algorithm/advanced.h>
8 #include <SimoxUtility/algorithm/string/string_tools.h>
9 
11 
12 #include "error/ArMemError.h"
13 
14 namespace armarx::armem
15 {
16 
17  // This is constant, not a variable.
18  const std::string MemoryID::delimiter = "/";
19 
21  {
22  }
23 
24  MemoryID::MemoryID(const std::string& string)
25  {
26  //ARMARX_INFO << "Trying to create MemoryID from string";
27  //ARMARX_INFO << VAROUT(string);
28  std::forward_list<std::string> items;
29  boost::split(items, string, boost::is_any_of(delimiter));
30 
31  // Handle escaped /'s
32  for (auto it = items.begin(); it != items.end(); ++it)
33  {
34  while (it->size() > 0 && it->back() == '\\')
35  {
36  // The / causing the split was escaped. Merge the items together.
37  auto next = simox::alg::advanced(it, 1);
38  if (next != items.end())
39  {
40  // "it\" + "next" => "it/next"
41  *it = it->substr(0, it->size() - 1) + delimiter + *next;
42  items.erase_after(it); // Invalidates `next`, but not `it`.
43  }
44  }
45  }
46 
47  auto it = items.begin();
48  if (it == items.end())
49  {
50  return;
51  }
52  this->memoryName = *it;
53 
54  if (++it == items.end())
55  {
56  return;
57  }
58  this->coreSegmentName = *it;
59 
60  if (++it == items.end())
61  {
62  return;
63  }
64  this->providerSegmentName = *it;
65 
66  if (++it == items.end())
67  {
68  return;
69  }
70  this->entityName = *it;
71 
72  if (++it == items.end())
73  {
74  return;
75  }
76  this->timestamp = timestampFromStr(*it);
77 
78  if (++it == items.end())
79  {
80  return;
81  }
83  //ARMARX_INFO << this->str();
84  }
85 
86  MemoryID::MemoryID(const std::string& memoryName,
87  const std::string& coreSegmentName,
88  const std::string& providerSegmentName,
89  const std::string& entityName,
90  Time timestamp,
91  int instanceIndex) :
93  coreSegmentName(coreSegmentName),
94  providerSegmentName(providerSegmentName),
95  entityName(entityName),
96  timestamp(timestamp),
97  instanceIndex(instanceIndex)
98  {
99  }
100 
101  std::string
102  MemoryID::str(bool escapeDelimiters) const
103  {
104  return str(delimiter, escapeDelimiters);
105  }
106 
107  std::string
108  MemoryID::str(const std::string& delimiter, bool escapeDelimiter) const
109  {
110  std::vector<std::string> items = getAllItems(escapeDelimiter);
111  while (items.size() > 0 && items.back().empty())
112  {
113  items.pop_back();
114  }
115  return simox::alg::join(items, delimiter, false, false);
116  }
117 
118  std::string
120  {
121  std::vector<std::string> items = getAllItems();
122  for (auto it = items.rbegin(); it != items.rend(); ++it)
123  {
124  if (!it->empty())
125  {
126  return *it;
127  }
128  }
129  return "";
130  }
131 
132  MemoryID
134  {
135  std::vector<std::string> allItems = this->getAllItems(true);
136  std::string newID = "";
137  for (std::size_t i = 0; i < allItems.size(); i++)
138  {
139  if (!allItems.at(i).empty())
140  {
141  std::string toAppend = allItems.at(i);
142  if (allItems.at(i).find(delimiter) != std::string::npos)
143  {
144  size_t pos = 0;
145  std::string token;
146  while ((pos = toAppend.find(delimiter)) != std::string::npos)
147  {
148  token = toAppend.substr(0, pos);
149  toAppend.erase(0, pos + delimiter.length());
150  }
151  }
152  newID.append(toAppend);
153  if (i < allItems.size() - 1 && !allItems.at(i + 1).empty())
154  {
155  newID.append(delimiter);
156  }
157  }
158  }
159  return MemoryID(newID);
160  }
161 
162  bool
164  {
165  bool emptyFound = false;
166  for (const std::string& item : getAllItems())
167  {
168  if (item.empty())
169  {
170  emptyFound = true;
171  }
172  else if (emptyFound)
173  {
174  // Found a non-empty item after an empty item.
175  return true;
176  }
177  }
178  return false;
179  }
180 
181  bool
183  {
184  return !hasGap();
185  }
186 
187  MemoryID
188  MemoryID::fromString(const std::string& string)
189  {
190  return MemoryID(string);
191  }
192 
193  MemoryID
194  MemoryID::fromItems(const std::vector<std::string>& items)
195  {
196  MemoryID id;
197 
198  std::size_t i = 0;
199  if (i < items.size())
200  {
201  id.memoryName = items[i];
202  ++i;
203  }
204  if (i < items.size())
205  {
206  id.coreSegmentName = items[i];
207  ++i;
208  }
209  if (i < items.size())
210  {
211  id.providerSegmentName = items[i];
212  ++i;
213  }
214  if (i < items.size())
215  {
216  id.entityName = items[i];
217  ++i;
218  }
219  if (i < items.size())
220  {
221  id.timestamp = timestampFromStr(items[i]);
222  ++i;
223  }
224  if (i < items.size())
225  {
226  id.instanceIndex = instanceIndexFromStr(items[i]);
227  ++i;
228  }
229  return id;
230  }
231 
232  std::vector<std::string>
233  MemoryID::getItems(bool escapeDelimiters) const
234  {
235  std::vector<std::string> items;
236 
237  items.push_back(escape(memoryName, escapeDelimiters));
238 
239  if (!hasCoreSegmentName())
240  {
241  return items;
242  }
243  items.push_back(escape(coreSegmentName, escapeDelimiters));
244 
245  if (!hasProviderSegmentName())
246  {
247  return items;
248  }
249  items.push_back(escape(providerSegmentName, escapeDelimiters));
250 
251  if (!hasEntityName())
252  {
253  return items;
254  }
255  items.push_back(escape(entityName, escapeDelimiters));
256 
257  if (!hasTimestamp())
258  {
259  return items;
260  }
261  items.push_back(timestampStr());
262 
263  if (!hasInstanceIndex())
264  {
265  return items;
266  }
267  items.push_back(instanceIndexStr());
268 
269  return items;
270  }
271 
272  std::vector<std::string>
273  MemoryID::getAllItems(bool escapeDelimiters) const
274  {
275  return {
276  escape(memoryName, escapeDelimiters),
277  escape(coreSegmentName, escapeDelimiters),
278  escape(providerSegmentName, escapeDelimiters),
279  escape(entityName, escapeDelimiters),
280  timestampStr(),
282  };
283  }
284 
285  MemoryID
287  {
288  MemoryID id;
289  id.memoryName = memoryName;
290  return id;
291  }
292 
293  MemoryID
295  {
296  MemoryID id = getMemoryID();
297  id.coreSegmentName = coreSegmentName;
298  return id;
299  }
300 
301  MemoryID
303  {
304  MemoryID id = getCoreSegmentID();
305  id.providerSegmentName = providerSegmentName;
306  return id;
307  }
308 
309  MemoryID
311  {
313  id.entityName = entityName;
314  return id;
315  }
316 
317  MemoryID
319  {
320  MemoryID id = getEntityID();
321  id.timestamp = timestamp;
322  return id;
323  }
324 
325  MemoryID
327  {
329  id.instanceIndex = instanceIndex;
330  return id;
331  }
332 
333  MemoryID
335  {
336  if (instanceIndex != -1)
337  {
338  return getEntitySnapshotID();
339  }
340  if (timestamp.isValid())
341  {
342  return getEntityID();
343  }
344  if (!entityName.empty())
345  {
346  return getProviderSegmentID();
347  }
348  if (!providerSegmentName.empty())
349  {
350  return getCoreSegmentID();
351  }
352  if (!coreSegmentName.empty())
353  {
354  return getMemoryID();
355  }
356  return {}; // return empty if already empty. Client needs to check (Avoids using optional as additional include)
357  }
358 
359  void
361  {
362  memoryName = id.memoryName;
363  }
364 
365  void
367  {
368  setMemoryID(id);
369  coreSegmentName = id.coreSegmentName;
370  }
371 
372  void
374  {
375  setCoreSegmentID(id);
376  providerSegmentName = id.providerSegmentName;
377  }
378 
379  void
381  {
383  entityName = id.entityName;
384  }
385 
386  void
388  {
389  setEntityID(id);
390  timestamp = id.timestamp;
391  }
392 
393  void
395  {
397  instanceIndex = id.instanceIndex;
398  }
399 
400  MemoryID
401  MemoryID::withMemoryName(const std::string& name) const
402  {
403  MemoryID id = *this;
404  id.memoryName = name;
405  return id;
406  }
407 
408  MemoryID
409  MemoryID::withCoreSegmentName(const std::string& name) const
410  {
411  MemoryID id = *this;
412  id.coreSegmentName = name;
413  return id;
414  }
415 
416  MemoryID
417  MemoryID::withProviderSegmentName(const std::string& name) const
418  {
419  MemoryID id = *this;
420  id.providerSegmentName = name;
421  return id;
422  }
423 
424  MemoryID
425  MemoryID::withEntityName(const std::string& name) const
426  {
427  MemoryID id = *this;
428  id.entityName = name;
429  return id;
430  }
431 
432  MemoryID
434  {
435  MemoryID id = *this;
436  id.timestamp = time;
437  return id;
438  }
439 
440  MemoryID
442  {
443  MemoryID id = *this;
444  id.instanceIndex = index;
445  return id;
446  }
447 
448  std::string
450  {
452  }
453 
454  std::string
456  {
458  }
459 
460  Time
461  MemoryID::timestampFromStr(const std::string& string)
462  {
463  return Time(Duration::MicroSeconds(parseInteger(string, "timestamp")));
464  }
465 
466  int
467  MemoryID::instanceIndexFromStr(const std::string& string)
468  {
469  return int(parseInteger(string, "instance index"));
470  }
471 
472  bool
473  MemoryID::operator==(const MemoryID& other) const
474  {
475  return memoryName == other.memoryName and coreSegmentName == other.coreSegmentName and
477  entityName == other.entityName and timestamp == other.timestamp and
478  instanceIndex == other.instanceIndex;
479  }
480 
481  bool
482  MemoryID::operator<(const MemoryID& rhs) const
483  {
484  int c = memoryName.compare(rhs.memoryName);
485  if (c != 0)
486  {
487  return c < 0;
488  }
489  // Equal memory name
490  c = coreSegmentName.compare(rhs.coreSegmentName);
491  if (c != 0)
492  {
493  return c < 0;
494  }
495  // Equal core segment ID
497  if (c != 0)
498  {
499  return c < 0;
500  }
501  // Equal provider segment ID
502  c = entityName.compare(rhs.entityName);
503  if (c != 0)
504  {
505  return c < 0;
506  }
507  // Equal entity ID
508  if (timestamp != rhs.timestamp)
509  {
510  return timestamp < rhs.timestamp;
511  }
512  // Equal entity snapshot ID
513  return instanceIndex < rhs.instanceIndex;
514  }
515 
516  long long
517  MemoryID::parseInteger(const std::string& string, const std::string& semanticName)
518  {
519  if (string.empty())
520  {
522  }
523  try
524  {
525  return std::stoll(string);
526  }
527  catch (const std::invalid_argument&)
528  {
529  throw error::ParseIntegerError(string, semanticName);
530  }
531  catch (const std::out_of_range&)
532  {
533  throw error::ParseIntegerError(string, semanticName);
534  }
535  }
536 
537  std::string
538  MemoryID::escapeDelimiter(const std::string& name)
539  {
540  return simox::alg::replace_all(name, delimiter, "\\" + delimiter);
541  }
542 
543  std::string
544  MemoryID::escape(const std::string& name, bool escapeDelimiters)
545  {
546  if (escapeDelimiters)
547  {
548  return escapeDelimiter(name);
549  }
550  else
551  {
552  return name;
553  }
554  }
555 
556  std::ostream&
557  operator<<(std::ostream& os, const MemoryID id)
558  {
559  return os << "'" << id.str() << "'";
560  }
561 
562  bool
563  contains(const MemoryID& general, const MemoryID& specific)
564  {
565  if (!general.isWellDefined())
566  {
567  std::stringstream ss;
568  ss << "\nGeneral ID " << general << " is not well-defined, which is required for `"
569  << __FUNCTION__ << "()`.";
570  throw error::InvalidMemoryID(general, ss.str());
571  }
572  if (!specific.isWellDefined())
573  {
574  std::stringstream ss;
575  ss << "\nSpecific ID " << specific << " is not well-defined, which is required for `"
576  << __FUNCTION__ << "()`.";
577  throw error::InvalidMemoryID(specific, ss.str());
578  }
579 
580  if (general.memoryName.empty())
581  {
582  return true;
583  }
584  else if (general.memoryName != specific.memoryName)
585  {
586  return false;
587  }
588 
589  if (general.coreSegmentName.empty())
590  {
591  return true;
592  }
593  else if (general.coreSegmentName != specific.coreSegmentName)
594  {
595  return false;
596  }
597 
598  if (general.providerSegmentName.empty())
599  {
600  return true;
601  }
602  else if (general.providerSegmentName != specific.providerSegmentName)
603  {
604  return false;
605  }
606 
607  if (general.entityName.empty())
608  {
609  return true;
610  }
611  else if (general.entityName != specific.entityName)
612  {
613  return false;
614  }
615 
616  if (general.timestamp.isInvalid())
617  {
618  return true;
619  }
620  else if (general.timestamp != specific.timestamp)
621  {
622  return false;
623  }
624 
625  if (general.instanceIndex < 0)
626  {
627  return true;
628  }
629  else if (general.instanceIndex != specific.instanceIndex)
630  {
631  return false;
632  }
633 
634  return true;
635  }
636 
637 } // namespace armarx::armem
armarx::armem::MemoryID::isWellDefined
bool isWellDefined() const
Indicate whether this ID is well-defined.
Definition: MemoryID.cpp:182
armarx::armem::MemoryID::timestamp
Time timestamp
Definition: MemoryID.h:54
armarx::armem::MemoryID::setCoreSegmentID
void setCoreSegmentID(const MemoryID &id)
Definition: MemoryID.cpp:366
armarx::armem::MemoryID::getEntityInstanceID
MemoryID getEntityInstanceID() const
Definition: MemoryID.cpp:326
armarx::core::time::DateTime::isValid
bool isValid() const
Definition: DateTime.cpp:123
armarx::armem::MemoryID::timestampFromStr
static Time timestampFromStr(const std::string &timestamp)
Reconstruct a timestamp from a string as returned by timestampStr().
Definition: MemoryID.cpp:461
armarx::core::time::DateTime::isInvalid
bool isInvalid() const
Definition: DateTime.cpp:129
armarx::armem::MemoryID::providerSegmentName
std::string providerSegmentName
Definition: MemoryID.h:52
armarx::armem::MemoryID::removeLeafItem
MemoryID removeLeafItem() const
Definition: MemoryID.cpp:334
armarx::armem::MemoryID::withMemoryName
MemoryID withMemoryName(const std::string &name) const
Definition: MemoryID.cpp:401
index
uint8_t index
Definition: EtherCATFrame.h:59
MemoryID.h
armarx::armem::MemoryID::str
std::string str(bool escapeDelimiters=true) const
Get a string representation of this memory ID.
Definition: MemoryID.cpp:102
armarx::armem
Definition: LegacyRobotStateMemoryAdapter.cpp:32
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
armarx::armem::MemoryID::instanceIndex
int instanceIndex
Definition: MemoryID.h:55
armarx::armem::contains
bool contains(const MemoryID &general, const MemoryID &specific)
Indicates whether general is "less specific" than, or equal to, specific, i.e.
Definition: MemoryID.cpp:563
armarx::armem::MemoryID::operator==
bool operator==(const MemoryID &other) const
Definition: MemoryID.cpp:473
armarx::armem::MemoryID::coreSegmentName
std::string coreSegmentName
Definition: MemoryID.h:51
cxxopts::empty
bool empty(const std::string &s)
Definition: cxxopts.hpp:234
armarx::armem::operator<<
std::ostream & operator<<(std::ostream &os, const EntityUpdate &rhs)
Definition: Commit.cpp:13
ArMemError.h
armarx::armem::MemoryID::withProviderSegmentName
MemoryID withProviderSegmentName(const std::string &name) const
Definition: MemoryID.cpp:417
armarx::armem::MemoryID
A memory ID.
Definition: MemoryID.h:47
armarx::armem::MemoryID::withCoreSegmentName
MemoryID withCoreSegmentName(const std::string &name) const
Definition: MemoryID.cpp:409
armarx::armem::MemoryID::operator<
bool operator<(const MemoryID &rhs) const
Definition: MemoryID.cpp:482
armarx::armem::MemoryID::getEntitySnapshotID
MemoryID getEntitySnapshotID() const
Definition: MemoryID.cpp:318
armarx::armem::MemoryID::setProviderSegmentID
void setProviderSegmentID(const MemoryID &id)
Definition: MemoryID.cpp:373
armarx::armem::MemoryID::fromItems
static MemoryID fromItems(const std::vector< std::string > &items)
Constructor memory ID from items as returned by getItems().
Definition: MemoryID.cpp:194
armarx::armem::MemoryID::MemoryID
MemoryID()
Construct a default (empty) memory ID.
Definition: MemoryID.cpp:20
armarx::armem::MemoryID::hasTimestamp
bool hasTimestamp() const
Definition: MemoryID.h:127
armarx::armem::MemoryID::setEntitySnapshotID
void setEntitySnapshotID(const MemoryID &id)
Definition: MemoryID.cpp:387
armarx::armem::MemoryID::hasInstanceIndex
bool hasInstanceIndex() const
Definition: MemoryID.h:139
armarx::armem::MemoryID::getProviderSegmentID
MemoryID getProviderSegmentID() const
Definition: MemoryID.cpp:302
armarx::armem::MemoryID::hasGap
bool hasGap() const
Indicate whether this ID has a gap such as in 'Memory//MyProvider' (no core segment name).
Definition: MemoryID.cpp:163
armarx::core::time::DateTime::toMicroSecondsSinceEpoch
std::int64_t toMicroSecondsSinceEpoch() const
Definition: DateTime.cpp:87
armarx::armem::MemoryID::getAllItems
std::vector< std::string > getAllItems(bool escapeDelimiters=false) const
Get all levels as strings.
Definition: MemoryID.cpp:273
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
armarx::armem::MemoryID::entityName
std::string entityName
Definition: MemoryID.h:53
armarx::armem::MemoryID::setMemoryID
void setMemoryID(const MemoryID &id)
Definition: MemoryID.cpp:360
armarx::armem::MemoryID::hasEntityName
bool hasEntityName() const
Definition: MemoryID.h:121
armarx::armem::MemoryID::memoryName
std::string memoryName
Definition: MemoryID.h:50
armarx::armem::MemoryID::fromString
static MemoryID fromString(const std::string &string)
Alias for constructor from string.
Definition: MemoryID.cpp:188
armarx::core::time::DateTime
Represents a point in time.
Definition: DateTime.h:24
armarx::armem::MemoryID::getCoreSegmentID
MemoryID getCoreSegmentID() const
Definition: MemoryID.cpp:294
armarx::armem::MemoryID::getEntityID
MemoryID getEntityID() const
Definition: MemoryID.cpp:310
armarx::armem::error::InvalidMemoryID
Indicates that a memory ID is invalid, e.g.
Definition: ArMemError.h:151
armarx::armem::MemoryID::setEntityInstanceID
void setEntityInstanceID(const MemoryID &id)
Definition: MemoryID.cpp:394
armarx::armem::MemoryID::withEntityName
MemoryID withEntityName(const std::string &name) const
Definition: MemoryID.cpp:425
armarx::armem::MemoryID::cleanID
MemoryID cleanID() const
Definition: MemoryID.cpp:133
armarx::armem::MemoryID::getMemoryID
MemoryID getMemoryID() const
Definition: MemoryID.cpp:286
armarx::armem::laser_scans::constants::memoryName
const std::string memoryName
Definition: constants.h:28
armarx::armem::MemoryID::hasProviderSegmentName
bool hasProviderSegmentName() const
Definition: MemoryID.h:115
armarx::armem::MemoryID::hasCoreSegmentName
bool hasCoreSegmentName() const
Definition: MemoryID.h:109
armarx::armem::MemoryID::withTimestamp
MemoryID withTimestamp(Time time) const
Definition: MemoryID.cpp:433
armarx::armem::MemoryID::getItems
std::vector< std::string > getItems(bool escapeDelimiters=false) const
Get the levels from root to first not defined level (excluding).
Definition: MemoryID.cpp:233
armarx::armem::MemoryID::withInstanceIndex
MemoryID withInstanceIndex(int index) const
Definition: MemoryID.cpp:441
Logging.h
min
T min(T t1, T t2)
Definition: gdiam.h:44
armarx::armem::MemoryID::setEntityID
void setEntityID(const MemoryID &id)
Definition: MemoryID.cpp:380
armarx::core::time::Duration::MicroSeconds
static Duration MicroSeconds(std::int64_t microSeconds)
Constructs a duration in microseconds.
Definition: Duration.cpp:24
armarx::armem::MemoryID::getLeafItem
std::string getLeafItem() const
Get the lowest defined level (or empty string if there is none).
Definition: MemoryID.cpp:119
armarx::armem::MemoryID::instanceIndexStr
std::string instanceIndexStr() const
Get the instance index as string.
Definition: MemoryID.cpp:455
armarx::split
std::vector< std::string > split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelpers.cpp:38
armarx::armem::MemoryID::timestampStr
std::string timestampStr() const
Get the timestamp as string.
Definition: MemoryID.cpp:449
armarx::armem::MemoryID::instanceIndexFromStr
static int instanceIndexFromStr(const std::string &index)
Reconstruct an instance index from a string as returned by instanceIndexStr().
Definition: MemoryID.cpp:467