2 #include "fmt/color.hpp"
3 #include "qip/String.hpp"
13 #include <string_view>
43 constexpr
static bool v =
false;
48 constexpr
static bool v =
true;
60 constexpr
static bool v =
false;
62 static constexpr std::size_t size = 0;
64 template <
typename T, std::
size_t N>
65 struct IsArray<std::array<T, N>> {
66 constexpr
static bool v =
true;
69 static constexpr std::size_t size = N;
74 inline void print_line(
const char c =
'*',
const int num = 80) {
75 for (
int i = 0; i < num; i++)
81 inline std::string time_date() {
83 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
85 std::strftime(
buffer, 30,
"%F %T", localtime(&now));
88 inline std::string date() {
90 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
92 std::strftime(
buffer, 30,
"%F", localtime(&now));
95 inline std::string time() {
97 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
99 std::strftime(
buffer, 30,
"%T", localtime(&now));
107 std::string value_str;
109 friend bool operator==(
Option option, std::string_view tkey) {
113 friend bool operator==(std::string_view tkey,
Option option) {
114 return option == tkey;
116 friend bool operator!=(
Option option, std::string_view tkey) {
117 return !(option == tkey);
119 friend bool operator!=(std::string_view tkey,
Option option) {
120 return !(option == tkey);
144 std::string m_name{};
145 std::vector<Option> m_options{};
146 std::vector<InputBlock> m_blocks{};
154 : m_name(name), m_options(
options) {}
157 InputBlock(std::string_view name,
const std::string &string_input)
163 InputBlock(std::string_view name,
const std::istream &file) : m_name(name) {
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); }
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; }
187 friend inline bool operator!=(
InputBlock block, std::string_view name);
188 friend inline bool operator!=(std::string_view name,
InputBlock block);
192 template <
typename T>
193 T
get(std::string_view key, T default_value)
const;
197 template <
typename T = std::
string>
198 std::optional<T>
get(std::string_view key)
const;
202 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
203 return !(option == m_options.crend());
208 return !(
get(key) == std::nullopt);
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;
222 inline std::optional<InputBlock>
getBlock(std::string_view name)
const;
223 inline std::optional<InputBlock>
225 std::string_view name)
const;
238 return temp != std::nullopt;
242 std::string_view name)
const {
244 return temp != std::nullopt;
248 inline std::optional<Option>
getOption(std::string_view key)
const;
252 inline void print(std::ostream &os = std::cout,
int indent_depth = 0)
const;
262 const std::vector<std::pair<std::string, std::string>> &list,
263 bool print =
false)
const;
267 check(
const std::vector<std::pair<std::string, std::string>> &list,
268 bool print =
false)
const {
269 return checkBlock(list,
print);
274 checkBlock(
const std::vector<std::pair<std::string, std::string>> &list,
275 bool print =
false)
const;
278 inline InputBlock *getBlock_ptr(std::string_view name);
279 inline const InputBlock *getBlock_cptr(std::string_view name)
const;
282 template <
typename T>
283 std::optional<std::vector<T>> get_vector(std::string_view key)
const;
286 template <
typename T, std::
size_t N>
287 std::optional<std::array<T, N>> get_array(std::string_view key)
const;
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();
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());
303 m_blocks.push_back(block);
310 for (
const auto &option :
options)
311 m_options.push_back(option);
316 add_blocks_from_string(
325 bool operator==(std::string_view name,
InputBlock block) {
326 return block == name;
328 bool operator!=(InputBlock block, std::string_view name) {
329 return !(block == name);
331 bool operator!=(std::string_view name, InputBlock block) {
332 return !(block == name);
336 template <
typename T>
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())
347 option->value_str ==
"")
349 const auto &str = option->value_str;
357 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
358 if (option == m_options.crend())
361 option->value_str ==
"")
363 return parse_str_to_T<T>(option->value_str);
371 template <
typename T>
372 std::optional<std::vector<T>>
373 InputBlock::get_vector(std::string_view key)
const {
377 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
378 if (option == m_options.crend())
380 if (option->value_str ==
"")
382 std::stringstream ss(option->value_str);
386 std::getline(ss, substr,
',');
387 out.push_back(parse_str_to_T<T>(substr));
392 template <
typename T, std::
size_t N>
393 std::optional<std::array<T, N>>
394 InputBlock::get_array(std::string_view key)
const {
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())
401 if (option->value_str ==
"")
403 std::stringstream ss(option->value_str);
404 std::size_t index = 0;
408 std::getline(ss, substr,
',');
410 out.at(index) = parse_str_to_T<T>(substr);
416 template <
typename T>
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);
423 template <
typename T>
425 std::string_view key, T default_value)
const {
426 return get<T>(
blocks, key).value_or(default_value);
429 template <
typename T>
431 std::string_view key)
const {
434 for (
const auto &block :
blocks) {
435 pB = pB->getBlock_cptr(block);
439 return pB->
get<T>(key);
445 const auto block = std::find(m_blocks.crbegin(), m_blocks.crend(), name);
446 if (block == m_blocks.crend())
451 std::optional<InputBlock>
453 std::string_view name)
const {
456 for (
const auto &block :
blocks) {
457 pB = pB->getBlock_cptr(block);
468 const auto option = std::find(m_options.crbegin(), m_options.crend(), key);
469 if (option != m_options.crend())
477 std::string indent =
"";
478 for (
int i = 1; i < depth; ++i)
483 os << indent << m_name <<
" { ";
485 const auto multi_entry = (!m_blocks.empty() || (m_options.size() > 1));
487 if (depth != 0 && multi_entry)
490 for (
const auto &[key, value] : m_options) {
491 os << (depth != 0 && multi_entry ? indent +
" " :
"");
495 os << key <<
" = " << value <<
';';
496 os << (multi_entry ?
'\n' :
' ');
499 for (
const auto &block : m_blocks)
500 block.print(os, depth + 1);
502 if (depth != 0 && multi_entry)
510 bool InputBlock::checkBlock(
511 const std::vector<std::pair<std::string, std::string>> &list,
517 for (
const auto &option : m_options) {
518 const auto is_optionQ = [&](
const auto &l) {
522 const auto bad_option =
523 !std::any_of(list.cbegin(), list.cend(), is_optionQ);
527 if (bad_option && !help) {
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";
535 auto compare_sc = [&option](
const auto &s1,
const auto &s2) {
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";
546 using namespace std::string_literals;
547 for (
const auto &block : m_blocks) {
548 const auto is_blockQ = [&](
const auto &b) {
551 const auto bad_block = !std::any_of(list.cbegin(), list.cend(), is_blockQ);
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";
560 auto compare_sc = [&block](
const auto &s1,
const auto &s2) {
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";
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);
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,
" // "));
582 if (!s.first.empty()) {
583 std::cout <<
" " << s.first << (option_is_block ?
"\n" :
";\n");
588 std::cout <<
"}\n\n";
595 std::initializer_list<std::string> blocks,
596 const std::vector<std::pair<std::string, std::string>> &list,
600 for (
const auto &block :
blocks) {
601 pB = pB->getBlock_cptr(block);
613 void InputBlock::add_blocks_from_string(std::string_view
string,
bool merge) {
618 while (start <
string.length()) {
622 auto end = std::min(
string.find(
';', start),
string.find(
'{', start));
623 if (end >
string.length() || start >= end)
626 if (
string.at(end) ==
';') {
629 this->add_option(
string.substr(start, end - start));
635 const auto block_name =
string.substr(start, end - start);
640 auto next_start = start;
641 while (depth_count != 0) {
642 if (next_start >
string.length())
644 const auto next_end = std::min(
string.find(
'{', next_start),
645 string.find(
'}', next_start));
646 if (next_end >
string.length())
650 if (
string.at(next_end) ==
'{')
655 if (depth_count == 0) {
659 if (depth_count > 100) {
660 std::cerr <<
"FAIL 271 in InputBlock::add_blocks_from_string: Depth "
661 "error. Check balanced {} in input\n";
665 next_start = next_end + 1;
670 auto &block = m_blocks.emplace_back(block_name);
673 block.add_blocks_from_string(
string.substr(start, end - start), merge);
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)});
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())
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())
709 void InputBlock::consolidate() {
710 for (
auto bl = m_blocks.end() - 1; bl != m_blocks.begin() - 1; --bl) {
712 auto bl2 = std::find(m_blocks.begin(), bl, bl->name());
714 bl2->m_options.insert(bl2->m_options.end(), bl->m_options.cbegin(),
715 bl->m_options.cend());
725 const std::string include_text =
"#include";
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));
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);
747 auto lambda = [&inside](
unsigned char x) {
748 if (x ==
'\"' || x ==
'\'')
750 return ((x ==
' ' || x ==
'\t' || x ==
'\n') && !inside);
753 str.erase(std::remove_if(str.begin(), str.end(), lambda), str.end());
761 str.erase(std::remove_if(str.begin(), str.end(),
762 [](
unsigned char x) { return x ==
'\''; }),
764 str.erase(std::remove_if(str.begin(), str.end(),
765 [](
unsigned char x) { return x ==
'\"'; }),
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);
779 input = input.substr(0, posi);
786 std::string str =
"";
789 std::stringstream stream1(input);
790 while (std::getline(stream1, line,
'\n')) {
793 const auto comm3 = line.find(
"//");
795 str += line.substr(0, comm3);
805 template <
typename T>
807 if constexpr (std::is_same_v<T, std::string>) {
813 std::stringstream ss(value_as_str);
825 std::ostringstream ss;
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