318
|
1 // Copyright Toru Niina 2017.
|
|
2 // Distributed under the MIT License.
|
|
3 #ifndef TOML11_GET_HPP
|
|
4 #define TOML11_GET_HPP
|
|
5 #include <algorithm>
|
|
6
|
|
7 #include "from.hpp"
|
|
8 #include "result.hpp"
|
|
9 #include "value.hpp"
|
|
10
|
|
11 namespace toml
|
|
12 {
|
|
13
|
|
14 // ============================================================================
|
|
15 // exact toml::* type
|
|
16
|
|
17 template<typename T, typename C,
|
|
18 template<typename ...> class M, template<typename ...> class V>
|
|
19 detail::enable_if_t<detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> &
|
|
20 get(basic_value<C, M, V>& v)
|
|
21 {
|
|
22 return v.template cast<detail::type_to_enum<T, basic_value<C, M, V>>::value>();
|
|
23 }
|
|
24
|
|
25 template<typename T, typename C,
|
|
26 template<typename ...> class M, template<typename ...> class V>
|
|
27 detail::enable_if_t<detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> const&
|
|
28 get(const basic_value<C, M, V>& v)
|
|
29 {
|
|
30 return v.template cast<detail::type_to_enum<T, basic_value<C, M, V>>::value>();
|
|
31 }
|
|
32
|
|
33 template<typename T, typename C,
|
|
34 template<typename ...> class M, template<typename ...> class V>
|
|
35 detail::enable_if_t<detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>
|
|
36 get(basic_value<C, M, V>&& v)
|
|
37 {
|
|
38 return T(std::move(v).template cast<detail::type_to_enum<T, basic_value<C, M, V>>::value>());
|
|
39 }
|
|
40
|
|
41 // ============================================================================
|
|
42 // T == toml::value; identity transformation.
|
|
43
|
|
44 template<typename T, typename C,
|
|
45 template<typename ...> class M, template<typename ...> class V>
|
|
46 inline detail::enable_if_t<std::is_same<T, basic_value<C, M, V>>::value, T>&
|
|
47 get(basic_value<C, M, V>& v)
|
|
48 {
|
|
49 return v;
|
|
50 }
|
|
51
|
|
52 template<typename T, typename C,
|
|
53 template<typename ...> class M, template<typename ...> class V>
|
|
54 inline detail::enable_if_t<std::is_same<T, basic_value<C, M, V>>::value, T> const&
|
|
55 get(const basic_value<C, M, V>& v)
|
|
56 {
|
|
57 return v;
|
|
58 }
|
|
59
|
|
60 template<typename T, typename C,
|
|
61 template<typename ...> class M, template<typename ...> class V>
|
|
62 inline detail::enable_if_t<std::is_same<T, basic_value<C, M, V>>::value, T>
|
|
63 get(basic_value<C, M, V>&& v)
|
|
64 {
|
|
65 return basic_value<C, M, V>(std::move(v));
|
|
66 }
|
|
67
|
|
68 // ============================================================================
|
|
69 // T == toml::basic_value<C2, M2, V2>; basic_value -> basic_value
|
|
70
|
|
71 template<typename T, typename C,
|
|
72 template<typename ...> class M, template<typename ...> class V>
|
|
73 inline detail::enable_if_t<detail::conjunction<detail::is_basic_value<T>,
|
|
74 detail::negation<std::is_same<T, basic_value<C, M, V>>>
|
|
75 >::value, T>
|
|
76 get(const basic_value<C, M, V>& v)
|
|
77 {
|
|
78 return T(v);
|
|
79 }
|
|
80
|
|
81 // ============================================================================
|
|
82 // integer convertible from toml::Integer
|
|
83
|
|
84 template<typename T, typename C,
|
|
85 template<typename ...> class M, template<typename ...> class V>
|
|
86 inline detail::enable_if_t<detail::conjunction<
|
|
87 std::is_integral<T>, // T is integral
|
|
88 detail::negation<std::is_same<T, bool>>, // but not bool
|
|
89 detail::negation< // but not toml::integer
|
|
90 detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
|
91 >::value, T>
|
|
92 get(const basic_value<C, M, V>& v)
|
|
93 {
|
|
94 return static_cast<T>(v.as_integer());
|
|
95 }
|
|
96
|
|
97 // ============================================================================
|
|
98 // floating point convertible from toml::Float
|
|
99
|
|
100 template<typename T, typename C,
|
|
101 template<typename ...> class M, template<typename ...> class V>
|
|
102 inline detail::enable_if_t<detail::conjunction<
|
|
103 std::is_floating_point<T>, // T is floating_point
|
|
104 detail::negation< // but not toml::floating
|
|
105 detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
|
106 >::value, T>
|
|
107 get(const basic_value<C, M, V>& v)
|
|
108 {
|
|
109 return static_cast<T>(v.as_floating());
|
|
110 }
|
|
111
|
|
112 // ============================================================================
|
|
113 // std::string; toml uses its own toml::string, but it should be convertible to
|
|
114 // std::string seamlessly
|
|
115
|
|
116 template<typename T, typename C,
|
|
117 template<typename ...> class M, template<typename ...> class V>
|
|
118 inline detail::enable_if_t<std::is_same<T, std::string>::value, std::string>&
|
|
119 get(basic_value<C, M, V>& v)
|
|
120 {
|
|
121 return v.as_string().str;
|
|
122 }
|
|
123
|
|
124 template<typename T, typename C,
|
|
125 template<typename ...> class M, template<typename ...> class V>
|
|
126 inline detail::enable_if_t<std::is_same<T, std::string>::value, std::string> const&
|
|
127 get(const basic_value<C, M, V>& v)
|
|
128 {
|
|
129 return v.as_string().str;
|
|
130 }
|
|
131
|
|
132 template<typename T, typename C,
|
|
133 template<typename ...> class M, template<typename ...> class V>
|
|
134 inline detail::enable_if_t<std::is_same<T, std::string>::value, std::string>
|
|
135 get(basic_value<C, M, V>&& v)
|
|
136 {
|
|
137 return std::string(std::move(v.as_string().str));
|
|
138 }
|
|
139
|
|
140 // ============================================================================
|
|
141 // std::string_view
|
|
142
|
|
143 #if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
|
|
144 template<typename T, typename C,
|
|
145 template<typename ...> class M, template<typename ...> class V>
|
|
146 inline detail::enable_if_t<std::is_same<T, std::string_view>::value, std::string_view>
|
|
147 get(const basic_value<C, M, V>& v)
|
|
148 {
|
|
149 return std::string_view(v.as_string().str);
|
|
150 }
|
|
151 #endif
|
|
152
|
|
153 // ============================================================================
|
|
154 // std::chrono::duration from toml::local_time.
|
|
155
|
|
156 template<typename T, typename C,
|
|
157 template<typename ...> class M, template<typename ...> class V>
|
|
158 inline detail::enable_if_t<detail::is_chrono_duration<T>::value, T>
|
|
159 get(const basic_value<C, M, V>& v)
|
|
160 {
|
|
161 return std::chrono::duration_cast<T>(
|
|
162 std::chrono::nanoseconds(v.as_local_time()));
|
|
163 }
|
|
164
|
|
165 // ============================================================================
|
|
166 // std::chrono::system_clock::time_point from toml::datetime variants
|
|
167
|
|
168 template<typename T, typename C,
|
|
169 template<typename ...> class M, template<typename ...> class V>
|
|
170 inline detail::enable_if_t<
|
|
171 std::is_same<std::chrono::system_clock::time_point, T>::value, T>
|
|
172 get(const basic_value<C, M, V>& v)
|
|
173 {
|
|
174 switch(v.type())
|
|
175 {
|
|
176 case value_t::local_date:
|
|
177 {
|
|
178 return std::chrono::system_clock::time_point(v.as_local_date());
|
|
179 }
|
|
180 case value_t::local_datetime:
|
|
181 {
|
|
182 return std::chrono::system_clock::time_point(v.as_local_datetime());
|
|
183 }
|
|
184 case value_t::offset_datetime:
|
|
185 {
|
|
186 return std::chrono::system_clock::time_point(v.as_offset_datetime());
|
|
187 }
|
|
188 default:
|
|
189 {
|
|
190 throw type_error(detail::format_underline("toml::value: "
|
|
191 "bad_cast to std::chrono::system_clock::time_point", {
|
|
192 {v.location(), concat_to_string("the actual type is ", v.type())}
|
|
193 }), v.location());
|
|
194 }
|
|
195 }
|
|
196 }
|
|
197
|
|
198 // ============================================================================
|
|
199 // forward declaration to use this recursively. ignore this and go ahead.
|
|
200
|
|
201 // array-like type with push_back(value) method
|
|
202 template<typename T, typename C,
|
|
203 template<typename ...> class M, template<typename ...> class V>
|
|
204 detail::enable_if_t<detail::conjunction<
|
|
205 detail::is_container<T>, // T is a container
|
|
206 detail::has_push_back_method<T>, // T::push_back(value) works
|
|
207 detail::negation< // but not toml::array
|
|
208 detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
|
209 >::value, T>
|
|
210 get(const basic_value<C, M, V>&);
|
|
211
|
|
212 // array-like type without push_back(value) method
|
|
213 template<typename T, typename C,
|
|
214 template<typename ...> class M, template<typename ...> class V>
|
|
215 detail::enable_if_t<detail::conjunction<
|
|
216 detail::is_container<T>, // T is a container
|
|
217 detail::negation<detail::has_push_back_method<T>>, // w/o push_back(...)
|
|
218 detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
|
|
219 detail::negation< // not toml::array
|
|
220 detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
|
221 >::value, T>
|
|
222 get(const basic_value<C, M, V>&);
|
|
223
|
|
224 // std::pair<T1, T2>
|
|
225 template<typename T, typename C,
|
|
226 template<typename ...> class M, template<typename ...> class V>
|
|
227 detail::enable_if_t<detail::is_std_pair<T>::value, T>
|
|
228 get(const basic_value<C, M, V>&);
|
|
229
|
|
230 // std::tuple<T1, T2, ...>
|
|
231 template<typename T, typename C,
|
|
232 template<typename ...> class M, template<typename ...> class V>
|
|
233 detail::enable_if_t<detail::is_std_tuple<T>::value, T>
|
|
234 get(const basic_value<C, M, V>&);
|
|
235
|
|
236 // map-like classes
|
|
237 template<typename T, typename C,
|
|
238 template<typename ...> class M, template<typename ...> class V>
|
|
239 detail::enable_if_t<detail::conjunction<
|
|
240 detail::is_map<T>, // T is map
|
|
241 detail::negation< // but not toml::table
|
|
242 detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
|
243 >::value, T>
|
|
244 get(const basic_value<C, M, V>&);
|
|
245
|
|
246 // T.from_toml(v)
|
|
247 template<typename T, typename C,
|
|
248 template<typename ...> class M, template<typename ...> class V>
|
|
249 detail::enable_if_t<detail::conjunction<
|
|
250 detail::negation< // not a toml::* type
|
|
251 detail::is_exact_toml_type<T, basic_value<C, M, V>>>,
|
|
252 detail::has_from_toml_method<T, C, M, V>, // but has from_toml(toml::value)
|
|
253 std::is_default_constructible<T> // and default constructible
|
|
254 >::value, T>
|
|
255 get(const basic_value<C, M, V>&);
|
|
256
|
|
257 // toml::from<T>::from_toml(v)
|
|
258 template<typename T, typename C,
|
|
259 template<typename ...> class M, template<typename ...> class V>
|
|
260 detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
|
261 get(const basic_value<C, M, V>&);
|
|
262
|
|
263 template<typename T, typename C,
|
|
264 template<typename ...> class M, template<typename ...> class V>
|
|
265 detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
|
266 get(basic_value<C, M, V>&);
|
|
267
|
|
268 // T(const toml::value&) and T is not toml::basic_value,
|
|
269 // and it does not have `from<T>` nor `from_toml`.
|
|
270 template<typename T, typename C,
|
|
271 template<typename ...> class M, template<typename ...> class V>
|
|
272 detail::enable_if_t<detail::conjunction<
|
|
273 detail::negation<detail::is_basic_value<T>>,
|
|
274 std::is_constructible<T, const basic_value<C, M, V>&>,
|
|
275 detail::negation<detail::has_from_toml_method<T, C, M, V>>,
|
|
276 detail::negation<detail::has_specialized_from<T>>
|
|
277 >::value, T>
|
|
278 get(const basic_value<C, M, V>&);
|
|
279
|
|
280 template<typename T, typename C,
|
|
281 template<typename ...> class M, template<typename ...> class V>
|
|
282 detail::enable_if_t<detail::conjunction<
|
|
283 detail::negation<detail::is_basic_value<T>>,
|
|
284 std::is_constructible<T, basic_value<C, M, V>&>,
|
|
285 detail::negation<detail::has_from_toml_method<T, C, M, V>>,
|
|
286 detail::negation<detail::has_specialized_from<T>>
|
|
287 >::value, T>
|
|
288 get(basic_value<C, M, V>&);
|
|
289
|
|
290 // ============================================================================
|
|
291 // array-like types; most likely STL container, like std::vector, etc.
|
|
292
|
|
293 template<typename T, typename C,
|
|
294 template<typename ...> class M, template<typename ...> class V>
|
|
295 detail::enable_if_t<detail::conjunction<
|
|
296 detail::is_container<T>, // T is a container
|
|
297 detail::has_push_back_method<T>, // container.push_back(elem) works
|
|
298 detail::negation< // but not toml::array
|
|
299 detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
|
300 >::value, T>
|
|
301 get(const basic_value<C, M, V>& v)
|
|
302 {
|
|
303 using value_type = typename T::value_type;
|
|
304 const auto& ary = v.as_array();
|
|
305
|
|
306 T container;
|
|
307 try_reserve(container, ary.size());
|
|
308
|
|
309 for(const auto& elem : ary)
|
|
310 {
|
|
311 container.push_back(get<value_type>(elem));
|
|
312 }
|
|
313 return container;
|
|
314 }
|
|
315
|
|
316 // ============================================================================
|
|
317 // std::forward_list does not have push_back, insert, or emplace.
|
|
318 // It has insert_after, emplace_after, push_front.
|
|
319
|
|
320 template<typename T, typename C,
|
|
321 template<typename ...> class M, template<typename ...> class V>
|
|
322 detail::enable_if_t<detail::is_std_forward_list<T>::value, T>
|
|
323 get(const basic_value<C, M, V>& v)
|
|
324 {
|
|
325 using value_type = typename T::value_type;
|
|
326 T container;
|
|
327 for(const auto& elem : v.as_array())
|
|
328 {
|
|
329 container.push_front(get<value_type>(elem));
|
|
330 }
|
|
331 container.reverse();
|
|
332 return container;
|
|
333 }
|
|
334
|
|
335 // ============================================================================
|
|
336 // array-like types, without push_back(). most likely [std|boost]::array.
|
|
337
|
|
338 template<typename T, typename C,
|
|
339 template<typename ...> class M, template<typename ...> class V>
|
|
340 detail::enable_if_t<detail::conjunction<
|
|
341 detail::is_container<T>, // T is a container
|
|
342 detail::negation<detail::has_push_back_method<T>>, // w/o push_back
|
|
343 detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
|
|
344 detail::negation< // T is not toml::array
|
|
345 detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
|
346 >::value, T>
|
|
347 get(const basic_value<C, M, V>& v)
|
|
348 {
|
|
349 using value_type = typename T::value_type;
|
|
350 const auto& ar = v.as_array();
|
|
351
|
|
352 T container;
|
|
353 if(ar.size() != container.size())
|
|
354 {
|
|
355 throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
356 "toml::get: specified container size is ", container.size(),
|
|
357 " but there are ", ar.size(), " elements in toml array."), {
|
|
358 {v.location(), "here"}
|
|
359 }));
|
|
360 }
|
|
361 for(std::size_t i=0; i<ar.size(); ++i)
|
|
362 {
|
|
363 container[i] = ::toml::get<value_type>(ar[i]);
|
|
364 }
|
|
365 return container;
|
|
366 }
|
|
367
|
|
368 // ============================================================================
|
|
369 // std::pair.
|
|
370
|
|
371 template<typename T, typename C,
|
|
372 template<typename ...> class M, template<typename ...> class V>
|
|
373 detail::enable_if_t<detail::is_std_pair<T>::value, T>
|
|
374 get(const basic_value<C, M, V>& v)
|
|
375 {
|
|
376 using first_type = typename T::first_type;
|
|
377 using second_type = typename T::second_type;
|
|
378
|
|
379 const auto& ar = v.as_array();
|
|
380 if(ar.size() != 2)
|
|
381 {
|
|
382 throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
383 "toml::get: specified std::pair but there are ", ar.size(),
|
|
384 " elements in toml array."), {{v.location(), "here"}}));
|
|
385 }
|
|
386 return std::make_pair(::toml::get<first_type >(ar.at(0)),
|
|
387 ::toml::get<second_type>(ar.at(1)));
|
|
388 }
|
|
389
|
|
390 // ============================================================================
|
|
391 // std::tuple.
|
|
392
|
|
393 namespace detail
|
|
394 {
|
|
395 template<typename T, typename Array, std::size_t ... I>
|
|
396 T get_tuple_impl(const Array& a, index_sequence<I...>)
|
|
397 {
|
|
398 return std::make_tuple(
|
|
399 ::toml::get<typename std::tuple_element<I, T>::type>(a.at(I))...);
|
|
400 }
|
|
401 } // detail
|
|
402
|
|
403 template<typename T, typename C,
|
|
404 template<typename ...> class M, template<typename ...> class V>
|
|
405 detail::enable_if_t<detail::is_std_tuple<T>::value, T>
|
|
406 get(const basic_value<C, M, V>& v)
|
|
407 {
|
|
408 const auto& ar = v.as_array();
|
|
409 if(ar.size() != std::tuple_size<T>::value)
|
|
410 {
|
|
411 throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
412 "toml::get: specified std::tuple with ",
|
|
413 std::tuple_size<T>::value, " elements, but there are ", ar.size(),
|
|
414 " elements in toml array."), {{v.location(), "here"}}));
|
|
415 }
|
|
416 return detail::get_tuple_impl<T>(ar,
|
|
417 detail::make_index_sequence<std::tuple_size<T>::value>{});
|
|
418 }
|
|
419
|
|
420 // ============================================================================
|
|
421 // map-like types; most likely STL map, like std::map or std::unordered_map.
|
|
422
|
|
423 template<typename T, typename C,
|
|
424 template<typename ...> class M, template<typename ...> class V>
|
|
425 detail::enable_if_t<detail::conjunction<
|
|
426 detail::is_map<T>, // T is map
|
|
427 detail::negation< // but not toml::array
|
|
428 detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
|
429 >::value, T>
|
|
430 get(const basic_value<C, M, V>& v)
|
|
431 {
|
|
432 using key_type = typename T::key_type;
|
|
433 using mapped_type = typename T::mapped_type;
|
|
434 static_assert(std::is_convertible<std::string, key_type>::value,
|
|
435 "toml::get only supports map type of which key_type is "
|
|
436 "convertible from std::string.");
|
|
437 T map;
|
|
438 for(const auto& kv : v.as_table())
|
|
439 {
|
|
440 map.emplace(key_type(kv.first), get<mapped_type>(kv.second));
|
|
441 }
|
|
442 return map;
|
|
443 }
|
|
444
|
|
445 // ============================================================================
|
|
446 // user-defined, but compatible types.
|
|
447
|
|
448 template<typename T, typename C,
|
|
449 template<typename ...> class M, template<typename ...> class V>
|
|
450 detail::enable_if_t<detail::conjunction<
|
|
451 detail::negation< // not a toml::* type
|
|
452 detail::is_exact_toml_type<T, basic_value<C, M, V>>>,
|
|
453 detail::has_from_toml_method<T, C, M, V>, // but has from_toml(toml::value) memfn
|
|
454 std::is_default_constructible<T> // and default constructible
|
|
455 >::value, T>
|
|
456 get(const basic_value<C, M, V>& v)
|
|
457 {
|
|
458 T ud;
|
|
459 ud.from_toml(v);
|
|
460 return ud;
|
|
461 }
|
|
462 template<typename T, typename C,
|
|
463 template<typename ...> class M, template<typename ...> class V>
|
|
464 detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
|
465 get(const basic_value<C, M, V>& v)
|
|
466 {
|
|
467 return ::toml::from<T>::from_toml(v);
|
|
468 }
|
|
469 template<typename T, typename C,
|
|
470 template<typename ...> class M, template<typename ...> class V>
|
|
471 detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
|
472 get(basic_value<C, M, V>& v)
|
|
473 {
|
|
474 return ::toml::from<T>::from_toml(v);
|
|
475 }
|
|
476
|
|
477 template<typename T, typename C,
|
|
478 template<typename ...> class M, template<typename ...> class V>
|
|
479 detail::enable_if_t<detail::conjunction<
|
|
480 detail::negation<detail::is_basic_value<T>>, // T is not a toml::value
|
|
481 std::is_constructible<T, const basic_value<C, M, V>&>, // T is constructible from toml::value
|
|
482 detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
|
|
483 detail::negation<detail::has_specialized_from<T>> // and T does not have toml::from<T>{};
|
|
484 >::value, T>
|
|
485 get(const basic_value<C, M, V>& v)
|
|
486 {
|
|
487 return T(v);
|
|
488 }
|
|
489
|
|
490 template<typename T, typename C,
|
|
491 template<typename ...> class M, template<typename ...> class V>
|
|
492 detail::enable_if_t<detail::conjunction<
|
|
493 detail::negation<detail::is_basic_value<T>>, // T is not a toml::value
|
|
494 std::is_constructible<T, basic_value<C, M, V>&>, // T is constructible from toml::value
|
|
495 detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
|
|
496 detail::negation<detail::has_specialized_from<T>> // and T does not have toml::from<T>{};
|
|
497 >::value, T>
|
|
498 get(basic_value<C, M, V>& v)
|
|
499 {
|
|
500 return T(v);
|
|
501 }
|
|
502
|
|
503 // ============================================================================
|
|
504 // find
|
|
505
|
|
506 // ----------------------------------------------------------------------------
|
|
507 // these overloads do not require to set T. and returns value itself.
|
|
508 template<typename C,
|
|
509 template<typename ...> class M, template<typename ...> class V>
|
|
510 basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
|
|
511 {
|
|
512 const auto& tab = v.as_table();
|
|
513 if(tab.count(ky) == 0)
|
|
514 {
|
|
515 detail::throw_key_not_found_error(v, ky);
|
|
516 }
|
|
517 return tab.at(ky);
|
|
518 }
|
|
519 template<typename C,
|
|
520 template<typename ...> class M, template<typename ...> class V>
|
|
521 basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
|
|
522 {
|
|
523 auto& tab = v.as_table();
|
|
524 if(tab.count(ky) == 0)
|
|
525 {
|
|
526 detail::throw_key_not_found_error(v, ky);
|
|
527 }
|
|
528 return tab.at(ky);
|
|
529 }
|
|
530 template<typename C,
|
|
531 template<typename ...> class M, template<typename ...> class V>
|
|
532 basic_value<C, M, V> find(basic_value<C, M, V>&& v, const key& ky)
|
|
533 {
|
|
534 typename basic_value<C, M, V>::table_type tab = std::move(v).as_table();
|
|
535 if(tab.count(ky) == 0)
|
|
536 {
|
|
537 detail::throw_key_not_found_error(v, ky);
|
|
538 }
|
|
539 return basic_value<C, M, V>(std::move(tab.at(ky)));
|
|
540 }
|
|
541
|
|
542 // ----------------------------------------------------------------------------
|
|
543 // find(value, idx)
|
|
544 template<typename C,
|
|
545 template<typename ...> class M, template<typename ...> class V>
|
|
546 basic_value<C, M, V> const&
|
|
547 find(const basic_value<C, M, V>& v, const std::size_t idx)
|
|
548 {
|
|
549 const auto& ary = v.as_array();
|
|
550 if(ary.size() <= idx)
|
|
551 {
|
|
552 throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
553 "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
|
554 }
|
|
555 return ary.at(idx);
|
|
556 }
|
|
557 template<typename C,
|
|
558 template<typename ...> class M, template<typename ...> class V>
|
|
559 basic_value<C, M, V>& find(basic_value<C, M, V>& v, const std::size_t idx)
|
|
560 {
|
|
561 auto& ary = v.as_array();
|
|
562 if(ary.size() <= idx)
|
|
563 {
|
|
564 throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
565 "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
|
566 }
|
|
567 return ary.at(idx);
|
|
568 }
|
|
569 template<typename C,
|
|
570 template<typename ...> class M, template<typename ...> class V>
|
|
571 basic_value<C, M, V> find(basic_value<C, M, V>&& v, const std::size_t idx)
|
|
572 {
|
|
573 auto& ary = v.as_array();
|
|
574 if(ary.size() <= idx)
|
|
575 {
|
|
576 throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
577 "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
|
578 }
|
|
579 return basic_value<C, M, V>(std::move(ary.at(idx)));
|
|
580 }
|
|
581
|
|
582 // ----------------------------------------------------------------------------
|
|
583 // find<T>(value, key);
|
|
584
|
|
585 template<typename T, typename C,
|
|
586 template<typename ...> class M, template<typename ...> class V>
|
|
587 decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))
|
|
588 find(const basic_value<C, M, V>& v, const key& ky)
|
|
589 {
|
|
590 const auto& tab = v.as_table();
|
|
591 if(tab.count(ky) == 0)
|
|
592 {
|
|
593 detail::throw_key_not_found_error(v, ky);
|
|
594 }
|
|
595 return ::toml::get<T>(tab.at(ky));
|
|
596 }
|
|
597
|
|
598 template<typename T, typename C,
|
|
599 template<typename ...> class M, template<typename ...> class V>
|
|
600 decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
|
|
601 find(basic_value<C, M, V>& v, const key& ky)
|
|
602 {
|
|
603 auto& tab = v.as_table();
|
|
604 if(tab.count(ky) == 0)
|
|
605 {
|
|
606 detail::throw_key_not_found_error(v, ky);
|
|
607 }
|
|
608 return ::toml::get<T>(tab.at(ky));
|
|
609 }
|
|
610
|
|
611 template<typename T, typename C,
|
|
612 template<typename ...> class M, template<typename ...> class V>
|
|
613 decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
|
|
614 find(basic_value<C, M, V>&& v, const key& ky)
|
|
615 {
|
|
616 typename basic_value<C, M, V>::table_type tab = std::move(v).as_table();
|
|
617 if(tab.count(ky) == 0)
|
|
618 {
|
|
619 detail::throw_key_not_found_error(v, ky);
|
|
620 }
|
|
621 return ::toml::get<T>(std::move(tab.at(ky)));
|
|
622 }
|
|
623
|
|
624 // ----------------------------------------------------------------------------
|
|
625 // find<T>(value, idx)
|
|
626 template<typename T, typename C,
|
|
627 template<typename ...> class M, template<typename ...> class V>
|
|
628 decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))
|
|
629 find(const basic_value<C, M, V>& v, const std::size_t idx)
|
|
630 {
|
|
631 const auto& ary = v.as_array();
|
|
632 if(ary.size() <= idx)
|
|
633 {
|
|
634 throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
635 "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
|
636 }
|
|
637 return ::toml::get<T>(ary.at(idx));
|
|
638 }
|
|
639 template<typename T, typename C,
|
|
640 template<typename ...> class M, template<typename ...> class V>
|
|
641 decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
|
|
642 find(basic_value<C, M, V>& v, const std::size_t idx)
|
|
643 {
|
|
644 auto& ary = v.as_array();
|
|
645 if(ary.size() <= idx)
|
|
646 {
|
|
647 throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
648 "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
|
649 }
|
|
650 return ::toml::get<T>(ary.at(idx));
|
|
651 }
|
|
652 template<typename T, typename C,
|
|
653 template<typename ...> class M, template<typename ...> class V>
|
|
654 decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
|
|
655 find(basic_value<C, M, V>&& v, const std::size_t idx)
|
|
656 {
|
|
657 typename basic_value<C, M, V>::array_type ary = std::move(v).as_array();
|
|
658 if(ary.size() <= idx)
|
|
659 {
|
|
660 throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
661 "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
|
662 }
|
|
663 return ::toml::get<T>(std::move(ary.at(idx)));
|
|
664 }
|
|
665
|
|
666 // --------------------------------------------------------------------------
|
|
667 // toml::find(toml::value, toml::key, Ts&& ... keys)
|
|
668
|
|
669 namespace detail
|
|
670 {
|
|
671 // It suppresses warnings by -Wsign-conversion. Let's say we have the following
|
|
672 // code.
|
|
673 // ```cpp
|
|
674 // const auto x = toml::find<std::string>(data, "array", 0);
|
|
675 // ```
|
|
676 // Here, the type of literal number `0` is `int`. `int` is a signed integer.
|
|
677 // `toml::find` takes `std::size_t` as an index. So it causes implicit sign
|
|
678 // conversion and `-Wsign-conversion` warns about it. Using `0u` instead of `0`
|
|
679 // suppresses the warning, but it makes user code messy.
|
|
680 // To suppress this warning, we need to be aware of type conversion caused
|
|
681 // by `toml::find(v, key1, key2, ... keys)`. But the thing is that the types of
|
|
682 // keys can be any combination of {string-like, size_t-like}. Of course we can't
|
|
683 // write down all the combinations. Thus we need to use some function that
|
|
684 // recognize the type of argument and cast it into `std::string` or
|
|
685 // `std::size_t` depending on the context.
|
|
686 // `key_cast` does the job. It has 2 overloads. One is invoked when the
|
|
687 // argument type is an integer and cast the argument into `std::size_t`. The
|
|
688 // other is invoked when the argument type is not an integer, possibly one of
|
|
689 // std::string, const char[N] or const char*, and construct std::string from
|
|
690 // the argument.
|
|
691 // `toml::find(v, k1, k2, ... ks)` uses `key_cast` before passing `ks` to
|
|
692 // `toml::find(v, k)` to suppress -Wsign-conversion.
|
|
693
|
|
694 template<typename T>
|
|
695 enable_if_t<conjunction<std::is_integral<remove_cvref_t<T>>,
|
|
696 negation<std::is_same<remove_cvref_t<T>, bool>>>::value, std::size_t>
|
|
697 key_cast(T&& v) noexcept
|
|
698 {
|
|
699 return std::size_t(v);
|
|
700 }
|
|
701 template<typename T>
|
|
702 enable_if_t<negation<conjunction<std::is_integral<remove_cvref_t<T>>,
|
|
703 negation<std::is_same<remove_cvref_t<T>, bool>>>>::value, std::string>
|
|
704 key_cast(T&& v) noexcept
|
|
705 {
|
|
706 return std::string(std::forward<T>(v));
|
|
707 }
|
|
708 } // detail
|
|
709
|
|
710 template<typename C,
|
|
711 template<typename ...> class M, template<typename ...> class V,
|
|
712 typename Key1, typename Key2, typename ... Keys>
|
|
713 const basic_value<C, M, V>&
|
|
714 find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
|
715 {
|
|
716 return ::toml::find(::toml::find(v, detail::key_cast(k1)),
|
|
717 detail::key_cast(k2), std::forward<Keys>(keys)...);
|
|
718 }
|
|
719 template<typename C,
|
|
720 template<typename ...> class M, template<typename ...> class V,
|
|
721 typename Key1, typename Key2, typename ... Keys>
|
|
722 basic_value<C, M, V>&
|
|
723 find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
|
724 {
|
|
725 return ::toml::find(::toml::find(v, detail::key_cast(k1)),
|
|
726 detail::key_cast(k2), std::forward<Keys>(keys)...);
|
|
727 }
|
|
728 template<typename C,
|
|
729 template<typename ...> class M, template<typename ...> class V,
|
|
730 typename Key1, typename Key2, typename ... Keys>
|
|
731 basic_value<C, M, V>
|
|
732 find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
|
733 {
|
|
734 return ::toml::find(::toml::find(std::move(v), std::forward<Key1>(k1)),
|
|
735 detail::key_cast(k2), std::forward<Keys>(keys)...);
|
|
736 }
|
|
737
|
|
738 template<typename T, typename C,
|
|
739 template<typename ...> class M, template<typename ...> class V,
|
|
740 typename Key1, typename Key2, typename ... Keys>
|
|
741 decltype(::toml::get<T>(std::declval<const basic_value<C, M, V>&>()))
|
|
742 find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
|
743 {
|
|
744 return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
|
|
745 detail::key_cast(k2), std::forward<Keys>(keys)...);
|
|
746 }
|
|
747 template<typename T, typename C,
|
|
748 template<typename ...> class M, template<typename ...> class V,
|
|
749 typename Key1, typename Key2, typename ... Keys>
|
|
750 decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
|
|
751 find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
|
752 {
|
|
753 return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
|
|
754 detail::key_cast(k2), std::forward<Keys>(keys)...);
|
|
755 }
|
|
756 template<typename T, typename C,
|
|
757 template<typename ...> class M, template<typename ...> class V,
|
|
758 typename Key1, typename Key2, typename ... Keys>
|
|
759 decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
|
|
760 find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
|
761 {
|
|
762 return ::toml::find<T>(::toml::find(std::move(v), detail::key_cast(k1)),
|
|
763 detail::key_cast(k2), std::forward<Keys>(keys)...);
|
|
764 }
|
|
765
|
|
766 // ============================================================================
|
|
767 // get_or(value, fallback)
|
|
768
|
|
769 template<typename C,
|
|
770 template<typename ...> class M, template<typename ...> class V>
|
|
771 basic_value<C, M, V> const&
|
|
772 get_or(const basic_value<C, M, V>& v, const basic_value<C, M, V>&)
|
|
773 {
|
|
774 return v;
|
|
775 }
|
|
776 template<typename C,
|
|
777 template<typename ...> class M, template<typename ...> class V>
|
|
778 basic_value<C, M, V>&
|
|
779 get_or(basic_value<C, M, V>& v, basic_value<C, M, V>&)
|
|
780 {
|
|
781 return v;
|
|
782 }
|
|
783 template<typename C,
|
|
784 template<typename ...> class M, template<typename ...> class V>
|
|
785 basic_value<C, M, V>
|
|
786 get_or(basic_value<C, M, V>&& v, basic_value<C, M, V>&&)
|
|
787 {
|
|
788 return v;
|
|
789 }
|
|
790
|
|
791 // ----------------------------------------------------------------------------
|
|
792 // specialization for the exact toml types (return type becomes lvalue ref)
|
|
793
|
|
794 template<typename T, typename C,
|
|
795 template<typename ...> class M, template<typename ...> class V>
|
|
796 detail::enable_if_t<
|
|
797 detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> const&
|
|
798 get_or(const basic_value<C, M, V>& v, const T& opt)
|
|
799 {
|
|
800 try
|
|
801 {
|
|
802 return get<detail::remove_cvref_t<T>>(v);
|
|
803 }
|
|
804 catch(...)
|
|
805 {
|
|
806 return opt;
|
|
807 }
|
|
808 }
|
|
809 template<typename T, typename C,
|
|
810 template<typename ...> class M, template<typename ...> class V>
|
|
811 detail::enable_if_t<
|
|
812 detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&
|
|
813 get_or(basic_value<C, M, V>& v, T& opt)
|
|
814 {
|
|
815 try
|
|
816 {
|
|
817 return get<detail::remove_cvref_t<T>>(v);
|
|
818 }
|
|
819 catch(...)
|
|
820 {
|
|
821 return opt;
|
|
822 }
|
|
823 }
|
|
824 template<typename T, typename C,
|
|
825 template<typename ...> class M, template<typename ...> class V>
|
|
826 detail::enable_if_t<detail::is_exact_toml_type<detail::remove_cvref_t<T>,
|
|
827 basic_value<C, M, V>>::value, detail::remove_cvref_t<T>>
|
|
828 get_or(basic_value<C, M, V>&& v, T&& opt)
|
|
829 {
|
|
830 try
|
|
831 {
|
|
832 return get<detail::remove_cvref_t<T>>(std::move(v));
|
|
833 }
|
|
834 catch(...)
|
|
835 {
|
|
836 return detail::remove_cvref_t<T>(std::forward<T>(opt));
|
|
837 }
|
|
838 }
|
|
839
|
|
840 // ----------------------------------------------------------------------------
|
|
841 // specialization for std::string (return type becomes lvalue ref)
|
|
842
|
|
843 template<typename T, typename C,
|
|
844 template<typename ...> class M, template<typename ...> class V>
|
|
845 detail::enable_if_t<std::is_same<detail::remove_cvref_t<T>, std::string>::value,
|
|
846 std::string> const&
|
|
847 get_or(const basic_value<C, M, V>& v, const T& opt)
|
|
848 {
|
|
849 try
|
|
850 {
|
|
851 return v.as_string().str;
|
|
852 }
|
|
853 catch(...)
|
|
854 {
|
|
855 return opt;
|
|
856 }
|
|
857 }
|
|
858 template<typename T, typename C,
|
|
859 template<typename ...> class M, template<typename ...> class V>
|
|
860 detail::enable_if_t<std::is_same<T, std::string>::value, std::string>&
|
|
861 get_or(basic_value<C, M, V>& v, T& opt)
|
|
862 {
|
|
863 try
|
|
864 {
|
|
865 return v.as_string().str;
|
|
866 }
|
|
867 catch(...)
|
|
868 {
|
|
869 return opt;
|
|
870 }
|
|
871 }
|
|
872 template<typename T, typename C,
|
|
873 template<typename ...> class M, template<typename ...> class V>
|
|
874 detail::enable_if_t<
|
|
875 std::is_same<detail::remove_cvref_t<T>, std::string>::value, std::string>
|
|
876 get_or(basic_value<C, M, V>&& v, T&& opt)
|
|
877 {
|
|
878 try
|
|
879 {
|
|
880 return std::move(v.as_string().str);
|
|
881 }
|
|
882 catch(...)
|
|
883 {
|
|
884 return std::string(std::forward<T>(opt));
|
|
885 }
|
|
886 }
|
|
887
|
|
888 // ----------------------------------------------------------------------------
|
|
889 // specialization for string literal
|
|
890
|
|
891 template<typename T, typename C,
|
|
892 template<typename ...> class M, template<typename ...> class V>
|
|
893 detail::enable_if_t<detail::is_string_literal<
|
|
894 typename std::remove_reference<T>::type>::value, std::string>
|
|
895 get_or(const basic_value<C, M, V>& v, T&& opt)
|
|
896 {
|
|
897 try
|
|
898 {
|
|
899 return std::move(v.as_string().str);
|
|
900 }
|
|
901 catch(...)
|
|
902 {
|
|
903 return std::string(std::forward<T>(opt));
|
|
904 }
|
|
905 }
|
|
906
|
|
907 // ----------------------------------------------------------------------------
|
|
908 // others (require type conversion and return type cannot be lvalue reference)
|
|
909
|
|
910 template<typename T, typename C,
|
|
911 template<typename ...> class M, template<typename ...> class V>
|
|
912 detail::enable_if_t<detail::conjunction<
|
|
913 detail::negation<detail::is_exact_toml_type<detail::remove_cvref_t<T>,
|
|
914 basic_value<C, M, V>>>,
|
|
915 detail::negation<std::is_same<std::string, detail::remove_cvref_t<T>>>,
|
|
916 detail::negation<detail::is_string_literal<
|
|
917 typename std::remove_reference<T>::type>>
|
|
918 >::value, detail::remove_cvref_t<T>>
|
|
919 get_or(const basic_value<C, M, V>& v, T&& opt)
|
|
920 {
|
|
921 try
|
|
922 {
|
|
923 return get<detail::remove_cvref_t<T>>(v);
|
|
924 }
|
|
925 catch(...)
|
|
926 {
|
|
927 return detail::remove_cvref_t<T>(std::forward<T>(opt));
|
|
928 }
|
|
929 }
|
|
930
|
|
931 // ===========================================================================
|
|
932 // find_or(value, key, fallback)
|
|
933
|
|
934 template<typename C,
|
|
935 template<typename ...> class M, template<typename ...> class V>
|
|
936 basic_value<C, M, V> const&
|
|
937 find_or(const basic_value<C, M, V>& v, const key& ky,
|
|
938 const basic_value<C, M, V>& opt)
|
|
939 {
|
|
940 if(!v.is_table()) {return opt;}
|
|
941 const auto& tab = v.as_table();
|
|
942 if(tab.count(ky) == 0) {return opt;}
|
|
943 return tab.at(ky);
|
|
944 }
|
|
945
|
|
946 template<typename C,
|
|
947 template<typename ...> class M, template<typename ...> class V>
|
|
948 basic_value<C, M, V>&
|
|
949 find_or(basic_value<C, M, V>& v, const toml::key& ky, basic_value<C, M, V>& opt)
|
|
950 {
|
|
951 if(!v.is_table()) {return opt;}
|
|
952 auto& tab = v.as_table();
|
|
953 if(tab.count(ky) == 0) {return opt;}
|
|
954 return tab.at(ky);
|
|
955 }
|
|
956
|
|
957 template<typename C,
|
|
958 template<typename ...> class M, template<typename ...> class V>
|
|
959 basic_value<C, M, V>
|
|
960 find_or(basic_value<C, M, V>&& v, const toml::key& ky, basic_value<C, M, V>&& opt)
|
|
961 {
|
|
962 if(!v.is_table()) {return opt;}
|
|
963 auto tab = std::move(v).as_table();
|
|
964 if(tab.count(ky) == 0) {return opt;}
|
|
965 return basic_value<C, M, V>(std::move(tab.at(ky)));
|
|
966 }
|
|
967
|
|
968 // ---------------------------------------------------------------------------
|
|
969 // exact types (return type can be a reference)
|
|
970 template<typename T, typename C,
|
|
971 template<typename ...> class M, template<typename ...> class V>
|
|
972 detail::enable_if_t<
|
|
973 detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> const&
|
|
974 find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
|
|
975 {
|
|
976 if(!v.is_table()) {return opt;}
|
|
977 const auto& tab = v.as_table();
|
|
978 if(tab.count(ky) == 0) {return opt;}
|
|
979 return get_or(tab.at(ky), opt);
|
|
980 }
|
|
981
|
|
982 template<typename T, typename C,
|
|
983 template<typename ...> class M, template<typename ...> class V>
|
|
984 detail::enable_if_t<
|
|
985 detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&
|
|
986 find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
|
|
987 {
|
|
988 if(!v.is_table()) {return opt;}
|
|
989 auto& tab = v.as_table();
|
|
990 if(tab.count(ky) == 0) {return opt;}
|
|
991 return get_or(tab.at(ky), opt);
|
|
992 }
|
|
993
|
|
994 template<typename T, typename C,
|
|
995 template<typename ...> class M, template<typename ...> class V>
|
|
996 detail::enable_if_t<
|
|
997 detail::is_exact_toml_type<T, basic_value<C, M, V>>::value,
|
|
998 detail::remove_cvref_t<T>>
|
|
999 find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
|
|
1000 {
|
|
1001 if(!v.is_table()) {return std::forward<T>(opt);}
|
|
1002 auto tab = std::move(v).as_table();
|
|
1003 if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
|
1004 return get_or(std::move(tab.at(ky)), std::forward<T>(opt));
|
|
1005 }
|
|
1006
|
|
1007 // ---------------------------------------------------------------------------
|
|
1008 // std::string (return type can be a reference)
|
|
1009
|
|
1010 template<typename T, typename C,
|
|
1011 template<typename ...> class M, template<typename ...> class V>
|
|
1012 detail::enable_if_t<std::is_same<T, std::string>::value, std::string> const&
|
|
1013 find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
|
|
1014 {
|
|
1015 if(!v.is_table()) {return opt;}
|
|
1016 const auto& tab = v.as_table();
|
|
1017 if(tab.count(ky) == 0) {return opt;}
|
|
1018 return get_or(tab.at(ky), opt);
|
|
1019 }
|
|
1020 template<typename T, typename C,
|
|
1021 template<typename ...> class M, template<typename ...> class V>
|
|
1022 detail::enable_if_t<std::is_same<T, std::string>::value, std::string>&
|
|
1023 find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
|
|
1024 {
|
|
1025 if(!v.is_table()) {return opt;}
|
|
1026 auto& tab = v.as_table();
|
|
1027 if(tab.count(ky) == 0) {return opt;}
|
|
1028 return get_or(tab.at(ky), opt);
|
|
1029 }
|
|
1030 template<typename T, typename C,
|
|
1031 template<typename ...> class M, template<typename ...> class V>
|
|
1032 detail::enable_if_t<std::is_same<T, std::string>::value, std::string>
|
|
1033 find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
|
|
1034 {
|
|
1035 if(!v.is_table()) {return std::forward<T>(opt);}
|
|
1036 auto tab = std::move(v).as_table();
|
|
1037 if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
|
1038 return get_or(std::move(tab.at(ky)), std::forward<T>(opt));
|
|
1039 }
|
|
1040
|
|
1041 // ---------------------------------------------------------------------------
|
|
1042 // string literal (deduced as std::string)
|
|
1043 template<typename T, typename C,
|
|
1044 template<typename ...> class M, template<typename ...> class V>
|
|
1045 detail::enable_if_t<
|
|
1046 detail::is_string_literal<typename std::remove_reference<T>::type>::value,
|
|
1047 std::string>
|
|
1048 find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
|
|
1049 {
|
|
1050 if(!v.is_table()) {return std::string(opt);}
|
|
1051 const auto& tab = v.as_table();
|
|
1052 if(tab.count(ky) == 0) {return std::string(opt);}
|
|
1053 return get_or(tab.at(ky), std::forward<T>(opt));
|
|
1054 }
|
|
1055
|
|
1056 // ---------------------------------------------------------------------------
|
|
1057 // others (require type conversion and return type cannot be lvalue reference)
|
|
1058 template<typename T, typename C,
|
|
1059 template<typename ...> class M, template<typename ...> class V>
|
|
1060 detail::enable_if_t<detail::conjunction<
|
|
1061 // T is not an exact toml type
|
|
1062 detail::negation<detail::is_exact_toml_type<
|
|
1063 detail::remove_cvref_t<T>, basic_value<C, M, V>>>,
|
|
1064 // T is not std::string
|
|
1065 detail::negation<std::is_same<std::string, detail::remove_cvref_t<T>>>,
|
|
1066 // T is not a string literal
|
|
1067 detail::negation<detail::is_string_literal<
|
|
1068 typename std::remove_reference<T>::type>>
|
|
1069 >::value, detail::remove_cvref_t<T>>
|
|
1070 find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
|
|
1071 {
|
|
1072 if(!v.is_table()) {return std::forward<T>(opt);}
|
|
1073 const auto& tab = v.as_table();
|
|
1074 if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
|
1075 return get_or(tab.at(ky), std::forward<T>(opt));
|
|
1076 }
|
|
1077
|
|
1078 // ---------------------------------------------------------------------------
|
|
1079 // recursive find-or with type deduction (find_or(value, keys, opt))
|
|
1080
|
|
1081 template<typename Value, typename ... Ks,
|
|
1082 typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
|
|
1083 // here we need to add SFINAE in the template parameter to avoid
|
|
1084 // infinite recursion in type deduction on gcc
|
|
1085 auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
|
|
1086 -> decltype(find_or(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
|
|
1087 {
|
|
1088 if(!v.is_table())
|
|
1089 {
|
|
1090 return detail::last_one(std::forward<Ks>(keys)...);
|
|
1091 }
|
|
1092 auto&& tab = std::forward<Value>(v).as_table();
|
|
1093 if(tab.count(ky) == 0)
|
|
1094 {
|
|
1095 return detail::last_one(std::forward<Ks>(keys)...);
|
|
1096 }
|
|
1097 return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
|
|
1098 }
|
|
1099
|
|
1100 // ---------------------------------------------------------------------------
|
|
1101 // recursive find_or with explicit type specialization, find_or<int>(value, keys...)
|
|
1102
|
|
1103 template<typename T, typename Value, typename ... Ks,
|
|
1104 typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
|
|
1105 // here we need to add SFINAE in the template parameter to avoid
|
|
1106 // infinite recursion in type deduction on gcc
|
|
1107 auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
|
|
1108 -> decltype(find_or<T>(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
|
|
1109 {
|
|
1110 if(!v.is_table())
|
|
1111 {
|
|
1112 return detail::last_one(std::forward<Ks>(keys)...);
|
|
1113 }
|
|
1114 auto&& tab = std::forward<Value>(v).as_table();
|
|
1115 if(tab.count(ky) == 0)
|
|
1116 {
|
|
1117 return detail::last_one(std::forward<Ks>(keys)...);
|
|
1118 }
|
|
1119 return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
|
|
1120 }
|
|
1121
|
|
1122 // ============================================================================
|
|
1123 // expect
|
|
1124
|
|
1125 template<typename T, typename C,
|
|
1126 template<typename ...> class M, template<typename ...> class V>
|
|
1127 result<T, std::string> expect(const basic_value<C, M, V>& v) noexcept
|
|
1128 {
|
|
1129 try
|
|
1130 {
|
|
1131 return ok(get<T>(v));
|
|
1132 }
|
|
1133 catch(const std::exception& e)
|
|
1134 {
|
|
1135 return err(e.what());
|
|
1136 }
|
|
1137 }
|
|
1138 template<typename T, typename C,
|
|
1139 template<typename ...> class M, template<typename ...> class V>
|
|
1140 result<T, std::string>
|
|
1141 expect(const basic_value<C, M, V>& v, const toml::key& k) noexcept
|
|
1142 {
|
|
1143 try
|
|
1144 {
|
|
1145 return ok(find<T>(v, k));
|
|
1146 }
|
|
1147 catch(const std::exception& e)
|
|
1148 {
|
|
1149 return err(e.what());
|
|
1150 }
|
|
1151 }
|
|
1152
|
|
1153 } // toml
|
|
1154 #endif// TOML11_GET
|