131 lines
4.6 KiB
C++
131 lines
4.6 KiB
C++
#include <algorithm>
|
|
#include <array>
|
|
#include <functional>
|
|
#include <format>
|
|
#include <iostream>
|
|
#include <optional>
|
|
#include <sstream>
|
|
#include <string_view>
|
|
|
|
#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<std::string> &selected_objects,
|
|
const std::vector<std::string> &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<std::size_t, std::string> &line_data,
|
|
std::optional<std::string> &target_filter
|
|
)
|
|
>;
|
|
using check_filter_func_t = std::function<bool()>;
|
|
|
|
static const auto return_true = []()->bool { return true; };
|
|
std::optional<std::string> 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<std::size_t, std::string> &line_data,
|
|
std::optional<std::string> &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<char, 4096 + 1> 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<std::string, line_processor_func_t> 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;
|
|
}
|
|
} |