scenario_simulator_v2 C++ API
element.hpp
Go to the documentation of this file.
1 // Copyright 2015 TIER IV, Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef OPENSCENARIO_INTERPRETER__READER__ELEMENT_HPP_
16 #define OPENSCENARIO_INTERPRETER__READER__ELEMENT_HPP_
17 
18 #include <functional>
19 #include <iterator>
20 #include <limits>
24 #include <pugixml.hpp>
25 #include <string>
26 #include <type_traits>
27 #include <unordered_map>
28 #include <utility>
29 
30 /* ---- NOTE -------------------------------------------------------------------
31  *
32  * The functions in the reader header only deal with XML parsing and should
33  * not have any prerequisite knowledge about OpenSCENARIO data structures.
34  *
35  * -------------------------------------------------------------------------- */
36 
38 {
39 inline namespace reader
40 {
41 using Cardinality =
42  typename std::iterator_traits<typename pugi::xml_node::iterator>::difference_type;
43 
44 constexpr auto unbounded = std::numeric_limits<Cardinality>::max();
45 
46 template <Cardinality MinOccurs, Cardinality MaxOccurs, typename F>
47 auto traverse(const pugi::xml_node & parent, const std::string & name, F && f) -> void
48 {
49  const auto children = parent.children(name.c_str());
50 
51  if (const auto size = iterator::size(children)) {
52  if (MinOccurs != 0 and size < MinOccurs) {
53  throw SyntaxError(
54  parent.name(), " requires class ", name, " at least ", MinOccurs, " element",
55  (1 < MinOccurs ? "s" : ""), ", but ", size, " element", (1 < size ? "s" : ""),
56  " specified");
57  } else if (MaxOccurs < size) {
58  throw SyntaxError(
59  parent.name(), " requires class ", name, " at most ", MaxOccurs, " element",
60  (1 < MaxOccurs ? "s" : ""), ", but ", size, " element", (1 < size ? "s" : ""),
61  " specified");
62  } else {
63  for (const auto & child : children) {
64  f(child);
65  }
66  }
67  } else if (MinOccurs != 0) {
68  throw SyntaxError(
69  parent.name(), " requires class ", name, " at least ", MinOccurs, " element",
70  (1 < MinOccurs ? "s" : ""), ", but there is no specification");
71  }
72 }
73 
74 template <typename T, typename Scope>
75 auto readElement(const std::string & name, const pugi::xml_node & parent, Scope & scope)
76 {
77  if (const auto child = parent.child(name.c_str())) {
78  return T(child, scope);
79  } else {
80  /* ---- NOTE ---------------------------------------------------------------
81  *
82  * If the given XML node does not have a child element (T type) with the
83  * specified name, it assumes that the T type is an optional element and
84  * attempts to build a default T type.
85  *
86  * ---------------------------------------------------------------------- */
88  parent.name(), " requires class ", name, " as element, but there is no declaration"));
89  }
90 }
91 
92 template <typename T, typename U, typename Scope>
93 auto readElement(const std::string & name, const pugi::xml_node & parent, Scope & scope, U && value)
94 {
95  if constexpr (std::is_same<T, typename std::decay<U>::type>::value) {
96  // use 'value' as a default element.
97  // the default element will be used when current scope has no description about 'name'.
98  if (const auto child = parent.child(name.c_str())) {
99  return T(child, scope);
100  } else {
101  return value;
102  }
103  } else {
104  // use "value" as an additional arguments to the constructor
105  if (const auto child = parent.child(name.c_str())) {
106  return T(child, scope, value);
107  } else {
109  parent.name(), " requires class ", name, " as element, but there is no declaration"));
110  }
111  }
112 }
113 
114 template <typename T, Cardinality MinOccurs, Cardinality MaxOccurs = unbounded, typename... Ts>
115 auto readElements(const std::string & name, const pugi::xml_node & node, Ts &&... xs)
116 {
117  std::list<T> elements;
118 
119  traverse<MinOccurs, MaxOccurs>(node, name, [&](auto && x) {
120  elements.emplace_back(std::forward<decltype(x)>(x), std::forward<decltype(xs)>(xs)...);
121  });
122 
123  return elements;
124 }
125 
126 template <typename GroupT, Cardinality MinOccurs, Cardinality MaxOccurs = unbounded, typename... Ts>
127 auto readGroups(const pugi::xml_node & node, Ts &&... xs)
128 {
129  std::list<GroupT> groups;
130 
131  for (auto child = node.begin(); child != node.end(); ++child) {
132  try {
133  groups.template emplace_back(
134  std::forward<decltype(*child)>(*child), std::forward<decltype(xs)>(xs)...);
135  } catch (...) {
136  }
137  }
138 
139  if (MinOccurs != 0 and groups.size() < MinOccurs) {
140  throw SyntaxError(
141  node.name(), " requires Group ", demangle(typeid(GroupT)), " at least ", MinOccurs,
142  " element", (1 < MinOccurs ? "s" : ""), ", but ", groups.size(), " element",
143  (1 < groups.size() ? "s" : ""), " specified");
144  }
145 
146  if (MaxOccurs < groups.size()) {
147  throw SyntaxError(
148  node.name(), " requires Group ", demangle(typeid(GroupT)), " at most ", MaxOccurs, " element",
149  (1 < MaxOccurs ? "s" : ""), ", but ", groups.size(), " element",
150  (1 < groups.size() ? "s" : ""), " specified");
151  }
152 
153  return groups;
154 }
155 
156 template <typename... Ts>
157 auto choice(const pugi::xml_node & node, Ts &&... xs) -> decltype(auto)
158 {
159  const std::unordered_map<std::string, std::function<Object(const pugi::xml_node &)>> callees{
160  std::forward<decltype(xs)>(xs)...};
161 
162  std::unordered_map<std::string, pugi::xml_node> specs{};
163 
164  for (const auto & each : callees) {
165  if (const auto child = node.child(std::get<0>(each).c_str())) {
166  specs.emplace(std::get<0>(each), child);
167  }
168  }
169 
170  auto print_keys_to = [&](auto & os, const auto & xs) -> decltype(auto) {
171  if (not xs.empty()) {
172  for (auto iter = std::begin(xs); iter != std::end(xs); ++iter) {
173  os << std::get<0>(*iter);
174 
175  switch (std::distance(iter, std::end(xs))) {
176  case 1:
177  return os;
178 
179  case 2:
180  os << " and ";
181  break;
182 
183  default:
184  os << ", ";
185  break;
186  }
187  }
188  }
189 
190  return os;
191  };
192 
193  if (specs.empty()) {
194  std::stringstream what;
195  what << "Class " << node.name() << " requires one of following elements: ";
196  print_keys_to(what, callees);
197  what << ". But no element specified";
198  throw SyntaxError(what.str());
199  } else if (1 < specs.size()) {
200  std::stringstream what;
201  what << "Class " << node.name() << " requires just one of following elements: ";
202  print_keys_to(what, callees);
203  what << ". But " << specs.size() << " element" << (1 < specs.size() ? "s" : "") << " (";
204  print_keys_to(what, specs);
205  what << ") specified";
206  throw SyntaxError(what.str());
207  } else {
208  const auto iter = std::cbegin(specs);
209  return callees.at(std::get<0>(*iter))(std::get<1>(*iter));
210  }
211 }
212 } // namespace reader
213 } // namespace openscenario_interpreter
214 
215 #endif // OPENSCENARIO_INTERPRETER__READER__ELEMENT_HPP_
Definition: scope.hpp:154
auto size(const T &range)
Definition: size.hpp:25
auto choice(const pugi::xml_node &node, Ts &&... xs) -> decltype(auto)
Definition: element.hpp:157
auto readElements(const std::string &name, const pugi::xml_node &node, Ts &&... xs)
Definition: element.hpp:115
auto traverse(const pugi::xml_node &parent, const std::string &name, F &&f) -> void
Definition: element.hpp:47
typename std::iterator_traits< typename pugi::xml_node::iterator >::difference_type Cardinality
Definition: element.hpp:42
auto readElement(const std::string &name, const pugi::xml_node &parent, Scope &scope)
Definition: element.hpp:75
constexpr auto unbounded
Definition: element.hpp:44
auto readGroups(const pugi::xml_node &node, Ts &&... xs)
Definition: element.hpp:127
auto demangle(const char *name) -> std::string
Definition: demangle.cpp:26
auto print_keys_to
Definition: print.hpp:38
Definition: escape_sequence.hpp:22
Pointer< Expression > Object
Definition: object.hpp:26
auto distance(const geometry_msgs::Pose &pose1, const geometry_msgs::Pose &pose2)
Definition: detection_sensor.cpp:34
Definition: junit5.hpp:25
std::string string
Definition: junit5.hpp:26
Definition: must_be_default_constructible.hpp:27