2#include "fmt/color.hpp"
3#include "qip/String.hpp"
20 const std::vector<std::string> &list) {
22 std::cout <<
": Unknown option: " << test_string <<
"\n";
54 constexpr static bool v =
false;
59 constexpr static bool v =
true;
71 constexpr static bool v =
false;
73 static constexpr std::size_t size = 0;
75template <
typename T, std::
size_t N>
76struct IsArray<std::array<T, N>> {
77 constexpr static bool v =
true;
80 static constexpr std::size_t size = N;
85inline void print_line(
const char c =
'*',
const int num = 80) {
86 for (
int i = 0; i < num; i++)
92inline std::string time_date() {
94 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
96 std::strftime(buffer, 30,
"%F %T", localtime(&now));
99inline std::string date() {
101 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
103 std::strftime(buffer, 30,
"%F", localtime(&now));
106inline std::string time() {
108 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
110 std::strftime(buffer, 30,
"%T", localtime(&now));
118 std::string value_str;
120 friend bool operator==(
Option option, std::string_view tkey) {
124 friend bool operator==(std::string_view tkey,
Option option) {
125 return option == tkey;
127 friend bool operator!=(
Option option, std::string_view tkey) {
128 return !(option == tkey);
130 friend bool operator!=(std::string_view tkey,
Option option) {
131 return !(option == tkey);
155 std::string m_name{};
156 std::vector<Option> m_options{};
157 std::vector<InputBlock> m_blocks{};
165 : m_name(name), m_options(
options) {}
168 InputBlock(std::string_view name,
const std::string &string_input)
174 InputBlock(std::string_view name,
const std::istream &file) : m_name(name) {
183 inline void add(Option option);
184 inline void add(
const std::vector<Option> &
options);
186 inline void add(
const std::string &
string,
bool merge =
false);
187 inline void merge(
const std::string &
string) {
add(
string,
true); }
189 std::string_view name()
const {
return m_name; }
191 const std::vector<Option> &
options()
const {
return m_options; }
193 const std::vector<InputBlock> &
blocks()
const {
return m_blocks; }
198 friend inline bool operator!=(
InputBlock block, std::string_view name);
199 friend inline bool operator!=(std::string_view name,
InputBlock block);
203 template <
typename T>
204 T
get(std::string_view key, T default_value)
const;
208 template <
typename T = std::
string>
209 std::optional<T>
get(std::string_view key)
const;
213 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
214 return !(option == m_options.crend());
219 return !(
get(key) == std::nullopt);
223 template <
typename T>
224 T
get(std::initializer_list<std::string>
blocks, std::string_view key,
225 T default_value)
const;
227 template <
typename T>
228 std::optional<T>
get(std::initializer_list<std::string>
blocks,
229 std::string_view key)
const;
233 inline std::optional<InputBlock>
getBlock(std::string_view name)
const;
234 inline std::optional<InputBlock>
236 std::string_view name)
const;
249 return temp != std::nullopt;
253 std::string_view name)
const {
255 return temp != std::nullopt;
259 inline std::optional<Option>
getOption(std::string_view key)
const;
263 inline void print(std::ostream &os = std::cout,
int indent_depth = 0)
const;
273 const std::vector<std::pair<std::string, std::string>> &list,
274 bool print =
false)
const;
278 check(
const std::vector<std::pair<std::string, std::string>> &list,
279 bool print =
false)
const {
280 return checkBlock(list,
print);
285 checkBlock(
const std::vector<std::pair<std::string, std::string>> &list,
286 bool print =
false)
const;
289 inline InputBlock *getBlock_ptr(std::string_view name);
290 inline const InputBlock *getBlock_cptr(std::string_view name)
const;
293 template <
typename T>
294 std::optional<std::vector<T>> get_vector(std::string_view key)
const;
297 template <
typename T, std::
size_t N>
298 std::optional<std::array<T, N>> get_array(std::string_view key)
const;
300 inline void add_option(std::string_view in_string);
301 inline void add_blocks_from_string(std::string_view
string,
bool merge);
302 inline void consolidate();
308 auto existing_block = getBlock_ptr(block.m_name);
309 if (merge && existing_block) {
310 existing_block->m_options.insert(existing_block->m_options.end(),
311 block.m_options.cbegin(),
312 block.m_options.cend());
314 m_blocks.push_back(block);
321 for (
const auto &option :
options)
322 m_options.push_back(option);
327 add_blocks_from_string(
336bool operator==(std::string_view name,
InputBlock block) {
337 return block == name;
339bool operator!=(InputBlock block, std::string_view name) {
340 return !(block == name);
342bool operator!=(std::string_view name, InputBlock block) {
343 return !(block == name);
350 return get_vector<typename IsVector<T>::t>(key);
351 }
else if constexpr (IsArray<T>::v) {
352 return get_array<typename IsArray<T>::t, IsArray<T>::size>(key);
353 }
else if constexpr (std::is_same_v<T, bool>) {
354 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
355 if (option == m_options.crend())
358 option->value_str ==
"")
360 const auto &str = option->value_str;
368 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
369 if (option == m_options.crend())
372 option->value_str ==
"")
374 return parse_str_to_T<T>(option->value_str);
383std::optional<std::vector<T>>
384InputBlock::get_vector(std::string_view key)
const {
388 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
389 if (option == m_options.crend())
391 if (option->value_str ==
"")
393 std::stringstream ss(option->value_str);
397 std::getline(ss, substr,
',');
398 out.push_back(parse_str_to_T<T>(substr));
403template <
typename T, std::
size_t N>
404std::optional<std::array<T, N>>
405InputBlock::get_array(std::string_view key)
const {
408 std::array<T, N> out;
409 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
410 if (option == m_options.crend())
412 if (option->value_str ==
"")
414 std::stringstream ss(option->value_str);
415 std::size_t index = 0;
419 std::getline(ss, substr,
',');
421 out.at(index) = parse_str_to_T<T>(substr);
429 static_assert(!std::is_same_v<T, const char *>,
430 "Cannot use get with const char* - use std::string");
431 return get<T>(key).value_or(default_value);
436 std::string_view key, T default_value)
const {
437 return get<T>(
blocks, key).value_or(default_value);
442 std::string_view key)
const {
445 for (
const auto &block :
blocks) {
446 pB = pB->getBlock_cptr(block);
450 return pB->
get<T>(key);
456 const auto block = std::find(m_blocks.crbegin(), m_blocks.crend(), name);
457 if (block == m_blocks.crend())
462std::optional<InputBlock>
464 std::string_view name)
const {
467 for (
const auto &block :
blocks) {
468 pB = pB->getBlock_cptr(block);
479 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
480 if (option != m_options.crend())
488 std::string indent =
"";
489 for (
int i = 1; i < depth; ++i)
494 os << indent << m_name <<
" { ";
496 const auto multi_entry = (!m_blocks.empty() || (m_options.size() > 1));
498 if (depth != 0 && multi_entry)
501 for (
const auto &[key, value] : m_options) {
502 os << (depth != 0 && multi_entry ? indent +
" " :
"");
506 os << key <<
" = " << value <<
';';
507 os << (multi_entry ?
'\n' :
' ');
510 for (
const auto &block : m_blocks)
511 block.print(os, depth + 1);
513 if (depth != 0 && multi_entry)
521bool InputBlock::checkBlock(
522 const std::vector<std::pair<std::string, std::string>> &list,
528 for (
const auto &option : m_options) {
529 const auto is_optionQ = [&](
const auto &l) {
533 const auto bad_option =
534 !std::any_of(list.cbegin(), list.cend(), is_optionQ);
538 if (bad_option && !help) {
540 fmt2::styled_print(fg(fmt::color::orange),
"\nWARNING\n");
541 std::cout <<
"Unclear input option in " << m_name <<
": " << option.key
542 <<
" = " << option.value_str <<
";\n"
543 <<
"Option may be ignored!\n"
544 <<
"Check spelling (or update list of options)\n";
546 auto compare_sc = [&option](
const auto &s1,
const auto &s2) {
550 auto guess = std::min_element(list.cbegin(), list.cend(), compare_sc);
551 if (guess != list.cend()) {
552 std::cout <<
"\nDid you mean: " << guess->first <<
" ?\n";
557 using namespace std::string_literals;
558 for (
const auto &block : m_blocks) {
559 const auto is_blockQ = [&](
const auto &b) {
562 const auto bad_block = !std::any_of(list.cbegin(), list.cend(), is_blockQ);
565 fmt2::styled_print(fg(fmt::color::orange),
"\nWARNING\n");
566 std::cout <<
"Unclear input block within " << m_name <<
": "
567 << block.name() <<
"{}\n"
568 <<
"Block and containing options may be ignored!\n"
569 <<
"Check spelling (or update list of options)\n";
571 auto compare_sc = [&block](
const auto &s1,
const auto &s2) {
575 auto guess = std::min_element(list.cbegin(), list.cend(), compare_sc);
576 if (guess != list.cend()) {
577 std::cout <<
"\nDid you mean: " << guess->first <<
" ?\n";
582 if (!all_ok ||
print) {
583 fmt2::styled_print(fg(fmt::color::light_blue),
584 "\n// Available {} options/blocks\n", m_name);
585 fmt2::styled_print(fmt::emphasis::bold, m_name);
587 std::for_each(list.cbegin(), list.cend(), [](
const auto &s) {
588 const auto option_is_block = s.first.back() ==
'}';
589 const auto leading_spaces = s.first.empty() ?
""s :
" ";
590 if (!s.first.empty()) {
591 std::cout <<
" " << s.first << (option_is_block ?
"\n" :
";\n");
593 if (!s.second.empty()) {
594 fmt2::styled_print(fg(fmt::color::light_blue),
"{}\n",
595 qip::wrap(s.second, 60, leading_spaces +
" // "));
600 std::cout <<
"}\n\n";
606bool InputBlock::check(
607 std::initializer_list<std::string> blocks,
608 const std::vector<std::pair<std::string, std::string>> &list,
612 for (
const auto &block : blocks) {
613 pB = pB->getBlock_cptr(block);
621 return pB->
check(list, print);
625void InputBlock::add_blocks_from_string(std::string_view
string,
bool merge) {
630 while (start <
string.length()) {
634 auto end = std::min(
string.find(
';', start),
string.find(
'{', start));
635 if (end >
string.length() || start >= end)
638 if (
string.at(end) ==
';') {
641 this->add_option(
string.substr(start, end - start));
647 const auto block_name =
string.substr(start, end - start);
652 auto next_start = start;
653 while (depth_count != 0) {
654 if (next_start >
string.length())
656 const auto next_end =
657 std::min(
string.find(
'{', next_start),
string.find(
'}', next_start));
658 if (next_end >
string.length())
662 if (
string.at(next_end) ==
'{')
667 if (depth_count == 0) {
671 if (depth_count > 100) {
672 std::cerr <<
"FAIL 271 in InputBlock::add_blocks_from_string: Depth "
673 "error. Check balanced {} in input\n";
677 next_start = next_end + 1;
682 auto &block = m_blocks.emplace_back(block_name);
685 block.add_blocks_from_string(
string.substr(start, end - start), merge);
698void InputBlock::add_option(std::string_view in_string) {
699 const auto pos = in_string.find(
'=');
700 const auto option = in_string.substr(0, pos);
701 const auto value = pos < in_string.length() ? in_string.substr(pos + 1) :
"";
702 m_options.push_back({std::string(option), std::string(value)});
706InputBlock *InputBlock::getBlock_ptr(std::string_view name) {
707 auto block = std::find(m_blocks.rbegin(), m_blocks.rend(), name);
708 if (block == m_blocks.rend())
713const InputBlock *InputBlock::getBlock_cptr(std::string_view name)
const {
714 auto block = std::find(m_blocks.crbegin(), m_blocks.crend(), name);
715 if (block == m_blocks.rend())
721void InputBlock::consolidate() {
722 for (
auto bl = m_blocks.end() - 1; bl != m_blocks.begin() - 1; --bl) {
724 auto bl2 = std::find(m_blocks.begin(), bl, bl->name());
726 bl2->m_options.insert(bl2->m_options.end(), bl->m_options.cbegin(),
727 bl->m_options.cend());
737 const std::string include_text =
"#include";
739 for (
auto ipos = str.find(include_text); ipos != std::string::npos;
740 ipos = str.find(include_text)) {
741 const auto start = std::min(str.find(
'"', ipos), str.find(
'<', ipos));
743 std::min(str.find(
'"', start + 1), str.find(
'>', start + 1));
744 const auto fname = str.substr(start + 1, end - start - 1);
745 str.erase(ipos, end - ipos + 1);
746 std::ifstream ifile(fname);
759 auto lambda = [&inside](
unsigned char x) {
760 if (x ==
'\"' || x ==
'\'')
762 return ((x ==
' ' || x ==
'\t' || x ==
'\n') && !inside);
765 str.erase(std::remove_if(str.begin(), str.end(), lambda), str.end());
773 str.erase(std::remove_if(str.begin(), str.end(),
774 [](
unsigned char x) { return x ==
'\''; }),
776 str.erase(std::remove_if(str.begin(), str.end(),
777 [](
unsigned char x) { return x ==
'\"'; }),
784inline void removeBlockComments(std::string &input) {
785 for (
auto posi = input.find(
"/*"); posi != std::string::npos;
786 posi = input.find(
"/*")) {
787 auto posf = input.find(
"*/");
788 if (posf != std::string::npos) {
789 input = input.substr(0, posi) + input.substr(posf + 2);
791 input = input.substr(0, posi);
798 std::string str =
"";
801 std::stringstream stream1(input);
802 while (std::getline(stream1, line,
'\n')) {
805 const auto comm3 = line.find(
"//");
807 str += line.substr(0, comm3);
811 removeBlockComments(str);
819 if constexpr (std::is_same_v<T, std::string>) {
825 std::stringstream ss(value_as_str);
837 std::ostringstream ss;
In-out (timers, profilers, and read/write data)
Definition ChronoTimer.hpp:9
void unkown_option(std::string_view test_string, const std::vector< std::string > &list)
Prints unkown option warning, with suggested alternative.
Definition InputBlock.hpp:19
void removeBlockComments(std::string &input)
Removes all c++ style block comments from a string.
Definition InputBlock.hpp:784
std::string expandIncludes(std::string input)
Expands "#include" files.
Definition InputBlock.hpp:736
std::string removeSpaces(std::string str)
Removes all white space (space, tab, newline), except for those in quotes.
Definition InputBlock.hpp:756
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:85
std::string file_to_string(const std::istream &file)
Parses entire file into string. Note: v. inefficient.
Definition InputBlock.hpp:832
std::string removeComments(const std::string &input)
Removes all c++ style comments from a string (block and line)
Definition InputBlock.hpp:797
T parse_str_to_T(const std::string &value_as_str)
Parses a string to type T by stringstream.
Definition InputBlock.hpp:818
std::string removeQuoteMarks(std::string str)
Removes all quote marks.
Definition InputBlock.hpp:770
std::string ci_closest_match(const std::string_view test_string, const std::vector< std::string > &list)
Finds the closest match (case insensitive) in list to test_string (return iterator)
Definition String.hpp:231
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:194
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:140
Class to determine if a class template in vector.
Definition InputBlock.hpp:53
Simple struct; holds key-value pair, both strings. == compares key.
Definition InputBlock.hpp:116