Анализ положительных чисел из файла


Мне нужно, чтобы проанализировать некоторые положительные числа со следующими ограничениями:

  • Если можно использовать C++ (без интерфейса API для C)

  • Должен уметь обрабатывать полученные данные после каждой строки

  • Должен быть достаточно быстрым

  • Использование памяти должна быть низкой (т. е. не читать весь файл за один раз)

  • CSV-файл сформирован правильно, поэтому ошибок может быть в основном опущены

  • Неизвестное количество строк в файле

  • Следует поддерживать как Unix (\n) и Windows (\r\n) окончаний строк

Этот код работает нормально, и работает быстрее, чем стандартный подход течь через >>. В среднем это занимает 290ms разобрать 10,000,000 строк, в то время как версия с >> занимает 1.1-ы , которые я считаю не плохой улучшения.

Однако у меня есть некоторые опасения по этому поводу:

  • Есть какие-то очевидные ошибки, которые делают это медленнее, чем она должна быть?

  • Есть ли побочные эффекты или неопределенному поведению?

  • Шаблон части применены правильно или есть ли лучший способ сделать это?

  • Тут называние смысл?

Просьба также указать что-то еще вы заметили.

Образец ввода:

1,22,333
4444,55555,666666

Код:

#include <algorithm>
#include <fstream>
#include <string>
#include <vector>

inline void parse_uints(
        const char* buffer_ptr,
        std::vector<uint_fast16_t>& numbers) {
    bool is_eol = false;
    while (!is_eol) {
        uint_fast16_t parsed_number = 0;
        for (;;) {
            if (*buffer_ptr == ',') {
                break;
            }
            if (*buffer_ptr == '\r' || *buffer_ptr == '\0') {
                is_eol = true;
                break;
            }
            parsed_number = (parsed_number * 10) + (*buffer_ptr++ - '0');
        }
        // skip delimiter
        ++buffer_ptr;
        numbers.emplace_back(parsed_number);
    }
}

template<typename T>
void read_line(
        const std::string& filename,
        const uint_fast8_t& line_length,
        const uint_fast8_t& values_per_line,
        T callback) {
    std::ifstream infile{filename};
    if (!infile.good()) {
        return;
    }

    std::vector<uint_fast16_t> numbers;
    numbers.reserve(values_per_line);

    std::string buffer;
    buffer.reserve(line_length);

    while (infile.good() && std::getline(infile, buffer)) {
        parse_uints(buffer.data(), numbers);
        callback(numbers);
        numbers.clear();
    }
}

int main(int argc, char** argv) {
    constexpr uint_fast8_t line_length = 25;
    constexpr uint_fast8_t values_per_line = 3;
    read_line(argv[1], line_length, values_per_line, [](auto& values) {
        // do something with the values here, for example get the max
        auto max = std::max_element(std::begin(values), std::end(values));
    });
}


Комментарии
1 ответ

Какая-то парочка гнид.


  1. Вы функция read_line не то, что он предлагает. Он считывает файл построчно. Поэтому вы должны найти подходящее имя.

  2. Ваш выбор uint_fast8_t/uint_fast16_t интересно, учитывая, что ваш пример таблицы CSV провести несколько большие значения. Вы измерили воздействие против неподписанных int или std::size_t, так. Следует помнить, что современный процессор может считывать несколько элементов сразу, так что выбор на самом деле может иметь негативные последствия.

  3. В каждой линии вы ясно и наращивать. Это будет полезно для всего инициализировать ее один раз через resize а потом просто перезаписать старое значение. Таким образом, вы можете опустить ненужные clear

  4. Гэтлину принимает третий аргумент, который является delemiter. Также Гэтлину останавливается на символ перевода строки и конца файла, так что вам не нужно все, что проверка на ошибки, учитывая, что сейчас количество записей в каждой строке можно просто петлю и накапливать

    while (infile.good()) {
    for (auto&& elem : numbers) {
    std::getline(infile, buffer, ",");
    elem = 0;
    for (auto&& digit : buffer) {
    elem *= 10;
    elem += (digit - '0');
    }
    }
    callback(numbers);
    }

Если вы хотите быть уверены, вы можете проверить Гэтлином и вернуться, если его плохо.

    while (infile.good()) {
for (auto&& elem : numbers) {
if (!std::getline(infile, buffer, ",")) {
return;
}
elem = 0;
for (auto&& digit : buffer) {
elem *= 10;
elem += (digit - '0');
}
}
callback(numbers);
}

2
ответ дан 9 марта 2018 в 07:03 Источник Поделиться