136 lines
4.4 KiB
C++
136 lines
4.4 KiB
C++
#include "csv_loader.hpp"
|
||
#include <fstream>
|
||
#include <sstream>
|
||
#include <iostream>
|
||
#include <stdexcept>
|
||
|
||
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<Record> load_csv_parallel(int rank, int size) {
|
||
std::vector<Record> data;
|
||
|
||
// Читаем настройки из переменных окружения
|
||
std::string data_path = get_data_path();
|
||
std::vector<int> 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<char> 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;
|
||
}
|