Flatland
yaml_reader.h
1 /*
2  * ______ __ __ __
3  * /\ _ \ __ /\ \/\ \ /\ \__
4  * \ \ \L\ \ __ __ /\_\ \_\ \ \ \____ ___\ \ ,_\ ____
5  * \ \ __ \/\ \/\ \\/\ \ /'_` \ \ '__`\ / __`\ \ \/ /',__\
6  * \ \ \/\ \ \ \_/ |\ \ \/\ \L\ \ \ \L\ \/\ \L\ \ \ \_/\__, `\
7  * \ \_\ \_\ \___/ \ \_\ \___,_\ \_,__/\ \____/\ \__\/\____/
8  * \/_/\/_/\/__/ \/_/\/__,_ /\/___/ \/___/ \/__/\/___/
9  * @copyright Copyright 2017 Avidbots Corp.
10  * @name yaml_reader.h
11  * @brief Defines yaml_reader
12  * @author Chunshang Li
13  *
14  * Software License Agreement (BSD License)
15  *
16  * Copyright (c) 2017, Avidbots Corp.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  *
23  * * Redistributions of source code must retain the above copyright
24  * notice, this list of conditions and the following disclaimer.
25  * * Redistributions in binary form must reproduce the above
26  * copyright notice, this list of conditions and the following
27  * disclaimer in the documentation and/or other materials provided
28  * with the distribution.
29  * * Neither the name of the Avidbots Corp. nor the names of its
30  * contributors may be used to endorse or promote products derived
31  * from this software without specific prior written permission.
32  *
33  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
36  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
39  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
40  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
43  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44  * POSSIBILITY OF SUCH DAMAGE.
45  */
46 
47 #ifndef FLATLAND_SERVER_YAML_READER_H
48 #define FLATLAND_SERVER_YAML_READER_H
49 
50 #include <Box2D/Box2D.h>
51 #include <flatland_server/exceptions.h>
52 #include <flatland_server/types.h>
53 #include <yaml-cpp/yaml.h>
54 #include <array>
55 #include <boost/algorithm/string.hpp>
56 #include <boost/version.hpp>
57 
58 // If we have a version of boost with type_index
59 #if BOOST_VERSION / 100 % 1000 >= 56
60 #include <boost/type_index.hpp>
61 #define TYPESTRING(T) (boost::typeindex::type_id<T>().pretty_name())
62 #else
63 #include <typeindex>
64 #include <typeinfo>
65 #define TYPESTRING(T) (typeid(T).name())
66 #endif
67 
68 #include <set>
69 #include <string>
70 #include <vector>
71 
72 namespace flatland_server {
73 
76 class YamlReader {
77  public:
78  enum NodeTypeCheck { MAP, LIST, NO_CHECK };
79 
80  YAML::Node node_;
81  std::set<std::string> accessed_keys_;
82  std::string filename_;
84  std::string file_path_;
85  std::string entry_location_;
87  std::string entry_name_;
88  std::string fmt_in_;
89  std::string fmt_name_;
90 
95  YamlReader();
96 
101  YamlReader(const YAML::Node &node);
102 
108  YamlReader(const std::string &path);
109 
118  void SetErrorInfo(std::string entry_location, std::string entry_name = "");
119 
125  void SetFile(const std::string &file_path);
126 
131  void EnsureAccessedAllKeys();
132 
136  YAML::Node Node();
137 
141  bool IsNodeNull();
142 
146  int NodeSize();
147 
158  YamlReader Subnode(int index, NodeTypeCheck type_check,
159  std::string sub_node_location = "");
170  YamlReader Subnode(const std::string &key, NodeTypeCheck type_check,
171  std::string sub_node_location = "");
183  YamlReader SubnodeOpt(const std::string &key, NodeTypeCheck type_check,
184  std::string sub_node_location = "");
192  template <typename T>
193  T As();
194 
200  template <typename T>
201  std::vector<T> AsList(int min_size, int max_size);
202 
208  template <typename T, int N>
209  std::array<T, N> AsArray();
210 
217  template <typename T>
218  T Get(const std::string &key);
219 
228  template <typename T>
229  T Get(const std::string &key, const T &default_val);
230 
239  template <typename T>
240  std::vector<T> GetList(const std::string &key, int min_size, int max_size);
241 
251  template <typename T>
252  std::vector<T> GetList(const std::string &key,
253  const std::vector<T> default_val, int min_size,
254  int max_size);
255 
262  template <typename T, int N>
263  std::array<T, N> GetArray(const std::string &key);
264 
272  template <typename T, int N>
273  std::array<T, N> GetArray(const std::string &key,
274  const std::array<T, N> default_val);
275 
279  Vec2 GetVec2(const std::string &key);
280 
285  Vec2 GetVec2(const std::string &key, const Vec2 &default_val);
286 
291  Color GetColor(const std::string &key, const Color &default_val);
292 
296  Pose GetPose(const std::string &key);
297 
302  Pose GetPose(const std::string &key, const Pose &default_val);
303 };
304 
308 inline std::string Q(const std::string &str) { return "\"" + str + "\""; }
309 
310 template <typename T>
312  T ret;
313 
314  try {
315  ret = node_.as<T>();
316  } catch (const YAML::RepresentationException &e) {
317  throw YAMLException("Error converting entry" + fmt_name_ + " to " +
318  TYPESTRING(T) + fmt_in_);
319  } catch (const YAML::Exception &e) {
320  throw YAMLException("Error reading entry" + fmt_name_ + fmt_in_);
321  }
322 
323  return ret;
324 }
325 
326 template <typename T>
327 std::vector<T> YamlReader::AsList(int min_size, int max_size) {
328  std::vector<T> list;
329 
330  if (min_size > 0 && max_size > 0 && min_size == max_size &&
331  NodeSize() != max_size) {
332  throw YAMLException("Entry" + fmt_name_ + " must have size of exactly " +
333  std::to_string(min_size) + fmt_in_);
334  }
335 
336  if (min_size > 0 && NodeSize() < min_size) {
337  throw YAMLException("Entry" + fmt_name_ + " must have size >= " +
338  std::to_string(min_size) + fmt_in_);
339  }
340 
341  if (max_size > 0 && NodeSize() > max_size) {
342  throw YAMLException("Entry" + fmt_name_ + " must have size <= " +
343  std::to_string(max_size) + fmt_in_);
344  }
345 
346  for (int i = 0; i < NodeSize(); i++) {
347  list.push_back(Subnode(i, NO_CHECK).As<T>());
348  }
349 
350  return list;
351 }
352 
353 template <typename T, int N>
354 std::array<T, N> YamlReader::AsArray() {
355  std::vector<T> list_ret = AsList<T>(N, N);
356  std::array<T, N> array_ret;
357 
358  for (int i = 0; i < N; i++) {
359  array_ret[i] = list_ret[i];
360  }
361  return array_ret;
362 }
363 
364 template <typename T>
365 T YamlReader::Get(const std::string &key) {
366  return Subnode(key, NO_CHECK).As<T>();
367 }
368 
369 template <typename T>
370 T YamlReader::Get(const std::string &key, const T &default_val) {
371  if (!node_[key]) {
372  accessed_keys_.insert(key);
373  return default_val;
374  }
375  return Get<T>(key);
376 }
377 
378 template <typename T>
379 std::vector<T> YamlReader::GetList(const std::string &key, int min_size,
380  int max_size) {
381  return Subnode(key, LIST).AsList<T>(min_size, max_size);
382 }
383 
384 template <typename T>
385 std::vector<T> YamlReader::GetList(const std::string &key,
386  const std::vector<T> default_val,
387  int min_size, int max_size) {
388  if (!node_[key]) {
389  accessed_keys_.insert(key);
390  return default_val;
391  }
392 
393  return GetList<T>(key, min_size, max_size);
394 }
395 
396 template <typename T, int N>
397 std::array<T, N> YamlReader::GetArray(const std::string &key) {
398  return Subnode(key, LIST).AsArray<T, N>();
399 }
400 
401 template <typename T, int N>
402 std::array<T, N> YamlReader::GetArray(const std::string &key,
403  const std::array<T, N> default_val) {
404  if (!node_[key]) {
405  accessed_keys_.insert(key);
406  return default_val;
407  }
408 
409  return GetArray<T, N>(key);
410 }
411 }
412 
413 // encode and decode functions for yaml-cpp to convert values for commonly used
414 // types in flatland server
415 namespace YAML {
416 template <>
417 struct convert<b2Vec2> {
418  static bool decode(const Node &node, b2Vec2 &rhs) {
419  if (!node.IsSequence() || node.size() != 2) {
420  return false;
421  }
422 
423  rhs.x = node[0].as<double>();
424  rhs.y = node[1].as<double>();
425  return true;
426  }
427 };
428 
429 template <>
430 struct convert<flatland_server::Vec2> {
431  static bool decode(const Node &node, flatland_server::Vec2 &rhs) {
432  if (!node.IsSequence() || node.size() != 2) {
433  return false;
434  }
435 
436  rhs.x = node[0].as<double>();
437  rhs.y = node[1].as<double>();
438  return true;
439  }
440 };
441 
442 template <>
443 struct convert<flatland_server::Color> {
444  static bool decode(const Node &node, flatland_server::Color &rhs) {
445  if (!node.IsSequence() || node.size() != 4) {
446  return false;
447  }
448 
449  rhs.r = node[0].as<double>();
450  rhs.g = node[1].as<double>();
451  rhs.b = node[2].as<double>();
452  rhs.a = node[3].as<double>();
453  return true;
454  }
455 };
456 
457 template <>
458 struct convert<flatland_server::Pose> {
459  static bool decode(const Node &node, flatland_server::Pose &rhs) {
460  if (!node.IsSequence() || node.size() != 3) {
461  return false;
462  }
463 
464  rhs.x = node[0].as<double>();
465  rhs.y = node[1].as<double>();
466  rhs.theta = node[2].as<double>();
467  return true;
468  }
469 };
470 }
471 
472 #endif
YamlReader SubnodeOpt(const std::string &key, NodeTypeCheck type_check, std::string sub_node_location="")
Optionally get one of the subnode using a key, throws exception on failure, file path is inherited fr...
Definition: yaml_reader.cpp:135
T As()
Convert the current node in yaml reader to a given template type. It uses yaml-cpp&#39;s as<T>() function...
Definition: yaml_reader.h:311
Vec2 GetVec2(const std::string &key)
Definition: yaml_reader.cpp:145
void EnsureAccessedAllKeys()
This method checks all keys in the yaml node are used, otherwise it throws an exception.
Definition: yaml_reader.cpp:223
YAML::Node Node()
Definition: yaml_reader.cpp:80
std::vector< T > GetList(const std::string &key, int min_size, int max_size)
Get subnode with a given key and converted to list of the given type, throws on failure.
Definition: yaml_reader.h:379
std::string fmt_in_
formatted entry location for display
Definition: yaml_reader.h:88
Definition: body.h:55
Pose GetPose(const std::string &key)
Definition: yaml_reader.cpp:165
YamlReader()
Default constructor for yaml reader, initialize with a empty yaml Node.
Definition: yaml_reader.cpp:53
std::string fmt_name_
formatted entry location for display
Definition: yaml_reader.h:89
std::vector< T > AsList(int min_size, int max_size)
Convert the current node to a list of given type, throws exception on failure.
Definition: yaml_reader.h:327
Definition: exceptions.h:86
YAML::Node node_
The YAML Node this processes.
Definition: yaml_reader.h:80
Definition: types.h:84
YamlReader Subnode(int index, NodeTypeCheck type_check, std::string sub_node_location="")
Get one of the subnode using a index, throws exception on failure, file path is inherited from the pa...
Definition: yaml_reader.cpp:86
Definition: types.h:55
Definition: types.h:110
Color GetColor(const std::string &key, const Color &default_val)
Definition: yaml_reader.cpp:159
int NodeSize()
Definition: yaml_reader.cpp:84
T Get(const std::string &key)
Get subnode with a given key and converted to the given type, throws on failure.
Definition: yaml_reader.h:365
std::string filename_
< location of the entry, used to show where the error come from
Definition: yaml_reader.h:83
void SetFile(const std::string &file_path)
Use this method to set the file location of the yaml node.
Definition: yaml_reader.cpp:213
double theta
theta
Definition: types.h:87
std::string entry_location_
name of the yaml entry, used to show where the error come from
Definition: yaml_reader.h:85
Definition: yaml_reader.h:415
void SetErrorInfo(std::string entry_location, std::string entry_name="")
Use this method to set the entry location and entry name for error message purposes.
Definition: yaml_reader.cpp:179
Definition: yaml_reader.h:76
std::array< T, N > GetArray(const std::string &key)
Get subnode with a given key and converted to array of the given type, throws on failure.
Definition: yaml_reader.h:397
bool IsNodeNull()
Definition: yaml_reader.cpp:82
std::array< T, N > AsArray()
Convert the current node to a array of given type, throws exception on failure.
Definition: yaml_reader.h:354