VPTissue Reference Manual
PTreeUtils.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
20 #include "PTreeUtils.h"
21 
22 #include "util/misc/StringUtils.h"
23 
24 #include <boost/property_tree/ptree.hpp>
25 #include <boost/xpressive/xpressive.hpp>
26 
27 using namespace boost::property_tree;
28 using namespace std;
29 
30 namespace SimPT_Sim {
31 namespace Util {
32 
33 namespace {
34 
35 const string ARRAY_SUFFIX = "_array";
36 
37 
45 list<pair<string, string>> FlattenArray(const ptree& pt, const string& elementsKey, const string& path)
46 {
47  if (pt.size() == 0) {
48  return list<pair<string, string>>({make_pair(path, pt.data().c_str())});
49  } else {
50  list<pair<string, string>> entries;
51  int index = 0;
52  for (ptree::const_iterator it = pt.begin(); it != pt.end(); it++) {
53  const string& key = it->first;
54  string newPath;
55  if (key == elementsKey) {
56  newPath = path + "[" + to_string(index++) + "]";
57  } else {
58  newPath = path == "" ? key : path + "." + key;
59  }
60  entries.splice(entries.end(), PTreeUtils::Flatten(it->second, true, newPath));
61  }
62  return entries;
63  }
64 }
65 
66 }
67 
68 void PTreeUtils::CopyNonExistingChildren(ptree const& from, ptree& into, set<string> const& ignore)
69 {
70  for (ptree::value_type const& v : from) {
71  if (ignore.find(v.first) != ignore.end()) {
72  continue;
73  }
74  try {
75  // Will throw if child doesn't exist in result.
76  ptree & child = into.get_child(v.first);
77  // Continue recursively with subtree.
78  CopyNonExistingChildren(v.second, child, ignore);
79  }
80  catch (ptree_bad_path&) {
81  // Child didn't exist, copy entire subtree.
82  into.put_child(v.first, v.second);
83  }
84  }
85 }
86 
87 void PTreeUtils::CopyStructure(ptree const& from, ptree& into, string const& fill_value, set<string> const& ignore)
88 {
89  for (ptree::value_type const& v : from) {
90  if (ignore.find(v.first) != ignore.end()) {
91  continue;
92  }
93  try {
94  ptree & child = into.get_child(v.first); // Will throw if child doesn't exist in result.
95  // Continue recursively with subtree.
96  CopyStructure(v.second, child, fill_value, ignore);
97  }
98  catch (ptree_bad_path&) {
99  if (v.second.empty()) {
100  // Add child present in src to dst, replace value by fill_value
101  into.put_child(v.first, ptree(fill_value));
102  } else {
103  // Add empty child in dst, continue recursively to fill child up.
104  auto& inserted = into.put_child(v.first, ptree());
105  CopyStructure(v.second, inserted, fill_value, ignore);
106  }
107  }
108  }
109 }
110 
111 void PTreeUtils::FillPTree(ptree& pt1, const ptree& pt2)
112 {
113  assert(pt1.size() == pt2.size() && "The ptrees don't have the same structure.");
114  if (pt1.size() == 0) {
115  if (pt1.data() == "") {
116  pt1.data() = pt2.data();
117  }
118  } else {
119  ptree::iterator it1 = pt1.begin();
120  ptree::const_iterator it2 = pt2.begin();
121  while (it1 != pt1.end()) {
122  assert(it1->first == it2->first && "The ptrees don't have the same structure.");
123  FillPTree(it1->second, it2->second);
124  ++it1;
125  ++it2;
126  }
127  }
128 }
129 
130 list<pair<string, string>> PTreeUtils::Flatten(const ptree& pt, bool indexedArray, const string& path)
131 {
132  if (pt.size() == 0) {
133  return list<pair<string, string>>({make_pair(path, pt.data().c_str())});
134  } else {
135  list<pair<string, string>> entries;
136  for (ptree::const_iterator it = pt.begin(); it != pt.end(); ++it) {
137  const string& key = it->first;
138  string newPath = (path == "" ? key : path + "." + key);
139  if (indexedArray && key.length() > ARRAY_SUFFIX.length()
140  && key.compare(key.length() - ARRAY_SUFFIX.length(),
141  ARRAY_SUFFIX.length(), ARRAY_SUFFIX) == 0) {
142  entries.splice(entries.end(), FlattenArray(it->second,
143  key.substr(0, key.length() - ARRAY_SUFFIX.length()), newPath));
144  } else {
145  entries.splice(entries.end(), Flatten(it->second, indexedArray, newPath));
146  }
147  }
148  return entries;
149  }
150 }
151 
152 const ptree& PTreeUtils::GetIndexedChild(const ptree& pt, const string& path)
153 {
154  if (path == "") {
155  return pt;
156  } else {
157  string pathElement = path;
158  string newPath = "";
159 
160  size_t separatorIndex = path.find('.');
161  if (separatorIndex != string::npos) {
162  pathElement = path.substr(0, separatorIndex);
163  newPath = path.substr(separatorIndex + 1);
164  }
165  assert(pathElement != "" && "There's no element after the separator.");
166 
167 
168  //Check whether the path element is of this format: *_array[int].
169  const boost::xpressive::sregex match_indexed
170  = boost::xpressive::sregex::compile("(.+)_array\\[(\\d+)\\]");
171  boost::xpressive::smatch match;
172  if (boost::xpressive::regex_match(pathElement, match, match_indexed)) {
173  string arrayElementKey = match[1];
174  const ptree& subPtree = pt.get_child(arrayElementKey + ARRAY_SUFFIX);
175  unsigned int index = FromString<unsigned int>(match[2]);
176  for (const auto& entry : subPtree) {
177  if (entry.first == arrayElementKey) {
178  if (index == 0) {
179  return GetIndexedChild(entry.second, newPath);
180  } else {
181  --index;
182  }
183  }
184  }
185 
186  throw ptree_bad_path("No such node", boost::property_tree::path(pathElement));
187  } else {
188  return GetIndexedChild(pt.get_child(pathElement), newPath);
189  }
190  }
191 }
192 
193 void PTreeUtils::PutIndexedChild(ptree& pt, const string& path, const ptree& child)
194 {
195  if (path == "") {
196  pt = child;
197  } else {
198  string pathElement = path;
199  string newPath = "";
200 
201  size_t separatorIndex = path.find('.');
202  if (separatorIndex != string::npos) {
203  pathElement = path.substr(0, separatorIndex);
204  newPath = path.substr(separatorIndex + 1);
205  }
206  assert(pathElement != "" && "There's no element after the separator.");
207 
208  //Check whether the path element is of this format: *_array[int].
209  const boost::xpressive::sregex match_indexed
210  = boost::xpressive::sregex::compile("(.+)_array\\[(\\d+)\\]");
211  boost::xpressive::smatch match;
212  if (boost::xpressive::regex_match(pathElement, match, match_indexed)) {
213  string arrayElementKey = match[1];
214  ptree& subPtree = pt.get_child(arrayElementKey + ARRAY_SUFFIX);
215  unsigned int index = FromString<unsigned int>(match[2]);
216 
217  for (auto& entry : subPtree) {
218  if (entry.first == arrayElementKey) {
219  if (index == 0) {
220  PutIndexedChild(entry.second, newPath, child);
221  return;
222  } else {
223  --index;
224  }
225  }
226  }
227 
228  throw ptree_bad_path("No such node", boost::property_tree::path(pathElement));
229  } else {
230  PutIndexedChild(pt.get_child(pathElement), newPath, child);
231  }
232  }
233 }
234 
235 void PTreeUtils::RemoveNonExistingChildren(const ptree& src, ptree& dst, const set<string>& ignore)
236 {
237  for (auto dst_it = dst.begin(); dst_it != dst.end(); ++dst_it) {
238  if (ignore.find(dst_it->first) != ignore.end()) {
239  continue;
240  }
241  try {
242  // Will throw if child doesn't exist in src.
243  const ptree& child = src.get_child(dst_it->first);
244  // Continue recursively with subtree.
245  RemoveNonExistingChildren(child, dst_it->second, ignore);
246  }
247  catch (ptree_bad_path&) {
248  // Child didn't exist, copy entire subtree.
249  dst_it = dst.erase(dst_it);
250  }
251  }
252 }
253 
254 } // namespace Util
255 } // namespace SimPT_Sim
STL namespace.
PTreeUtils interface.
Namespace for the core simulator.
String manipulation utilities.