#include #include #include #include #include #include #include #include #include "trim.hpp" #include "scan.hpp" namespace wavefront { scan_result::scan_result() : total_lines(0), line_data(), category_map{ { "v", {0} }, { "vn", {0} }, { "vt", {0} }, { "f", {} }, } {} scan_result scan( std::istream &input, const std::vector &selected_objects, const std::vector &selected_groups ) { using line_processor_func_t = std::function< void(const std::string &type, const std::size_t &line_number) >; using store_filter_factory_func_t = std::function< line_processor_func_t( const std::map &line_data, std::optional &target_filter ) >; using check_filter_func_t = std::function; static const auto return_true = []()->bool { return true; }; std::optional current_object, current_group; check_filter_func_t check_object = return_true; check_filter_func_t check_group = return_true; if (selected_objects.size() > 0) { check_object = [&]()->bool { auto begin = selected_objects.begin(); auto end = selected_objects.end(); return std::find(begin, end, current_object.value_or("")) != end; }; } if (selected_groups.size() > 0) { check_group = [&]()->bool { auto begin = selected_groups.begin(); auto end = selected_groups.end(); return std::find(begin, end, current_group.value_or("")) != end; }; } static const store_filter_factory_func_t create_filter_store = []( const std::map &line_data, std::optional &target_filter ) { return [&](const std::string &type, const std::size_t &line_number) { auto line = line_data.at(line_number); auto trimmed_name = trim(std::string_view(line.data() + type.size(), line.size() - type.size())); if (trimmed_name.empty()) [[unlikely]] { target_filter.reset(); } else [[likely]] { target_filter = std::string(trimmed_name); } }; }; std::array buffer; scan_result result; const line_processor_func_t insert_by_type = [&]( const std::string &type, const std::size_t &line_number ) { result.category_map[type].push_back(line_number); }; const std::map line_processor_map{ { "v", insert_by_type }, { "vn", insert_by_type }, { "vt", insert_by_type }, { "f", [&](const std::string &type, const std::size_t &line_number) { if (check_object() && check_group()) { insert_by_type(type, line_number); } }}, { "o", create_filter_store(result.line_data, current_object) }, { "g", create_filter_store(result.line_data, current_group) }, }; const auto max_type_length = [&]() { std::size_t max_length = 0; for (const auto &[type, _] : line_processor_map) { if (type.size() > max_length) { max_length = type.size(); } } return max_length; }(); std::string line; while (std::getline(input, line)) { ++result.total_lines; if (line.empty() || line[0] == '#' || trim(line).empty()) [[unlikely]] { continue; } auto line_type_end_pos = line.substr(0, max_type_length + 1).find_first_of(' '); if (line_type_end_pos == std::string::npos) [[unlikely]] { continue; } auto line_type = std::string(line.substr(0, line_type_end_pos)); auto type_processing_iterator = line_processor_map.find(line_type); if (type_processing_iterator == line_processor_map.end()) [[unlikely]] { continue; } result.line_data[result.total_lines] = std::string(line); type_processing_iterator->second(line_type, result.total_lines); } return result; } }