Date: Mon, 18 Apr 2022 20:19:20 +0100
We can read from "cin" or any file (fstream) as though it were a container
in volatile memory, using istream_iterator. But we can't put a limit on how
many char's to take from the istream.
Sometimes there is an alternative function available to use, e.g. 'copy_n'
instead of 'copy', but sometimes there isn't.
I propose a new template class istream_iterator_limited(N) that will stop
reading from the istream after N characters.
- - - - WHY I NEEDED THIS:
I wanted to open a file using "ifstream", and then I wanted to read 32
bytes from the file and feed them directly into the function
'boost::algorithm::hex'.
Unfortunately I couldn't do this because 'hex' takes two iterators
[begin,end), and there's no alternative function called "hex_n". So I had
to read the file into a string object first with 'copy_n', and then pass
the string into the 'hex' function.
- - - - THE IDEA I CAME UP WITH:
Open the file using "ifstream", and then use a special iterator that will
stop reading from the file after 32 bytes, with syntax like this:
ifstream logfile("log.txt");
hex( istream_iterator_limited<char>(logfile,32u),
istream_iterator_limited<char>(), g_some_global_container.begin() );
- - - - HOW I CODED IT:
#include <cstddef> /* size_t */
#include <iterator> /* istream_iterator */
template <typename T>
class istream_iterator_limited : public std::istream_iterator<T> {
protected:
std::size_t const m_limit;
std::size_t m_current_count;
public:
/* Shorter names */
typedef std::istream_iterator<T> Base;
typedef istream_iterator_limited<T> This;
istream_iterator_limited(typename Base::istream_type &obj_stream,
size_t const arg_limit)
: Base(obj_stream), m_limit(arg_limit), m_current_count(1u)
{
/* The initialiser list above does all the construction
work */
}
istream_iterator_limited(void) /* This gives the End-Of-Stream
iterator */
: Base() , m_limit(0u), m_current_count(1u)
{
/* The initialiser list above does all the construction work */
}
This &operator++(void)
{
if ( m_limit <= m_current_count )
{
Base::operator=( Base() ); /* becomes End-Of-Stream
iterator */
}
else
{
++m_current_count;
Base::operator++();
}
return *this;
}
};
- - - - HOW I TESTED IT:
#include <algorithm> /* copy */
#include <string> /* string */
#include <sstream> /* istringstream */
#include <iostream> /* cout, endl */
#include <iterator> /* back_inserter */
auto main(void) -> int
{
std::istringstream iss("123456789");
std::string str;
/* Let's use copy to read 5 char's into our string */
std::copy( istream_iterator_limited<char>(iss,5),
istream_iterator_limited<char>(), std::back_inserter(str) );
std::cout << str << std::endl;
str.clear();
/* Get another 3 */
std::copy( istream_iterator_limited<char>(iss,3),
istream_iterator_limited<char>(), std::back_inserter(str) );
std::cout << str << std::endl;
}
in volatile memory, using istream_iterator. But we can't put a limit on how
many char's to take from the istream.
Sometimes there is an alternative function available to use, e.g. 'copy_n'
instead of 'copy', but sometimes there isn't.
I propose a new template class istream_iterator_limited(N) that will stop
reading from the istream after N characters.
- - - - WHY I NEEDED THIS:
I wanted to open a file using "ifstream", and then I wanted to read 32
bytes from the file and feed them directly into the function
'boost::algorithm::hex'.
Unfortunately I couldn't do this because 'hex' takes two iterators
[begin,end), and there's no alternative function called "hex_n". So I had
to read the file into a string object first with 'copy_n', and then pass
the string into the 'hex' function.
- - - - THE IDEA I CAME UP WITH:
Open the file using "ifstream", and then use a special iterator that will
stop reading from the file after 32 bytes, with syntax like this:
ifstream logfile("log.txt");
hex( istream_iterator_limited<char>(logfile,32u),
istream_iterator_limited<char>(), g_some_global_container.begin() );
- - - - HOW I CODED IT:
#include <cstddef> /* size_t */
#include <iterator> /* istream_iterator */
template <typename T>
class istream_iterator_limited : public std::istream_iterator<T> {
protected:
std::size_t const m_limit;
std::size_t m_current_count;
public:
/* Shorter names */
typedef std::istream_iterator<T> Base;
typedef istream_iterator_limited<T> This;
istream_iterator_limited(typename Base::istream_type &obj_stream,
size_t const arg_limit)
: Base(obj_stream), m_limit(arg_limit), m_current_count(1u)
{
/* The initialiser list above does all the construction
work */
}
istream_iterator_limited(void) /* This gives the End-Of-Stream
iterator */
: Base() , m_limit(0u), m_current_count(1u)
{
/* The initialiser list above does all the construction work */
}
This &operator++(void)
{
if ( m_limit <= m_current_count )
{
Base::operator=( Base() ); /* becomes End-Of-Stream
iterator */
}
else
{
++m_current_count;
Base::operator++();
}
return *this;
}
};
- - - - HOW I TESTED IT:
#include <algorithm> /* copy */
#include <string> /* string */
#include <sstream> /* istringstream */
#include <iostream> /* cout, endl */
#include <iterator> /* back_inserter */
auto main(void) -> int
{
std::istringstream iss("123456789");
std::string str;
/* Let's use copy to read 5 char's into our string */
std::copy( istream_iterator_limited<char>(iss,5),
istream_iterator_limited<char>(), std::back_inserter(str) );
std::cout << str << std::endl;
str.clear();
/* Get another 3 */
std::copy( istream_iterator_limited<char>(iss,3),
istream_iterator_limited<char>(), std::back_inserter(str) );
std::cout << str << std::endl;
}
Received on 2022-04-18 19:19:21