PDFxTMDLib  1.0.0
ConfigWrapper.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <fstream>
4 #include <map>
5 #include <optional>
6 #include <sstream>
7 #include <string>
8 #include <variant>
9 #include <vector>
10 
12 #include "PDFxTMDLib/external/rapidyaml/rapidyaml-0.9.0.hpp"
13 #include <iostream>
14 
15 #include <vector>
16 #include <type_traits>
17 
18 // General case: T is not a vector
19 template <typename T>
20 struct is_vector : std::false_type {};
21 
22 // Specialization: T is std::vector<U> for some U
23 template <typename U>
24 struct is_vector<std::vector<U>> : std::true_type {};
25 
26 namespace PDFxTMD
27 {
29 {
30  public:
31  enum class Format
32  {
33  YAML
34  };
35 
36  // Constructor initializes an empty YAML map
38  {
40  }
41 
42  bool loadFromFile(const std::filesystem::path &filepath, Format format);
43 
44  bool loadFromString(const std::string &data_string, Format format);
45 
46 template <typename T>
47 std::pair<std::optional<T>, ErrorType> get(const std::string &key) const {
48  if (data.format == Format::YAML) {
49  ryml::ConstNodeRef root = data.tree.rootref();
50  if (!root.is_map()) {
51  return {std::nullopt, ErrorType::CONFIG_KeyNotFound};
52  }
53  ryml::csubstr ckey(key.data(), key.size());
54  if (!root.has_child(ckey)) {
55  return {std::nullopt, ErrorType::CONFIG_KeyNotFound};
56  }
57 
58  ryml::ConstNodeRef node = root[ckey];
59  try {
60  if constexpr (is_vector<T>::value) {
61  // T is a std::vector<U>
62  if (node.is_seq()) {
63  using U = typename T::value_type; // U is the element type (e.g., int, std::string)
64  T values;
65  for (const auto& child : node) {
66  U val;
67  child >> val; // Extract each sequence element as U
68  values.push_back(val);
69  }
70  return {values, ErrorType::None};
71  } else {
72  return {std::nullopt, ErrorType::CONFIG_ConversionFailed};
73  }
74  } else {
75  // T is not a vector (e.g., int, std::string)
76  T value;
77  node >> value; // Direct streaming for non-vector types
78  return {value, ErrorType::None};
79  }
80  } catch (const std::exception &) {
81  return {std::nullopt, ErrorType::CONFIG_ConversionFailed};
82  }
83  }
84  return {std::nullopt, ErrorType::CONFIG_KeyNotFound};
85 }
86  template <typename T> bool set(const std::string &key, const T &value)
87  {
88  if (data.format == Format::YAML)
89  {
90  if (!data.tree.rootref().is_map())
91  {
92  return false;
93  }
94  try
95  {
96  ryml::csubstr ckey(key.data(), key.size());
97 
98  // BUG FIX 2: Stream directly to the node.
99  // This avoids creating a temporary string and the resulting
100  // dangling pointer. ryml will manage the memory.
101  data.tree[ckey] << value;
102  }
103  catch (const std::exception &e)
104  {
105  // It's generally better to let exceptions propagate or handle them more gracefully
106  // than re-throwing as a different type, but we'll keep the original logic.
107  throw std::runtime_error(e.what());
108  }
109  return true;
110  }
111  return false;
112  }
113 
114  bool saveToFile(const std::string &filename) const;
115 
117  {
118  data.tree.clear();
119  data.tree.rootref() |= ryml::MAP; // Set the root to be a map
120  data.format = Format::YAML;
121  }
122 
123  private:
124  struct Data
125  {
126  Format format;
127  ryml::Tree tree;
128  } data;
129 };
130 } // namespace PDFxTMD
Definition: ConfigWrapper.h:29
ConfigWrapper()
Definition: ConfigWrapper.h:37
void initializeEmptyYAML()
Definition: ConfigWrapper.h:116
bool saveToFile(const std::string &filename) const
std::pair< std::optional< T >, ErrorType > get(const std::string &key) const
Definition: ConfigWrapper.h:47
bool loadFromString(const std::string &data_string, Format format)
Format
Definition: ConfigWrapper.h:32
bool set(const std::string &key, const T &value)
Definition: ConfigWrapper.h:86
bool loadFromFile(const std::filesystem::path &filepath, Format format)
Definition: AllFlavorsShape.h:14
ErrorType
Definition: PartonUtils.h:42
Definition: ConfigWrapper.h:20