#include "csv_loader.hpp" #include #include #include #include bool parse_csv_line(const std::string& line, Record& record) { if (line.empty()) { return false; } std::stringstream ss(line); std::string item; try { // timestamp if (!std::getline(ss, item, ',') || item.empty()) return false; record.timestamp = std::stod(item); // open if (!std::getline(ss, item, ',') || item.empty()) return false; record.open = std::stod(item); // high if (!std::getline(ss, item, ',') || item.empty()) return false; record.high = std::stod(item); // low if (!std::getline(ss, item, ',') || item.empty()) return false; record.low = std::stod(item); // close if (!std::getline(ss, item, ',') || item.empty()) return false; record.close = std::stod(item); // volume if (!std::getline(ss, item, ',')) return false; // Volume может быть пустым или содержать данные if (item.empty()) { record.volume = 0.0; } else { record.volume = std::stod(item); } return true; } catch (const std::exception&) { return false; } } std::vector load_csv_parallel(int rank, int size) { std::vector data; // Читаем настройки из переменных окружения std::string data_path = get_data_path(); std::vector shares = get_data_read_shares(); int64_t overlap_bytes = get_read_overlap_bytes(); // Получаем размер файла int64_t file_size = get_file_size(data_path); // Вычисляем диапазон байт для этого ранка ByteRange range = calculate_byte_range(rank, size, file_size, shares, overlap_bytes); // Открываем файл и читаем нужный диапазон std::ifstream file(data_path, std::ios::binary); if (!file.is_open()) { throw std::runtime_error("Cannot open file: " + data_path); } // Переходим к началу диапазона file.seekg(range.start); // Читаем данные в буфер int64_t bytes_to_read = range.end - range.start; std::vector buffer(bytes_to_read); file.read(buffer.data(), bytes_to_read); int64_t bytes_read = file.gcount(); file.close(); // Преобразуем в строку для удобства парсинга std::string content(buffer.data(), bytes_read); // Находим позицию начала первой полной строки size_t parse_start = 0; if (rank == 0) { // Первый ранк: пропускаем заголовок (первую строку) size_t header_end = content.find('\n'); if (header_end != std::string::npos) { parse_start = header_end + 1; } } else { // Остальные ранки: начинаем с первого \n (пропускаем неполную строку) size_t first_newline = content.find('\n'); if (first_newline != std::string::npos) { parse_start = first_newline + 1; } } // Находим позицию конца последней полной строки size_t parse_end = content.size(); if (rank != size - 1) { // Не последний ранк: ищем последний \n size_t last_newline = content.rfind('\n'); if (last_newline != std::string::npos && last_newline > parse_start) { parse_end = last_newline; } } // Парсим строки size_t pos = parse_start; while (pos < parse_end) { size_t line_end = content.find('\n', pos); if (line_end == std::string::npos || line_end > parse_end) { line_end = parse_end; } std::string line = content.substr(pos, line_end - pos); // Убираем \r если есть (Windows line endings) if (!line.empty() && line.back() == '\r') { line.pop_back(); } Record record; if (parse_csv_line(line, record)) { data.push_back(record); } pos = line_end + 1; } return data; }