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
14namespace 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
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
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
188 MemoryID::fromString(const std::string& string)
189 {
190 return MemoryID(string);
191 }
192
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
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
287 {
288 MemoryID id;
289 id.memoryName = memoryName;
290 return id;
291 }
292
295 {
296 MemoryID id = getMemoryID();
297 id.coreSegmentName = coreSegmentName;
298 return id;
299 }
300
303 {
305 id.providerSegmentName = providerSegmentName;
306 return id;
307 }
308
311 {
313 id.entityName = entityName;
314 return id;
315 }
316
319 {
320 MemoryID id = getEntityID();
321 id.timestamp = timestamp;
322 return id;
323 }
324
327 {
329 id.instanceIndex = instanceIndex;
330 return id;
331 }
332
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 {
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
401 MemoryID::withMemoryName(const std::string& name) const
402 {
403 MemoryID id = *this;
404 id.memoryName = name;
405 return id;
406 }
407
409 MemoryID::withCoreSegmentName(const std::string& name) const
410 {
411 MemoryID id = *this;
412 id.coreSegmentName = name;
413 return id;
414 }
415
417 MemoryID::withProviderSegmentName(const std::string& name) const
418 {
419 MemoryID id = *this;
420 id.providerSegmentName = name;
421 return id;
422 }
423
425 MemoryID::withEntityName(const std::string& name) const
426 {
427 MemoryID id = *this;
428 id.entityName = name;
429 return id;
430 }
431
434 {
435 MemoryID id = *this;
436 id.timestamp = time;
437 return id;
438 }
439
442 {
443 MemoryID id = *this;
444 id.instanceIndex = index;
445 return id;
446 }
447
448 std::string
450 {
451 return hasTimestamp() ? std::to_string(timestamp.toMicroSecondsSinceEpoch()) : "";
452 }
453
454 std::string
456 {
457 return hasInstanceIndex() ? std::to_string(instanceIndex) : "";
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
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 {
521 return std::numeric_limits<long>::min();
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
constexpr T c
MemoryID getEntitySnapshotID() const
Definition MemoryID.cpp:318
static int instanceIndexFromStr(const std::string &index)
Reconstruct an instance index from a string as returned by instanceIndexStr().
Definition MemoryID.cpp:467
std::string coreSegmentName
Definition MemoryID.h:51
MemoryID withProviderSegmentName(const std::string &name) const
Definition MemoryID.cpp:417
void setProviderSegmentID(const MemoryID &id)
Definition MemoryID.cpp:373
static MemoryID fromItems(const std::vector< std::string > &items)
Constructor memory ID from items as returned by getItems().
Definition MemoryID.cpp:194
MemoryID getProviderSegmentID() const
Definition MemoryID.cpp:302
MemoryID withCoreSegmentName(const std::string &name) const
Definition MemoryID.cpp:409
std::vector< std::string > getAllItems(bool escapeDelimiters=false) const
Get all levels as strings.
Definition MemoryID.cpp:273
static Time timestampFromStr(const std::string &timestamp)
Reconstruct a timestamp from a string as returned by timestampStr().
Definition MemoryID.cpp:461
MemoryID withMemoryName(const std::string &name) const
Definition MemoryID.cpp:401
bool operator<(const MemoryID &rhs) const
Definition MemoryID.cpp:482
MemoryID getMemoryID() const
Definition MemoryID.cpp:286
bool hasProviderSegmentName() const
Definition MemoryID.h:115
void setMemoryID(const MemoryID &id)
Definition MemoryID.cpp:360
bool hasGap() const
Indicate whether this ID has a gap such as in 'Memory//MyProvider' (no core segment name).
Definition MemoryID.cpp:163
MemoryID cleanID() const
Definition MemoryID.cpp:133
std::string getLeafItem() const
Get the lowest defined level (or empty string if there is none).
Definition MemoryID.cpp:119
void setEntitySnapshotID(const MemoryID &id)
Definition MemoryID.cpp:387
bool isWellDefined() const
Indicate whether this ID is well-defined.
Definition MemoryID.cpp:182
MemoryID getCoreSegmentID() const
Definition MemoryID.cpp:294
bool hasEntityName() const
Definition MemoryID.h:121
std::string str(bool escapeDelimiters=true) const
Get a string representation of this memory ID.
Definition MemoryID.cpp:102
bool hasInstanceIndex() const
Definition MemoryID.h:139
MemoryID removeLeafItem() const
Definition MemoryID.cpp:334
MemoryID getEntityInstanceID() const
Definition MemoryID.cpp:326
void setCoreSegmentID(const MemoryID &id)
Definition MemoryID.cpp:366
MemoryID withEntityName(const std::string &name) const
Definition MemoryID.cpp:425
bool hasCoreSegmentName() const
Definition MemoryID.h:109
std::string entityName
Definition MemoryID.h:53
bool operator==(const MemoryID &other) const
Definition MemoryID.cpp:473
MemoryID withTimestamp(Time time) const
Definition MemoryID.cpp:433
bool hasTimestamp() const
Definition MemoryID.h:127
void setEntityInstanceID(const MemoryID &id)
Definition MemoryID.cpp:394
std::vector< std::string > getItems(bool escapeDelimiters=false) const
Get the levels from root to first not defined level (excluding).
Definition MemoryID.cpp:233
std::string memoryName
Definition MemoryID.h:50
std::string instanceIndexStr() const
Get the instance index as string.
Definition MemoryID.cpp:455
std::string timestampStr() const
Get the timestamp as string.
Definition MemoryID.cpp:449
MemoryID withInstanceIndex(int index) const
Definition MemoryID.cpp:441
static MemoryID fromString(const std::string &string)
Alias for constructor from string.
Definition MemoryID.cpp:188
std::string providerSegmentName
Definition MemoryID.h:52
MemoryID()
Construct a default (empty) memory ID.
Definition MemoryID.cpp:20
void setEntityID(const MemoryID &id)
Definition MemoryID.cpp:380
MemoryID getEntityID() const
Definition MemoryID.cpp:310
Indicates that a memory ID is invalid, e.g.
Definition ArMemError.h:152
static Duration MicroSeconds(std::int64_t microSeconds)
Constructs a duration in microseconds.
Definition Duration.cpp:24
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
std::ostream & operator<<(std::ostream &os, const EntityUpdate &rhs)
Definition Commit.cpp:13
armarx::core::time::DateTime Time