ampsci
c++ program for high-precision atomic structure calculations of single-valence systems
InputBlock.hpp
1 #pragma once
2 #include "fmt/color.hpp"
3 #include "qip/String.hpp" //for case insensitive
4 #include <algorithm>
5 #include <array>
6 #include <chrono>
7 #include <fstream>
8 #include <iostream>
9 #include <istream>
10 #include <optional>
11 #include <sstream>
12 #include <string>
13 #include <string_view>
14 #include <vector>
15 
16 namespace IO {
17 //==============================================================================
19 inline std::string removeSpaces(std::string str);
20 
22 inline std::string removeQuoteMarks(std::string str);
23 
25 inline void removeBlockComments(std::string &input);
26 
28 inline std::string removeComments(const std::string &input);
29 
31 inline std::string expandIncludes(std::string input);
32 
34 template <typename T>
35 inline T parse_str_to_T(const std::string &value_as_str);
36 
38 inline std::string file_to_string(const std::istream &file);
39 
41 template <typename T>
42 struct IsVector {
43  constexpr static bool v = false;
44  using t = T;
45 };
46 template <typename T>
47 struct IsVector<std::vector<T>> {
48  constexpr static bool v = true;
49  // nb: returns conatined type of vector
50  using t = T;
51 };
52 // e.g.:
53 // std::cout << std::boolalpha;
54 // std::cout << IO::IsVector<int>::v << "\n";
55 // std::cout << IO::IsVector<std::vector<int>>::v << "\n";
56 // std::cout << IO::IsVector<std::vector<double>>::v << "\n";
57 
58 template <typename T>
59 struct IsArray {
60  constexpr static bool v = false;
61  using t = T;
62  static constexpr std::size_t size = 0;
63 };
64 template <typename T, std::size_t N>
65 struct IsArray<std::array<T, N>> {
66  constexpr static bool v = true;
67  // nb: returns conatined type of array
68  using t = T;
69  static constexpr std::size_t size = N;
70 };
71 
74 inline void print_line(const char c = '*', const int num = 80) {
75  for (int i = 0; i < num; i++)
76  std::cout << c;
77  std::cout << "\n";
78 }
79 
80 //==============================================================================
81 inline std::string time_date() {
82  const auto now =
83  std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
84  char buffer[30];
85  std::strftime(buffer, 30, "%F %T", localtime(&now));
86  return buffer;
87 }
88 inline std::string date() {
89  const auto now =
90  std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
91  char buffer[30];
92  std::strftime(buffer, 30, "%F", localtime(&now));
93  return buffer;
94 }
95 inline std::string time() {
96  const auto now =
97  std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
98  char buffer[30];
99  std::strftime(buffer, 30, "%T", localtime(&now));
100  return buffer;
101 }
102 
103 //==============================================================================
105 struct Option {
106  std::string key;
107  std::string value_str;
108 
109  friend bool operator==(Option option, std::string_view tkey) {
110  // return option.key == tkey;
111  return qip::ci_wc_compare(tkey, option.key);
112  }
113  friend bool operator==(std::string_view tkey, Option option) {
114  return option == tkey;
115  }
116  friend bool operator!=(Option option, std::string_view tkey) {
117  return !(option == tkey);
118  }
119  friend bool operator!=(std::string_view tkey, Option option) {
120  return !(option == tkey);
121  }
122 };
123 
124 //==============================================================================
128 
139 // nb: I sepparate the function implementations below (in the header file) and
140 // mark them as inline. This is for readability only, and ensures this file
141 // works as a single-file header-only
142 class InputBlock {
143 private:
144  std::string m_name{};
145  std::vector<Option> m_options{};
146  std::vector<InputBlock> m_blocks{};
147 
148 public:
151 
153  InputBlock(std::string_view name, std::initializer_list<Option> options = {})
154  : m_name(name), m_options(options) {}
155 
157  InputBlock(std::string_view name, const std::string &string_input)
158  : m_name(name) {
159  add(string_input);
160  }
161 
163  InputBlock(std::string_view name, const std::istream &file) : m_name(name) {
164  add(file_to_string(file));
165  }
166 
169  inline void add(InputBlock block, bool merge = false);
170  inline void merge(InputBlock block) { add(block, true); }
172  inline void add(Option option);
173  inline void add(const std::vector<Option> &options);
175  inline void add(const std::string &string, bool merge = false);
176  inline void merge(const std::string &string) { add(string, true); }
177 
178  std::string_view name() const { return m_name; }
180  const std::vector<Option> &options() const { return m_options; }
182  const std::vector<InputBlock> &blocks() const { return m_blocks; }
183 
185  friend inline bool operator==(InputBlock block, std::string_view name);
186  friend inline bool operator==(std::string_view name, InputBlock block);
187  friend inline bool operator!=(InputBlock block, std::string_view name);
188  friend inline bool operator!=(std::string_view name, InputBlock block);
189 
192  template <typename T>
193  T get(std::string_view key, T default_value) const;
194 
197  template <typename T = std::string>
198  std::optional<T> get(std::string_view key) const;
199 
201  bool has_option(std::string_view key) const {
202  const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
203  return !(option == m_options.crend());
204  }
205 
207  bool option_is_set(std::string_view key) const {
208  return !(get(key) == std::nullopt);
209  }
210 
212  template <typename T>
213  T get(std::initializer_list<std::string> blocks, std::string_view key,
214  T default_value) const;
216  template <typename T>
217  std::optional<T> get(std::initializer_list<std::string> blocks,
218  std::string_view key) const;
219 
222  inline std::optional<InputBlock> getBlock(std::string_view name) const;
223  inline std::optional<InputBlock>
224  getBlock(std::initializer_list<std::string> blocks,
225  std::string_view name) const;
226 
228  inline InputBlock get_block(std::string_view name) const {
229  auto temp = getBlock(name);
230  if (temp)
231  return *temp;
232  return InputBlock{};
233  }
234 
236  bool has_block(std::string_view name) const {
237  auto temp = getBlock(name);
238  return temp != std::nullopt;
239  }
241  bool has_block(std::initializer_list<std::string> blocks,
242  std::string_view name) const {
243  auto temp = getBlock(blocks, name);
244  return temp != std::nullopt;
245  }
246 
248  inline std::optional<Option> getOption(std::string_view key) const;
249 
252  inline void print(std::ostream &os = std::cout, int indent_depth = 0) const;
253 
260  inline bool
261  check(std::initializer_list<std::string> blocks,
262  const std::vector<std::pair<std::string, std::string>> &list,
263  bool print = false) const;
264 
266  inline bool
267  check(const std::vector<std::pair<std::string, std::string>> &list,
268  bool print = false) const {
269  return checkBlock(list, print);
270  }
271 
272 private:
273  inline bool
274  checkBlock(const std::vector<std::pair<std::string, std::string>> &list,
275  bool print = false) const;
276 
278  inline InputBlock *getBlock_ptr(std::string_view name);
279  inline const InputBlock *getBlock_cptr(std::string_view name) const;
280 
281  // Allows returning std::vector: comma-separated list input
282  template <typename T>
283  std::optional<std::vector<T>> get_vector(std::string_view key) const;
284 
285  // Allows returning std::array: comma-separated list input
286  template <typename T, std::size_t N>
287  std::optional<std::array<T, N>> get_array(std::string_view key) const;
288 
289  inline void add_option(std::string_view in_string);
290  inline void add_blocks_from_string(std::string_view string, bool merge);
291  inline void consolidate();
292 };
293 
294 //==============================================================================
295 //==============================================================================
296 void InputBlock::add(InputBlock block, bool merge) {
297  auto existing_block = getBlock_ptr(block.m_name);
298  if (merge && existing_block) {
299  existing_block->m_options.insert(existing_block->m_options.end(),
300  block.m_options.cbegin(),
301  block.m_options.cend());
302  } else {
303  m_blocks.push_back(block);
304  }
305 }
306 
307 //==============================================================================
308 void InputBlock::add(Option option) { m_options.push_back(option); }
309 void InputBlock::add(const std::vector<Option> &options) {
310  for (const auto &option : options)
311  m_options.push_back(option);
312 }
313 //==============================================================================
314 void InputBlock::add(const std::string &string, bool merge) {
315 
316  add_blocks_from_string(
318  merge);
319 }
320 
321 //==============================================================================
322 bool operator==(InputBlock block, std::string_view name) {
323  return qip::ci_wc_compare(name, block.m_name);
324 }
325 bool operator==(std::string_view name, InputBlock block) {
326  return block == name;
327 }
328 bool operator!=(InputBlock block, std::string_view name) {
329  return !(block == name);
330 }
331 bool operator!=(std::string_view name, InputBlock block) {
332  return !(block == name);
333 }
334 
335 //==============================================================================
336 template <typename T>
337 std::optional<T> InputBlock::get(std::string_view key) const {
338  if constexpr (IsVector<T>::v) {
339  return get_vector<typename IsVector<T>::t>(key);
340  } else if constexpr (IsArray<T>::v) {
341  return get_array<typename IsArray<T>::t, IsArray<T>::size>(key);
342  } else if constexpr (std::is_same_v<T, bool>) {
343  const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
344  if (option == m_options.crend())
345  return std::nullopt;
346  if (qip::ci_wc_compare("default", option->value_str) ||
347  option->value_str == "")
348  return std::nullopt;
349  const auto &str = option->value_str;
350  if (qip::ci_wc_compare("true", str) || qip::ci_wc_compare("yes", str) ||
351  qip::ci_wc_compare("y", str))
352  return true;
353  return false;
354  } else {
355  // Use reverse iterators so that we find _last_ option that matches key
356  // i.e., assume later options override earlier ones.
357  const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
358  if (option == m_options.crend())
359  return std::nullopt;
360  if (qip::ci_wc_compare("default", option->value_str) ||
361  option->value_str == "")
362  return std::nullopt;
363  return parse_str_to_T<T>(option->value_str);
364  }
365 }
366 
367 // special function; allows return of std::vector (for comma-separated list
368 // input). Optional of vector is kind of redundant, but is this way so it
369 // aligns with the other functions (checks if optional is empty when deciding
370 // if should return the default value)
371 template <typename T>
372 std::optional<std::vector<T>>
373 InputBlock::get_vector(std::string_view key) const {
374  // Use reverse iterators so that we find _last_ option that matches key
375  // i.e., assume later options override earlier ones.
376  std::vector<T> out;
377  const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
378  if (option == m_options.crend())
379  return std::nullopt;
380  if (option->value_str == "")
381  return std::nullopt;
382  std::stringstream ss(option->value_str);
383  while (ss.good()) {
384  // note: *very* innefficient
385  std::string substr;
386  std::getline(ss, substr, ',');
387  out.push_back(parse_str_to_T<T>(substr));
388  }
389  return out;
390 }
391 
392 template <typename T, std::size_t N>
393 std::optional<std::array<T, N>>
394 InputBlock::get_array(std::string_view key) const {
395  // Use reverse iterators so that we find _last_ option that matches key
396  // i.e., assume later options override earlier ones.
397  std::array<T, N> out;
398  const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
399  if (option == m_options.crend())
400  return std::nullopt;
401  if (option->value_str == "")
402  return std::nullopt;
403  std::stringstream ss(option->value_str);
404  std::size_t index = 0;
405  while (ss.good()) {
406  // note: *very* innefficient
407  std::string substr;
408  std::getline(ss, substr, ',');
409  // out.push_back(parse_str_to_T<T>(substr));
410  out.at(index) = parse_str_to_T<T>(substr);
411  ++index;
412  }
413  return out;
414 }
415 
416 template <typename T>
417 T InputBlock::get(std::string_view key, T default_value) const {
418  static_assert(!std::is_same_v<T, const char *>,
419  "Cannot use get with const char* - use std::string");
420  return get<T>(key).value_or(default_value);
421 }
422 
423 template <typename T>
424 T InputBlock::get(std::initializer_list<std::string> blocks,
425  std::string_view key, T default_value) const {
426  return get<T>(blocks, key).value_or(default_value);
427 }
428 
429 template <typename T>
430 std::optional<T> InputBlock::get(std::initializer_list<std::string> blocks,
431  std::string_view key) const {
432  // Find key in nested blocks
433  const InputBlock *pB = this;
434  for (const auto &block : blocks) {
435  pB = pB->getBlock_cptr(block);
436  if (pB == nullptr)
437  return std::nullopt;
438  }
439  return pB->get<T>(key);
440 }
441 
442 //==============================================================================
443 std::optional<InputBlock> InputBlock::getBlock(std::string_view name) const {
444  // note: by copy!
445  const auto block = std::find(m_blocks.crbegin(), m_blocks.crend(), name);
446  if (block == m_blocks.crend())
447  return {};
448  return *block;
449 }
450 
451 std::optional<InputBlock>
452 InputBlock::getBlock(std::initializer_list<std::string> blocks,
453  std::string_view name) const {
454  // note: by copy!
455  const InputBlock *pB = this;
456  for (const auto &block : blocks) {
457  pB = pB->getBlock_cptr(block);
458  if (pB == nullptr)
459  return std::nullopt;
460  }
461  return pB->getBlock(name);
462 }
463 
464 //==============================================================================
465 std::optional<Option> InputBlock::getOption(std::string_view key) const {
466  // Use reverse iterators so that we find _last_ option that matches key
467  // i.e., assume later options override earlier ones.
468  const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
469  if (option != m_options.crend())
470  return *option;
471  return {};
472 }
473 
474 //==============================================================================
475 void InputBlock::print(std::ostream &os, int depth) const {
476 
477  std::string indent = "";
478  for (int i = 1; i < depth; ++i)
479  indent += " ";
480 
481  // Don't print outer-most name
482  if (depth != 0)
483  os << indent << m_name << " { ";
484 
485  const auto multi_entry = (!m_blocks.empty() || (m_options.size() > 1));
486 
487  if (depth != 0 && multi_entry)
488  os << "\n";
489 
490  for (const auto &[key, value] : m_options) {
491  os << (depth != 0 && multi_entry ? indent + " " : "");
492  if (value == "")
493  os << key << ';';
494  else
495  os << key << " = " << value << ';';
496  os << (multi_entry ? '\n' : ' ');
497  }
498 
499  for (const auto &block : m_blocks)
500  block.print(os, depth + 1);
501 
502  if (depth != 0 && multi_entry)
503  os << indent;
504 
505  if (depth != 0)
506  os << "}\n";
507 }
508 
509 //==============================================================================
510 bool InputBlock::checkBlock(
511  const std::vector<std::pair<std::string, std::string>> &list,
512  bool print) const {
513  // Check each option NOT each sub block!
514  // For each input option stored, see if it is allowed
515  // "allowed" means appears in list
516  bool all_ok = true;
517  for (const auto &option : m_options) {
518  const auto is_optionQ = [&](const auto &l) {
519  // return option.key == l.first;
520  return qip::ci_wc_compare(l.first, option.key);
521  };
522  const auto bad_option =
523  !std::any_of(list.cbegin(), list.cend(), is_optionQ);
524  const auto help = qip::ci_wc_compare("help", option.key) ? true : false;
525  if (help)
526  print = true;
527  if (bad_option && !help) {
528  all_ok = false;
529  fmt2::styled_print(fg(fmt::color::orange), "\nWARNING\n");
530  std::cout << "Unclear input option in " << m_name << ": " << option.key
531  << " = " << option.value_str << ";\n"
532  << "Option may be ignored!\n"
533  << "Check spelling (or update list of options)\n";
534  // spell-check + nearest suggestion:
535  auto compare_sc = [&option](const auto &s1, const auto &s2) {
536  return qip::ci_Levenstein(s1.first, option.key) <
537  qip::ci_Levenstein(s2.first, option.key);
538  };
539  auto guess = std::min_element(list.cbegin(), list.cend(), compare_sc);
540  if (guess != list.cend()) {
541  std::cout << "\nDid you mean: " << guess->first << " ?\n";
542  }
543  }
544  }
545 
546  using namespace std::string_literals;
547  for (const auto &block : m_blocks) {
548  const auto is_blockQ = [&](const auto &b) {
549  return qip::ci_wc_compare(std::string{block.name()} + "{}"s, b.first);
550  };
551  const auto bad_block = !std::any_of(list.cbegin(), list.cend(), is_blockQ);
552  if (bad_block) {
553  all_ok = false;
554  fmt2::styled_print(fg(fmt::color::orange), "\nWARNING\n");
555  std::cout << "Unclear input block within " << m_name << ": "
556  << block.name() << "{}\n"
557  << "Block and containing options may be ignored!\n"
558  << "Check spelling (or update list of options)\n";
559  // spell-check + nearest suggestion:
560  auto compare_sc = [&block](const auto &s1, const auto &s2) {
561  return qip::ci_Levenstein(s1.first, block.name()) <
562  qip::ci_Levenstein(s2.first, block.name());
563  };
564  auto guess = std::min_element(list.cbegin(), list.cend(), compare_sc);
565  if (guess != list.cend()) {
566  std::cout << "\nDid you mean: " << guess->first << " ?\n";
567  }
568  }
569  }
570 
571  if (!all_ok || print) {
572  fmt2::styled_print(fg(fmt::color::light_blue),
573  "\n// Available {} options/blocks\n", m_name);
574  fmt2::styled_print(fmt::emphasis::bold, m_name);
575  std::cout << "{\n";
576  std::for_each(list.cbegin(), list.cend(), [](const auto &s) {
577  const auto option_is_block = s.first.back() == '}';
578  if (!s.second.empty()) {
579  fmt2::styled_print(fg(fmt::color::light_blue), "{}\n",
580  qip::wrap(s.second, 80, " // "));
581  }
582  if (!s.first.empty()) {
583  std::cout << " " << s.first << (option_is_block ? "\n" : ";\n");
584  } else {
585  std::cout << "\n";
586  }
587  });
588  std::cout << "}\n\n";
589  }
590  return all_ok;
591 }
592 
595  std::initializer_list<std::string> blocks,
596  const std::vector<std::pair<std::string, std::string>> &list,
597  bool print) const {
598  // Find key in nested blocks
599  const InputBlock *pB = this;
600  for (const auto &block : blocks) {
601  pB = pB->getBlock_cptr(block);
602  if (pB == nullptr) {
603  // Did not fund nested block... may be fine
604  // Return true, since a missing block is not an issue (or sepparate
605  // issue) We are checking to see if blocks exist that shouldn't
606  return true;
607  }
608  }
609  return pB->check(list, print);
610 }
611 
612 //==============================================================================
613 void InputBlock::add_blocks_from_string(std::string_view string, bool merge) {
614 
615  // Expects that string has comments and spaces removed already
616 
617  auto start = 0ul;
618  while (start < string.length()) {
619 
620  // Find the first of either next ';' or open '{'
621  // This is the end of the next input option, or start of block
622  auto end = std::min(string.find(';', start), string.find('{', start));
623  if (end > string.length() || start >= end)
624  break;
625 
626  if (string.at(end) == ';') {
627  // end of option:
628 
629  this->add_option(string.substr(start, end - start));
630 
631  } else {
632  // start of block
633 
634  // 'name' directly preceeds "{"
635  const auto block_name = string.substr(start, end - start);
636  start = end + 1;
637 
638  // Now, find *matching* close '}' - ensure balanced
639  int depth_count = 1;
640  auto next_start = start; // + 1;
641  while (depth_count != 0) {
642  if (next_start > string.length())
643  break;
644  const auto next_end = std::min(string.find('{', next_start),
645  string.find('}', next_start));
646  if (next_end > string.length())
647  break;
648 
649  // count depth of bracket nesting:
650  if (string.at(next_end) == '{')
651  ++depth_count;
652  else
653  --depth_count;
654 
655  if (depth_count == 0) {
656  end = next_end;
657  break;
658  }
659  if (depth_count > 100) {
660  std::cerr << "FAIL 271 in InputBlock::add_blocks_from_string: Depth "
661  "error. Check balanced {} in input\n";
662  end = next_end;
663  break;
664  }
665  next_start = next_end + 1;
666  }
667 
668  // Add a new block, populate it with string. Recursive, since blocks may
669  // contain blocks
670  auto &block = m_blocks.emplace_back(block_name);
671 
672  if (end > start)
673  block.add_blocks_from_string(string.substr(start, end - start), merge);
674  }
675 
676  start = end + 1;
677  }
678 
679  // Merge duplicated blocks.
680  if (merge)
681  consolidate();
682  // No - want ability to have multiple blocks of same name
683 }
684 
685 //==============================================================================
686 void InputBlock::add_option(std::string_view in_string) {
687  const auto pos = in_string.find('=');
688  const auto option = in_string.substr(0, pos);
689  const auto value = pos < in_string.length() ? in_string.substr(pos + 1) : "";
690  m_options.push_back({std::string(option), std::string(value)});
691 }
692 
693 //==============================================================================
694 InputBlock *InputBlock::getBlock_ptr(std::string_view name) {
695  auto block = std::find(m_blocks.rbegin(), m_blocks.rend(), name);
696  if (block == m_blocks.rend())
697  return nullptr;
698  return &(*block);
699 }
700 
701 const InputBlock *InputBlock::getBlock_cptr(std::string_view name) const {
702  auto block = std::find(m_blocks.crbegin(), m_blocks.crend(), name);
703  if (block == m_blocks.rend())
704  return nullptr;
705  return &(*block);
706 }
707 
708 //==============================================================================
709 void InputBlock::consolidate() {
710  for (auto bl = m_blocks.end() - 1; bl != m_blocks.begin() - 1; --bl) {
711  bl->consolidate();
712  auto bl2 = std::find(m_blocks.begin(), bl, bl->name());
713  if (bl2 != bl) {
714  bl2->m_options.insert(bl2->m_options.end(), bl->m_options.cbegin(),
715  bl->m_options.cend());
716  m_blocks.erase(bl);
717  }
718  }
719 }
720 
721 //==============================================================================
722 //==============================================================================
723 //==============================================================================
724 inline std::string expandIncludes(std::string str) {
725  const std::string include_text = "#include";
726 
727  for (auto ipos = str.find(include_text); ipos != std::string::npos;
728  ipos = str.find(include_text)) {
729  const auto start = std::min(str.find('"', ipos), str.find('<', ipos));
730  const auto end =
731  std::min(str.find('"', start + 1), str.find('>', start + 1));
732  const auto fname = str.substr(start + 1, end - start - 1);
733  str.erase(ipos, end - ipos + 1);
734  std::ifstream ifile(fname);
735  if (ifile.good()) {
736  str.insert(ipos, removeComments(file_to_string(ifile)));
737  }
738  }
739 
740  return str;
741 }
742 
743 //==============================================================================
744 inline std::string removeSpaces(std::string str) {
745 
746  bool inside = false;
747  auto lambda = [&inside](unsigned char x) {
748  if (x == '\"' || x == '\'')
749  inside = !inside;
750  return ((x == ' ' || x == '\t' || x == '\n') && !inside);
751  };
752 
753  str.erase(std::remove_if(str.begin(), str.end(), lambda), str.end());
754 
755  return str;
756 }
757 
758 inline std::string removeQuoteMarks(std::string str) {
759 
760  // remove ' and "
761  str.erase(std::remove_if(str.begin(), str.end(),
762  [](unsigned char x) { return x == '\''; }),
763  str.end());
764  str.erase(std::remove_if(str.begin(), str.end(),
765  [](unsigned char x) { return x == '\"'; }),
766  str.end());
767 
768  return str;
769 }
770 
771 //==============================================================================
772 inline void removeBlockComments(std::string &input) {
773  for (auto posi = input.find("/*"); posi != std::string::npos;
774  posi = input.find("/*")) {
775  auto posf = input.find("*/");
776  if (posf != std::string::npos) {
777  input = input.substr(0, posi) + input.substr(posf + 2);
778  } else {
779  input = input.substr(0, posi);
780  }
781  }
782 }
783 
784 //==============================================================================
785 inline std::string removeComments(const std::string &input) {
786  std::string str = "";
787  {
788  std::string line;
789  std::stringstream stream1(input);
790  while (std::getline(stream1, line, '\n')) {
791  // const auto comm1 = line.find('!'); // nb: char, NOT string literal!
792  // auto comm2 = line.find('#');
793  const auto comm3 = line.find("//"); // str literal here
794  // const auto comm = std::min({comm1, comm3});
795  str += line.substr(0, comm3);
796  str += '\n';
797  }
798  }
799  removeBlockComments(str);
800 
801  return str;
802 }
803 
804 //==============================================================================
805 template <typename T>
806 T inline parse_str_to_T(const std::string &value_as_str) {
807  if constexpr (std::is_same_v<T, std::string>) {
808  // already a string, just return value
809  return value_as_str;
810  } else {
811  // T is not a string: convert using stringstream
812  T value_T;
813  std::stringstream ss(value_as_str);
814  ss >> value_T;
815  return value_T;
816  }
817 }
818 
819 //==============================================================================
820 inline std::string file_to_string(const std::istream &file) {
821  std::string out;
822  if (!file)
823  return "";
824  // Horribly inneficient...
825  std::ostringstream ss;
826  ss << file.rdbuf();
827  return ss.str();
828 }
829 
830 } // namespace IO
Holds list of Options, and a list of other InputBlocks. Can be initialised with a list of options,...
Definition: InputBlock.hpp:142
InputBlock(std::string_view name, const std::istream &file)
Construct from plain text file, in Block{option=value;} format.
Definition: InputBlock.hpp:163
bool has_block(std::string_view name) const
Checks if block 'name' is present in current block.
Definition: InputBlock.hpp:236
std::optional< Option > getOption(std::string_view key) const
Get an 'Option' (kay, value) - rarely needed.
Definition: InputBlock.hpp:465
InputBlock(std::string_view name, const std::string &string_input)
Construct from a string with the correct Block{option=value;} format.
Definition: InputBlock.hpp:157
void add(InputBlock block, bool merge=false)
Add a new InputBlock (merge: will be merged with existing if names match)
Definition: InputBlock.hpp:296
bool check(std::initializer_list< std::string > blocks, const std::vector< std::pair< std::string, std::string >> &list, bool print=false) const
Check all the options and blocks in this; if any of them are not present in 'list',...
Definition: InputBlock.hpp:594
const std::vector< InputBlock > & blocks() const
Return const reference to list of blocks.
Definition: InputBlock.hpp:182
void print(std::ostream &os=std::cout, int indent_depth=0) const
Prints options to screen in user-friendly form. Same form as input string. By default prints to cout,...
Definition: InputBlock.hpp:475
bool check(const std::vector< std::pair< std::string, std::string >> &list, bool print=false) const
Override for when condidering current block.
Definition: InputBlock.hpp:267
InputBlock(std::string_view name, std::initializer_list< Option > options={})
Construct from literal list of 'Options' (see Option struct)
Definition: InputBlock.hpp:153
InputBlock get_block(std::string_view name) const
If block is present, returns a copy of it. If not, returns empty block.
Definition: InputBlock.hpp:228
const std::vector< Option > & options() const
Return const reference to list of options.
Definition: InputBlock.hpp:180
std::optional< InputBlock > getBlock(std::string_view name) const
Returns optional InputBlock. Contains InputBlock if block of given name exists; empty otherwise.
Definition: InputBlock.hpp:443
bool option_is_set(std::string_view key) const
Check if option is present AND has been set.
Definition: InputBlock.hpp:207
bool has_option(std::string_view key) const
Check is option is present (even if not set) in current block.
Definition: InputBlock.hpp:201
T get(std::string_view key, T default_value) const
If 'key' exists in the options, returns value. Else, returns default_value. Note: If two keys with sa...
Definition: InputBlock.hpp:417
friend bool operator==(InputBlock block, std::string_view name)
Comparison of blocks compares the 'name'.
Definition: InputBlock.hpp:322
bool has_block(std::initializer_list< std::string > blocks, std::string_view name) const
Checks if block 'name' is present in nesteded block.
Definition: InputBlock.hpp:241
InputBlock()
Default constructor: name will be blank.
Definition: InputBlock.hpp:150
Definition: core.h:899
In-out (timers, profilers, and read/write data)
Definition: ChronoTimer.hpp:9
void removeBlockComments(std::string &input)
Removes all c++ style block comments from a string.
Definition: InputBlock.hpp:772
std::string expandIncludes(std::string input)
Expands "#include" files.
Definition: InputBlock.hpp:724
std::string removeSpaces(std::string str)
Removes all white space (space, tab, newline), except for those in quotes.
Definition: InputBlock.hpp:744
void print_line(const char c=' *', const int num=80)
Prints a line of 'c' characters (dflt '*'), num chars long (dflt 80) to cout.
Definition: InputBlock.hpp:74
std::string file_to_string(const std::istream &file)
Parses entire file into string. Note: v. inefficient.
Definition: InputBlock.hpp:820
std::string removeComments(const std::string &input)
Removes all c++ style comments from a string (block and line)
Definition: InputBlock.hpp:785
T parse_str_to_T(const std::string &value_as_str)
Parses a string to type T by stringstream.
Definition: InputBlock.hpp:806
std::string removeQuoteMarks(std::string str)
Removes all quote marks.
Definition: InputBlock.hpp:758
auto ci_Levenstein(std::string_view a, std::string_view b)
A simple non-optimised implementation of the Levenshtein distance (case insensitive)
Definition: String.hpp:154
bool ci_wc_compare(std::string_view s1, std::string_view s2)
Compares two strings, s1 and s2. s2 may contain ONE wildcard ('*') which will match anything....
Definition: String.hpp:100
Class to determine if a class template in vector.
Definition: InputBlock.hpp:42
Simple struct; holds key-value pair, both strings. == compares key.
Definition: InputBlock.hpp:105