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>
10 
11 #include "error/ArMemError.h"
12 
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 
133  {
134  std::vector<std::string> allItems = this->getAllItems(true);
135  std::string newID = "";
136  for(int i = 0; i < allItems.size(); i++){
137  if(!allItems.at(i).empty()){
138  std::string toAppend = allItems.at(i);
139  if(allItems.at(i).find(delimiter) != std::string::npos){
140  size_t pos = 0;
141  std::string token;
142  while ((pos = toAppend.find(delimiter)) != std::string::npos) {
143  token = toAppend.substr(0, pos);
144  toAppend.erase(0, pos + delimiter.length());
145  }
146  }
147  newID.append(toAppend);
148  if(i < allItems.size() - 1 && !allItems.at(i+1).empty()){
149  newID.append(delimiter);
150  }
151  }
152  }
153  return MemoryID(newID);
154  }
155 
156 
157  bool
159  {
160  bool emptyFound = false;
161  for (const std::string& item : getAllItems())
162  {
163  if (item.empty())
164  {
165  emptyFound = true;
166  }
167  else if (emptyFound)
168  {
169  // Found a non-empty item after an empty item.
170  return true;
171  }
172  }
173  return false;
174  }
175 
176  bool
178  {
179  return !hasGap();
180  }
181 
182  MemoryID
183  MemoryID::fromString(const std::string& string)
184  {
185  return MemoryID(string);
186  }
187 
188  MemoryID
189  MemoryID::fromItems(const std::vector<std::string>& items)
190  {
191  MemoryID id;
192 
193  std::size_t i = 0;
194  if (i < items.size())
195  {
196  id.memoryName = items[i];
197  ++i;
198  }
199  if (i < items.size())
200  {
201  id.coreSegmentName = items[i];
202  ++i;
203  }
204  if (i < items.size())
205  {
206  id.providerSegmentName = items[i];
207  ++i;
208  }
209  if (i < items.size())
210  {
211  id.entityName = items[i];
212  ++i;
213  }
214  if (i < items.size())
215  {
216  id.timestamp = timestampFromStr(items[i]);
217  ++i;
218  }
219  if (i < items.size())
220  {
221  id.instanceIndex = instanceIndexFromStr(items[i]);
222  ++i;
223  }
224  return id;
225  }
226 
227  std::vector<std::string>
228  MemoryID::getItems(bool escapeDelimiters) const
229  {
230  std::vector<std::string> items;
231 
232  items.push_back(escape(memoryName, escapeDelimiters));
233 
234  if (!hasCoreSegmentName())
235  {
236  return items;
237  }
238  items.push_back(escape(coreSegmentName, escapeDelimiters));
239 
240  if (!hasProviderSegmentName())
241  {
242  return items;
243  }
244  items.push_back(escape(providerSegmentName, escapeDelimiters));
245 
246  if (!hasEntityName())
247  {
248  return items;
249  }
250  items.push_back(escape(entityName, escapeDelimiters));
251 
252  if (!hasTimestamp())
253  {
254  return items;
255  }
256  items.push_back(timestampStr());
257 
258  if (!hasInstanceIndex())
259  {
260  return items;
261  }
262  items.push_back(instanceIndexStr());
263 
264  return items;
265  }
266 
267  std::vector<std::string>
268  MemoryID::getAllItems(bool escapeDelimiters) const
269  {
270  return {
271  escape(memoryName, escapeDelimiters),
272  escape(coreSegmentName, escapeDelimiters),
273  escape(providerSegmentName, escapeDelimiters),
274  escape(entityName, escapeDelimiters),
275  timestampStr(),
277  };
278  }
279 
280  MemoryID
282  {
283  MemoryID id;
284  id.memoryName = memoryName;
285  return id;
286  }
287 
288  MemoryID
290  {
291  MemoryID id = getMemoryID();
292  id.coreSegmentName = coreSegmentName;
293  return id;
294  }
295 
296  MemoryID
298  {
299  MemoryID id = getCoreSegmentID();
300  id.providerSegmentName = providerSegmentName;
301  return id;
302  }
303 
304  MemoryID
306  {
308  id.entityName = entityName;
309  return id;
310  }
311 
312  MemoryID
314  {
315  MemoryID id = getEntityID();
316  id.timestamp = timestamp;
317  return id;
318  }
319 
320  MemoryID
322  {
324  id.instanceIndex = instanceIndex;
325  return id;
326  }
327 
328  MemoryID
330  {
331  if (instanceIndex != -1)
332  {
333  return getEntitySnapshotID();
334  }
335  if (timestamp.isValid())
336  {
337  return getEntityID();
338  }
339  if (!entityName.empty())
340  {
341  return getProviderSegmentID();
342  }
343  if (!providerSegmentName.empty())
344  {
345  return getCoreSegmentID();
346  }
347  if (!coreSegmentName.empty())
348  {
349  return getMemoryID();
350  }
351  return {}; // return empty if already empty. Client needs to check (Avoids using optional as additional include)
352  }
353 
354  void
356  {
357  memoryName = id.memoryName;
358  }
359 
360  void
362  {
363  setMemoryID(id);
364  coreSegmentName = id.coreSegmentName;
365  }
366 
367  void
369  {
370  setCoreSegmentID(id);
371  providerSegmentName = id.providerSegmentName;
372  }
373 
374  void
376  {
378  entityName = id.entityName;
379  }
380 
381  void
383  {
384  setEntityID(id);
385  timestamp = id.timestamp;
386  }
387 
388  void
390  {
392  instanceIndex = id.instanceIndex;
393  }
394 
395  MemoryID
396  MemoryID::withMemoryName(const std::string& name) const
397  {
398  MemoryID id = *this;
399  id.memoryName = name;
400  return id;
401  }
402 
403  MemoryID
404  MemoryID::withCoreSegmentName(const std::string& name) const
405  {
406  MemoryID id = *this;
407  id.coreSegmentName = name;
408  return id;
409  }
410 
411  MemoryID
412  MemoryID::withProviderSegmentName(const std::string& name) const
413  {
414  MemoryID id = *this;
415  id.providerSegmentName = name;
416  return id;
417  }
418 
419  MemoryID
420  MemoryID::withEntityName(const std::string& name) const
421  {
422  MemoryID id = *this;
423  id.entityName = name;
424  return id;
425  }
426 
427  MemoryID
429  {
430  MemoryID id = *this;
431  id.timestamp = time;
432  return id;
433  }
434 
435  MemoryID
437  {
438  MemoryID id = *this;
439  id.instanceIndex = index;
440  return id;
441  }
442 
443  std::string
445  {
447  }
448 
449  std::string
451  {
453  }
454 
455  Time
456  MemoryID::timestampFromStr(const std::string& string)
457  {
458  return Time(Duration::MicroSeconds(parseInteger(string, "timestamp")));
459  }
460 
461  int
462  MemoryID::instanceIndexFromStr(const std::string& string)
463  {
464  return int(parseInteger(string, "instance index"));
465  }
466 
467  bool
468  MemoryID::operator==(const MemoryID& other) const
469  {
470  return memoryName == other.memoryName and coreSegmentName == other.coreSegmentName and
472  entityName == other.entityName and timestamp == other.timestamp and
473  instanceIndex == other.instanceIndex;
474  }
475 
476  bool
477  MemoryID::operator<(const MemoryID& rhs) const
478  {
479  int c = memoryName.compare(rhs.memoryName);
480  if (c != 0)
481  {
482  return c < 0;
483  }
484  // Equal memory name
485  c = coreSegmentName.compare(rhs.coreSegmentName);
486  if (c != 0)
487  {
488  return c < 0;
489  }
490  // Equal core segment ID
492  if (c != 0)
493  {
494  return c < 0;
495  }
496  // Equal provider segment ID
497  c = entityName.compare(rhs.entityName);
498  if (c != 0)
499  {
500  return c < 0;
501  }
502  // Equal entity ID
503  if (timestamp != rhs.timestamp)
504  {
505  return timestamp < rhs.timestamp;
506  }
507  // Equal entity snapshot ID
508  return instanceIndex < rhs.instanceIndex;
509  }
510 
511  long long
512  MemoryID::parseInteger(const std::string& string, const std::string& semanticName)
513  {
514  if (string.empty())
515  {
517  }
518  try
519  {
520  return std::stoll(string);
521  }
522  catch (const std::invalid_argument&)
523  {
524  throw error::ParseIntegerError(string, semanticName);
525  }
526  catch (const std::out_of_range&)
527  {
528  throw error::ParseIntegerError(string, semanticName);
529  }
530  }
531 
532  std::string
533  MemoryID::escapeDelimiter(const std::string& name)
534  {
535  return simox::alg::replace_all(name, delimiter, "\\" + delimiter);
536  }
537 
538  std::string
539  MemoryID::escape(const std::string& name, bool escapeDelimiters)
540  {
541  if (escapeDelimiters)
542  {
543  return escapeDelimiter(name);
544  }
545  else
546  {
547  return name;
548  }
549  }
550 
551  std::ostream&
552  operator<<(std::ostream& os, const MemoryID id)
553  {
554  return os << "'" << id.str() << "'";
555  }
556 
557  bool
558  contains(const MemoryID& general, const MemoryID& specific)
559  {
560  if (!general.isWellDefined())
561  {
562  std::stringstream ss;
563  ss << "\nGeneral ID " << general << " is not well-defined, which is required for `"
564  << __FUNCTION__ << "()`.";
565  throw error::InvalidMemoryID(general, ss.str());
566  }
567  if (!specific.isWellDefined())
568  {
569  std::stringstream ss;
570  ss << "\nSpecific ID " << specific << " is not well-defined, which is required for `"
571  << __FUNCTION__ << "()`.";
572  throw error::InvalidMemoryID(specific, ss.str());
573  }
574 
575  if (general.memoryName.empty())
576  {
577  return true;
578  }
579  else if (general.memoryName != specific.memoryName)
580  {
581  return false;
582  }
583 
584  if (general.coreSegmentName.empty())
585  {
586  return true;
587  }
588  else if (general.coreSegmentName != specific.coreSegmentName)
589  {
590  return false;
591  }
592 
593  if (general.providerSegmentName.empty())
594  {
595  return true;
596  }
597  else if (general.providerSegmentName != specific.providerSegmentName)
598  {
599  return false;
600  }
601 
602  if (general.entityName.empty())
603  {
604  return true;
605  }
606  else if (general.entityName != specific.entityName)
607  {
608  return false;
609  }
610 
611  if (general.timestamp.isInvalid())
612  {
613  return true;
614  }
615  else if (general.timestamp != specific.timestamp)
616  {
617  return false;
618  }
619 
620  if (general.instanceIndex < 0)
621  {
622  return true;
623  }
624  else if (general.instanceIndex != specific.instanceIndex)
625  {
626  return false;
627  }
628 
629  return true;
630  }
631 
632 } // namespace armarx::armem
armarx::armem::MemoryID::isWellDefined
bool isWellDefined() const
Indicate whether this ID is well-defined.
Definition: MemoryID.cpp:177
armarx::armem::MemoryID::timestamp
Time timestamp
Definition: MemoryID.h:54
armarx::armem::MemoryID::setCoreSegmentID
void setCoreSegmentID(const MemoryID &id)
Definition: MemoryID.cpp:361
armarx::armem::MemoryID::getEntityInstanceID
MemoryID getEntityInstanceID() const
Definition: MemoryID.cpp:321
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:456
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:329
armarx::armem::MemoryID::withMemoryName
MemoryID withMemoryName(const std::string &name) const
Definition: MemoryID.cpp:396
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: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:558
armarx::armem::MemoryID::operator==
bool operator==(const MemoryID &other) const
Definition: MemoryID.cpp:468
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:412
armarx::armem::MemoryID
A memory ID.
Definition: MemoryID.h:47
armarx::armem::MemoryID::withCoreSegmentName
MemoryID withCoreSegmentName(const std::string &name) const
Definition: MemoryID.cpp:404
armarx::armem::MemoryID::operator<
bool operator<(const MemoryID &rhs) const
Definition: MemoryID.cpp:477
armarx::armem::MemoryID::getEntitySnapshotID
MemoryID getEntitySnapshotID() const
Definition: MemoryID.cpp:313
armarx::armem::MemoryID::setProviderSegmentID
void setProviderSegmentID(const MemoryID &id)
Definition: MemoryID.cpp:368
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:189
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:382
armarx::armem::MemoryID::hasInstanceIndex
bool hasInstanceIndex() const
Definition: MemoryID.h:139
armarx::armem::MemoryID::getProviderSegmentID
MemoryID getProviderSegmentID() const
Definition: MemoryID.cpp:297
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:158
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:268
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:355
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:183
armarx::core::time::DateTime
Represents a point in time.
Definition: DateTime.h:24
armarx::armem::MemoryID::getCoreSegmentID
MemoryID getCoreSegmentID() const
Definition: MemoryID.cpp:289
armarx::armem::MemoryID::getEntityID
MemoryID getEntityID() const
Definition: MemoryID.cpp:305
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:389
armarx::armem::MemoryID::withEntityName
MemoryID withEntityName(const std::string &name) const
Definition: MemoryID.cpp:420
armarx::armem::MemoryID::cleanID
MemoryID cleanID() const
Definition: MemoryID.cpp:132
armarx::armem::MemoryID::getMemoryID
MemoryID getMemoryID() const
Definition: MemoryID.cpp:281
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:428
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:228
armarx::armem::MemoryID::withInstanceIndex
MemoryID withInstanceIndex(int index) const
Definition: MemoryID.cpp:436
Logging.h
min
T min(T t1, T t2)
Definition: gdiam.h:42
armarx::armem::MemoryID::setEntityID
void setEntityID(const MemoryID &id)
Definition: MemoryID.cpp:375
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:119
armarx::armem::MemoryID::instanceIndexStr
std::string instanceIndexStr() const
Get the instance index as string.
Definition: MemoryID.cpp:450
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:444
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:462