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