1 // --------------------------------------------------------------------- 2 // 3 // Copyright (C) 1998 - 2020 by the deal.II authors 4 // 5 // This file is part of the deal.II library. 6 // 7 // The deal.II library is free software; you can use it, redistribute 8 // it, and/or modify it under the terms of the GNU Lesser General 9 // Public License as published by the Free Software Foundation; either 10 // version 2.1 of the License, or (at your option) any later version. 11 // The full text of the license can be found in the file LICENSE.md at 12 // the top level directory of deal.II. 13 // 14 // --------------------------------------------------------------------- 15 16 17 #include <deal.II/base/logstream.h> 18 #include <deal.II/base/memory_consumption.h> 19 #include <deal.II/base/path_search.h> 20 #include <deal.II/base/patterns.h> 21 #include <deal.II/base/utilities.h> 22 23 DEAL_II_DISABLE_EXTRA_DIAGNOSTICS 24 #define BOOST_BIND_GLOBAL_PLACEHOLDERS 25 #include <boost/io/ios_state.hpp> 26 #include <boost/property_tree/json_parser.hpp> 27 #include <boost/property_tree/ptree.hpp> 28 #include <boost/property_tree/xml_parser.hpp> 29 #undef BOOST_BIND_GLOBAL_PLACEHOLDERS 30 DEAL_II_ENABLE_EXTRA_DIAGNOSTICS 31 32 #include <algorithm> 33 #include <cctype> 34 #include <cstdlib> 35 #include <cstring> 36 #include <fstream> 37 #include <iomanip> 38 #include <iostream> 39 #include <limits> 40 #include <sstream> 41 42 43 DEAL_II_NAMESPACE_OPEN 44 45 46 47 // TODO[WB]: various functions here could be simplified by using namespace 48 // Utilities 49 50 namespace Patterns 51 { 52 namespace internal 53 { 54 std::string escape(const std::string & input,const PatternBase::OutputStyle style)55 escape(const std::string &input, const PatternBase::OutputStyle style) 56 { 57 switch (style) 58 { 59 case PatternBase::Machine: 60 case PatternBase::Text: 61 return input; 62 case PatternBase::LaTeX: 63 { 64 std::string u; 65 u.reserve(input.size()); 66 for (const auto c : input) 67 { 68 switch (c) 69 { 70 case '#': 71 case '$': 72 case '%': 73 case '&': 74 case '_': 75 case '{': 76 case '}': 77 // simple escaping: 78 u.push_back('\\'); 79 u.push_back(c); 80 break; 81 82 case '\\': 83 u.append("\\textbackslash{}"); 84 break; 85 86 case '^': 87 u.append("\\^{}"); 88 break; 89 90 case '~': 91 u.append("\\~{}"); 92 break; 93 94 default: 95 // all other chars are just copied: 96 u.push_back(c); 97 } 98 } 99 return u; 100 } 101 default: 102 Assert(false, ExcNotImplemented()); 103 } 104 return ""; 105 } 106 107 } // namespace internal 108 109 110 namespace 111 { 112 /** 113 * Read to the end of the stream and 114 * return whether all there is is 115 * whitespace or whether there are other 116 * characters as well. 117 */ 118 bool has_only_whitespace(std::istream & in)119 has_only_whitespace(std::istream &in) 120 { 121 while (in) 122 { 123 char c; 124 125 // skip if we've reached the end of 126 // the line 127 if (!(in >> c)) 128 break; 129 130 if ((c != ' ') && (c != '\t')) 131 return false; 132 } 133 return true; 134 } 135 } // namespace 136 137 138 139 std::unique_ptr<PatternBase> pattern_factory(const std::string & description)140 pattern_factory(const std::string &description) 141 { 142 std::unique_ptr<PatternBase> p; 143 144 p = Integer::create(description); 145 if (p != nullptr) 146 return p; 147 148 p = Double::create(description); 149 if (p != nullptr) 150 return p; 151 152 p = Selection::create(description); 153 if (p != nullptr) 154 return p; 155 156 p = List::create(description); 157 if (p != nullptr) 158 return p; 159 160 p = Map::create(description); 161 if (p != nullptr) 162 return p; 163 164 p = MultipleSelection::create(description); 165 if (p != nullptr) 166 return p; 167 168 p = Bool::create(description); 169 if (p != nullptr) 170 return p; 171 172 p = Anything::create(description); 173 if (p != nullptr) 174 return p; 175 176 p = FileName::create(description); 177 if (p != nullptr) 178 return p; 179 180 p = DirectoryName::create(description); 181 if (p != nullptr) 182 return p; 183 184 Assert(false, ExcNotImplemented()); 185 186 return p; 187 } 188 189 190 191 std::size_t memory_consumption() const192 PatternBase::memory_consumption() const 193 { 194 if (dynamic_cast<const Integer *>(this) != nullptr) 195 return sizeof(Integer); 196 else if (dynamic_cast<const Double *>(this) != nullptr) 197 return sizeof(Double); 198 else if (dynamic_cast<const Bool *>(this) != nullptr) 199 return sizeof(Bool); 200 else if (dynamic_cast<const Anything *>(this) != nullptr) 201 return sizeof(Anything); 202 else 203 return sizeof(*this) + 32; 204 } 205 206 207 208 const int Integer::min_int_value = std::numeric_limits<int>::min(); 209 const int Integer::max_int_value = std::numeric_limits<int>::max(); 210 211 const char *Integer::description_init = "[Integer"; 212 Integer(const int lower_bound,const int upper_bound)213 Integer::Integer(const int lower_bound, const int upper_bound) 214 : lower_bound(lower_bound) 215 , upper_bound(upper_bound) 216 {} 217 218 219 220 bool match(const std::string & test_string) const221 Integer::match(const std::string &test_string) const 222 { 223 std::istringstream str(test_string); 224 225 int i; 226 if (!(str >> i)) 227 return false; 228 229 if (!has_only_whitespace(str)) 230 return false; 231 // check whether valid bounds 232 // were specified, and if so 233 // enforce their values 234 if (lower_bound <= upper_bound) 235 return ((lower_bound <= i) && (upper_bound >= i)); 236 else 237 return true; 238 } 239 240 241 242 std::string description(const OutputStyle style) const243 Integer::description(const OutputStyle style) const 244 { 245 switch (style) 246 { 247 case Machine: 248 { 249 // check whether valid bounds 250 // were specified, and if so 251 // output their values 252 if (lower_bound <= upper_bound) 253 { 254 std::ostringstream description; 255 256 description << description_init << " range " << lower_bound 257 << "..." << upper_bound << " (inclusive)]"; 258 return description.str(); 259 } 260 else 261 // if no bounds were given, then 262 // return generic string 263 return "[Integer]"; 264 } 265 case Text: 266 { 267 if (lower_bound <= upper_bound) 268 { 269 std::ostringstream description; 270 271 description << "An integer n such that " << lower_bound 272 << " <= n <= " << upper_bound; 273 274 return description.str(); 275 } 276 else 277 return "An integer"; 278 } 279 case LaTeX: 280 { 281 if (lower_bound <= upper_bound) 282 { 283 std::ostringstream description; 284 285 description << "An integer $n$ such that $" << lower_bound 286 << "\\leq n \\leq " << upper_bound << "$"; 287 288 return description.str(); 289 } 290 else 291 return "An integer"; 292 } 293 default: 294 AssertThrow(false, ExcNotImplemented()); 295 } 296 // Should never occur without an exception, but prevent compiler from 297 // complaining 298 return ""; 299 } 300 301 302 303 std::unique_ptr<PatternBase> clone() const304 Integer::clone() const 305 { 306 return std::unique_ptr<PatternBase>(new Integer(lower_bound, upper_bound)); 307 } 308 309 310 311 std::unique_ptr<Integer> create(const std::string & description)312 Integer::create(const std::string &description) 313 { 314 if (description.compare(0, 315 std::strlen(description_init), 316 description_init) == 0) 317 { 318 std::istringstream is(description); 319 320 if (is.str().size() > strlen(description_init) + 1) 321 { 322 // TODO: verify that description matches the pattern "^\[Integer 323 // range \d+\.\.\.\d+\]$" 324 int lower_bound, upper_bound; 325 326 is.ignore(strlen(description_init) + strlen(" range ")); 327 328 if (!(is >> lower_bound)) 329 return std::make_unique<Integer>(); 330 331 is.ignore(strlen("...")); 332 333 if (!(is >> upper_bound)) 334 return std::make_unique<Integer>(); 335 336 return std::make_unique<Integer>(lower_bound, upper_bound); 337 } 338 else 339 return std::make_unique<Integer>(); 340 } 341 else 342 return std::unique_ptr<Integer>(); 343 } 344 345 346 347 const double Double::min_double_value = -std::numeric_limits<double>::max(); 348 const double Double::max_double_value = std::numeric_limits<double>::max(); 349 350 const char *Double::description_init = "[Double"; 351 Double(const double lower_bound,const double upper_bound)352 Double::Double(const double lower_bound, const double upper_bound) 353 : lower_bound(lower_bound) 354 , upper_bound(upper_bound) 355 {} 356 357 358 359 bool match(const std::string & test_string) const360 Double::match(const std::string &test_string) const 361 { 362 std::istringstream str(test_string); 363 364 double d; 365 str >> d; 366 if (str.fail()) 367 return false; 368 369 if (!has_only_whitespace(str)) 370 return false; 371 // check whether valid bounds 372 // were specified, and if so 373 // enforce their values 374 if (lower_bound <= upper_bound) 375 return ((lower_bound <= d) && (upper_bound >= d)); 376 else 377 return true; 378 } 379 380 381 382 std::string description(const OutputStyle style) const383 Double::description(const OutputStyle style) const 384 { 385 switch (style) 386 { 387 case Machine: 388 { 389 std::ostringstream description; 390 391 if (lower_bound <= upper_bound) 392 { 393 // bounds are valid 394 description << description_init << " "; 395 // We really want to compare with ==, but -Wfloat-equal would 396 // create a warning here, so work around it. 397 if (0 == std::memcmp(&lower_bound, 398 &min_double_value, 399 sizeof(lower_bound))) 400 description << "-MAX_DOUBLE"; 401 else 402 description << lower_bound; 403 description << "..."; 404 if (0 == std::memcmp(&upper_bound, 405 &max_double_value, 406 sizeof(upper_bound))) 407 description << "MAX_DOUBLE"; 408 else 409 description << upper_bound; 410 description << " (inclusive)]"; 411 return description.str(); 412 } 413 else 414 { 415 // invalid bounds, assume unbounded double: 416 description << description_init << "]"; 417 return description.str(); 418 } 419 } 420 case Text: 421 { 422 if (lower_bound <= upper_bound) 423 { 424 std::ostringstream description; 425 426 description << "A floating point number v such that "; 427 if (0 == std::memcmp(&lower_bound, 428 &min_double_value, 429 sizeof(lower_bound))) 430 description << "-MAX_DOUBLE"; 431 else 432 description << lower_bound; 433 description << " <= v <= "; 434 if (0 == std::memcmp(&upper_bound, 435 &max_double_value, 436 sizeof(upper_bound))) 437 description << "MAX_DOUBLE"; 438 else 439 description << upper_bound; 440 441 return description.str(); 442 } 443 else 444 return "A floating point number"; 445 } 446 case LaTeX: 447 { 448 if (lower_bound <= upper_bound) 449 { 450 std::ostringstream description; 451 452 description << "A floating point number $v$ such that $"; 453 if (0 == std::memcmp(&lower_bound, 454 &min_double_value, 455 sizeof(lower_bound))) 456 description << "-\\text{MAX\\_DOUBLE}"; 457 else 458 description << lower_bound; 459 description << " \\leq v \\leq "; 460 if (0 == std::memcmp(&upper_bound, 461 &max_double_value, 462 sizeof(upper_bound))) 463 description << "\\text{MAX\\_DOUBLE}"; 464 else 465 description << upper_bound; 466 description << "$"; 467 468 return description.str(); 469 } 470 else 471 return "A floating point number"; 472 } 473 default: 474 AssertThrow(false, ExcNotImplemented()); 475 } 476 // Should never occur without an exception, but prevent compiler from 477 // complaining 478 return ""; 479 } 480 481 482 std::unique_ptr<PatternBase> clone() const483 Double::clone() const 484 { 485 return std::unique_ptr<PatternBase>(new Double(lower_bound, upper_bound)); 486 } 487 488 489 490 std::unique_ptr<Double> create(const std::string & description)491 Double::create(const std::string &description) 492 { 493 const std::string description_init_str = description_init; 494 if (description.compare(0, 495 description_init_str.size(), 496 description_init_str) != 0) 497 return std::unique_ptr<Double>(); 498 if (*description.rbegin() != ']') 499 return std::unique_ptr<Double>(); 500 501 std::string temp = description.substr(description_init_str.size()); 502 if (temp == "]") 503 return std::make_unique<Double>(1.0, 504 -1.0); // return an invalid range 505 506 if (temp.find("...") != std::string::npos) 507 temp.replace(temp.find("..."), 3, " "); 508 509 double lower_bound = min_double_value, upper_bound = max_double_value; 510 511 std::istringstream is(temp); 512 if (0 == temp.compare(0, std::strlen(" -MAX_DOUBLE"), " -MAX_DOUBLE")) 513 is.ignore(std::strlen(" -MAX_DOUBLE")); 514 else 515 { 516 // parse lower bound and give up if not a double 517 if (!(is >> lower_bound)) 518 return std::unique_ptr<Double>(); 519 } 520 521 // ignore failure here and assume we got MAX_DOUBLE as upper bound: 522 is >> upper_bound; 523 if (is.fail()) 524 upper_bound = max_double_value; 525 526 return std::make_unique<Double>(lower_bound, upper_bound); 527 } 528 529 530 531 const char *Selection::description_init = "[Selection"; 532 533 Selection(const std::string & seq)534 Selection::Selection(const std::string &seq) 535 : sequence(seq) 536 { 537 while (sequence.find(" |") != std::string::npos) 538 sequence.replace(sequence.find(" |"), 2, "|"); 539 while (sequence.find("| ") != std::string::npos) 540 sequence.replace(sequence.find("| "), 2, "|"); 541 } 542 543 544 545 bool match(const std::string & test_string) const546 Selection::match(const std::string &test_string) const 547 { 548 std::string tmp(sequence); 549 550 // remove whitespace at beginning 551 while ((tmp.length() != 0) && (std::isspace(tmp[0]))) 552 tmp.erase(0, 1); 553 554 // check the different possibilities 555 while (tmp.find('|') != std::string::npos) 556 { 557 if (test_string == std::string(tmp, 0, tmp.find('|'))) 558 return true; 559 560 tmp.erase(0, tmp.find('|') + 1); 561 } 562 563 // remove whitespace at the end 564 while ((tmp.length() != 0) && (std::isspace(*(tmp.end() - 1)))) 565 tmp.erase(tmp.end() - 1); 566 567 // check last choice, not finished by | 568 if (test_string == tmp) 569 return true; 570 571 // not found 572 return false; 573 } 574 575 576 577 std::string description(const OutputStyle style) const578 Selection::description(const OutputStyle style) const 579 { 580 switch (style) 581 { 582 case Machine: 583 { 584 std::ostringstream description; 585 586 description << description_init << " " << sequence << " ]"; 587 588 return description.str(); 589 } 590 case Text: 591 case LaTeX: 592 { 593 std::ostringstream description; 594 595 description << "Any one of " 596 << internal::escape( 597 Utilities::replace_in_string(sequence, "|", ", "), 598 style); 599 600 return description.str(); 601 } 602 default: 603 AssertThrow(false, ExcNotImplemented()); 604 } 605 // Should never occur without an exception, but prevent compiler from 606 // complaining 607 return ""; 608 } 609 610 611 612 std::unique_ptr<PatternBase> clone() const613 Selection::clone() const 614 { 615 return std::unique_ptr<PatternBase>(new Selection(sequence)); 616 } 617 618 619 std::size_t memory_consumption() const620 Selection::memory_consumption() const 621 { 622 return (sizeof(PatternBase) + 623 MemoryConsumption::memory_consumption(sequence)); 624 } 625 626 627 628 std::unique_ptr<Selection> create(const std::string & description)629 Selection::create(const std::string &description) 630 { 631 if (description.compare(0, 632 std::strlen(description_init), 633 description_init) == 0) 634 { 635 std::string sequence(description); 636 637 sequence.erase(0, std::strlen(description_init) + 1); 638 sequence.erase(sequence.length() - 2, 2); 639 640 return std::make_unique<Selection>(sequence); 641 } 642 else 643 return std::unique_ptr<Selection>(); 644 } 645 646 647 648 const unsigned int List::max_int_value = 649 std::numeric_limits<unsigned int>::max(); 650 651 const char *List::description_init = "[List"; 652 653 List(const PatternBase & p,const unsigned int min_elements,const unsigned int max_elements,const std::string & separator)654 List::List(const PatternBase &p, 655 const unsigned int min_elements, 656 const unsigned int max_elements, 657 const std::string &separator) 658 : pattern(p.clone()) 659 , min_elements(min_elements) 660 , max_elements(max_elements) 661 , separator(separator) 662 { 663 Assert(min_elements <= max_elements, 664 ExcInvalidRange(min_elements, max_elements)); 665 Assert(separator.size() > 0, 666 ExcMessage("The separator must have a non-zero length.")); 667 } 668 669 670 List(const List & other)671 List::List(const List &other) 672 : pattern(other.pattern->clone()) 673 , min_elements(other.min_elements) 674 , max_elements(other.max_elements) 675 , separator(other.separator) 676 {} 677 678 679 const std::string & get_separator() const680 List::get_separator() const 681 { 682 return separator; 683 } 684 685 686 687 const PatternBase & get_base_pattern() const688 List::get_base_pattern() const 689 { 690 return *pattern; 691 } 692 693 694 695 bool match(const std::string & test_string_list) const696 List::match(const std::string &test_string_list) const 697 { 698 const std::vector<std::string> split_list = 699 Utilities::split_string_list(test_string_list, separator); 700 701 if ((split_list.size() < min_elements) || 702 (split_list.size() > max_elements)) 703 return false; 704 705 // check the different possibilities 706 for (const std::string &string : split_list) 707 if (pattern->match(string) == false) 708 return false; 709 710 return true; 711 } 712 713 714 715 std::string description(const OutputStyle style) const716 List::description(const OutputStyle style) const 717 { 718 switch (style) 719 { 720 case Machine: 721 { 722 std::ostringstream description; 723 724 description << description_init << " of <" 725 << pattern->description(style) << ">" 726 << " of length " << min_elements << "..." 727 << max_elements << " (inclusive)"; 728 if (separator != ",") 729 description << " separated by <" << separator << ">"; 730 description << "]"; 731 732 return description.str(); 733 } 734 case Text: 735 case LaTeX: 736 { 737 std::ostringstream description; 738 739 description << "A list of " << min_elements << " to " 740 << max_elements << " elements "; 741 if (separator != ",") 742 description << "separated by <" 743 << internal::escape(separator, style) << "> "; 744 description << "where each element is [" 745 << pattern->description(style) << "]"; 746 747 return description.str(); 748 } 749 default: 750 AssertThrow(false, ExcNotImplemented()); 751 } 752 // Should never occur without an exception, but prevent compiler from 753 // complaining 754 return ""; 755 } 756 757 758 759 std::unique_ptr<PatternBase> clone() const760 List::clone() const 761 { 762 return std::unique_ptr<PatternBase>( 763 new List(*pattern, min_elements, max_elements, separator)); 764 } 765 766 767 std::size_t memory_consumption() const768 List::memory_consumption() const 769 { 770 return (sizeof(*this) + MemoryConsumption::memory_consumption(*pattern) + 771 MemoryConsumption::memory_consumption(separator)); 772 } 773 774 775 776 std::unique_ptr<List> create(const std::string & description)777 List::create(const std::string &description) 778 { 779 if (description.compare(0, 780 std::strlen(description_init), 781 description_init) == 0) 782 { 783 unsigned int min_elements = 0, max_elements = 0; 784 785 std::istringstream is(description); 786 is.ignore(strlen(description_init) + strlen(" of <")); 787 788 std::string str; 789 std::getline(is, str, '>'); 790 791 std::unique_ptr<PatternBase> base_pattern(pattern_factory(str)); 792 793 is.ignore(strlen(" of length ")); 794 if (!(is >> min_elements)) 795 return std::make_unique<List>(*base_pattern); 796 797 is.ignore(strlen("...")); 798 if (!(is >> max_elements)) 799 return std::make_unique<List>(*base_pattern, min_elements); 800 801 is.ignore(strlen(" (inclusive) separated by <")); 802 std::string separator; 803 if (!is.eof()) 804 std::getline(is, separator, '>'); 805 else 806 separator = ","; 807 808 return std::make_unique<List>(*base_pattern, 809 min_elements, 810 max_elements, 811 separator); 812 } 813 else 814 return std::unique_ptr<List>(); 815 } 816 817 818 819 const unsigned int Map::max_int_value = 820 std::numeric_limits<unsigned int>::max(); 821 822 const char *Map::description_init = "[Map"; 823 824 Map(const PatternBase & p_key,const PatternBase & p_value,const unsigned int min_elements,const unsigned int max_elements,const std::string & separator,const std::string & key_value_separator)825 Map::Map(const PatternBase &p_key, 826 const PatternBase &p_value, 827 const unsigned int min_elements, 828 const unsigned int max_elements, 829 const std::string &separator, 830 const std::string &key_value_separator) 831 : key_pattern(p_key.clone()) 832 , value_pattern(p_value.clone()) 833 , min_elements(min_elements) 834 , max_elements(max_elements) 835 , separator(separator) 836 , key_value_separator(key_value_separator) 837 { 838 Assert(min_elements <= max_elements, 839 ExcInvalidRange(min_elements, max_elements)); 840 Assert(separator.size() > 0, 841 ExcMessage("The separator must have a non-zero length.")); 842 Assert(key_value_separator.size() > 0, 843 ExcMessage("The key_value_separator must have a non-zero length.")); 844 Assert(separator != key_value_separator, 845 ExcMessage( 846 "The separator can not be the same of the key_value_separator " 847 "since that is used as the separator between the two elements " 848 "of <key:value> pairs")); 849 } 850 851 852 Map(const Map & other)853 Map::Map(const Map &other) 854 : key_pattern(other.key_pattern->clone()) 855 , value_pattern(other.value_pattern->clone()) 856 , min_elements(other.min_elements) 857 , max_elements(other.max_elements) 858 , separator(other.separator) 859 , key_value_separator(other.key_value_separator) 860 {} 861 862 863 864 bool match(const std::string & test_string_list) const865 Map::match(const std::string &test_string_list) const 866 { 867 std::vector<std::string> split_list = 868 Utilities::split_string_list(test_string_list, separator); 869 if ((split_list.size() < min_elements) || 870 (split_list.size() > max_elements)) 871 return false; 872 873 for (const auto &key_value_pair : split_list) 874 { 875 std::vector<std::string> pair = 876 Utilities::split_string_list(key_value_pair, key_value_separator); 877 878 // Check that we have in fact two matches 879 if (pair.size() != 2) 880 return false; 881 882 // then verify that the patterns are satisfied 883 if (key_pattern->match(pair[0]) == false) 884 return false; 885 if (value_pattern->match(pair[1]) == false) 886 return false; 887 } 888 889 return true; 890 } 891 892 893 894 std::string description(const OutputStyle style) const895 Map::description(const OutputStyle style) const 896 { 897 switch (style) 898 { 899 case Machine: 900 { 901 std::ostringstream description; 902 903 description << description_init << " of <" 904 << key_pattern->description(style) << ">" 905 << key_value_separator << "<" 906 << value_pattern->description(style) << ">" 907 << " of length " << min_elements << "..." 908 << max_elements << " (inclusive)"; 909 if (separator != ",") 910 description << " separated by <" << separator << ">"; 911 description << "]"; 912 913 return description.str(); 914 } 915 case Text: 916 case LaTeX: 917 { 918 std::ostringstream description; 919 920 description << "A key" 921 << internal::escape(key_value_separator, style) 922 << "value map of " << min_elements << " to " 923 << max_elements << " elements "; 924 if (separator != ",") 925 description << " separated by <" 926 << internal::escape(separator, style) << "> "; 927 description << " where each key is [" 928 << key_pattern->description(style) << "]" 929 << " and each value is [" 930 << value_pattern->description(style) << "]"; 931 932 return description.str(); 933 } 934 default: 935 AssertThrow(false, ExcNotImplemented()); 936 } 937 // Should never occur without an exception, but prevent compiler from 938 // complaining 939 return ""; 940 } 941 942 943 944 std::unique_ptr<PatternBase> clone() const945 Map::clone() const 946 { 947 return std::unique_ptr<PatternBase>(new Map(*key_pattern, 948 *value_pattern, 949 min_elements, 950 max_elements, 951 separator, 952 key_value_separator)); 953 } 954 955 956 std::size_t memory_consumption() const957 Map::memory_consumption() const 958 { 959 return (sizeof(*this) + 960 MemoryConsumption::memory_consumption(*key_pattern) + 961 MemoryConsumption::memory_consumption(*value_pattern) + 962 MemoryConsumption::memory_consumption(separator) + 963 MemoryConsumption::memory_consumption(key_value_separator)); 964 } 965 966 967 968 std::unique_ptr<Map> create(const std::string & description)969 Map::create(const std::string &description) 970 { 971 if (description.compare(0, 972 std::strlen(description_init), 973 description_init) == 0) 974 { 975 unsigned int min_elements = 0, max_elements = 0; 976 977 std::istringstream is(description); 978 is.ignore(strlen(description_init) + strlen(" of <")); 979 980 std::string key; 981 std::getline(is, key, '>'); 982 983 std::string key_value_separator; 984 std::getline(is, key_value_separator, '<'); 985 986 // split 'str' into key and value 987 std::string value; 988 std::getline(is, value, '>'); 989 990 std::unique_ptr<PatternBase> key_pattern(pattern_factory(key)); 991 std::unique_ptr<PatternBase> value_pattern(pattern_factory(value)); 992 993 is.ignore(strlen(" of length ")); 994 if (!(is >> min_elements)) 995 return std::make_unique<Map>(*key_pattern, *value_pattern); 996 997 is.ignore(strlen("...")); 998 if (!(is >> max_elements)) 999 return std::make_unique<Map>(*key_pattern, 1000 *value_pattern, 1001 min_elements); 1002 1003 is.ignore(strlen(" (inclusive) separated by <")); 1004 std::string separator; 1005 if (!is.eof()) 1006 std::getline(is, separator, '>'); 1007 else 1008 separator = ","; 1009 1010 return std::make_unique<Map>(*key_pattern, 1011 *value_pattern, 1012 min_elements, 1013 max_elements, 1014 separator, 1015 key_value_separator); 1016 } 1017 else 1018 return std::unique_ptr<Map>(); 1019 } 1020 1021 1022 1023 const PatternBase & get_key_pattern() const1024 Map::get_key_pattern() const 1025 { 1026 return *key_pattern; 1027 } 1028 1029 1030 1031 const PatternBase & get_value_pattern() const1032 Map::get_value_pattern() const 1033 { 1034 return *value_pattern; 1035 } 1036 1037 1038 1039 const std::string & get_separator() const1040 Map::get_separator() const 1041 { 1042 return separator; 1043 } 1044 1045 1046 const std::string & get_key_value_separator() const1047 Map::get_key_value_separator() const 1048 { 1049 return key_value_separator; 1050 } 1051 1052 1053 1054 const char *Tuple::description_init = "[Tuple"; 1055 1056 Tuple(const std::vector<std::unique_ptr<PatternBase>> & ps,const std::string & separator)1057 Tuple::Tuple(const std::vector<std::unique_ptr<PatternBase>> &ps, 1058 const std::string & separator) 1059 : separator(separator) 1060 { 1061 Assert(ps.size() > 0, 1062 ExcMessage("The Patterns list must have a non-zero length.")); 1063 Assert(separator.size() > 0, 1064 ExcMessage("The separator must have a non-zero length.")); 1065 patterns.resize(ps.size()); 1066 for (unsigned int i = 0; i < ps.size(); ++i) 1067 patterns[i] = ps[i]->clone(); 1068 } 1069 1070 1071 Tuple(const std::vector<std::unique_ptr<PatternBase>> & ps,const char * separator)1072 Tuple::Tuple(const std::vector<std::unique_ptr<PatternBase>> &ps, 1073 const char * separator) 1074 : Tuple(ps, std::string(separator)) 1075 {} 1076 1077 1078 Tuple(const Tuple & other)1079 Tuple::Tuple(const Tuple &other) 1080 : separator(other.separator) 1081 { 1082 patterns.resize(other.patterns.size()); 1083 for (unsigned int i = 0; i < other.patterns.size(); ++i) 1084 patterns[i] = other.patterns[i]->clone(); 1085 } 1086 1087 1088 1089 bool match(const std::string & test_string_list) const1090 Tuple::match(const std::string &test_string_list) const 1091 { 1092 std::vector<std::string> split_list = 1093 Utilities::split_string_list(test_string_list, separator); 1094 if (split_list.size() != patterns.size()) 1095 return false; 1096 1097 for (unsigned int i = 0; i < patterns.size(); ++i) 1098 { 1099 if (patterns[i]->match(split_list[i]) == false) 1100 return false; 1101 } 1102 1103 return true; 1104 } 1105 1106 1107 1108 std::string description(const OutputStyle style) const1109 Tuple::description(const OutputStyle style) const 1110 { 1111 switch (style) 1112 { 1113 case Machine: 1114 { 1115 std::ostringstream description; 1116 1117 description << description_init << " of <" << patterns.size() 1118 << "> elements <" << patterns[0]->description(style) 1119 << ">"; 1120 for (unsigned int i = 1; i < patterns.size(); ++i) 1121 description << ", <" << patterns[i]->description(style) << ">"; 1122 1123 if (separator != ":") 1124 description << " separated by <" << separator << ">"; 1125 description << "]"; 1126 1127 return description.str(); 1128 } 1129 case Text: 1130 case LaTeX: 1131 { 1132 std::ostringstream description; 1133 1134 description << "A Tuple of " << patterns.size() << " elements "; 1135 if (separator != ":") 1136 description << " separated by <" 1137 << internal::escape(separator, style) << "> "; 1138 description << " where each element is [" 1139 << patterns[0]->description(style) << "]"; 1140 for (unsigned int i = 1; i < patterns.size(); ++i) 1141 { 1142 description << internal::escape(separator, style) << "[" 1143 << patterns[i]->description(style) << "]"; 1144 } 1145 return description.str(); 1146 } 1147 1148 default: 1149 AssertThrow(false, ExcNotImplemented()); 1150 } 1151 // Should never occur without an exception, but prevent compiler from 1152 // complaining 1153 return ""; 1154 } 1155 1156 1157 1158 std::unique_ptr<PatternBase> clone() const1159 Tuple::clone() const 1160 { 1161 return std::unique_ptr<PatternBase>(new Tuple(patterns, separator)); 1162 } 1163 1164 1165 std::size_t memory_consumption() const1166 Tuple::memory_consumption() const 1167 { 1168 return (sizeof(*this) + MemoryConsumption::memory_consumption(patterns) + 1169 MemoryConsumption::memory_consumption(separator)); 1170 } 1171 1172 1173 1174 std::unique_ptr<Tuple> create(const std::string & description)1175 Tuple::create(const std::string &description) 1176 { 1177 if (description.compare(0, 1178 std::strlen(description_init), 1179 description_init) == 0) 1180 { 1181 std::vector<std::unique_ptr<PatternBase>> patterns; 1182 1183 std::istringstream is(description); 1184 is.ignore(strlen(description_init) + strlen(" of <")); 1185 1186 std::string len; 1187 std::getline(is, len, '>'); 1188 const unsigned int n_elements = Utilities::string_to_int(len); 1189 Assert(n_elements > 0, 1190 ExcMessage("Provide at least 1 element in the tuple.")); 1191 patterns.resize(n_elements); 1192 1193 is.ignore(strlen(" elements <")); 1194 1195 std::string element; 1196 std::getline(is, element, '>'); 1197 patterns[0] = pattern_factory(element); 1198 1199 for (unsigned int i = 1; i < n_elements; ++i) 1200 { 1201 is.ignore(strlen(", <")); 1202 std::getline(is, element, '>'); 1203 patterns[i] = pattern_factory(element); 1204 } 1205 1206 is.ignore(strlen(" separated by <")); 1207 1208 std::string separator; 1209 if (!is.eof()) 1210 std::getline(is, separator, '>'); 1211 else 1212 separator = ":"; 1213 1214 return std::make_unique<Tuple>(patterns, separator); 1215 } 1216 else 1217 return std::unique_ptr<Tuple>(); 1218 } 1219 1220 1221 1222 const PatternBase & get_pattern(const unsigned int i) const1223 Tuple::get_pattern(const unsigned int i) const 1224 { 1225 return *patterns[i]; 1226 } 1227 1228 1229 1230 const std::string & get_separator() const1231 Tuple::get_separator() const 1232 { 1233 return separator; 1234 } 1235 1236 1237 1238 const char *MultipleSelection::description_init = "[MultipleSelection"; 1239 1240 MultipleSelection(const std::string & seq)1241 MultipleSelection::MultipleSelection(const std::string &seq) 1242 { 1243 Assert(seq.find(',') == std::string::npos, 1244 ExcCommasNotAllowed(seq.find(','))); 1245 1246 sequence = seq; 1247 while (sequence.find(" |") != std::string::npos) 1248 sequence.replace(sequence.find(" |"), 2, "|"); 1249 while (sequence.find("| ") != std::string::npos) 1250 sequence.replace(sequence.find("| "), 2, "|"); 1251 } 1252 1253 1254 1255 bool match(const std::string & test_string_list) const1256 MultipleSelection::match(const std::string &test_string_list) const 1257 { 1258 std::string tmp = test_string_list; 1259 std::vector<std::string> split_names; 1260 1261 // first split the input list 1262 while (tmp.length() != 0) 1263 { 1264 std::string name; 1265 name = tmp; 1266 1267 if (name.find(',') != std::string::npos) 1268 { 1269 name.erase(name.find(','), std::string::npos); 1270 tmp.erase(0, tmp.find(',') + 1); 1271 } 1272 else 1273 tmp = ""; 1274 1275 while ((name.length() != 0) && (std::isspace(name[0]))) 1276 name.erase(0, 1); 1277 while (std::isspace(name[name.length() - 1])) 1278 name.erase(name.length() - 1, 1); 1279 1280 split_names.push_back(name); 1281 } 1282 1283 1284 // check the different possibilities 1285 for (const auto &test_string : split_names) 1286 { 1287 bool string_found = false; 1288 1289 tmp = sequence; 1290 while (tmp.find('|') != std::string::npos) 1291 { 1292 if (test_string == std::string(tmp, 0, tmp.find('|'))) 1293 { 1294 // string found, quit 1295 // loop. don't change 1296 // tmp, since we don't 1297 // need it anymore. 1298 string_found = true; 1299 break; 1300 } 1301 1302 tmp.erase(0, tmp.find('|') + 1); 1303 } 1304 // check last choice, not finished by | 1305 if (!string_found) 1306 if (test_string == tmp) 1307 string_found = true; 1308 1309 if (!string_found) 1310 return false; 1311 } 1312 1313 return true; 1314 } 1315 1316 1317 1318 std::string description(const OutputStyle style) const1319 MultipleSelection::description(const OutputStyle style) const 1320 { 1321 switch (style) 1322 { 1323 case Machine: 1324 { 1325 std::ostringstream description; 1326 1327 description << description_init << " " << sequence << " ]"; 1328 1329 return description.str(); 1330 } 1331 case Text: 1332 case LaTeX: 1333 { 1334 std::ostringstream description; 1335 1336 description << "A comma-separated list of any of " 1337 << internal::escape( 1338 Utilities::replace_in_string(sequence, "|", ", "), 1339 style); 1340 1341 return description.str(); 1342 } 1343 default: 1344 AssertThrow(false, ExcNotImplemented()); 1345 } 1346 // Should never occur without an exception, but prevent compiler from 1347 // complaining 1348 return ""; 1349 } 1350 1351 1352 1353 std::unique_ptr<PatternBase> clone() const1354 MultipleSelection::clone() const 1355 { 1356 return std::unique_ptr<PatternBase>(new MultipleSelection(sequence)); 1357 } 1358 1359 1360 std::size_t memory_consumption() const1361 MultipleSelection::memory_consumption() const 1362 { 1363 return (sizeof(PatternBase) + 1364 MemoryConsumption::memory_consumption(sequence)); 1365 } 1366 1367 1368 1369 std::unique_ptr<MultipleSelection> create(const std::string & description)1370 MultipleSelection::create(const std::string &description) 1371 { 1372 if (description.compare(0, 1373 std::strlen(description_init), 1374 description_init) == 0) 1375 { 1376 std::string sequence(description); 1377 1378 sequence.erase(0, std::strlen(description_init) + 1); 1379 sequence.erase(sequence.length() - 2, 2); 1380 1381 return std::make_unique<MultipleSelection>(sequence); 1382 } 1383 else 1384 return std::unique_ptr<MultipleSelection>(); 1385 } 1386 1387 1388 1389 const char *Bool::description_init = "[Bool"; 1390 1391 Bool()1392 Bool::Bool() 1393 : Selection("true|false") 1394 {} 1395 1396 1397 1398 std::string description(const OutputStyle style) const1399 Bool::description(const OutputStyle style) const 1400 { 1401 switch (style) 1402 { 1403 case Machine: 1404 { 1405 std::ostringstream description; 1406 1407 description << description_init << "]"; 1408 1409 return description.str(); 1410 } 1411 case Text: 1412 case LaTeX: 1413 { 1414 return "A boolean value (true or false)"; 1415 } 1416 default: 1417 AssertThrow(false, ExcNotImplemented()); 1418 } 1419 // Should never occur without an exception, but prevent compiler from 1420 // complaining 1421 return ""; 1422 } 1423 1424 1425 1426 std::unique_ptr<PatternBase> clone() const1427 Bool::clone() const 1428 { 1429 return std::unique_ptr<PatternBase>(new Bool()); 1430 } 1431 1432 1433 1434 std::unique_ptr<Bool> create(const std::string & description)1435 Bool::create(const std::string &description) 1436 { 1437 if (description.compare(0, 1438 std::strlen(description_init), 1439 description_init) == 0) 1440 return std::make_unique<Bool>(); 1441 else 1442 return std::unique_ptr<Bool>(); 1443 } 1444 1445 1446 1447 const char *Anything::description_init = "[Anything"; 1448 1449 1450 1451 bool match(const std::string &) const1452 Anything::match(const std::string &) const 1453 { 1454 return true; 1455 } 1456 1457 1458 1459 std::string description(const OutputStyle style) const1460 Anything::description(const OutputStyle style) const 1461 { 1462 switch (style) 1463 { 1464 case Machine: 1465 { 1466 std::ostringstream description; 1467 1468 description << description_init << "]"; 1469 1470 return description.str(); 1471 } 1472 case Text: 1473 case LaTeX: 1474 { 1475 return "Any string"; 1476 } 1477 default: 1478 AssertThrow(false, ExcNotImplemented()); 1479 } 1480 // Should never occur without an exception, but prevent compiler from 1481 // complaining 1482 return ""; 1483 } 1484 1485 1486 1487 std::unique_ptr<PatternBase> clone() const1488 Anything::clone() const 1489 { 1490 return std::unique_ptr<PatternBase>(new Anything()); 1491 } 1492 1493 1494 1495 std::unique_ptr<Anything> create(const std::string & description)1496 Anything::create(const std::string &description) 1497 { 1498 if (description.compare(0, 1499 std::strlen(description_init), 1500 description_init) == 0) 1501 return std::make_unique<Anything>(); 1502 else 1503 return std::unique_ptr<Anything>(); 1504 } 1505 1506 1507 1508 const char *FileName::description_init = "[FileName"; 1509 1510 FileName(const FileType type)1511 FileName::FileName(const FileType type) 1512 : file_type(type) 1513 {} 1514 1515 1516 1517 bool match(const std::string &) const1518 FileName::match(const std::string &) const 1519 { 1520 return true; 1521 } 1522 1523 1524 1525 std::string description(const OutputStyle style) const1526 FileName::description(const OutputStyle style) const 1527 { 1528 switch (style) 1529 { 1530 case Machine: 1531 { 1532 std::ostringstream description; 1533 1534 description << description_init; 1535 1536 if (file_type == input) 1537 description << " (Type: input)]"; 1538 else 1539 description << " (Type: output)]"; 1540 1541 return description.str(); 1542 } 1543 case Text: 1544 case LaTeX: 1545 { 1546 if (file_type == input) 1547 return "an input filename"; 1548 else 1549 return "an output filename"; 1550 } 1551 default: 1552 AssertThrow(false, ExcNotImplemented()); 1553 } 1554 // Should never occur without an exception, but prevent compiler from 1555 // complaining 1556 return ""; 1557 } 1558 1559 1560 1561 std::unique_ptr<PatternBase> clone() const1562 FileName::clone() const 1563 { 1564 return std::unique_ptr<PatternBase>(new FileName(file_type)); 1565 } 1566 1567 1568 1569 std::unique_ptr<FileName> create(const std::string & description)1570 FileName::create(const std::string &description) 1571 { 1572 if (description.compare(0, 1573 std::strlen(description_init), 1574 description_init) == 0) 1575 { 1576 std::istringstream is(description); 1577 std::string file_type; 1578 FileType type; 1579 1580 is.ignore(strlen(description_init) + strlen(" (Type:")); 1581 1582 is >> file_type; 1583 1584 if (file_type == "input)]") 1585 type = input; 1586 else 1587 type = output; 1588 1589 return std::make_unique<FileName>(type); 1590 } 1591 else 1592 return std::unique_ptr<FileName>(); 1593 } 1594 1595 1596 1597 const char *DirectoryName::description_init = "[DirectoryName"; 1598 1599 1600 1601 bool match(const std::string &) const1602 DirectoryName::match(const std::string &) const 1603 { 1604 return true; 1605 } 1606 1607 1608 1609 std::string description(const OutputStyle style) const1610 DirectoryName::description(const OutputStyle style) const 1611 { 1612 switch (style) 1613 { 1614 case Machine: 1615 { 1616 std::ostringstream description; 1617 1618 description << description_init << "]"; 1619 1620 return description.str(); 1621 } 1622 case Text: 1623 case LaTeX: 1624 { 1625 return "A directory name"; 1626 } 1627 default: 1628 AssertThrow(false, ExcNotImplemented()); 1629 } 1630 // Should never occur without an exception, but prevent compiler from 1631 // complaining 1632 return ""; 1633 } 1634 1635 1636 1637 std::unique_ptr<PatternBase> clone() const1638 DirectoryName::clone() const 1639 { 1640 return std::unique_ptr<PatternBase>(new DirectoryName()); 1641 } 1642 1643 1644 1645 std::unique_ptr<DirectoryName> create(const std::string & description)1646 DirectoryName::create(const std::string &description) 1647 { 1648 if (description.compare(0, 1649 std::strlen(description_init), 1650 description_init) == 0) 1651 return std::make_unique<DirectoryName>(); 1652 else 1653 return std::unique_ptr<DirectoryName>(); 1654 } 1655 1656 } // end namespace Patterns 1657 1658 DEAL_II_NAMESPACE_CLOSE 1659