Я использую следующую настройку:
#include <bits/stdc++.h>
using namespace std;
class foo {
public:
void bar( istream &in, int n ) {
vector<tuple<int,int,int,int>> q;
int x,y,a,b;
for ( q.clear(); in >> x >> y >> a >> b; q.push_back(make_tuple(x,y,a,b)) );
assert( n == q.size() );
}
};
int main() {
stringstream ss;
for ( int i= 0; i < 100; ++i )
ss << rand() << " " << rand() << " " << rand() << " " << rand() << endl;
ss.clear(), ss.seekg(0,std::ios::beg);
(new foo())->bar(ss,100);
}
На самом деле мой код более сложен, чем этот, но идея в том, что я помещаю вещи (точнее long long int
s) в stringstream
и вызываю функцию, предоставляя созданный stringstream
как istream
объект. Приведенный выше пример работает нормально, но в моем конкретном случае я поставил, скажем, 2 mln
кортежи. И проблема в том, что числа не полностью восстановлены на другом конце, внутри foo
(я получаю меньше 2000000
чисел). Можете ли вы представить сценарий, когда это может произойти? Может ли это in >> x >> y >> a >> b
как-то закончиться раньше, чем будет исчерпан ввод?
РЕДАКТИРОВАТЬ: Я использовал этот чек:
if ( ss.rdstate() and std::stringstream::badbit ) {
std::cerr << "Problem in putting stuff into stringstream!\n";
assert( false );
}
Каким-то образом все проходили эту проверку.
РЕДАКТИРОВАТЬ: Как я уже сказал, я проверяю работоспособность внутри main()
, восстанавливая входные номера с помощью >>
-метода и действительно возвращая 2 mln
(кортежи) чисел.
Когда объект stringstream
передается в foo
, он восстанавливает только часть чисел, а не все.
РЕДАКТИРОВАТЬ: Для чего это стоит, я вставляю фактический контекст здесь. Из-за его зависимостей он не будет компилироваться, но, по крайней мере, мы сможем увидеть ошибочные строки. Это метод run()
, который не может восстановить запросы, предоставленные методом main()
.
#include <iostream>
#include <algorithm>
#include <chrono>
const unsigned long long PERIOD= 0x1full;
class ExpRunnerJSONOutput : public ExperimentRunner {
std::string answers;
void set_name( std::string x ) {
this->answers= "answers."+x+".txt";
}
public:
ExpRunnerJSONOutput( query_processor *p ) : ExperimentRunner(p) {
set_name(p->method_name);
}
ExperimentRunner *setProcessor( query_processor *p) override {
ExperimentRunner::setProcessor(p);
set_name(p->method_name);
return this;
}
// in: the stream of queries
// out: where to write the results to
virtual void run( std::istream &in, std::ostream &out ) override {
node_type x,y;
value_type a,b;
unsigned long long i,j,rep_period= (16383+1)*2-1;
auto n= tree->size();
std::vector<std::tuple<node_type,node_type,value_type,value_type>> queries;
for ( queries.clear(); in >> x >> y >> a >> b; queries.push_back(std::make_tuple(x,y,a,b)) ) ;
value_type *results= new value_type[queries.size()], *ptr= results;
/* results are stored in JSON */
nlohmann::json sel;
long double total_elapsed_time= 0.00;
std::chrono::time_point<std::chrono::high_resolution_clock,std::chrono::nanoseconds> start, finish;
long long int nq= 0, it= 0;
start= std::chrono::high_resolution_clock::now();
int batch= 0;
for ( auto qr: queries ) {
x= std::get<0>(qr), y= std::get<1>(qr);
a= std::get<2>(qr), b= std::get<3>(qr);
auto ans= processor->count(x,y,a,b); nq+= ans, nq-= ans, ++nq, *ptr++= ans;
}
finish = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(finish-start);
total_elapsed_time= elapsed.count();
sel["avgtime_microsec"]= total_elapsed_time/nq*(1e-3);
out << sel << std::endl;
out.flush();
delete[] results;
}
~ExpRunnerJSONOutput() final {}
};
void runall( std::istream &in, char *res_file, ExpRunnerJSONOutput *er ) {
in.clear(), in.seekg(0,std::ios::beg);
std::string results_file= std::string(res_file);
std::ofstream out;
try {
out.open(results_file,std::ios::app);
}
catch ( std::exception &e ) {
throw e;
}
er->run(in,out), out.close();
}
using instant= std::chrono::time_point<std::chrono::steady_clock,std::chrono::nanoseconds>;
void sanity_check( std::istream &in, size_type nq ) {
node_type x,y;
value_type a,b;
size_type r= 0;
for ( ;in >> x >> y >> a >> b; ++r ) ;
assert( r == nq );
}
int main( int argc, char **argv ) {
if ( argc < 5 ) {
fprintf(stderr,"usage: ./<this_executable_name> <dataset_name> <num_queries> <result_file> K");
fflush(stderr);
return 1;
}
query_processor *processor;
std::string dataset_name= std::string(argv[1]);
auto num_queries= std::strtol(argv[2],nullptr,10);
auto K= std::strtol(argv[4],nullptr,10);
std::ifstream in;
std::ofstream logs;
try {
in.open(dataset_name+".puu");
logs.open(dataset_name+".log");
} catch ( std::exception &e ) {
throw e;
}
std::string s; in >> s;
std::vector<pq_types::value_type> w;
w.clear();
pq_types::value_type maxw= 0;
for ( auto l= 0; l < s.size()/2; ++l ) {
value_type entry;
in >> entry;
w.emplace_back(entry);
maxw= std::max(maxw,entry);
}
in.close();
const rlim_t kStackSize= s.size()*2;
struct rlimit r1{};
int result= getrlimit(RLIMIT_STACK,&r1);
if ( result == 0 ) {
if ( r1.rlim_cur < kStackSize ) {
r1.rlim_cur= kStackSize;
result= setrlimit(RLIMIT_STACK,&r1);
if ( result != 0 ) {
logs << "setrlimit returned result = " << result << std::endl;
assert( false );
}
}
}
logs << "stack limit successfully set" << std::endl;
instant start, finish;
remove(argv[3]);
auto sz= s.size()/2;
random1d_interval_generator<> rig(0,sz-1), wrig(0,maxw);
auto node_queries= rig(num_queries), weight_queries= wrig(num_queries,K);
assert( node_queries.size() == num_queries );
assert( weight_queries.size() == num_queries );
std::stringstream ss;
ss.clear(), ss.seekg(0,std::ios::beg);
for ( int i= 0; i < num_queries; ++i )
ss << node_queries[i].first << " " << node_queries[i].second << " " << weight_queries[i].first << " " << weight_queries[i].second << "\n";
ss.clear(), ss.seekg(0,std::ios::beg);
sanity_check(ss,num_queries);
start = std::chrono::steady_clock::now();
auto *er= new ExpRunnerJSONOutput(processor= new my_processor(s,w,dataset_name));
finish = std::chrono::steady_clock::now();
logit(logs,processor,start,finish);
runall(ss,argv[3],er), delete processor;
logs.close();
return 0;
}
EDIT: мне было интересно, связано ли это с ifstream.eof () - конец файла достигнут до реального конца
Теперь, как подтвердить гипотезу - чтение прекращается, когда мы достигаем байта со значением 26
?
РЕДАКТИРОВАТЬ: еще одно обновление. После прочтения вещей внутри foo
, rdstate()
вернул 4
, fail() == 1
и eof() == 0
. Таким образом, очевидно, что конец файла не был достигнут.