1 #pragma once 2 3 #include "types.hpp" 4 #include "config_mergeable.hpp" 5 #include "config_origin.hpp" 6 #include "config_object.hpp" 7 #include "config_resolve_options.hpp" 8 #include "config_value.hpp" 9 #include "config_list.hpp" 10 #include "config_exception.hpp" 11 #include "path.hpp" 12 #include <vector> 13 #include <string> 14 #include <set> 15 #include "export.h" 16 #include <leatherman/locale/locale.hpp> 17 18 namespace hocon { 19 20 enum class time_unit { NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS }; 21 22 /** 23 * An immutable map from config paths to config values. Paths are dot-separated 24 * expressions such as <code>foo.bar.baz</code>. Values are as in JSON 25 * (booleans, strings, numbers, lists, or objects), represented by 26 * {@link config_value} instances. Values accessed through the 27 * <code>config</code> interface are never null. 28 * 29 * <p> 30 * {@code config} is an immutable object and thus safe to use from multiple 31 * threads. There's never a need for "defensive copies." 32 * 33 * <p> 34 * Fundamental operations on a {@code config} include getting configuration 35 * values, <em>resolving</em> substitutions with {@link config#resolve()}, and 36 * merging configs using {@link config#with_fallback(config_mergeable)}. 37 * 38 * <p> 39 * All operations return a new immutable {@code config} rather than modifying 40 * the original instance. 41 * 42 * <p> 43 * <strong>Examples</strong> 44 * 45 * <p> 46 * You can find an example app and library <a 47 * href="https://github.com/typesafehub/config/tree/master/examples">on 48 * GitHub</a>. Also be sure to read the <a 49 * href="package-summary.html#package_description">package overview</a> which 50 * describes the big picture as shown in those examples. 51 * 52 * <p> 53 * <strong>Paths, keys, and config vs. config_object</strong> 54 * 55 * <p> 56 * <code>config</code> is a view onto a tree of {@link config_object}; the 57 * corresponding object tree can be found through {@link config#root()}. 58 * <code>config_object</code> is a map from config <em>keys</em>, rather than 59 * paths, to config values. Think of <code>config_object</code> as a JSON object 60 * and <code>config</code> as a configuration API. 61 * 62 * <p> 63 * The API tries to consistently use the terms "key" and "path." A key is a key 64 * in a JSON object; it's just a string that's the key in a map. A "path" is a 65 * parseable expression with a syntax and it refers to a series of keys. Path 66 * expressions are described in the <a 67 * href="https://github.com/typesafehub/config/blob/master/HOCON.md">spec for 68 * Human-Optimized Config Object Notation</a>. In brief, a path is 69 * period-separated so "a.b.c" looks for key c in object b in object a in the 70 * root object. Sometimes double quotes are needed around special characters in 71 * path expressions. 72 * 73 * <p> 74 * The API for a {@code config} is in terms of path expressions, while the API 75 * for a {@code config_object} is in terms of keys. Conceptually, {@code config} 76 * is a one-level map from <em>paths</em> to values, while a 77 * {@code config_object} is a tree of nested maps from <em>keys</em> to values. 78 * 79 * <p> 80 * Use {@link config_util#join_path} and {@link config_util#split_path} to convert 81 * between path expressions and individual path elements (keys). 82 * 83 * <p> 84 * Another difference between {@code config} and {@code config_object} is that 85 * conceptually, {@code config_value}s with a {@link config_value#value_type() 86 * value_type()} of {@link config_value::type#NULL NULL} exist in a 87 * {@code config_object}, while a {@code config} treats null values as if they 88 * were missing. (With the exception of two methods: {@link config#has_path_or_null} 89 * and {@link config#get_is_null} let you detect <code>null</code> values.) 90 * 91 * <p> 92 * <strong>Getting configuration values</strong> 93 * 94 * <p> 95 * The "getters" on a {@code config} all work in the same way. They never return 96 * null, nor do they return a {@code config_value} with 97 * {@link config_value#value_type() value_type()} of {@link config_value::type#NULL 98 * NULL}. Instead, they throw {@link config_exception} if the value is 99 * completely absent or set to null. If the value is set to null, a subtype of 100 * {@code config_exception.missing} called {@link config_exception.null} will be 101 * thrown. {@link config_excpetion.wrong_type} will be thrown anytime you ask for 102 * a type and the value has an incompatible type. Reasonable type conversions 103 * are performed for you though. 104 * 105 * <p> 106 * <strong>Iteration</strong> 107 * 108 * <p> 109 * If you want to iterate over the contents of a {@code config}, you can get its 110 * {@code config_object} with {@link #root()}, and then iterate over the 111 * {@code config_object} (which implements <code>java.util.Map</code>). Or, you 112 * can use {@link #entry_set()} which recurses the object tree for you and builds 113 * up a <code>set</code> of all path-value pairs where the value is not null. 114 * 115 * <p> 116 * <strong>Resolving substitutions</strong> 117 * 118 * <p> 119 * <em>Substitutions</em> are the <code>${foo.bar}</code> syntax in config 120 * files, described in the <a href= 121 * "https://github.com/typesafehub/config/blob/master/HOCON.md#substitutions" 122 * >specification</a>. Resolving substitutions replaces these references with real 123 * values. 124 * 125 * <p> 126 * Before using a {@code config} it's necessary to call {@link config#resolve()} 127 * to handle substitutions (though {@link config_factory#load()} and similar 128 * methods will do the resolve for you already). 129 * 130 * <p> 131 * <strong>Merging</strong> 132 * 133 * <p> 134 * The full <code>config</code> for your application can be constructed using 135 * the associative operation {@link config#with_fallback(config_mergeable)}. If 136 * you use {@link config_factory#load()} (recommended), it merges system 137 * properties over the top of <code>application.conf</code> over the top of 138 * <code>reference.conf</code>, using <code>with_fallback</code>. You can add in 139 * additional sources of configuration in the same way (usually, custom layers 140 * should go either just above or just below <code>application.conf</code>, 141 * keeping <code>reference.conf</code> at the bottom and system properties at 142 * the top). 143 * 144 * <p> 145 * <strong>Serialization</strong> 146 * 147 * <p> 148 * Convert a <code>config</code> to a JSON or HOCON string by calling 149 * {@link config_object#render()} on the root object, 150 * <code>my_config.root().render()</code>. There's also a variant 151 * {@link config_object#render(config_render_options)} which allows you to control 152 * the format of the rendered string. (See {@link config_render_options}.) Note 153 * that <code>config</code> does not remember the formatting of the original 154 * file, so if you load, modify, and re-save a config file, it will be 155 * substantially reformatted. 156 * 157 * <p> 158 * As an alternative to {@link config_object#render()}, the 159 * <code>to_string()</code> method produces a debug-output-oriented 160 * representation (which is not valid JSON). 161 * 162 * <p> 163 * <strong>This is an interface but don't implement it yourself</strong> 164 * 165 * <p> 166 * <em>Do not implement {@code config}</em>; it should only be implemented by 167 * the config library. Arbitrary implementations will not work because the 168 * library internals assume a specific concrete implementation. Also, this 169 * interface is likely to grow new methods over time, so third-party 170 * implementations will break. 171 */ 172 class LIBCPP_HOCON_EXPORT config : public config_mergeable, public std::enable_shared_from_this<config> { 173 friend class config_object; 174 friend class config_value; 175 friend class config_parseable; 176 friend class parseable; 177 178 public: 179 /** 180 * Parses a file with a flexible extension. If the <code>fileBasename</code> 181 * already ends in a known extension, this method parses it according to 182 * that extension (the file's syntax must match its extension). If the 183 * <code>fileBasename</code> does not end in an extension, it parses files 184 * with all known extensions and merges whatever is found. 185 * 186 * <p> 187 * In the current implementation, the extension ".conf" forces 188 * {@link ConfigSyntax#CONF}, ".json" forces {@link ConfigSyntax#JSON}. 189 * When merging files, ".conf" falls back to ".json". 190 * 191 * <p> 192 * Future versions of the implementation may add additional syntaxes or 193 * additional extensions. However, the ordering (fallback priority) of the 194 * three current extensions will remain the same. 195 * 196 * <p> 197 * If <code>options</code> forces a specific syntax, this method only parses 198 * files with an extension matching that syntax. 199 * 200 * <p> 201 * If {@link ConfigParseOptions#getAllowMissing options.getAllowMissing()} 202 * is true, then no files have to exist; if false, then at least one file 203 * has to exist. 204 * 205 * @param fileBasename 206 * a filename with or without extension 207 * @param options 208 * parse options 209 * @return the parsed configuration 210 */ 211 static shared_config parse_file_any_syntax(std::string file_basename, config_parse_options options); 212 213 /** 214 * Like {@link #parseFileAnySyntax(File,ConfigParseOptions)} but always uses 215 * default parse options. 216 * 217 * @param fileBasename 218 * a filename with or without extension 219 * @return the parsed configuration 220 */ 221 static shared_config parse_file_any_syntax(std::string file_basename); 222 223 /** 224 * Parses a string (which should be valid HOCON or JSON by default, or 225 * the syntax specified in the options otherwise). 226 * 227 * @param s string to parse 228 * @param options parse options 229 * @return the parsed configuration 230 */ 231 static shared_config parse_string(std::string s, config_parse_options options); 232 233 /** 234 * Parses a string (which should be valid HOCON or JSON). 235 * 236 * @param s string to parse 237 * @return the parsed configuration 238 */ 239 static shared_config parse_string(std::string s); 240 241 /** 242 * Gets the {@code Config} as a tree of {@link ConfigObject}. This is a 243 * constant-time operation (it is not proportional to the number of values 244 * in the {@code Config}). 245 * 246 * @return the root object in the configuration 247 */ 248 virtual shared_object root() const; 249 250 /** 251 * Gets the origin of the {@code Config}, which may be a file, or a file 252 * with a line number, or just a descriptive phrase. 253 * 254 * @return the origin of the {@code Config} for use in error messages 255 */ 256 virtual shared_origin origin() const; 257 258 std::shared_ptr<const config_mergeable> with_fallback(std::shared_ptr<const config_mergeable> other) const override; 259 260 shared_value to_fallback_value() const override; 261 262 /** 263 * Returns a replacement config with all substitutions (the 264 * <code>${foo.bar}</code> syntax, see <a 265 * href="https://github.com/typesafehub/config/blob/master/HOCON.md">the 266 * spec</a>) resolved. Substitutions are looked up using this 267 * <code>config</code> as the root object, that is, a substitution 268 * <code>${foo.bar}</code> will be replaced with the result of 269 * <code>get_value("foo.bar")</code>. 270 * 271 * <p> 272 * This method uses {@link config_resolve_options()}, there is 273 * another variant {@link config#resolve(config_resolve_options)} which lets 274 * you specify non-default options. 275 * 276 * <p> 277 * A given {@link config} must be resolved before using it to retrieve 278 * config values, but ideally should be resolved one time for your entire 279 * stack of fallbacks (see {@link config#with_fallback}). Otherwise, some 280 * substitutions that could have resolved with all fallbacks available may 281 * not resolve, which will be potentially confusing for your application's 282 * users. 283 * 284 * <p> 285 * <code>resolve()</code> should be invoked on root config objects, rather 286 * than on a subtree (a subtree is the result of something like 287 * <code>config.get_config("foo")</code>). The problem with 288 * <code>resolve()</code> on a subtree is that substitutions are relative to 289 * the root of the config and the subtree will have no way to get values 290 * from the root. For example, if you did 291 * <code>config.get_config("foo").resolve()</code> on the below config file, 292 * it would not work: 293 * 294 * <pre> 295 * common-value = 10 296 * foo { 297 * whatever = ${common-value} 298 * } 299 * </pre> 300 * 301 * <p> 302 * Many methods on {@link config_factory} such as 303 * {@link config_factory#load()} automatically resolve the loaded 304 * <code>config</code> on the loaded stack of config files. 305 * 306 * <p> 307 * Resolving an already-resolved config is a harmless no-op, but again, it 308 * is best to resolve an entire stack of fallbacks (such as all your config 309 * files combined) rather than resolving each one individually. 310 * 311 * @return an immutable object with substitutions resolved 312 */ 313 virtual shared_config resolve() const; 314 315 /** 316 * Like {@link config#resolve()} but allows you to specify non-default 317 * options. 318 * 319 * @param options 320 * resolve options 321 * @return the resolved <code>config</code> (may be only partially resolved if options are 322 * set to allow unresolved) 323 */ 324 virtual shared_config resolve(config_resolve_options options) const; 325 326 /** 327 * Checks whether the config is completely resolved. After a successful call 328 * to {@link config#resolve()} it will be completely resolved, but after 329 * calling {@link config#resolve(config_resolve_options)} with 330 * <code>allow_unresolved</code> set in the options, it may or may not be 331 * completely resolved. A newly-loaded config may or may not be completely 332 * resolved depending on whether there were substitutions present in the 333 * file. 334 * 335 * @return true if there are no unresolved substitutions remaining in this 336 * configuration. 337 */ 338 virtual bool is_resolved() const; 339 340 /** 341 * Like {@link config#resolve()} except that substitution values are looked 342 * up in the given source, rather than in this instance. This is a 343 * special-purpose method which doesn't make sense to use in most cases; 344 * it's only needed if you're constructing some sort of app-specific custom 345 * approach to configuration. The more usual approach if you have a source 346 * of substitution values would be to merge that source into your config 347 * stack using {@link config#withFallback} and then resolve. 348 * <p> 349 * Note that this method does NOT look in this instance for substitution 350 * values. If you want to do that, you could either merge this instance into 351 * your value source using {@link config#with_fallback}, or you could resolve 352 * multiple times with multiple sources (using 353 * {@link config_resolve_options#setAllowUnresolved(boolean)} so the partial 354 * resolves don't fail). 355 * 356 * @param source 357 * configuration to pull values from 358 * @return an immutable object with substitutions resolved 359 */ 360 virtual shared_config resolve_with(shared_config source) const; 361 362 /** 363 * Like {@link config#resolve_with(config)} but allows you to specify 364 * non-default options. 365 * 366 * @param source 367 * source configuration to pull values from 368 * @param options 369 * resolve options 370 * @return the resolved <code>config</code> (may be only partially resolved 371 * if options are set to allow unresolved) 372 */ 373 virtual shared_config resolve_with(shared_config source, config_resolve_options options) const; 374 375 /** 376 * Validates this config against a reference config, throwing an exception 377 * if it is invalid. The purpose of this method is to "fail early" with a 378 * comprehensive list of problems; in general, anything this method can find 379 * would be detected later when trying to use the config, but it's often 380 * more user-friendly to fail right away when loading the config. 381 * 382 * <p> 383 * Using this method is always optional, since you can "fail late" instead. 384 * 385 * <p> 386 * You must restrict validation to paths you "own" (those whose meaning are 387 * defined by your code module). If you validate globally, you may trigger 388 * errors about paths that happen to be in the config but have nothing to do 389 * with your module. It's best to allow the modules owning those paths to 390 * validate them. Also, if every module validates only its own stuff, there 391 * isn't as much redundant work being done. 392 * 393 * <p> 394 * If no paths are specified in <code>check_valid()</code>'s parameter list, 395 * validation is for the entire config. 396 * 397 * <p> 398 * If you specify paths that are not in the reference config, those paths 399 * are ignored. (There's nothing to validate.) 400 * 401 * <p> 402 * Here's what validation involves: 403 * 404 * <ul> 405 * <li>All paths found in the reference config must be present in this 406 * config or an exception will be thrown. 407 * <li> 408 * Some changes in type from the reference config to this config will cause 409 * an exception to be thrown. Not all potential type problems are detected, 410 * in particular it's assumed that strings are compatible with everything 411 * except objects and lists. This is because string types are often "really" 412 * some other type (system properties always start out as strings, or a 413 * string like "5ms" could be used with {@link #get_milliseconds}). Also, 414 * it's allowed to set any type to null or override null with any type. 415 * <li> 416 * Any unresolved substitutions in this config will cause a validation 417 * failure; both the reference config and this config should be resolved 418 * before validation. If the reference config is unresolved, it's a bug in 419 * the caller of this method. 420 * </ul> 421 * 422 * <p> 423 * If you want to allow a certain setting to have a flexible type (or 424 * otherwise want validation to be looser for some settings), you could 425 * either remove the problematic setting from the reference config provided 426 * to this method, or you could intercept the validation exception and 427 * screen out certain problems. Of course, this will only work if all other 428 * callers of this method are careful to restrict validation to their own 429 * paths, as they should be. 430 * 431 * <p> 432 * If validation fails, the thrown exception contains a list of all problems 433 * found. The exception will have all the problem concatenated into one huge string. 434 * 435 * <p> 436 * Again, <code>check_valid()</code> can't guess every domain-specific way a 437 * setting can be invalid, so some problems may arise later when attempting 438 * to use the config. <code>check_valid()</code> is limited to reporting 439 * generic, but common, problems such as missing settings and blatant type 440 * incompatibilities. 441 * 442 * @param reference 443 * a reference configuration 444 * @param restrictToPaths 445 * only validate values underneath these paths that your code 446 * module owns and understands 447 */ 448 virtual void check_valid(shared_config reference, std::vector<std::string> restrict_to_paths) const; 449 450 /** 451 * Checks whether a value is present and non-null at the given path. This 452 * differs in two ways from {@code Map.containsKey()} as implemented by 453 * {@link config_object}: it looks for a path expression, not a key; and it 454 * returns false for null values, while {@code contains_key()} returns true 455 * indicating that the object contains a null value for the key. 456 * 457 * <p> 458 * If a path exists according to {@link #has_path(string)}, then 459 * {@link #get_value(string)} will never throw an exception. However, the 460 * typed getters will still throw if the value is not convertible to the 461 * requested type. 462 * 463 * <p> 464 * Note that path expressions have a syntax and sometimes require quoting 465 * (see {@link config_util#join_path} and {@link config_util#split_path}). 466 * 467 * @param path 468 * the path expression 469 * @return true if a non-null value is present at the path 470 */ 471 virtual bool has_path(std::string const& path) const; 472 473 /** 474 * Checks whether a value is present at the given path, even 475 * if the value is null. Most of the getters on 476 * <code>config</code> will throw if you try to get a null 477 * value, so if you plan to call {@link #get_value(string)}, 478 * {@link #get_int(string)}, or another getter you may want to 479 * use plain {@link #has_path(string)} rather than this method. 480 * 481 * <p> 482 * To handle all three cases (unset, null, and a non-null value) 483 * the code might look like: 484 * <pre><code> 485 * if (config.has_path_or_null(path)) { 486 * if (config.get_is_null(path)) { 487 * // handle null setting 488 * } else { 489 * // get and use non-null setting 490 * } 491 * } else { 492 * // handle entirely unset path 493 * } 494 * </code></pre> 495 * 496 * <p> However, the usual thing is to allow entirely unset 497 * paths to be a bug that throws an exception (because you set 498 * a default in your <code>reference.conf</code>), so in that 499 * case it's OK to call {@link #get_is_null(string)} without 500 * checking <code>has_path_or_null</code> first. 501 * 502 * <p> 503 * Note that path expressions have a syntax and sometimes require quoting 504 * (see {@link config_util#join_path} and {@link config_util#split_path}). 505 * 506 * @param path 507 * the path expression 508 * @return true if a value is present at the path, even if the value is null 509 */ 510 virtual bool has_path_or_null(std::string const& path) const; 511 512 /** 513 * Returns true if the {@code Config}'s root object contains no key-value 514 * pairs. 515 * 516 * @return true if the configuration is empty 517 */ 518 virtual bool is_empty() const; 519 520 /** 521 * Returns the set of path-value pairs, excluding any null values, found by 522 * recursing {@link #root() the root object}. Note that this is very 523 * different from <code>root().entry_set()</code> which returns the set of 524 * immediate-child keys in the root object and includes null values. 525 * <p> 526 * Entries contain <em>path expressions</em> meaning there may be quoting 527 * and escaping involved. Parse path expressions with 528 * {@link config_util#split_path}. 529 * <p> 530 * Because a <code>config</code> is conceptually a single-level map from 531 * paths to values, there will not be any {@link config_object} values in the 532 * entries (that is, all entries represent leaf nodes). Use 533 * {@link config_object} rather than <code>config</code> if you want a tree. 534 * (OK, this is a slight lie: <code>config</code> entries may contain 535 * {@link config_list} and the lists may contain objects. But no objects are 536 * directly included as entry values.) 537 * 538 * @return set of paths with non-null values, built up by recursing the 539 * entire tree of {@link config_object} and creating an entry for 540 * each leaf value. 541 */ 542 virtual std::set<std::pair<std::string, std::shared_ptr<const config_value>>> entry_set() const; 543 544 /** 545 * Checks whether a value is set to null at the given path, 546 * but throws an exception if the value is entirely 547 * unset. This method will not throw if {@link 548 * #has_path_or_null(string)} returned true for the same path, so 549 * to avoid any possible exception check 550 * <code>has_path_or_null()</code> first. However, an exception 551 * for unset paths will usually be the right thing (because a 552 * <code>reference.conf</code> should exist that has the path 553 * set, the path should never be unset unless something is 554 * broken). 555 * 556 * <p> 557 * Note that path expressions have a syntax and sometimes require quoting 558 * (see {@link config_util#join_path} and {@link config_util#split_path}). 559 * 560 * @param path 561 * the path expression 562 * @return true if the value exists and is null, false if it 563 * exists and is not null 564 */ 565 virtual bool get_is_null(std::string const& path) const; 566 567 virtual bool get_bool(std::string const& path) const; 568 virtual int get_int(std::string const& path) const; 569 virtual int64_t get_long(std::string const& path) const; 570 virtual double get_double(std::string const& path) const; 571 virtual std::string get_string(std::string const& path) const; 572 virtual std::shared_ptr<const config_object> get_object(std::string const& path) const; 573 virtual shared_config get_config(std::string const& path) const; 574 virtual unwrapped_value get_any_ref(std::string const& path) const; 575 virtual std::shared_ptr<const config_value> get_value(std::string const& path) const; 576 577 template<typename T> get_homogeneous_unwrapped_list(std::string const & path) const578 std::vector<T> get_homogeneous_unwrapped_list(std::string const& path) const { 579 auto list = boost::get<std::vector<unwrapped_value>>(get_list(path)->unwrapped()); 580 std::vector<T> T_list; 581 for (auto item : list) { 582 try { 583 T_list.push_back(boost::get<T>(item)); 584 } catch (boost::bad_get &ex) { 585 throw config_exception(leatherman::locale::format("The list did not contain only the desired type.")); 586 } 587 } 588 return T_list; 589 } 590 591 virtual shared_list get_list(std::string const& path) const; 592 virtual std::vector<bool> get_bool_list(std::string const& path) const; 593 virtual std::vector<int> get_int_list(std::string const& path) const; 594 virtual std::vector<int64_t> get_long_list(std::string const& path) const; 595 virtual std::vector<double> get_double_list(std::string const& path) const; 596 virtual std::vector<std::string> get_string_list(std::string const& path) const; 597 virtual std::vector<shared_object> get_object_list(std::string const& path) const; 598 virtual std::vector<shared_config> get_config_list(std::string const& path) const; 599 600 // TODO: memory parsing 601 602 /** 603 * Gets a value as an integer number of the specified units. 604 * If the result would have a fractional part, the number is truncated. 605 * Correctly handles durations within the range +/-2^63 seconds. 606 * @param path the path to the time value 607 * @param unit the units of the number returned 608 * @return a 64-bit integer representing the value converted to the requested units 609 */ 610 virtual int64_t get_duration(std::string const& path, time_unit unit) const; 611 612 /** 613 * Clone the config with only the given path (and its children) retained; 614 * all sibling paths are removed. 615 * <p> 616 * Note that path expressions have a syntax and sometimes require quoting 617 * (see {@link config_util#join_path} and {@link config_util#split_path}). 618 * 619 * @param path 620 * path to keep 621 * @return a copy of the config minus all paths except the one specified 622 */ 623 virtual shared_config with_only_path(std::string const& path) const; 624 625 /** 626 * Clone the config with the given path removed. 627 * <p> 628 * Note that path expressions have a syntax and sometimes require quoting 629 * (see {@link config_util#join_path} and {@link config_util#split_path}). 630 * 631 * @param path 632 * path expression to remove 633 * @return a copy of the config minus the specified path 634 */ 635 virtual shared_config without_path(std::string const& path) const; 636 637 /** 638 * Places the config inside another {@code config} at the given path. 639 * <p> 640 * Note that path expressions have a syntax and sometimes require quoting 641 * (see {@link config_util#join_path} and {@link config_util#split_path}). 642 * 643 * @param path 644 * path expression to store this config at. 645 * @return a {@code config} instance containing this config at the given 646 * path. 647 */ 648 virtual shared_config at_path(std::string const& path) const; 649 650 /** 651 * Places the config inside a {@code config} at the given key. See also 652 * at_path(). Note that a key is NOT a path expression (see 653 * {@link config_util#join_path} and {@link config_util#split_path}). 654 * 655 * @param key 656 * key to store this config at. 657 * @return a {@code config} instance containing this config at the given 658 * key. 659 */ 660 virtual shared_config at_key(std::string const& key) const; 661 662 /** 663 * Returns a {@code config} based on this one, but with the given path set 664 * to the given value. Does not modify this instance (since it's immutable). 665 * If the path already has a value, that value is replaced. To remove a 666 * value, use withoutPath(). 667 * <p> 668 * Note that path expressions have a syntax and sometimes require quoting 669 * (see {@link config_util#join_path} and {@link config_util#split_path}). 670 * 671 * @param path 672 * path expression for the value's new location 673 * @param value 674 * value at the new path 675 * @return the new instance with the new map entry 676 */ 677 virtual shared_config with_value(std::string const& path, std::shared_ptr<const config_value> value) const; 678 679 bool operator==(config const& other) const; 680 681 config(shared_object object); 682 683 static shared_object env_variables_as_config_object(); 684 685 protected: 686 shared_value find(std::string const& path_expression, config_value::type expected) const; 687 shared_value find(path path_expression, config_value::type expected, path original_path) const; 688 shared_value find(path path_expression, config_value::type expected) const; 689 shared_config at_key(shared_origin origin, std::string const& key) const; 690 691 static shared_includer default_includer(); 692 693 // TODO: memory and duration parsing 694 695 private: 696 /** 697 * Parses a duration string. If no units are specified in the string, it is assumed to be in 698 * milliseconds. 699 * Valid suffixes include ns, us, ms, s, m, h, and d. The units can also be specified as complete 700 * words (e.g. "seconds"). 701 * @param input the string to parse 702 * @param origin_for_exception the origin of the value being parsed 703 * @param path_for_exception the path to the value being parsed 704 * @return the value parsed as a time_duration 705 */ 706 static duration parse_duration(std::string input, shared_origin origin_for_exception, std::string path_for_exception); 707 708 static duration convert(int64_t number, time_unit units); 709 static duration convert(double number, time_unit units); 710 static time_unit get_units(std::string const& unit_string); 711 duration get_duration(std::string const& path) const; 712 713 shared_value has_path_peek(std::string const& path_expression) const; 714 shared_value peek_path(path desired_path) const; 715 716 static void find_paths(std::set<std::pair<std::string, std::shared_ptr<const config_value>>>& entries, 717 path parent, shared_object obj); 718 static shared_value throw_if_null(shared_value v, config_value::type expected, path original_path); 719 static shared_value find_key(shared_object self, std::string const& key, 720 config_value::type expected, path original_path); 721 static shared_value find_key_or_null(shared_object self, std::string const& key, 722 config_value::type expected, path original_path); 723 static shared_value find_or_null(shared_object self, path desired_path, 724 config_value::type expected, path original_path); 725 shared_value find_or_null(std::string const& path_expression, config_value::type expected) const; 726 shared_value find_or_null(path path_expression, config_value::type expected, path original_path) const; 727 728 shared_object _object; 729 }; 730 731 template<> 732 std::vector<int64_t> config::get_homogeneous_unwrapped_list(std::string const& path) const; 733 734 } // namespace hocon 735