Re: Reading last 'n' lines from a ifstream
In article
<47ad2772-f5c4-45b1-9ca2-32075ae41610@s19g2000prg.googlegroups.com>,
<anubhav.saxena@wipro.com> wrote:
Hi,
I would like to know of a simple STL way of reading last n lines from
a file. I know about the istream_iterator but could not find any thing
that would read it from the end.
There is no provided iterator in standard libraray and
std::istream_iterator<std::string> will read by 'words' not 'lines'.
You need a custom iterator that reads lines not words and a custom
algorithm that keeps the last n [or less] lines read from the stream.
problem 2: last_n algorithm , is easy if we use a queue of some kind
to hold the last n or fewer lines read.
problem 1: an input iterator that reads lines not words from an istream.
Easiest to get right if boost is available is to write the iterator
deriving it from boost::iterator_facade<...>. Something like:
// line iterator.hpp
#ifndef LINE_ITERATOR_HPP_INCLUDED
#define LINE_ITERATOR_HPP_INCLUDED
#include <boost/iterator/iterator_facade.hpp>
#include <string>
#include <istream>
class line_iterator:public boost::iterator_facade
<
line_iterator,
std::string,
std::input_iterator_tag
{
friend class boost::iterator_core_access;
std::istream *p_is;
mutable std::string line;
char delim;
typename boost::iterator_facade
<
line_iterator,
std::string,
std::input_iterator_tag
>::reference dereference()const {return line;}
void increment()
{
if(p_is && !std::getline(*p_is,line,delim))
p_is = 0;
}
bool equal (const line_iterator &rhs) const
{
return p_is == rhs.p_is;
}
public:
line_iterator():p_is(0){}
line_iterator(std::istream &is,char d)
:p_is(&is),delim(d){}
char delimiter() const {return delim;}
void delimiter(char x) {delim = x;}
};
#endif
// end line_iterator.hpp
// begin last_n.hpp
#ifndef LAST_N_HPP_INCLUDED
#define LAST_N_HPP_INCLUDED
#include <iterator>
template <class In,class C>
void last_n(In begin,In end,int n,C &buffer,std::input_iterator_tag)
{
while(begin != end && n--)
{
buffer.push_back(*begin);
++begin;
}
while(begin !=end)
{
buffer.pop_front();
buffer.push_back(*begin);
++begin;
}
}
template <class BI,class C>
void last_n(BI begin,BI end,int n,C &buffer,
std::bidirectional_iterator_tag)
{
while(begin != end && n--)
{
buffer.push_front(*--end);
}
}
/*
Iter is an an STL compatible iterator,
C is a container of string with push_back,push_front
and pop_front()..
best of above chosen for category of given iterator.
*/
template <class Iter,class C>
void last_n(Iter begin,Iter end,int n,C &buffer)
{
typedef typename std::iterator_traits<Iter>::iterator_category Cat;
last_n(begin,end,n,buffer,Cat());
}
#endif
// end last_n.hpp
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]