Turi Create  4.0
boost_property_tree_utils.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_INI_BOOST_PROPERTY_TREE_UTILS_HPP
7 #define TURI_INI_BOOST_PROPERTY_TREE_UTILS_HPP
8 
9 #define BOOST_SPIRIT_THREADSAFE
10 
11 #include <map>
12 #include <vector>
13 #include <string>
14 #include <boost/property_tree/ptree.hpp>
15 #include <boost/lexical_cast.hpp>
16 #include <core/logging/logger.hpp>
17 namespace turi {
18 namespace ini {
19 
20 /**
21  * \defgroup groupini INI Utilities
22  * \brief Simple ini parsing utilities
23  */
24 
25 /**
26  * \ingroup groupini
27  *
28  * Reads a key in an ini/json file as a sequence of values. In the ini file
29  * this will be represented as
30  *
31  * [key]
32  * 0000 = "hello"
33  * 0001 = "pika"
34  * 0002 = "chu"
35  *
36  * But in a JSON file this could be
37  * {"0000":"hello","0001":"pika","0002":"chu"}
38  * or
39  * ["hello","pika","chu"]
40  * depending on which writer is used. (The boost property tree writer will
41  * create the first, a regular JSON writer will create the second).
42  *
43  * This will return a 3 element vector containing {"hello", "pika", "chu"}
44  *
45  * \see write_sequence_section
46  */
47 template <typename T>
48 std::vector<T> read_sequence_section(const boost::property_tree::ptree& data,
49  std::string key,
50  size_t expected_elements) {
51  std::vector<T> ret;
52  if (expected_elements == 0) return ret;
53  const boost::property_tree::ptree& section = data.get_child(key);
54  ret.resize(expected_elements);
55 
56  // loop through the children of the column_names section
57  size_t sid = 0;
58  for(const auto& val: section) {
59  const auto& key = val.first;
60  if (key.empty()) {
61  // this is the array-like sequences
62  ret[sid] = boost::lexical_cast<T>(val.second.get_value<std::string>());
63  ++sid;
64  } else {
65  // this is a dictionary-like sequence
66  sid = std::stoi(key);
67  if (sid >= ret.size()) {
68  log_and_throw(std::string("Invalid ID in ") + key + " section."
69  "Segment IDs are expected to be sequential.");
70  }
71  ret[sid] = boost::lexical_cast<T>(val.second.get_value<std::string>());
72  }
73  }
74  return ret;
75 }
76 
77 
78 
79 
80 /**
81  * \ingroup groupini
82  * Reads a key in an ini/json file as a dictionary of values. In the ini file
83  * this will be represented as
84  *
85  * [key]
86  * fish = "hello"
87  * and = "pika"
88  * chips = "chu"
89  *
90  * In a JSON file this will be represented as
91  * {"fish":"hello", "and":"pika", "chips":"chu"}
92  *
93  * This will return a 3 element map containing
94  * {"fish":"hello", "and":"pika", "chips":"chu"}.
95  *
96  * \see write_dictionary_section
97  */
98 template <typename T>
99 std::map<std::string, T> read_dictionary_section(const boost::property_tree::ptree& data,
100  std::string key) {
101  std::map<std::string, T> ret;
102  // no section found
103  if (data.count(key) == 0) {
104  return ret;
105  }
106  const boost::property_tree::ptree& section = data.get_child(key);
107 
108  // loop through the children of the column_names section
109  for(const auto& val: section) {
110  ret.insert(std::make_pair(val.first,
111  val.second.get_value<T>()));
112  }
113  return ret;
114 }
115 
116 
117 /**
118  * \ingroup groupini
119  * Writes a vector of values into an ini file as a section.
120  *
121  * For instance, given a 3 element vector containing {"hello", "pika", "chu"}
122  * The vector be represented as
123  *
124  * [key]
125  * 0000 = "hello"
126  * 0001 = "pika"
127  * 0002 = "chu"
128  *
129  * \see read_sequence_section
130  *
131  */
132 template <typename T>
133 void write_sequence_section(boost::property_tree::ptree& data,
134  const std::string& key,
135  const std::vector<T>& values) {
136  for (size_t i = 0; i < values.size(); ++i) {
137  // make the 4 digit suffix
138  std::stringstream strm;
139  strm.fill('0'); strm.width(4); strm << i;
140  data.put(key + "." + strm.str(), values[i]);
141  }
142 }
143 
144 /**
145  * \ingroup groupini
146  * Writes a dictionary of values into an ini file as a section.
147  * For instance, given a 3 element map containing
148  * {"fish":"hello", "and":"pika", "chips":"chu"}.
149  *
150  * In the ini file this will be represented as:
151  *
152  * [key]
153  * fish = "hello"
154  * and = "pika"
155  * chips = "chu"
156  *
157  * \see read_dictionary_section
158  *
159  */
160 template <typename T>
161 void write_dictionary_section(boost::property_tree::ptree& data,
162  const std::string& key,
163  const std::map<std::string, T>& values) {
164  // Write out metadata
165  std::string m_heading = key + ".";
166  for(const auto& map_entry : values) {
167  std::string mkey(m_heading);
168  mkey += map_entry.first;
169  data.put(mkey, map_entry.second);
170  }
171 }
172 
173 
174 } // ini
175 } // namespace turi
176 #endif
std::map< std::string, T > read_dictionary_section(const boost::property_tree::ptree &data, std::string key)
std::set< T > values(const std::map< Key, T > &map)
Definition: stl_util.hpp:386
std::vector< T > read_sequence_section(const boost::property_tree::ptree &data, std::string key, size_t expected_elements)
void write_dictionary_section(boost::property_tree::ptree &data, const std::string &key, const std::map< std::string, T > &values)
void write_sequence_section(boost::property_tree::ptree &data, const std::string &key, const std::vector< T > &values)