Был бы рад, если бы кто-нибудь покритиковал эту маленькую программку.
Нужно было сконвертировать большой файл состоящий из double в файл состоящий из float. По идее эту програмку можно использовать для конвертации любых простых POD струкур. Первая версия этой программы открывала поток, читала по одному значению и сразу его писала в другой поток. Конвертация трёхгигового файла занимала:
$ time double2float tmp.double tmp.float
real 1m24.239s
user 1m9.987s
sys 0m8.628s
Для сравнения, копирование файла занимает столько:
$ time cp input.vel.double tmp.double
real 0m13.322s
user 0m0.521s
sys 0m10.723s[/code]
Эта версия с буффером отрабатывает заметно быстрее:
[code]
$ time double2float tmp.double tmp.float
real 0m9.680s
user 0m1.511s
sys 0m7.625s
Вот код:
#include <algorithm>
#include <cassert>
#include <fstream>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
template<typename UnaryFunction>
void buffered_binary_stream_transform(std::ifstream& input, std::ofstream& output, UnaryFunction op, size_t buffer_size_bytes)
{
typedef typename UnaryFunction::argument_type argument_type;
typedef typename UnaryFunction::result_type result_type;
const size_t argument_type_size = sizeof(argument_type);
assert(buffer_size_bytes >= argument_type_size);
const size_t result_type_size = sizeof(result_type);
const typename std::vector<argument_type>::size_type buffer_size_elements = buffer_size_bytes / argument_type_size; //might truncate actual buffer_size_bytes
const int bytes_to_read = argument_type_size * buffer_size_elements;
std::vector<argument_type> elements_to_transform(buffer_size_elements);
std::vector<result_type> transformed_elements(buffer_size_elements);
while(true) {
input.read(reinterpret_cast<char*>(&elements_to_transform[0]), bytes_to_read);
const std::streamsize bytes_read = input.gcount();
if (bytes_read == 0) break;
const std::streamsize elements_read = bytes_read / argument_type_size;
const std::streamsize bytes_to_write = result_type_size * elements_read;
std::transform(elements_to_transform.begin(),
elements_to_transform.begin() + elements_read,
transformed_elements.begin(),
op);
output.write(reinterpret_cast<const char*>(&transformed_elements[0]), bytes_to_write);
}
}
struct Double2FloatConverter : public std::unary_function<double, float>
{
result_type operator() (const argument_type& to_convert)
{
return static_cast<result_type>(to_convert);
}
};
int main (int args, char** argv)
{
if (! (args == 4 || args == 3 ) )
{
std::cerr << "Wrong number of args" << std::endl << "usage: " << argv[0]
<< " input_file output_file" << std::endl;
exit(EXIT_FAILURE);
}
std::string input_file_name(argv[1]);
std::ifstream input(input_file_name.c_str(), std::ios::binary);
if(!input)
{
std::cerr << "Can't open input file \"" << input_file_name << "\"" << std::endl;
exit(EXIT_FAILURE);
}
std::string outputFileName(argv[2]);
if (outputFileName == input_file_name)
{
std::cerr << "Can't write to the same file I am reading from\n";
exit(EXIT_FAILURE);
}
std::ofstream output(outputFileName.c_str(), std::ios::binary);
if(!output)
{
std::cerr << "Can't open output file \"" << input_file_name.c_str() << "\"" << std::endl;
exit(EXIT_FAILURE);
}
const int buffer_size = 4*1024*1024;
buffered_binary_stream_transform(input, output, Double2FloatConverter(), buffer_size);
}
Есть ли смысл передавать элементарные типы данных по константной ссылке, как это делается в Double2FloatConverter::operator() ?
Функтор наследует от unary_function и этого типа требует шаблон и я не знаю хорошо это или плохо. Выходит, что с этим требованием в buffered_binary_stream_transform нельзя использовать функтор, который не наследует от unary_function.