SPH
Settings.impl.h
Go to the documentation of this file.
1 #include "io/FileSystem.h"
2 #include "objects/Exceptions.h"
5 #include "system/Settings.h"
6 #include <fstream>
7 #include <regex>
8 
10 
12 
13 template <typename TEnum>
14 Settings<TEnum>::Settings(std::initializer_list<Entry> list) {
15  for (auto& entry : list) {
16  SPH_ASSERT(!entries.contains(entry.id), "Duplicate settings ID ", int(entry.id));
17  entries.insert(entry.id, entry);
18  }
19 }
20 
21 template <typename TEnum>
23  : Settings(Settings::getDefaults()) {}
24 
25 template <typename TEnum>
27 
28 template <typename TEnum>
30  : entries(other.entries.clone()) {}
31 
32 template <typename TEnum>
34  : entries(std::move(other.entries)) {}
35 
36 template <typename TEnum>
37 Settings<TEnum>& Settings<TEnum>::operator=(std::initializer_list<Entry> list) {
38  entries.clear();
39  for (auto& entry : list) {
40  entries.insert(entry.id, entry);
41  }
42  return *this;
43 }
44 
45 template <typename TEnum>
47  entries = other.entries.clone();
48  return *this;
49 }
50 
51 template <typename TEnum>
53  entries = std::move(other.entries);
54  return *this;
55 }
56 
57 template <typename TEnum>
58 bool Settings<TEnum>::setValueByType(Entry& entry, const Value& defaultValue, const std::string& str) {
59  const Size typeIdx = defaultValue.getTypeIdx();
60  std::stringstream ss(str.c_str());
61  switch (typeIdx) {
62  case BOOL: {
63  std::string value;
64  ss >> value;
65  if (ss.fail()) {
66  return false;
67  } else if (value == "true") {
68  entry.value = true;
69  return true;
70  } else if (value == "false") {
71  entry.value = false;
72  return true;
73  } else {
74  return false;
75  }
76  }
77  case INT:
78  int i;
79  ss >> i;
80  if (ss.fail()) {
81  return false;
82  } else {
83  entry.value = i;
84  return true;
85  }
86  case FLOAT:
87  Float f;
88  ss >> f;
89  if (ss.fail()) {
90  return false;
91  } else {
92  entry.value = f;
93  return true;
94  }
95  case INTERVAL: {
96  std::string s1, s2;
97  ss >> s1 >> s2;
98  if (ss.fail()) {
99  return false;
100  }
101  Float lower, upper;
102  if (s1 == "-infinity") {
103  lower = -INFTY;
104  } else {
105  ss.clear();
106  ss.str(s1);
107  Float value;
108  ss >> value;
109  lower = value;
110  }
111  if (s2 == "infinity") {
112  upper = INFTY;
113  } else {
114  ss.clear();
115  ss.str(s2);
116  Float value;
117  ss >> value;
118  upper = value;
119  }
120  if (ss.fail()) {
121  return false;
122  } else {
123  entry.value = Interval(lower, upper);
124  return true;
125  }
126  }
127  case STRING: {
128  // trim leading and trailing spaces
129  const std::string trimmed = trim(str);
130  entry.value = trimmed;
131  return true;
132  }
133  case VECTOR:
134  Float v1, v2, v3;
135  ss >> v1 >> v2 >> v3;
136  if (ss.fail()) {
137  return false;
138  } else {
139  entry.value = Vector(v1, v2, v3);
140  return true;
141  }
142  case SYMMETRIC_TENSOR:
143  Float sxx, syy, szz, sxy, sxz, syz;
144  ss >> sxx >> syy >> szz >> sxy >> sxz >> syz;
145  if (ss.fail()) {
146  return false;
147  } else {
148  entry.value = SymmetricTensor(Vector(sxx, syy, szz), Vector(sxy, sxz, syz));
149  return true;
150  }
151  case TRACELESS_TENSOR:
152  Float txx, tyy, txy, txz, tyz;
153  ss >> txx >> tyy >> txy >> txz >> tyz;
154  if (ss.fail()) {
155  return false;
156  } else {
157  entry.value = TracelessTensor(txx, tyy, txy, txz, tyz);
158  return true;
159  }
160  case ENUM: {
161  const EnumIndex index = defaultValue.template get<EnumWrapper>().index;
162  std::string textValue;
163  int flags = 0;
164  while (true) {
165  ss >> textValue;
166  if (ss.fail()) {
167  return false;
168  }
169  if (textValue == "0") {
170  // special value representing empty flags;
171  // we need to check that this is the only thing on the line
172  ss >> textValue;
173  if (!ss && flags == 0) {
174  flags = 0;
175  break;
176  } else {
177  return false;
178  }
179  }
180  Optional<int> value = EnumMap::fromString(textValue, index);
181  if (!value) {
182  return false;
183  } else {
184  flags |= value.value();
185  }
186  ss >> textValue;
187  if (!ss || textValue != "|") {
188  break;
189  }
190  }
191  entry.value = EnumWrapper(flags, index);
192  return true;
193  }
194  default:
196  }
197 }
198 
199 template <typename TEnum>
201  std::ifstream ifs(path.native());
202  if (!ifs) {
203  return makeFailed("File ", path.native(), " cannot be opened for reading.");
204  }
205  std::string line;
206  const Settings& descriptors = getDefaults();
207  while (std::getline(ifs, line, '\n')) {
208  if (line.empty() || line[0] == '#') {
209  continue;
210  }
211  const std::size_t idx = line.find("=", 0);
212  if (idx == std::string::npos) {
213  return makeFailed("Invalid format of the file, didn't find separating '='");
214  }
215  std::string key = line.substr(0, idx);
216  std::string value = line.substr(idx + 1);
217  // throw away spaces from key
218  std::string trimmedKey = trim(key);
219 
220  // find the key in decriptor settings
221  bool found = false;
222  for (auto& e : descriptors.entries) {
223  if (e.value.name == trimmedKey) {
224  entries.insert(e.value.id, e.value);
225  if (!setValueByType(entries[e.value.id], e.value.value, value)) {
226  return makeFailed("Invalid value of key ", trimmedKey, ": ", value);
227  }
228  found = true;
229  break;
230  }
231  }
232  if (!found) {
233  return makeFailed("Key ", trimmedKey, " was not find in settings");
234  }
235  }
236  ifs.close();
237  return SUCCESS;
238 }
239 
240 template <typename TEnum>
242  const Outcome dirCreated = FileSystem::createDirectory(path.parentPath());
243  if (!dirCreated) {
244  return makeFailed("Cannot save settings: ", dirCreated.error());
245  }
246 
247  const Settings& descriptors = getDefaults();
248  try {
249  std::ofstream ofs(path.native());
250  for (auto& e : entries) {
251  const Entry& entry = e.value;
252  const Entry& descriptor = descriptors.entries[e.key];
253  if (!descriptor.desc.empty()) {
254  std::string desc = "# " + descriptor.desc;
255  desc = setLineBreak(desc, 120);
256  desc = replaceAll(desc, "\n", "\n# ");
257  ofs << desc << std::endl;
258  }
259 
260  ofs << std::setw(30) << std::left << descriptor.name << " = ";
261  switch (entry.value.getTypeIdx()) {
262  case BOOL:
263  ofs << (entry.value.template get<bool>() ? "true" : "false");
264  break;
265  case INT:
266  ofs << entry.value.template get<int>();
267  break;
268  case FLOAT:
269  ofs << entry.value.template get<Float>();
270  break;
271  case INTERVAL:
272  ofs << entry.value.template get<Interval>();
273  break;
274  case STRING:
275  ofs << entry.value.template get<std::string>();
276  break;
277  case VECTOR:
278  ofs << entry.value.template get<Vector>();
279  break;
280  case SYMMETRIC_TENSOR:
281  ofs << entry.value.template get<SymmetricTensor>();
282  break;
283  case TRACELESS_TENSOR:
284  ofs << entry.value.template get<TracelessTensor>();
285  break;
286  case ENUM: {
287  EnumWrapper e = entry.value.template get<EnumWrapper>();
288  ofs << EnumMap::toString(e.value, e.index);
289  break;
290  }
291  default:
293  }
294  ofs << std::endl;
295  }
296  ofs.close();
297  return SUCCESS;
298  } catch (const std::exception& e) {
299  return makeFailed("Cannot save settings: ", e.what());
300  }
301 }
302 
303 template <typename TEnum>
304 bool Settings<TEnum>::tryLoadFileOrSaveCurrent(const Path& path, const Settings& overrides) {
305  if (FileSystem::pathExists(path)) {
306  // load from file and apply the overrides
307  const Outcome result = this->loadFromFile(path);
308  if (!result) {
309  throw IoError(result.error());
310  }
311  this->addEntries(overrides);
312  return true;
313  } else {
314  // apply overrides and then save
315  this->addEntries(overrides);
316  this->saveToFile(path);
317  return false;
318  }
319 }
320 
321 template <typename TEnum>
322 std::string Settings<TEnum>::typeToString(const int type) {
323  static StaticArray<std::string, 9> names = {
324  "bool",
325  "int",
326  "float",
327  "interval",
328  "string",
329  "vector",
330  "symmetric_tensor",
331  "traceless_tensor",
332  "enum",
333  };
334  if (type >= 0 && type < int(names.size())) {
335  return names[type];
336  } else {
337  throw Exception("Unknown settings type " + std::to_string(type));
338  }
339 }
340 
341 template <typename TEnum>
343  return SettingsIterator<TEnum>(entries.begin(), {});
344 }
345 
346 template <typename TEnum>
348  return SettingsIterator<TEnum>(entries.end(), {});
349 }
350 
351 template <typename TEnum>
353  return entries.size();
354 }
355 
356 template <typename TEnum>
358  SPH_ASSERT(instance != nullptr);
359  return *instance;
360 }
361 
362 template <typename TEnum>
364  : iter(iter) {}
365 
366 template <typename TEnum>
368  return { iter->key, iter->value.value };
369 }
370 
371 template <typename TEnum>
373  ++iter;
374  return *this;
375 }
376 
377 template <typename TEnum>
379  return iter == other.iter;
380 }
381 
382 template <typename TEnum>
384  return iter != other.iter;
385 }
386 
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
#define NOT_IMPLEMENTED
Helper macro marking missing implementation.
Definition: Assert.h:100
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
void saveToFile(const wxBitmap &wx, const Path &path)
Definition: Bitmap.cpp:59
@ SYMMETRIC_TENSOR
@ TRACELESS_TENSOR
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Definition: Globals.h:13
constexpr Float INFTY
Definition: MathUtils.h:38
#define NAMESPACE_SPH_END
Definition: Object.h:12
Return value of function that may fail, containing either SUCCEES (true) or error message.
const SuccessTag SUCCESS
Global constant for successful outcome.
Definition: Outcome.h:141
INLINE Outcome makeFailed(TArgs &&... args)
Constructs failed object with error message.
Definition: Outcome.h:157
std::string setLineBreak(const std::string &s, const Size lineWidth)
Inserts to string so that no line is longer than given limit.
std::string trim(const std::string &s)
Removes all leading and trailing spaces from a string.
Definition: StringUtils.cpp:74
std::string replaceAll(const std::string &source, const std::string &old, const std::string &s)
Replaces all occurences of string with a new string.
BasicVector< Float > Vector
Definition: Vector.h:539
Helper class used to allow calling a function only from within T.
Definition: Object.h:94
INLINE const TError & error() const
Returns the error message.
Definition: Outcome.h:88
static Optional< TEnum > fromString(const std::string &value)
Definition: EnumMap.h:101
static std::string toString(const TEnum value)
Definition: EnumMap.h:67
Generic exception.
Definition: Exceptions.h:10
FlatMap clone() const
Definition: FlatMap.h:182
Object representing a 1D interval of real numbers.
Definition: Interval.h:17
Exception thrown when file cannot be read, it has invalid format, etc.
Definition: Exceptions.h:31
INLINE Type & value()
Returns the reference to the stored value.
Definition: Optional.h:172
Object representing a path on a filesystem.
Definition: Path.h:17
std::string native() const
Returns the native version of the path.
Definition: Path.cpp:71
Path parentPath() const
Returns the parent directory. If the path is empty or root, return empty path.
Definition: Path.cpp:35
Iterator useful for iterating over all entries in the settings.
Definition: Settings.h:486
SettingsIterator & operator++()
Moves to next entry.
bool operator==(const SettingsIterator &other) const
Equality operator between settings operators.
SettingsIterator(const ActIterator &iter, Badge< Settings< TEnum >>)
Constructs an iterator from iternal implementation; use Settings::begin and Settings::end.
IteratorValue operator*() const
Dereference the iterator, yielding a pair of entry ID and its value.
bool operator!=(const SettingsIterator &other) const
Unequality operator between settings operators.
Generic object containing various settings and parameters of the run.
Definition: Settings.h:108
static std::string typeToString(const int type)
Returns the string name for given type index.
static const Settings & getDefaults()
\brief Returns a reference to object containing default values of all settings.
Outcome saveToFile(const Path &path) const
Saves all values stored in settings into file.
Settings & operator=(std::initializer_list< Entry > list)
Assigns a list of settings into the object, erasing all previous entries.
Definition: Settings.impl.h:37
Settings()
Initialize settings by settings all value to their defaults.
Definition: Settings.impl.h:22
SettingsIterator< TEnum > begin() const
Iterator to the first entry of the settings storage.
Size size() const
Returns the number of entries in the settings.
bool tryLoadFileOrSaveCurrent(const Path &path, const Settings &overrides=EMPTY_SETTINGS)
If the specified file exists, loads the settings from it, otherwise creates the file and saves the cu...
Outcome loadFromFile(const Path &path)
Loads the settings from file.
SettingsIterator< TEnum > end() const
Iterator to the one-past-end entry the settings storage.
Array with fixed number of allocated elements.
Definition: StaticArray.h:19
INLINE TCounter size() const
Returns the current size of the array (number of constructed elements).
Definition: StaticArray.h:147
Symmetric tensor of 2nd order.
Symmetric traceless 2nd order tensor.
Generic storage and input/output routines of settings.
bool pathExists(const Path &path)
Checks if a file or directory exists (or more precisely, if a file or directory is accessible).
Definition: FileSystem.cpp:21
Outcome createDirectory(const Path &path, const Flags< CreateDirectoryFlag > flags=CreateDirectoryFlag::ALLOW_EXISTING)
Creates a directory with given path. Creates all parent directories as well.
Definition: FileSystem.cpp:119
Overload of std::swap for Sph::Array.
Definition: Array.h:578
Tag for initialization of empty settings object.
Definition: Settings.h:30
Wrapper of an enum.
Definition: Settings.h:37
int value
Definition: Settings.h:38
EnumIndex index
Definition: Settings.h:40
Settings< TEnum >::Value value
Variant holding the value of the entry.
Definition: Settings.h:501