Mercurial > minori
comparison dep/toml11/toml/get.hpp @ 318:3b355fa948c7
config: use TOML instead of INI
unfortunately, INI is not enough, and causes some paths including
semicolons to break with our current storage of the library folders.
so, I decided to switch to TOML which does support real arrays...
| author | Paper <paper@paper.us.eu.org> |
|---|---|
| date | Wed, 12 Jun 2024 05:25:41 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 317:b1f4d1867ab1 | 318:3b355fa948c7 |
|---|---|
| 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 |
