Line data Source code
1 : // SPDX-License-Identifier: Apache-2.0
2 : /**
3 : * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
4 : *
5 : * @file ini_wrapper.h
6 : * @date 08 April 2021
7 : * @brief NNTrainer Ini Wrapper helps to save ini
8 : * @note this is to be used with ini_interpreter
9 : * @see https://github.com/nnstreamer/nntrainer
10 : * @author Jihoon Lee <jhoon.it.lee@samsung.com>
11 : * @bug No known bugs except for NYI items
12 : */
13 : #ifndef __INI_WRAPPER_H__
14 : #define __INI_WRAPPER_H__
15 :
16 : #include <cstring>
17 : #include <fstream>
18 : #include <iosfwd>
19 : #include <map>
20 : #include <string>
21 : #include <vector>
22 :
23 : #include <node_exporter.h>
24 :
25 : namespace nntrainer {
26 :
27 : /**
28 : * @brief IniSection class that maps to one ini section
29 : * @todo consider API style setEntry function
30 : *
31 : */
32 0 : class IniSection {
33 :
34 : public:
35 : /**
36 : * @brief Construct a new Ini Section object
37 : *
38 : * @param name section name
39 : */
40 : IniSection(const std::string &name);
41 :
42 : /**
43 : * @brief Construct a new Ini Section object
44 : *
45 : * @param section_name section name
46 : * @param entry_str entry representing string (separated by `|`)
47 : */
48 : IniSection(const std::string §ion_name, const std::string &entry_str);
49 :
50 : /**
51 : * @brief Copy Construct a new Ini Section object
52 : * @note this function copies entry from @a from and overwrite entry and
53 : * section_name
54 : *
55 : * @param from Ini Section to copy from
56 : * @param section_name section name to override, if empty, section name is not
57 : * updated
58 : * @param entry_str entry string to override the given section name
59 : */
60 : IniSection(IniSection &from, const std::string §ion_name,
61 : const std::string &entry_str);
62 :
63 : /**
64 : * @brief Construct a new Ini Section object
65 : *
66 : * @param from Ini Section to copy from
67 : * @param entry_str entry string to override the given section name
68 : */
69 : IniSection(IniSection &from, const std::string &entry_str) :
70 : IniSection(from, "", entry_str) {}
71 :
72 : /**
73 : * @brief Default constructor for the Ini Section object
74 : *
75 : */
76 : IniSection() : section_name(""), entry{} {};
77 :
78 : /**
79 : * @brief Construct a new Ini Section object from which implements
80 : * object::exportTo
81 : *
82 : * @tparam Exportable object with member object::exportTo
83 : * @param section_name section name
84 : * @param exportable exportable object
85 : * @return IniSection created section
86 : */
87 : template <typename Exportable>
88 2335 : static IniSection FromExportable(const std::string §ion_name,
89 : const Exportable &exportable) {
90 2335 : IniSection s(section_name);
91 2335 : Exporter e;
92 2335 : exportable.exportTo(e, ml::train::ExportMethods::METHOD_STRINGVECTOR);
93 2335 : const auto key_val_pairs =
94 : e.getResult<ml::train::ExportMethods::METHOD_STRINGVECTOR>();
95 :
96 2335 : if (!key_val_pairs) {
97 0 : throw std::invalid_argument("returned pairs are nullptr!");
98 : }
99 :
100 23180 : for (const auto &pair : *key_val_pairs) {
101 20845 : s.setEntry(pair.first, pair.second);
102 : }
103 2335 : return s;
104 2335 : }
105 :
106 : /**
107 : * @brief Default destructor for the Ini Section object
108 : *
109 : */
110 35355 : ~IniSection() = default;
111 :
112 : /**
113 : * @brief +=operator from IniSection
114 : *
115 : * @param rhs operand to add
116 : * @return IniSection& this
117 : */
118 : IniSection &operator+=(const IniSection &rhs) {
119 78 : setEntry(rhs.entry);
120 : return *this;
121 : }
122 :
123 : /**
124 : * @brief + operator from IniSection
125 : *
126 : * @param rhs operand to add
127 : * @return IniSection new Inisection
128 : */
129 72 : IniSection operator+(const IniSection &rhs) const {
130 216 : return IniSection(*this) += rhs;
131 : }
132 :
133 : /**
134 : * @brief += operator from string
135 : *
136 : * @param s string representation to add
137 : * @return IniSection& this
138 : */
139 : IniSection &operator+=(const std::string &s) {
140 1219 : setEntry(s);
141 : return *this;
142 : }
143 :
144 : /**
145 : * @brief + operator from string
146 : *
147 : * @param s string representation to add
148 : * @return IniSection Newly created section
149 : */
150 3657 : IniSection operator+(const std::string &s) { return IniSection(*this) += s; }
151 :
152 : /**
153 : * @brief equal operator between ini section
154 : *
155 : * @param rhs ini section to compare
156 : * @retval true two inisections are equal
157 : * @retval false two ini sections are not equal
158 : */
159 : bool operator==(const IniSection &rhs) const {
160 : return section_name == rhs.section_name && entry == rhs.entry;
161 : }
162 :
163 : /**
164 : * @brief not equal operator between ini section
165 : *
166 : * @param rhs ini section to compare
167 : * @retval true two inisections are not equal
168 : * @retval false two inisections are equal
169 : */
170 : bool operator!=(const IniSection &rhs) const { return !operator==(rhs); }
171 :
172 : /**
173 : * @brief print out a section
174 : *
175 : * @param out ostream to print
176 : */
177 : void print(std::ostream &out) const;
178 :
179 : /**
180 : * @brief Get the Name object
181 : *
182 : * @return std::string section name
183 : */
184 10 : std::string getName() const { return section_name; }
185 :
186 : /**
187 : * @brief Set the Entry object by key and value
188 : *
189 : * @param key key to update
190 : * @param value value to be added
191 : */
192 : void setEntry(const std::string &key, const std::string &value);
193 :
194 : private:
195 : /**
196 : * @brief Set the Entry
197 : *
198 : * @param entry set entry from a given map
199 : */
200 : void setEntry(const std::map<std::string, std::string> &entry);
201 :
202 : /**
203 : * @brief set entry from the string representation
204 : *
205 : * @param entry_str setEntry as "Type = neuralnetwork | decayrate = 0.96 |
206 : * -epochs = 1" will delete epochs, and overwrite type and decayrate
207 : */
208 : void setEntry(const std::string &entry_str);
209 :
210 : std::string section_name; /**< section name of the ini section */
211 :
212 : /// @note if ini_wrapper needs to be optimized, change this to unordered_map
213 : std::map<std::string, std::string>
214 : entry; /**< entry information that this ini contains */
215 :
216 : /**
217 : * @brief <<operator of a section
218 : *
219 : * @param os ostream
220 : * @param section section to print
221 : * @return std::ostream& ostream
222 : */
223 : friend std::ostream &operator<<(std::ostream &os, const IniSection §ion) {
224 : return os << section.section_name;
225 : }
226 : };
227 :
228 : /**
229 : * @brief IniWrapper using IniSections
230 : *
231 : */
232 2743 : class IniWrapper {
233 : public:
234 : using Sections = std::vector<IniSection>;
235 :
236 : /**
237 : * @brief Construct a new Ini Test Wrapper object
238 : *
239 : */
240 : IniWrapper() = default;
241 :
242 : /**
243 : * @brief Construct a new Ini Test Wrapper object
244 : *
245 : * @param name_ name of the ini without `.ini` extension
246 : * @param sections_ sections that should go into ini
247 : */
248 866 : IniWrapper(const std::string &name_, const Sections §ions_ = {}) :
249 866 : name(name_),
250 866 : sections(sections_){};
251 :
252 : /**
253 : * @brief ini operator== to check if IniWrapper is equal
254 : *
255 : * @param rhs IniWrapper to compare
256 : * @retval true true if ini is equal (deeply)
257 : * @retval false false if ini is not equal
258 : */
259 : bool operator==(const IniWrapper &rhs) const {
260 : return name == rhs.name && sections == rhs.sections;
261 : }
262 :
263 : /**
264 : * @brief ini operator!= to check if IniWrapper is not equal
265 : *
266 : * @param rhs IniWrapper to compare
267 : * @retval true if not equal
268 : * @retval false if equal
269 : */
270 : bool operator!=(const IniWrapper &rhs) const { return !operator==(rhs); }
271 :
272 : /**
273 : * @brief update sections if section is empty, else update section by section
274 : * by key
275 : *
276 : * @param[in] ini IniWrapper
277 : * @return IniWrapper& this
278 : */
279 11 : IniWrapper &operator+=(const IniWrapper &ini) {
280 11 : if (sections.empty()) {
281 11 : sections = ini.sections;
282 : } else {
283 0 : updateSections(ini.sections);
284 : }
285 :
286 11 : return *this;
287 : }
288 :
289 : /**
290 : * @brief update sections if section is empty, else update section by section
291 : * by key
292 : *
293 : * @param[in] rhs IniWrapper
294 : * @return IniWrapper& a new instance
295 : */
296 11 : IniWrapper operator+(const IniWrapper &rhs) const {
297 22 : return IniWrapper(*this) += rhs;
298 : }
299 :
300 : /**
301 : * @brief update a single section using operator+=
302 : *
303 : * @param string format of `sectionkey / propkey=val | propkey=val| ..`
304 : * @return IniWrapper& ini wrapper
305 : */
306 : IniWrapper &operator+=(const std::string &s) {
307 6 : updateSection(s);
308 : return *this;
309 : }
310 :
311 : /**
312 : * @brief update a single section using operator+=
313 : *
314 : * @param string format of `sectionkey / propkey=val | propkey=val| ..`
315 : * @return IniWrapper& ini wrapper
316 : */
317 : IniWrapper &operator+=(const IniSection §ion_) {
318 10 : sections.push_back(section_);
319 : return *this;
320 : }
321 :
322 : /**
323 : * @brief update a single section using operator +
324 : *
325 : * @param rhs string representatioin to merge
326 : * @return IniWrapper ini wrapper
327 : */
328 6 : IniWrapper operator+(const std::string &rhs) const {
329 18 : return IniWrapper(*this) += rhs;
330 : }
331 :
332 : /**
333 : * @brief update a single section using operator +
334 : *
335 : * @param rhs string representatioin to merge
336 : * @return IniWrapper ini wrapper
337 : */
338 10 : IniWrapper operator+(const IniSection §ion_) const {
339 30 : return IniWrapper(*this) += section_;
340 : }
341 :
342 : /**
343 : * @brief Get the Ini Name object
344 : *
345 : * @return std::string ini name with extension appended
346 : */
347 1280 : std::string getIniName() const { return name + ".ini"; }
348 :
349 : /**
350 : * @brief Get the Name
351 : *
352 : * @return std::string name
353 : */
354 132 : std::string getName() const { return name; }
355 :
356 : /**
357 : * @brief save ini to a file, (getIniName() is used to save)
358 : */
359 : void save_ini() const;
360 :
361 : /**
362 : * @brief save ini by ini_name
363 : *
364 : * @param ini_name ini name to svae
365 : */
366 : void save_ini(const std::string &ini_name) const;
367 :
368 : /**
369 : * @brief erase ini
370 : *
371 : */
372 : void erase_ini() const noexcept;
373 :
374 : /**
375 : * @brief operator<< to print information to outstream
376 : *
377 : * @param os outstream
378 : * @param ini ini wrapper
379 : * @return std::ostream& outstream
380 : */
381 : friend std::ostream &operator<<(std::ostream &os, const IniWrapper &ini) {
382 : return os << ini.name;
383 : }
384 :
385 : private:
386 : /**
387 : * @brief update a section from a formatted string, `sectionkey / propkey=val
388 : * | propkey=val`
389 : * @note add containered version of this, something like std::pair
390 : * @param string_representation "model/optimizer=SGD | ..."
391 : */
392 : void updateSection(const std::string &string_representation);
393 :
394 : /**
395 : * @brief update Section that matches section key of @a sections
396 : *
397 : * @param section section
398 : */
399 : void updateSection(const IniSection §ion);
400 :
401 : /**
402 : * @brief update sections with following rule
403 : * if there is a section key, update entry of the section else throw
404 : * std::invalid_argument
405 : * @param sections sections to update
406 : */
407 : void updateSections(const Sections §ions_);
408 :
409 : std::string name; /**< name of ini */
410 : Sections sections; /**< sections of ini */
411 : };
412 :
413 : } // namespace nntrainer
414 :
415 : #endif // __INI_WRAPPER_H__
|