#include "editdistance.h" #include #include #include #include #include #include #include #include #include #include #define resolve(func, arg) \ static_castdecltype(func(arg))>(func) namespace C { static double a; static double b; static double c; static double d; static double e; static double f; static double g; static double h; } // namespace C void set_globals1() { std::ifstream in{"config.txt"}; std::string name; using namespace C; #define CHECK_SET(var) \ if (name == #var) { \ in >> var; \ continue; \ } \ ((void)0) while (in >> name) { CHECK_SET(a); CHECK_SET(b); CHECK_SET(c); CHECK_SET(d); CHECK_SET(e); CHECK_SET(f); CHECK_SET(g); CHECK_SET(h); } #undef CHECK_SET return; } template inline void read(std::istream& is, T& val) { is >> val; } template <> inline void read(std::istream& is, std::string& val) { is >> std::quoted(val); } struct Constant { static std::unordered_map& jump_table() { static std::unordered_map map; return map; } #define VAR(type, name) \ type name = [] { \ jump_table().emplace(#name, [](std::istream& is, Constant* obj) { \ ::read(is, obj->name); \ }); \ return type{}; \ }() VAR(double, a); VAR(int, b); VAR(std::string, c); VAR(double, d); VAR(double, e); VAR(double, f); VAR(double, g); VAR(double, h); #undef VAR void read(std::istream& is) { auto table = jump_table(); std::string name; while (is >> name) { auto pos = table.find(name); if (pos == table.end()) { if (jump_table().find(name) != jump_table().end()) { throw std::invalid_argument("Repeated name " + kblib::quoted(name)); } else { throw std::invalid_argument("Invalid name " + kblib::quoted(name)); } } pos->second(is, this); table.erase(pos); } if (! table.empty()) { throw std::logic_error("Not all variables set"); } /* std::string name; while (is >> name) { jump_table().at(name)(is, this); }*/ } void print(std::ostream& out) { #define PRINT(name) out << #name " " << name << '\n' PRINT(a); PRINT(b); PRINT(c); PRINT(d); PRINT(e); PRINT(f); PRINT(g); PRINT(h); #undef PRINT } }; namespace constant { inline std::unordered_map& jump_table() { static std::unordered_map map; return map; } #define VAR(type, name) \ inline type name = [] { \ jump_table().emplace(#name, [](std::istream& is) { read(is, name); }); \ return type{}; \ }() VAR(double, a); VAR(int, b); VAR(std::string, c); VAR(double, d); VAR(double, e); VAR(double, f); VAR(double, g); VAR(double, h); #undef VAR void set_globals(std::istream& is) { auto table = jump_table(); std::string name; while (not table.empty() and is >> name) { auto pos = table.find(name); if (pos == table.end()) { if (jump_table().find(name) != jump_table().end()) { throw std::invalid_argument("Repeated name " + kblib::quoted(name)); } else { throw std::invalid_argument("Invalid name " + kblib::quoted(name)); } } pos->second(is); table.erase(pos); } if (! table.empty()) { throw std::logic_error("Not all variables set"); } } } // namespace constant bool last_input_was_complete(std::istream& is) { int c = is.peek(); return (is && std::isspace(c)) || c == EOF; } void test_case(); int main_main(int argc, char** argv) { test_case(); Constant constants; if (argc > 1) { std::ifstream file{argv[1]}; constants.read(file); } else { constants.read(std::cin); } constants.print(std::cout); do { int val{}; std::cout << "> " << std::boolalpha; std::cin >> val; if (std::cin.good()) { std::cout << "Got: " << val << '\n'; } else { std::cout << "invalid input\n"; } std::cout << "good: " << std::cin.good() << "\nbad: " << std::cin.bad() << "\nfail: " << std::cin.fail() << "\neof: " << std::cin.eof() << '\n'; std::cout << "check: " << last_input_was_complete(std::cin) << '\n'; int next = std::cin.peek(); std::string remainder; std::getline(std::cin, remainder); std::cout << "remainder of line: " << std::quoted(remainder) << '\n'; std::cout << "Next character " << (std::isspace(next) ? "is" : "is not") << " a space\n"; } while (std::cin); return 0; } int midi_main(int argc, char** argv) { if (argc != 2) { std::cerr << "Usage: midi N\n"; return 1; } int note = std::atoi(argv[1]); std::cout << (440 * std::exp2((note - 69) / 12.f)) << '\n'; return 0; } template decltype(auto) map(F f, T&& t) { return std::apply( [&](auto&&... x) { return std::make_tuple(f(std::forward(x))...); }, std::forward(t)); } using func_t = auto(int, char**) -> int; func_t atrocity_main; func_t cat_main; func_t deleter_main; func_t dyn_main; func_t hexdump_main; func_t multi_main; func_t name_main; func_t packed_main; func_t primes_main; func_t sines_main; func_t sums_main; func_t triangles_main; namespace bad { func_t tudc_main; } // namespace bad namespace good { func_t tudc_main; } // namespace good func_t tuples_main; func_t uniq_main; func_t vector2_main; func_t vector_n_main; func_t random_main; template decltype(auto) map_args(F f, T&&... t) { return std::array{std::apply(f, std::forward(t))...}; } std::ptrdiff_t prefix_match_length(std::string_view a, std::string_view b) { auto [pa, pb] = std::mismatch(a.begin(), a.end(), b.begin(), b.end()); return pa - a.begin(); } int parse_int(std::string_view s) { constexpr int max = std::numeric_limits::max(); int value{}; for (std::size_t i{}, n{s.length()}; i < n; ++i) { if ((value > max / 10) or (max - value > s[i] - '0')) { return max; } value = value * 10 + s[i] - '0'; } return value; } const std::type_info& mangle2(); namespace { struct Class { double a; }; } // namespace int mangle(int, char**) { auto& id = typeid(Class); std::printf("%p: %s %ld\n", &id, id.name(), id.hash_code()); auto& id2 = mangle2(); std::printf("%p: %s %ld\n", &id2, id2.name(), id2.hash_code()); std::puts((id == id2) ? "equal" : "not equal"); return 0; } auto score(std::string_view a, std::string_view b) { return editDistance(a, b) - 3 * prefix_match_length(a, b); }; int do_lookup(int argc, char** argv) { struct MenuEntry { std::ptrdiff_t cost; int (*fun)(int, char**); std::string_view name; }; auto distance = [a = argv[1]](const auto& b, auto fun) { return MenuEntry{score(a, b), fun, b}; }; using std::pair; static auto dists = map_args( distance, pair( "help ", +[](int, char**) -> int { return 0; }), pair("atrocity ", &atrocity_main), pair("cat ", &cat_main), pair("constants", &main_main), pair("deleter ", &deleter_main), pair("dyncall", &dyn_main), pair("hexdump ", &hexdump_main), pair("midi ", &midi_main), pair("multi ", &multi_main), pair("name ", &name_main), pair("packed ", &packed_main), pair("primes ", &primes_main), pair("sines ", &sines_main), pair("sums ", &sums_main), pair("tudc(bad)", &bad::tudc_main), pair("tudc(good)", &good::tudc_main), pair("tuples ", &tuples_main), pair("triangles", &triangles_main), pair("unique ", &uniq_main), pair("vector2 ", &vector2_main), pair("vector_n ", &vector_n_main), pair("mangle", &mangle), pair("random", &random_main)); auto help = [](int argc, char** argv) -> int { auto filecontents = kblib::get_file_contents(argv[-1]); std::cout << "Executable hash: " << std::hex << kblib::FNV_hash{}(filecontents) << '\n'; if (argc > 1) { for (auto p : dists) { p.cost = score(argv[1], p.name); } std::stable_sort(dists.begin(), dists.end(), [](auto a, auto b) { return a.cost < b.cost; }); std::cout << "Calculated similarity scores: query " << std::quoted(argv[1]) << '\n'; for (auto& e : dists) { std::cout << "- " << e.name << ": " << 10 - e.cost << '\n'; } } std::cout << "Available commands are:\n"; for (auto& f : *static_cast(&dists)) { std::cout << "- " << f.name << '\n'; } return 0; }; dists.front().fun = help; std::stable_sort(dists.begin(), dists.end(), [](auto a, auto b) { return a.cost < b.cost; }); if (dists[0].cost == dists[1].cost) { std::cout << "operation not found: " << std::quoted(argv[1]) << '\n'; std::cout << "Calculated similarity scores:\n"; for (auto& e : dists) { std::cout << "- " << e.name << ": " << 10 - e.cost << '\n'; } } else { return dists[0].fun(argc - 1, argv + 1); } return 0; } int main(int argc, char** argv) { if (argc > 1) { do_lookup(argc, argv); } else { char c[] = {""}; char* t[] = {argv[0], c, nullptr}; do_lookup(argc, t); } }