Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkPropertyKeyPath.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include <algorithm>
14 #include <utility>
15 
16 #include <mitkExceptionMacro.h>
17 #include <mitkPropertyKeyPath.h>
18 
19 #include <regex>
20 
21 namespace mitk
22 {
23  PropertyKeyPath::NodeInfo::NodeInfo() : type(NodeType::Invalid), selection(0){};
24 
26  : type(type), name(name), selection(index){};
27 
29  {
30  if (this->name != right.name)
31  return false;
32  if (this->type != right.type)
33  return false;
34  if (this->selection != right.selection)
35  return false;
36 
37  return true;
38  };
39 
41  {
42  if (type == NodeType::Invalid || right.type == NodeType::Invalid)
43  {
44  return false;
45  }
46  else if (type == NodeType::AnyElement || right.type == NodeType::AnyElement)
47  {
48  return true;
49  }
50  else if (name == right.name)
51  {
52  if (type == NodeType::Element && right.type == NodeType::Element)
53  {
54  return true;
55  }
56  else if (selection == right.selection || type == NodeType::AnySelection || right.type == NodeType::AnySelection)
57  {
58  return true;
59  }
60  }
61  return false;
62  };
63 
64  bool PropertyKeyPath::IsEmpty() const { return m_NodeInfos.empty(); };
65 
67  {
68  for (const auto &pos : m_NodeInfos)
69  {
70  if ((pos.type == NodeInfo::NodeType::AnySelection) || (pos.type == NodeInfo::NodeType::AnyElement))
71  {
72  return false;
73  }
74  }
75 
76  return true;
77  };
78 
80  {
81  bool result = false;
82  for (const auto &pos : m_NodeInfos)
83  {
84  if (pos.type == NodeInfo::NodeType::AnyElement)
85  {
86  return false;
87  }
88  result = result || pos.type == NodeInfo::NodeType::AnySelection;
89  }
90 
91  return result;
92  };
93 
95 
97  {
98  m_NodeInfos.push_back(newNode);
99  return m_NodeInfos.size() - 1;
100  };
101 
103  {
104  if (index >= GetSize())
105  {
107  << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index
108  << "; Path: " << PropertyKeyPathToPropertyName(*this);
109  }
110 
111  return m_NodeInfos[index];
112  };
113 
115  {
116  if (index >= this->GetSize())
117  {
119  << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index
120  << "; Path: " << PropertyKeyPathToPropertyName(*this);
121  }
122 
123  return m_NodeInfos[index];
124  };
125 
127  {
128  if (m_NodeInfos.empty())
129  {
130  mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty.";
131  }
132  return this->GetNode(0);
133  };
134 
136  {
137  if (m_NodeInfos.empty())
138  {
139  mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty.";
140  }
141  return this->GetNode(0);
142  };
143 
145  {
146  if (m_NodeInfos.empty())
147  {
148  mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty.";
149  }
150  return this->GetNode(GetSize() - 1);
151  };
152 
154  {
155  if (m_NodeInfos.empty())
156  {
157  mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty.";
158  }
159  return this->GetNode(GetSize() - 1);
160  };
161 
163 
164  bool PropertyKeyPath::operator==(const PropertyKeyPath &path) const { return m_NodeInfos == path.m_NodeInfos; };
165 
167  {
168  auto rightIter = right.m_NodeInfos.cbegin();
169  const auto rightEnd = right.m_NodeInfos.cend();
170  for (const auto &leftPos : m_NodeInfos)
171  {
172  if (rightIter == rightEnd)
173  {
174  return false;
175  }
176 
177  if (leftPos.name < rightIter->name)
178  {
179  return true;
180  }
181  if (rightIter->name < leftPos.name)
182  {
183  return false;
184  }
185 
186  if (leftPos.type < rightIter->type)
187  {
188  return true;
189  }
190  if (rightIter->type < leftPos.type)
191  {
192  return false;
193  }
194 
195  if (leftPos.selection < rightIter->selection)
196  {
197  return true;
198  }
199  if (rightIter->selection < leftPos.selection)
200  {
201  return false;
202  }
203 
204  ++rightIter;
205  }
206  return rightIter != rightEnd;
207  }
208 
210  {
211  auto rightIter = right.m_NodeInfos.cbegin();
212  const auto rightEnd = right.m_NodeInfos.cend();
213  for (const auto &leftPos : m_NodeInfos)
214  {
215  if (rightIter == rightEnd)
216  return false;
217 
218  if (leftPos.name > rightIter->name)
219  return true;
220  if (rightIter->name > leftPos.name)
221  return false;
222 
223  if (leftPos.type > rightIter->type)
224  return true;
225  if (rightIter->type > leftPos.type)
226  return false;
227 
228  if (leftPos.selection > rightIter->selection)
229  return true;
230  if (rightIter->selection > leftPos.selection)
231  return false;
232  ++rightIter;
233  }
234  return rightIter != rightEnd;
235  }
236 
237  bool PropertyKeyPath::operator>=(const PropertyKeyPath &right) const { return !(*this < right); }
238 
239  bool PropertyKeyPath::operator<=(const PropertyKeyPath &right) const { return !(*this > right); }
240 
241  bool PropertyKeyPath::Equals(const PropertyKeyPath &path) const { return PropertyKeyPathsMatch(*this, path); };
242 
244  {
245  if (this != &path)
246  {
247  m_NodeInfos = path.m_NodeInfos;
248  }
249 
250  return *this;
251  };
252 
254  {
256  return *this;
257  };
258 
260  {
261  m_NodeInfos.emplace_back(name, NodeInfo::NodeType::Element);
262  return *this;
263  };
264 
266  {
267  m_NodeInfos.emplace_back(name, NodeInfo::NodeType::AnySelection);
268  return *this;
269  };
270 
272  {
273  m_NodeInfos.emplace_back(name, NodeInfo::NodeType::ElementSelection, index);
274  return *this;
275  };
276 
278 
279  PropertyKeyPath::PropertyKeyPath(const PropertyKeyPath &path) { *this = path; };
280 
282 
283  void PropertyKeyPath::Reset() { m_NodeInfos.clear(); };
284 
286  {
287  auto leftPos = left.GetNodes().cbegin();
288  auto rightPos = right.GetNodes().cbegin();
289  auto leftEnd = left.GetNodes().cend();
290  auto rightEnd = right.GetNodes().cend();
291 
292  while (leftPos != leftEnd && rightPos != rightEnd)
293  {
294  if (!leftPos->Matches(*rightPos))
295  {
296  break;
297  }
298  ++leftPos;
299  ++rightPos;
300  }
301 
302  if (leftPos == leftEnd && rightPos == rightEnd)
303  {
304  return true;
305  }
306  else
307  {
308  return false;
309  }
310  };
311 
312  std::ostream &operator<<(std::ostream &os, const PropertyKeyPath &value)
313  {
314  os << PropertyKeyPathToPropertyName(value);
315  return os;
316  };
317 
319  {
320  std::ostringstream nameStream;
321 
323 
324  for (const auto &node : tagPath.GetNodes())
325  {
326  if (i)
327  {
328  nameStream << "\\.";
329  }
330  ++i;
331 
333  {
334  nameStream << "([a-zA-Z0-9- ]+)";
335  }
336  else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
337  {
338  nameStream << node.name;
339 
341  {
342  nameStream << "\\.\\[" << node.selection << "\\]";
343  }
345  {
346  nameStream << "\\.\\[(\\d*)\\]";
347  }
348  }
349  else
350  {
351  nameStream << "INVALIDNODE";
352  }
353  }
354 
355  return nameStream.str();
356  };
357 
359  {
360  std::ostringstream nameStream;
361 
363 
364  for (const auto &node : tagPath.GetNodes())
365  {
366  if (i)
367  {
368  nameStream << "_";
369  }
370  ++i;
371 
373  {
374  nameStream << "([a-zA-Z0-9- ]+)";
375  }
376  else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
377  {
378  nameStream << node.name;
379 
381  {
382  nameStream << "_\\[" << node.selection << "\\]";
383  }
385  {
386  nameStream << "_\\[(\\d*)\\]";
387  }
388  }
389  else
390  {
391  nameStream << "INVALIDNODE";
392  }
393  }
394 
395  return nameStream.str();
396  };
397 
399  {
400  std::ostringstream nameStream;
401 
402  int captureGroup = 1;
403 
405 
406  for (const auto &node : tagPath.GetNodes())
407  {
408  if (i)
409  {
410  nameStream << "_";
411  }
412  ++i;
413 
415  {
416  nameStream << "$" << captureGroup++;
417  }
418  else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
419  {
420  nameStream << node.name;
421 
423  {
424  nameStream << "_[" << node.selection << "]";
425  }
427  {
428  nameStream << "_[$" << captureGroup++ << "]";
429  }
430  }
431  else
432  {
433  nameStream << "INVALID_NODE";
434  }
435  }
436 
437  return nameStream.str();
438  };
439 
441  {
442  std::ostringstream nameStream;
443 
444  int captureGroup = 1;
445 
447 
448  for (const auto &node : tagPath.GetNodes())
449  {
450  if (i)
451  {
452  nameStream << ".";
453  }
454  ++i;
455 
457  {
458  nameStream << "$" << captureGroup++;
459  }
460  else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
461  {
462  nameStream << node.name;
463 
465  {
466  nameStream << ".[" << node.selection << "]";
467  }
469  {
470  nameStream << ".[$" << captureGroup++ << "]";
471  }
472  }
473  else
474  {
475  nameStream << "INVALID_NODE";
476  }
477  }
478 
479  return nameStream.str();
480  };
481 
482  PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName)
483  {
484  PropertyKeyPath result;
485 
486  std::regex reg_element("([a-zA-Z0-9- ]+)");
487  std::regex reg_anySelection("\\[\\*\\]");
488  std::regex reg_Selection("\\[(\\d+)\\]");
489 
490  std::istringstream f(propertyName);
491  std::string subStr;
492 
494 
495  while (getline(f, subStr, '.'))
496  {
497  if (subStr == "*")
498  {
499  if (!name.empty())
500  {
501  result.AddElement(name);
502  name.clear();
503  }
504 
505  result.AddAnyElement();
506  }
507  else
508  {
509  std::smatch sm;
510  if (std::regex_match(subStr, sm, reg_anySelection))
511  {
512  if (!name.empty())
513  {
514  result.AddAnySelection(name);
515  name.clear();
516  }
517  else
518  { // invalid path
519  return PropertyKeyPath();
520  }
521  }
522  else if (std::regex_match(subStr, sm, reg_Selection))
523  {
524  if (!name.empty())
525  {
526  result.AddSelection(name, std::stoi(sm[1]));
527  name.clear();
528  }
529  else
530  { // invalid path
531  return PropertyKeyPath();
532  }
533  }
534  else if (std::regex_match(subStr, sm, reg_element))
535  {
536  if (!name.empty())
537  { // store the last element and start the next
538  result.AddElement(name);
539  }
540  name = sm[1];
541  }
542  else
543  {
544  return PropertyKeyPath();
545  }
546  }
547  }
548 
549  if (!name.empty())
550  { // add last element
551  result.AddElement(name);
552  }
553 
554  return result;
555  };
556 
558  {
559  std::ostringstream nameStream;
560 
562 
563  for (const auto &node : tagPath.GetNodes())
564  {
565  if (i)
566  {
567  nameStream << ".";
568  }
569  ++i;
570 
572  {
573  nameStream << "*";
574  }
575  else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
576  {
577  nameStream << node.name;
578 
580  {
581  nameStream << ".[" << node.selection << "]";
582  }
584  {
585  nameStream << ".[*]";
586  }
587  }
588  else
589  {
590  nameStream << "INVALID_NODE";
591  }
592  }
593 
594  return nameStream.str();
595  };
596 } // namespace mitk
MITKCORE_EXPORT std::string PropertyKeyPathToPropertyName(const PropertyKeyPath &tagPath)
bool operator>(const PropertyKeyPath &right) const
bool operator<=(const PropertyKeyPath &right) const
bool operator>=(const PropertyKeyPath &right) const
PathIndexType GetSize() const
DataCollection - Class to facilitate loading/accessing structured data.
PropertyKeyPath & AddElement(const ElementNameType &name)
PathIndexType AddNode(const NodeInfo &newNode)
const NodeInfo & GetNode(const PathIndexType &index) const
static bool PropertyKeyPathsMatch(const PropertyKeyPath &left, const PropertyKeyPath &right)
PropertyKeyPath & AddSelection(const ElementNameType &name, ItemSelectionIndex index)
std::vector< NodeInfo > NodeInfoVectorType
PropertyKeyPath & operator=(const PropertyKeyPath &path)
MITKCORE_EXPORT PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName)
std::vcl_size_t ItemSelectionIndex
bool HasItemSelectionWildcardsOnly() const
bool operator==(const PropertyKeyPath &path) const
MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceNameTemplate(const PropertyKeyPath &tagPath)
const NodeInfoVectorType & GetNodes() const
#define mitkThrowException(classname)
MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyTemplate(const PropertyKeyPath &tagPath)
NodeInfoVectorType m_NodeInfos
NodeInfoVectorType::size_type PathIndexType
PropertyKeyPath & AddAnyElement()
bool operator==(const NodeInfo &right) const
bool operator<(const PropertyKeyPath &right) const
bool Equals(const PropertyKeyPath &path) const
Class that can be used to specify nested or wild carded property keys. E.g. for the use in context of...
bool Matches(const NodeInfo &right) const
MITKCORE_EXPORT std::string PropertyKeyPathToPropertyRegEx(const PropertyKeyPath &tagPath)
MITKCORE_EXPORT std::ostream & operator<<(std::ostream &o, DataNode::Pointer &dtn)
MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyRegEx(const PropertyKeyPath &tagPath)
PropertyKeyPath & AddAnySelection(const ElementNameType &name)