The source code and dockerfile for the GSW2024 AI Lab.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

200 lines
5.4 KiB

4 weeks ago
  1. # Introduction #
  2. A typical example, loading a configuration file, might look like this:
  3. ```cpp
  4. YAML::Node config = YAML::LoadFile("config.yaml");
  5. if (config["lastLogin"]) {
  6. std::cout << "Last logged in: " << config["lastLogin"].as<DateTime>() << "\n";
  7. }
  8. const std::string username = config["username"].as<std::string>();
  9. const std::string password = config["password"].as<std::string>();
  10. login(username, password);
  11. config["lastLogin"] = getCurrentDateTime();
  12. std::ofstream fout("config.yaml");
  13. fout << config;
  14. ```
  15. # Basic Parsing and Node Editing #
  16. All nodes in a YAML document (including the root) are represented by `YAML::Node`. You can check what kind it is:
  17. ```cpp
  18. YAML::Node node = YAML::Load("[1, 2, 3]");
  19. assert(node.Type() == YAML::NodeType::Sequence);
  20. assert(node.IsSequence()); // a shortcut!
  21. ```
  22. Collection nodes (sequences and maps) act somewhat like STL vectors and maps:
  23. ```cpp
  24. YAML::Node primes = YAML::Load("[2, 3, 5, 7, 11]");
  25. for (std::size_t i=0;i<primes.size();i++) {
  26. std::cout << primes[i].as<int>() << "\n";
  27. }
  28. // or:
  29. for (YAML::const_iterator it=primes.begin();it!=primes.end();++it) {
  30. std::cout << it->as<int>() << "\n";
  31. }
  32. primes.push_back(13);
  33. assert(primes.size() == 6);
  34. ```
  35. and
  36. ```cpp
  37. YAML::Node lineup = YAML::Load("{1B: Prince Fielder, 2B: Rickie Weeks, LF: Ryan Braun}");
  38. for(YAML::const_iterator it=lineup.begin();it!=lineup.end();++it) {
  39. std::cout << "Playing at " << it->first.as<std::string>() << " is " << it->second.as<std::string>() << "\n";
  40. }
  41. lineup["RF"] = "Corey Hart";
  42. lineup["C"] = "Jonathan Lucroy";
  43. assert(lineup.size() == 5);
  44. ```
  45. Querying for keys does **not** create them automatically (this makes handling optional map entries very easy)
  46. ```cpp
  47. YAML::Node node = YAML::Load("{name: Brewers, city: Milwaukee}");
  48. if (node["name"]) {
  49. std::cout << node["name"].as<std::string>() << "\n";
  50. }
  51. if (node["mascot"]) {
  52. std::cout << node["mascot"].as<std::string>() << "\n";
  53. }
  54. assert(node.size() == 2); // the previous call didn't create a node
  55. ```
  56. If you're not sure what kind of data you're getting, you can query the type of a node:
  57. ```cpp
  58. switch (node.Type()) {
  59. case Null: // ...
  60. case Scalar: // ...
  61. case Sequence: // ...
  62. case Map: // ...
  63. case Undefined: // ...
  64. }
  65. ```
  66. or ask directly whether it's a particular type, e.g.:
  67. ```cpp
  68. if (node.IsSequence()) {
  69. // ...
  70. }
  71. ```
  72. # Building Nodes #
  73. You can build `YAML::Node` from scratch:
  74. ```cpp
  75. YAML::Node node; // starts out as null
  76. node["key"] = "value"; // it now is a map node
  77. node["seq"].push_back("first element"); // node["seq"] automatically becomes a sequence
  78. node["seq"].push_back("second element");
  79. node["mirror"] = node["seq"][0]; // this creates an alias
  80. node["seq"][0] = "1st element"; // this also changes node["mirror"]
  81. node["mirror"] = "element #1"; // and this changes node["seq"][0] - they're really the "same" node
  82. node["self"] = node; // you can even create self-aliases
  83. node[node["mirror"]] = node["seq"]; // and strange loops :)
  84. ```
  85. The above node is now:
  86. ```yaml
  87. &1
  88. key: value
  89. &2 seq: [&3 "element #1", second element]
  90. mirror: *3
  91. self: *1
  92. *3 : *2
  93. ```
  94. # How Sequences Turn Into Maps #
  95. Sequences can be turned into maps by asking for non-integer keys. For example,
  96. ```cpp
  97. YAML::Node node = YAML::Load("[1, 2, 3]");
  98. node[1] = 5; // still a sequence, [1, 5, 3]
  99. node.push_back(-3) // still a sequence, [1, 5, 3, -3]
  100. node["key"] = "value"; // now it's a map! {0: 1, 1: 5, 2: 3, 3: -3, key: value}
  101. ```
  102. Indexing a sequence node by an index that's not in its range will _usually_ turn it into a map, but if the index is one past the end of the sequence, then the sequence will grow by one to accommodate it. (That's the **only** exception to this rule.) For example,
  103. ```cpp
  104. YAML::Node node = YAML::Load("[1, 2, 3]");
  105. node[3] = 4; // still a sequence, [1, 2, 3, 4]
  106. node[10] = 10; // now it's a map! {0: 1, 1: 2, 2: 3, 3: 4, 10: 10}
  107. ```
  108. # Converting To/From Native Data Types #
  109. Yaml-cpp has built-in conversion to and from most built-in data types, as well as `std::vector`, `std::list`, and `std::map`. The following examples demonstrate when those conversions are used:
  110. ```cpp
  111. YAML::Node node = YAML::Load("{pi: 3.14159, [0, 1]: integers}");
  112. // this needs the conversion from Node to double
  113. double pi = node["pi"].as<double>();
  114. // this needs the conversion from double to Node
  115. node["e"] = 2.71828;
  116. // this needs the conversion from Node to std::vector<int> (*not* the other way around!)
  117. std::vector<int> v;
  118. v.push_back(0);
  119. v.push_back(1);
  120. std::string str = node[v].as<std::string>();
  121. ```
  122. To use yaml-cpp with your own data types, you need to specialize the YAML::convert<> template class. For example, suppose you had a simple `Vec3` class:
  123. ```cpp
  124. struct Vec3 { double x, y, z; /* etc - make sure you have overloaded operator== */ };
  125. ```
  126. You could write
  127. ```cpp
  128. namespace YAML {
  129. template<>
  130. struct convert<Vec3> {
  131. static Node encode(const Vec3& rhs) {
  132. Node node;
  133. node.push_back(rhs.x);
  134. node.push_back(rhs.y);
  135. node.push_back(rhs.z);
  136. return node;
  137. }
  138. static bool decode(const Node& node, Vec3& rhs) {
  139. if(!node.IsSequence() || node.size() != 3) {
  140. return false;
  141. }
  142. rhs.x = node[0].as<double>();
  143. rhs.y = node[1].as<double>();
  144. rhs.z = node[2].as<double>();
  145. return true;
  146. }
  147. };
  148. }
  149. ```
  150. Then you could use `Vec3` wherever you could use any other type:
  151. ```cpp
  152. YAML::Node node = YAML::Load("start: [1, 3, 0]");
  153. Vec3 v = node["start"].as<Vec3>();
  154. node["end"] = Vec3(2, -1, 0);
  155. ```