How to report custom istream failures - c++

I would like to use operator>>() for reading linear algebraic data from console. I would like operator>>() to behave like it does for build-in data (like int, double), but I also wish to report appropriate messages when input cannot be parsed.
I’ve finally constructed a ‘custom_istream_failure’ class, but all together it was quite a hassle. Now I wonder: Is this the way to go, or does another mechanism exist for this purpose? Is this in the spirit of the standard?
I’ve included a small test program which reports a custom failure in the ‘expect’ function. Additionally I’ve included the ‘custom_istream_failure.h’ header file this question is about.
#include <iostream>
#include "custom_istream_failure.h"
struct vector_t { int x, y, z; };
bool expect(std::istream& is, char e)
{
if (is.get() != e)
{
custom_istream_failure(is)
<< "Expected '" << e << '\''
<< and_throw;
return false;
}
return true;
}
std::istream& operator>>(
std::istream& is, vector_t& v)
{
expect(is, '(') &&
(is >> v.x) &&
expect(is, ',') &&
(is >> v.y) &&
expect(is, ',') &&
(is >> v.z) &&
expect(is, ')');
return is;
}
int main()
{
try
{
std::cin.exceptions(std::istream::failbit);
vector_t vector;
std::cin >> vector;
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
#ifndef CUSTOM_ISTREAM_FAILURE
#define CUSTOM_ISTREAM_FAILURE
#include <iostream>
#include <string>
#include <sstream>
class custom_istream_failure
: protected std::stringstream
{
public:
explicit custom_istream_failure(std::istream& is)
: m_is(is)
{}
custom_istream_failure& operator<<(
custom_istream_failure&
(*pf)(custom_istream_failure&))
{
return ((*pf)(*this));
}
#define CUSTOM_ISTREAM_FAILURE_SOP(D) \
custom_istream_failure& operator<<(D) \
{ \
*static_cast<std::stringstream*>(this) << v; \
return *this; \
}
CUSTOM_ISTREAM_FAILURE_SOP(bool v)
CUSTOM_ISTREAM_FAILURE_SOP(short v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned short v)
CUSTOM_ISTREAM_FAILURE_SOP(int v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned int v)
CUSTOM_ISTREAM_FAILURE_SOP(long v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned long v)
CUSTOM_ISTREAM_FAILURE_SOP(long long v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned long long v)
CUSTOM_ISTREAM_FAILURE_SOP(float v)
CUSTOM_ISTREAM_FAILURE_SOP(double v)
CUSTOM_ISTREAM_FAILURE_SOP(long double v)
CUSTOM_ISTREAM_FAILURE_SOP(void* v)
CUSTOM_ISTREAM_FAILURE_SOP(std::streambuf* v)
CUSTOM_ISTREAM_FAILURE_SOP(
std::ostream& (*v)(std::ostream&))
CUSTOM_ISTREAM_FAILURE_SOP(
std::ios& (*v)(std::ios&))
CUSTOM_ISTREAM_FAILURE_SOP(
std::ios_base& (*v)(std::ios_base&))
CUSTOM_ISTREAM_FAILURE_SOP(char v)
CUSTOM_ISTREAM_FAILURE_SOP(signed char v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned char v)
CUSTOM_ISTREAM_FAILURE_SOP(const char* v)
CUSTOM_ISTREAM_FAILURE_SOP(const signed char* v)
CUSTOM_ISTREAM_FAILURE_SOP(const unsigned char*v);
#undef CUSTOM_ISTREAM_FAILURE_SOP
private:
std::istream& m_is;
friend custom_istream_failure& and_throw(
custom_istream_failure&);
};
inline custom_istream_failure& and_throw(
custom_istream_failure& cif)
{
try { throw std::ios_base::failure(cif.str()); }
catch (...)
{
cif.m_is.setstate(std::ios::failbit, true);
}
return (cif);
}
#endif // CUSTOM_ISTREAM_FAILURE

One approach is to just make the input operator for your type handle the error conditions (example below). If a user wants exceptions to be thrown on error the setstate will trigger an appropriate exception. And for users that don't want exceptions will just check the status of the input stream in the usual manner.
std::istream &operator>>(std::istream &is, vector_t &v) {
char c;
if (is >> c && c == '(') {
int x = 0;
if (is >> x >> c && c == ',') {
int y = 0;
if (is >> y >> c && c == ',') {
int z = 0;
if (is >> z >> c && c == ')') {
v = {x, y, z};
return is;
}
}
}
}
is.setstate(std::ios_base::failbit);
return is;
}

Related

Parsing a string to create a geometry

What is the algorithm for developing a string parser to create a geometry? The geometry is generated in 2 steps: at the first step, we create primitives; at the second, we combine primitives into objects.
The syntax is presented in the string below.
string str="[GEOMETRY]
PRIMITIVE1=SPHERE(RADIUS=5.5);
PRIMITIVE2=BOX(A=-5.2, B=7.3);
//...
OBJECT1=PRIMITIVE2*(-PRIMITIVE1);
//..."
class PRIMITIVE{
int number;
public:
Primitive& operator+ (Primitive& primitive) {}; //overloading arithmetic operations
Primitive& operator* (Primitive& primitive) {};
Primitive& operator- (Primitive& primitive) {};
virtual bool check_in_point_inside_primitive = 0;
};
class SPHERE:public PRIMITIVE{
double m_radius;
public:
SPHERE(double radius): m_radius(radius) {}; //In which part of the parser to create objects?
bool check_in_point_inside_sphere(Point& point){};
};
class BOX:public PRIMITIVE{
double m_A;
double m_B;
public:
BOX(double A, double B): m_A(A), m_B(B) {};
bool check_in_point_inside_box(Point& point){};
};
class OBJECT{
int number;
PRIMITIVE& primitive;
public:
OBJECT(){};
bool check_in_point_inside_object(Primitive& PRIMITIVE1, Primitive& PRIMITIVE2, Point& point){
//>How to construct a function from an expression 'PRIMITIVE2*(-PRIMITIVE1)' when parsing?
}
};
How to analyze the string PRIMITIVE1=SPHERE(RADIUS=5.5) and pass a parameter to the constructor of SPHERE()? How to identify this object with the name PRIMITIVE 1 to call to it in OBJECT? Is it possible to create a pair<PRIMITIVE1,SPHERE(5.5)> and store all primitives in map?
How to parse the string of the OBJECT1 and to construct a function from an expression PRIMITIVE2*(-PRIMITIVE1) inside an OBJECT1? This expression will be required multiple times when determining the position of each point relative to the object.
How to use boost::spirit for this task? Tokenize a string using boost::spirit::lex, and then develop rules using boost::spirit::qi?
As a finger exercise, and despite the serious problems I see with the chosen virtual type hierarchy, let's try to make a value-oriented container of Primitives that can be indexed by their id (ById):
Live On Coliru
#include <boost/intrusive/set.hpp>
#include <boost/poly_collection/base_collection.hpp>
#include <iostream>
namespace bi = boost::intrusive;
struct Point {
};
using IndexHook = bi::set_member_hook<bi::link_mode<bi::auto_unlink>>;
class Primitive {
int _id;
public:
struct ById {
bool operator()(auto const&... oper) const { return std::less<>{}(access(oper)...); }
private:
static int access(int id) { return id; }
static int access(Primitive const& p) { return p._id; }
};
IndexHook _index;
Primitive(int id) : _id(id) {}
virtual ~Primitive() = default;
int id() const { return _id; }
Primitive& operator+= (Primitive const& primitive) { return *this; } //overloading arithmetic operations
Primitive& operator*= (Primitive const& primitive) { return *this; }
Primitive& operator-= (Primitive const& primitive) { return *this; }
virtual bool check_in_point_inside(Point const&) const = 0;
};
using Index =
bi::set<Primitive, bi::constant_time_size<false>,
bi::compare<Primitive::ById>,
bi::member_hook<Primitive, IndexHook, &Primitive::_index>>;
class Sphere : public Primitive {
double _radius;
public:
Sphere(int id, double radius)
: Primitive(id)
, _radius(radius) {} // In which part of the parser to create objects?
bool check_in_point_inside(Point const& point) const override { return false; }
};
class Box : public Primitive {
double _A;
double _B;
public:
Box(int id, double A, double B) : Primitive(id), _A(A), _B(B) {}
bool check_in_point_inside(Point const& point) const override { return false; }
};
class Object{
int _id;
Primitive& _primitive;
public:
Object(int id, Primitive& p) : _id(id), _primitive(p) {}
bool check_in_point_inside_object(Primitive const& p1, Primitive const& p2,
Point const& point) const
{
//>How to construct a function from an expression
//'PRIMITIVE2*(-PRIMITIVE1)' when parsing?
return false;
}
};
using Primitives = boost::poly_collection::base_collection<Primitive>;
int main() {
Primitives test;
test.insert(Sphere{2, 4.0});
test.insert(Sphere{4, 4.0});
test.insert(Box{2, 5, 6});
test.insert(Sphere{1, 4.0});
test.insert(Box{3, 5, 6});
Index idx;
for (auto& p : test)
if (not idx.insert(p).second)
std::cout << "Duplicate id " << p.id() << " not indexed\n";
for (auto& p : idx)
std::cout << typeid(p).name() << " " << p.id() << "\n";
std::cout << "---\n";
for (auto& p : test)
std::cout << typeid(p).name() << " " << p.id() << "\n";
}
Prints
Duplicate id 2 not indexed
6Sphere 1
3Box 2
3Box 3
6Sphere 4
---
3Box 2
3Box 3
6Sphere 2
6Sphere 4
6Sphere 1
So far so good. This is an important building block to prevent all manner of pain when dealing with virtual types in Spirit grammars¹
PS: I've since dropped the idea of intrusive_set. It doesn't work because the base_container moves items around on reallocation, and that unlinks the items from their intrusive set.
Instead, see below for an approach that doesn't try to resolve ids during the parse.
Parsing primitives
We get the ID from the PRIMITIVE1. We could store it somewhere before naturally parsing the primitives themselves, then set the id on it on commit.
Let's start with defining a State object for the parser:
struct State {
Ast::Id next_id;
Ast::Primitives primitives;
Ast::Objects objects;
template <typename... T> void commit(boost::variant<T...>& val) {
boost::apply_visitor([this](auto& obj) { commit(obj); }, val);
}
template <typename T> void commit(T& primitiveOrExpr) {
auto id = std::exchange(next_id, 0);
if constexpr (std::is_base_of_v<Ast::Primitive, T>) {
primitiveOrExpr.id = id;
primitives.insert(std::move(primitiveOrExpr));
} else {
objects.push_back(Ast::Object{id, std::move(primitiveOrExpr)});
}
}
};
As you can see, we just have a place to store the primitives, objects. And then there is the temporary storage for our next_id while we're still parsing the next entity.
The commit function helps sorting the products of the parser rules. As it happens, they can be variant, which is why we have the apply_visitor dispatch for commit on a variant.
Again, as the footnote¹ explains, Spirit's natural attribute synthesis favors static polymorphism.
The semantic actions we need are now:
static inline auto& state(auto& ctx) { return get<State>(ctx); }
auto draft = [](auto& ctx) { state(ctx).next_id = _attr(ctx); };
auto commit = [](auto& ctx) { state(ctx).commit(_attr(ctx)); };
Now let's jump ahead to the primitives:
auto sphere = as<Ast::Sphere>(eps >> "sphere" >>'(' >> param("radius") >> ')');
auto box = as<Ast::Box>(eps >> "box" >> '(' >> param('a') >> ',' >> param('b') >> ')');
auto primitive =
("primitive" >> uint_[draft] >> '=' >> (sphere | box)[commit]) > ';';
That's still cheating a little, as I've used the param helper to reduce typing:
auto number = as<Ast::Number>(double_, "number");
auto param(auto name, auto p) { return eps >> omit[name] >> '=' >> p; }
auto param(auto name) { return param(name, number); }
As you can see I've already assumed most parameters will have numerical nature.
What Are Objects Really?
Looking at it for a while, I concluded that really an Object is defined as an id number (OBJECT1, OBJECT2...) which is tied to an expression. The expression can reference primitives and have some unary and binary operators.
Let's sketch an AST for that:
using Number = double;
struct RefPrimitive { Id id; };
struct Binary;
struct Unary;
using Expr = boost::variant< //
Number, //
RefPrimitive, //
boost::recursive_wrapper<Unary>, //
boost::recursive_wrapper<Binary> //
>;
struct Unary { char op; Expr oper; };
struct Binary { Expr lhs; char op; Expr rhs; };
struct Object { Id id; Expr expr; };
Now To Parse Into That Expression AST
It's really 1:1 rules for each Ast node type. E.g.:
auto ref_prim = as<Ast::RefPrimitive>(lexeme["primitive" >> uint_]);
Now many of the expression rules can recurse, so we need declared rules with definitions via BOOST_SPIRIT_DEFINE:
// object expression grammar
rule<struct simple_tag, Ast::Expr> simple{"simple"};
rule<struct unary_tag, Ast::Unary> unary{"unary"};
rule<struct expr_tag, Ast::Expr> expr{"expr"};
rule<struct term_tag, Ast::Expr> term{"term"};
rule<struct factor_tag, Ast::Expr> factor{"factor"};
As you can tell, some of these are not 1:1 with the Ast nodes, mainly because of the recursion and the difference in operator precedence (term vs factor vs. simple). It's easier to see with the rule definition:
auto unary_def = char_("-+") >> simple;
auto simple_def = ref_prim | unary | '(' >> expr >> ")";
auto factor_def = simple;
auto term_def = factor[assign] >> *(char_("*/") >> term)[make_binary];
auto expr_def = term[assign] >> *(char_("-+") >> expr)[make_binary];
Because none of the rules actually expose a Binary, automatic attribute propagation is not convenient there². Instead, we use assign and make_binary semantic actions:
auto assign = [](auto& ctx) { _val(ctx) = _attr(ctx); };
auto make_binary = [](auto& ctx) {
using boost::fusion::at_c;
auto& attr = _attr(ctx);
auto op = at_c<0>(attr);
auto& rhs = at_c<1>(attr);
_val(ctx) = Ast::Binary { _val(ctx), op, rhs };
};
Finally, let's tie the defintions to the declared rules (using their tag types):
BOOST_SPIRIT_DEFINE(simple, unary, expr, term, factor)
All we need is a similar line to primitive:
auto object =
("object" >> uint_[draft] >> '=' >> (expr)[commit]) > ';';
And we can finish up by defining each line as a primitive|object:
auto line = primitive | object;
auto file = no_case[skip(ws_comment)[*eol >> "[geometry]" >> (-line % eol) >> eoi]];
At the top level we expect the [GEOMETRY] header, specify that we want to be case insensitive and ... that ws_comment is to be skipped³:
auto ws_comment = +(blank | lexeme["//" >> *(char_ - eol) >> eol]);
This allows us to ignore the // comments as well.
Live Demo Time
Live On Compiler Explorer
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/poly_collection/base_collection.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <list>
#include <map>
namespace x3 = boost::spirit::x3;
namespace Ast {
using Id = uint32_t;
struct Point { }; // ?? where does this belong?
struct Primitive {
Id id;
virtual ~Primitive() = default;
};
struct Sphere : Primitive { double radius; };
struct Box : Primitive { double a, b; };
using Number = double;
struct RefPrimitive { Id id; };
struct Binary;
struct Unary;
using Expr = boost::variant< //
Number, //
RefPrimitive, //
boost::recursive_wrapper<Unary>, //
boost::recursive_wrapper<Binary> //
>;
struct Unary { char op; Expr oper; };
struct Binary { Expr lhs; char op; Expr rhs; };
struct Object { Id id; Expr expr; };
using Primitives = boost::poly_collection::base_collection<Primitive>;
using Objects = std::list<Object>;
using Index = std::map<Id, std::reference_wrapper<Primitive const>>;
std::ostream& operator<<(std::ostream& os, Primitive const& p) {
return os << boost::core::demangle(typeid(p).name()) << " "
<< "(id: " << p.id << ")";
}
std::ostream& operator<<(std::ostream& os, Object const& o) {
return os << "object(id:" << o.id << ", expr:" << o.expr << ")";
}
std::ostream& operator<<(std::ostream& os, RefPrimitive ref) {
return os << "reference(prim:" << ref.id << ")";
}
std::ostream& operator<<(std::ostream& os, Binary const& b) {
return os << '(' << b.lhs << b.op << b.rhs << ')';
}
std::ostream& operator<<(std::ostream& os, Unary const& u) {
return os << '(' << u.op << u.oper << ')';
}
} // namespace Ast
BOOST_FUSION_ADAPT_STRUCT(Ast::Primitive, id)
BOOST_FUSION_ADAPT_STRUCT(Ast::Sphere, radius)
BOOST_FUSION_ADAPT_STRUCT(Ast::Box, a, b)
BOOST_FUSION_ADAPT_STRUCT(Ast::Object, id)
BOOST_FUSION_ADAPT_STRUCT(Ast::RefPrimitive, id)
BOOST_FUSION_ADAPT_STRUCT(Ast::Unary, op, oper)
namespace Parser {
using namespace x3;
struct State {
Ast::Id next_id;
Ast::Primitives primitives;
Ast::Objects objects;
template <typename... T> void commit(boost::variant<T...>& val) {
boost::apply_visitor([this](auto& obj) { commit(obj); }, val);
}
template <typename T> void commit(T& val) {
auto id = std::exchange(next_id, 0);
if constexpr (std::is_base_of_v<Ast::Primitive, T>) {
val.id = id;
primitives.insert(std::move(val));
} else {
objects.push_back(Ast::Object{id, std::move(val)});
}
}
};
static inline auto& state(auto& ctx) { return get<State>(ctx); }
auto draft = [](auto& ctx) { state(ctx).next_id = _attr(ctx); };
auto commit = [](auto& ctx) { state(ctx).commit(_attr(ctx)); };
template <typename T>
auto as = [](auto p, char const* name = "as") {
return rule<struct _, T>{name} = p;
};
auto ws_comment = +(blank | lexeme["//" >> *(char_ - eol) >> (eol | eoi)]);
auto number = as<Ast::Number>(double_, "number");
auto param(auto name, auto p) { return eps >> omit[name] >> '=' >> p; }
auto param(auto name) { return param(name, number); }
auto sphere = as<Ast::Sphere>(eps >> "sphere" >>'(' >> param("radius") >> ')');
auto box = as<Ast::Box>(eps >> "box" >> '(' >> param('a') >> ',' >> param('b') >> ')');
auto primitive =
("primitive" >> uint_[draft] >> '=' >> (sphere | box)[commit]) > ';';
auto ref_prim = as<Ast::RefPrimitive>(lexeme["primitive" >> uint_], "ref_prim");
// object expression grammar
rule<struct simple_tag, Ast::Expr> simple{"simple"};
rule<struct unary_tag, Ast::Unary> unary{"unary"};
rule<struct expr_tag, Ast::Expr> expr{"expr"};
rule<struct term_tag, Ast::Expr> term{"term"};
rule<struct factor_tag, Ast::Expr> factor{"factor"};
auto assign = [](auto& ctx) { _val(ctx) = _attr(ctx); };
auto make_binary = [](auto& ctx) {
using boost::fusion::at_c;
auto& attr = _attr(ctx);
auto op = at_c<0>(attr);
auto& rhs = at_c<1>(attr);
_val(ctx) = Ast::Binary { _val(ctx), op, rhs };
};
auto unary_def = char_("-+") >> simple;
auto simple_def = ref_prim | unary | '(' >> expr >> ")";
auto factor_def = simple;
auto term_def = factor[assign] >> *(char_("*/") >> term)[make_binary];
auto expr_def = term[assign] >> *(char_("-+") >> expr)[make_binary];
BOOST_SPIRIT_DEFINE(simple, unary, expr, term, factor)
auto object =
("object" >> uint_[draft] >> '=' >> (expr)[commit]) > ';';
auto line = primitive | object;
auto file = no_case[skip(ws_comment)[*eol >> "[geometry]" >> (-line % eol) >> eoi]];
} // namespace Parser
int main() {
for (std::string const input :
{
R"(
[geometry]
primitive1=sphere(radius=5.5);
primitive2=box(a=-5.2, b=7.3);
//...
object1=primitive2*(-primitive1);
//...)",
R"(
[GEOMETRY]
PRIMITIVE1=SPHERE(RADIUS=5.5);
PRIMITIVE2=BOX(A=-5.2, B=7.3);
//...
OBJECT1=PRIMITIVE2*(-PRIMITIVE1);
//...)",
}) //
{
Parser::State state;
bool ok = parse(begin(input), end(input),
x3::with<Parser::State>(state)[Parser::file]);
std::cout << "Parse success? " << std::boolalpha << ok << "\n";
Ast::Index index;
for (auto& p : state.primitives)
if (auto[it,ok] = index.emplace(p.id, p); not ok) {
std::cout << "Duplicate id " << p
<< " (conflicts with existing " << it->second.get()
<< ")\n";
}
std::cout << "Primitives by ID:\n";
for (auto& [id, prim] : index)
std::cout << " - " << prim << "\n";
std::cout << "Objects in definition order:\n";
for (auto& obj: state.objects)
std::cout << " - " << obj << "\n";
}
}
Prints
Parse success? true
Primitives by ID:
- Ast::Sphere (id: 1)
- Ast::Box (id: 2)
Objects in definition order:
- object(id:1, expr:(reference(prim:2)*(-reference(prim:1))))
Parse success? true
Primitives by ID:
- Ast::Sphere (id: 1)
- Ast::Box (id: 2)
Objects in definition order:
- object(id:1, expr:(reference(prim:2)*(-reference(prim:1))))
¹ How can I use polymorphic attributes with boost::spirit::qi parsers?
² and insisting on that leads to classical in-efficiency with rules that cause a lot of backtracking
³ outside of lexemes

how to use istream_iterators to split an equation?

I'm trying to split a string like ( 1 + 2 ) into a vector and when using an istream_iterators<string> it doesn't split the parentheses so I get vector outputs like
(1 , + , 2) when I want ( , 1, + , 2 ,)
Is it possible to use istream_iterators to achieve this?
string eq = "(1 + 2)";
istringstream ss(eq);
istream_iterator<string> begin(ss);
istream_iterator<string> end;
vector<string> vec(begin, end);
You can do this by creating a custom type Token and using it with
istream_iterator. Bonus feature: this code will parse multiple digits, multiple operators, and nested expressions. So enjoy. :)
#include <iterator>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include <cctype>
using namespace std;
class Token {
private:
string val;
public:
Token() : val("") {}
Token(string& v) : val(v) {}
friend istream& operator>>(istream &in, Token& tok);
friend ostream& operator<<(ostream &out, Token& tok);
};
istream& operator>>(istream &in, Token& tok) {
char c;
string v;
if (in >> c) {
if (isdigit(c)) {
v.push_back(c);
while (in >> c && isdigit(c)) {
v.push_back(c);
}
in.putback(c);
} else if (c == ' ') {
while (in >> c && c == ' ') ;
in.putback(c);
} else {
v.push_back(c);
}
}
tok = v;
return in;
}
ostream& operator<<(ostream &out, Token& tok) {
out << tok.val;
return out;
}
int main() {
string eq = "(1 + 2)";
//eq = "(100 + 200)"; // multiple digits
//eq = "(100 + 200 * 300)"; // extra operator
//eq = "(100 + (200 * 300))"; // nested parens
istringstream ss(eq);
istream_iterator<Token> begin(ss);
istream_iterator<Token> end;
vector<Token> vec(begin, end);
for (auto& x : vec) {
cout << "[" << x << "] ";
}
cout << endl;
}
I don't think you can do it using istream_iterator. Instead, simply do it by hand:
vector<string> vec;
vec.reserve(eq.size() / 4); // rough guess
bool in_number = false;
for (char ch : eq) {
if (isspace(ch)) {
in_number = false;
} else if (isdigit(ch)) {
if (in_number) {
vec.back().push_back(ch);
} else {
vec.emplace_back(1, ch);
in_number = true;
}
} else {
vec.emplace_back(1, ch);
in_number = false;
}
}

Is there a way to stop std::cin when it encounters a `\n`

I've written code that works pretty well except for one thing. The task that I'm making this code for inputs data into the program as a whitespace seperated string of doubles. And their precicion may be larger than 10^-25. So I made my own class that can handle that.
The problem is, when I was writing the code, I was testing it by entering two values into the console by hand each time pressing enter so that my program can understand where one double ends and another starts (it was looking for a '\n' basically).
Now I really need to adapt this code to make i work with my task's input (whitespace seperated list of doubles like 2.521 32.12334656 23.21 .....). But I'm having a problem with getline in my overloaded >> operator. It simply eats the '\n' character and starts looking for more input. The only way I can get it to work is by manually enetering values and manually entering an additional whitespace after the last value and only then hit enter.
I'm asking for your help.
Here's the full code:
#include <iostream>
#include <string>
#include <algorithm>
class BigNumber {
private:
std::string fullPart;
std::string floatPart;
public:
BigNumber() : fullPart("0"), floatPart("0") {}
friend std::ostream & operator << (std::ostream & os, const BigNumber & bn);
friend std::istream & operator >> (std::istream & os, BigNumber & bn);
void operator+=(BigNumber & bn);
};
int main()
{
BigNumber bn, bntemp;
while (std::cin >> bntemp)
{
bn += bntemp;
if (std::cin.peek() == '\n')
break;
}
std::cout << bn << std::endl;
return 0;
}
void addFullPart(const std::string & add, std::string & add_to)
{
auto addConv = std::stold(add);
auto addToConv = std::stold(add_to);
auto newFull = std::to_string(addConv + addToConv);
add_to = std::string(newFull.begin(), std::find(newFull.begin(), newFull.end(), '.'));
}
bool carryReminder(std::string & add_to, int32_t indx_from)
{
for (auto curr = indx_from; curr >= 0; --curr)
{
if (add_to[curr] != '9')
{
++(add_to[curr]);
return true;
}
else
add_to[curr] = '0';
}
return false;
}
std::pair<std::string, int32_t> addFloatPart(std::string & add, std::string & add_to)
{
std::string resultFloat;
int32_t reminderReturn{};
// don't forget to reverse str
if (add.size() != add_to.size())
{
// add remaining 0's
if (add.size() < add_to.size())
{
while (add.size() != add_to.size())
{
auto tempBigger = add_to.back();
add_to.pop_back();
resultFloat.push_back(tempBigger);
}
}
else
{
while (add.size() != add_to.size())
{
auto tempBigger = add.back();
add.pop_back();
resultFloat.push_back(tempBigger);
}
}
}
// now they are equal and have a form of 120(3921) 595
for (int32_t i = add_to.size() - 1; i >= 0; --i)
{
int32_t add_toDigit = add_to[i] - '0';
int32_t addDigit = add[i] - '0';
if (add_toDigit + addDigit >= 10)
{
resultFloat.append(std::to_string((add_toDigit + addDigit) - 10));
// we have a remainder
if (i == 0 || !carryReminder(add_to, i - 1))
reminderReturn = 1;
}
else
{
resultFloat.append(std::to_string(add_toDigit + addDigit));
}
}
std::reverse(resultFloat.begin(), resultFloat.end());
return std::make_pair(resultFloat, reminderReturn);
}
std::ostream & operator<<(std::ostream & os, const BigNumber & bn)
{
os << bn.fullPart << "." << bn.floatPart;
return os;
}
std::istream & operator>>(std::istream & is, BigNumber & bn)
{
std::string temp;
std::getline(is, temp, ' ');
auto fullPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.'));
auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end());
bn.floatPart = floatPartTemp;
bn.fullPart = fullPartTemp;
return is;
}
void BigNumber::operator+=(BigNumber & bn)
{
auto pair = addFloatPart(bn.floatPart, floatPart);
floatPart = pair.first;
if (pair.second > 0)
addFullPart(std::to_string(std::stoi(bn.fullPart) + 1), fullPart);
else
addFullPart(bn.fullPart, fullPart);
}
I suggest that you first use getline to read a line. Then you can make an istringstream and use your >> on that. Specifically, you could add #include <sstream> and change the main function to the following:
int main()
{
BigNumber bn, bntemp;
std::string temp;
std::getline(std::cin, temp);
std::istringstream ln(temp);
while (ln.good()) {
ln >> bntemp;
bn += bntemp;
}
std::cout << bn << std::endl;
return 0;
}
Two changes are needed. In main
Discarded the peek approach. Too brittle.
int main()
{
BigNumber bn, bntemp;
std::string line;
std::getline(std::cin, line);
std::stringstream stream(line);
while (stream >> bntemp)
{
bn += bntemp;
}
std::cout << bn << std::endl;
return 0;
}
And in operator>>
std::istream & operator >> (std::istream & is, BigNumber & bn)
{
std::string temp;
// also do NOTHING if the read fails!
if (std::getline(is, temp, ' '))
{
// recommend some isdigit testing in here to make sure you're not
// being fed garbage. Set fail flag in stream and bail out.
auto floatPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.'));
// if there is no . you are in for a world of hurt here
auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end());
bn.floatPart = ;
bn.fullPart = fullPartTemp;
}
return is;
}
So it should probably look more like
std::istream & operator >> (std::istream & is, BigNumber & bn)
{
std::string temp;
if (std::getline(is, temp, ' '))
{
if (std::all_of(temp.cbegin(), temp.cend(), [](char ch) { return isdigit(ch) || ch == '.'; }))
{
auto dotpos = std::find(temp.begin(), temp.end(), '.');
bn.fullPart = std::string(temp.begin(), dotpos);
std::string floatPartTemp;
if (dotpos != temp.end())
{
floatPartTemp = std::string(dotpos + 1, temp.end());
}
bn.floatPart = floatPartTemp;
}
else
{
is.setstate(std::ios::failbit);
}
}
return is;
}
Perhaps you could then use
std::string temp;
is >> temp;
instead of std::getline().
If I remember well that breaks on spaces and keeps the newline in the buffer.

Iterating over mmaped gzip file with boost

I am trying to learn boost and some template programming in C++ but I am really having such an hard time to implement a simple class for iterating over Gzip files using mapped_file_source. I essentially have an edge list in TSV format such that each line in the gzip file is of the format: <src:int><tab><dst:int>. What I want is to implement a gz_file class that exposes a begin and end iterator over which I can get an edge (std::pair<int,int>) each time I query the iterator.
The problem is the copy constructor which is broken since I cannot known where I am positioned in the gzip file.
Here is the code I have so far:
class gz_graph {
public:
gz_graph(const char * filename)
{
m_file.open(filename);
if (!m_file.is_open()) {
throw std::runtime_error("Error opening file");
}
m_data = m_file.data();
m_data_size = m_file.size() / sizeof(m_data[0]);
auto ret = posix_madvise((void*)m_data, m_data_size, POSIX_MADV_SEQUENTIAL);
}
class iterator;
iterator begin() const
{
return iterator(this, false);
}
iterator end() const
{
return iterator(this, true);
}
class iterator : public std::iterator<std::forward_iterator_tag, Edge> {
public:
iterator(gz_graph const * ref, bool consumed)
: m_ref(ref),
m_cur_edge(-1, -1),
m_consumed(consumed)
{
if (!consumed) {
initialize();
advance();
}
}
iterator(const iterator& x)
: m_ref(x.m_ref),
m_cur_edge(x.m_cur_edge)
{
if (!x.m_consumed) {
initialize();
advance();
}
std::cout << "Copy constructor" << std::endl;
}
value_type const& operator*() const
{
return m_cur_edge;
}
value_type const* operator->() const
{
return &m_cur_edge;
}
iterator& operator++()
{
advance();
return *this;
}
bool operator==(iterator const& other) const
{
assert(m_ref == other.m_ref);
return m_cur_edge == other.m_cur_edge;
}
bool operator!=(iterator const& other) const
{
return !(*this == other);
}
private:
void initialize()
{
boost::iostreams::array_source source(m_ref->m_data, m_ref->m_data_size);
m_in.push(boost::iostreams::gzip_decompressor());
m_in.push(source);
}
void advance()
{
std::string line_str;
if (!getline(m_in, line_str)) {
m_consumed = true;
m_cur_edge = Edge(-1, -1);
return;
}
std::vector<std::string> strs;
boost::split(strs, line_str, boost::is_any_of("\t"));
if (strs.size() != 2)
throw std::runtime_error("Required 2 fields per line");
int src = boost::lexical_cast<int>(strs.at(0));
int dst = boost::lexical_cast<int>(strs.at(1));
m_cur_edge = Edge(src, dst);
// std::cout << "Read line " << line_str << std::endl;
}
gz_graph const * m_ref;
Edge m_cur_edge;
boost::iostreams::filtering_istream m_in;
bool m_consumed;
};
private:
boost::iostreams::mapped_file_source m_file;
char const* m_data;
size_t m_data_size;
};
I would just use a std::istream_iterator here. I'm not sure how exactly to interpret your "input pseudo-code", so let me humor you and do the "complicated" parsing:
struct Edge : std::pair<int, int> { };
std::istream& operator>>(std::istream& is, Edge& edge)
{
using namespace boost::spirit::qi;
return is >> match("src:" > int_ > '\t' > "dst:" > int_ >> eol, edge.first, edge.second);
}
I expect you would be happy to have it much simpler, but simpler is easier, right?
Now the main program looks like
for (
std::istream_iterator<Edge> it(fs >> std::noskipws), end;
it != end;
++it)
{
std::cout << it->first << " to " << it->second << "\n";
}
Where fs is the filtering_istream that has the gzip_decompressor. See it Live On Coliru
Full Code
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_match.hpp>
#include <iterator>
struct Edge : std::pair<int, int> {
};
std::istream& operator>>(std::istream& is, Edge& edge)
{
using namespace boost::spirit::qi;
return is >> match("src:" > int_ > '\t' > "dst:" > int_ >> eol, edge.first, edge.second);
}
namespace io = boost::iostreams;
int main()
{
io::mapped_file_source csv("csv.txt.gz");
io::stream<io::mapped_file_source> textstream(csv);
io::filtering_istream fs;
fs.push(io::gzip_decompressor{});
fs.push(textstream);
for (
std::istream_iterator<Edge> it(fs >> std::noskipws), last;
it != last;
++it)
{
std::cout << it->first << " to " << it->second << "\n";
}
}

Convert string to int with bool/fail in C++

I have a std::string which could be a string or could be a value (such as 0).
What is the best or easiest way to convert the std::string to int with the ability to fail? I want a C++ version of C#'s Int32.TryParse.
Use boost::lexical_cast. If the cast cannot be done, it will throw an exception.
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
int main(void)
{
std::string s;
std::cin >> s;
try
{
int i = boost::lexical_cast<int>(s);
/* ... */
}
catch(...)
{
/* ... */
}
}
Without boost:
#include <iostream>
#include <sstream>
#include <string>
int main(void)
{
std::string s;
std::cin >> s;
try
{
std::stringstream ss(s);
int i;
if ((ss >> i).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
/* ... */
}
catch(...)
{
/* ... */
}
}
Faking boost:
#include <iostream>
#include <sstream>
#include <string>
template <typename T>
T lexical_cast(const std::string& s)
{
std::stringstream ss(s);
T result;
if ((ss >> result).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
return result;
}
int main(void)
{
std::string s;
std::cin >> s;
try
{
int i = lexical_cast<int>(s);
/* ... */
}
catch(...)
{
/* ... */
}
}
If you want no-throw versions of these functions, you'll have to catch the appropriate exceptions (I don't think boost::lexical_cast provides a no-throw version), something like this:
#include <iostream>
#include <sstream>
#include <string>
template <typename T>
T lexical_cast(const std::string& s)
{
std::stringstream ss(s);
T result;
if ((ss >> result).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
return result;
}
template <typename T>
bool lexical_cast(const std::string& s, T& t)
{
try
{
// code-reuse! you could wrap
// boost::lexical_cast up like
// this as well
t = lexical_cast<T>(s);
return true;
}
catch (const std::bad_cast& e)
{
return false;
}
}
int main(void)
{
std::string s;
std::cin >> s;
int i;
if (!lexical_cast(s, i))
{
std::cout << "Bad cast." << std::endl;
}
}
The other answers that use streams will succeed even if the string contains invalid characters after a valid number e.g. "123abc". I'm not familiar with boost, so can't comment on its behavior.
If you want to know if the string contains a number and only a number, you have to use strtol:
#include <iostream>
#include <string>
int main(void)
{
std::string s;
std::cin >> s;
char *end;
long i = strtol( s.c_str(), &end, 10 );
if ( *end == '\0' )
{
// Success
}
else
{
// Failure
}
}
strtol returns a pointer to the character that ended the parse, so you can easily check if the entire string was parsed.
Note that strtol returns a long not an int, but depending on your compiler these are probably the same. There is no strtoi function in the standard library, only atoi, which doesn't return the parse ending character.
Exceptions should not be used for boolean tests
The accepted answer is really a terrible answer for question as asked, as it violates the precept "use exceptions for exceptional cases".
Exceptions are an excellent tool for handling exceptional cases -- cases where something has genuinely gone wrong. They are poor tools for existing use-cases. Partly because throwing and catching an exception is expensive, and partly because it is misleading code -- when a developer sees an exception they should reasonably be able to assume something is going wrong there. Good discussions of this basic principle abound, but I like "The Pragmatic Programmer"'s, or this isn't bad: http://www.lohmy.de/2013/03/06/writing-use-cases-exception-or-alternate-flow/
Use boost::lexical_cast if you always expect a number
boost::lexical_cast is an optimal solution when it really is an exception for it to be receiving a non-number.
Use boost::try_lexical_convert if non-numbers are part of your use case
If you are going through a string and want to do one thing if it's a number, and another if it's a number, don't use an exception for the boolean test. That's just bad programming.
In fact, boost offers try_lexical_convert, which is used in the implementation of lexical_cast (taken from the documentation here:
http://www.boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/synopsis.html#boost_lexical_cast.synopsis.lexical_cast).
template <typename Target, typename Source>
inline Target lexical_cast(const Source &arg)
{
Target result;
if (!conversion::try_lexical_convert(arg, result))
throw bad_lexical_cast();
return result;
}
Another way using standard streams :
#include <sstream>
#include <iostream>
#include <string>
int main()
{
std::stringstream convertor;
std::string numberString = "Not a number!";
int number;
convertor << numberString;
convertor >> number;
if(convertor.fail())
{
// numberString is not a number!
std::cout << "Not a Number!";
}
}
Before boost's lexical_cast was available, I used to do the following:
namespace detail {
template< typename Target, typename Source >
struct stream_caster {
static Target stream_cast(const Source& s)
{
std::stringstream ss;
if( (ss << s).fail() ) {
throw std::bad_cast("could not stream from source");
}
Target t;
if( (ss >> t).fail() || !(ss >> ws).eof()) {
throw std::bad_cast("could not stream to target");
}
return t;
}
};
template< typename T >
struct stream_caster<T,T> {
static const T& stream_cast(const T& s)
{
return s;
}
};
template< typename Source >
struct stream_caster<std::string,Source> {
static std::string stream_cast(const Source& s)
{
std::ostringstream oss;
if( (oss << s).fail() ) {
throw std::bad_cast("could not stream from source");
}
return oss.str();
}
};
template< typename Target >
struct stream_caster<Target,std::string> {
static Target stream_cast(const std::string& s)
{
std::stringstream ss(s);
Target t;
if( (ss >> t).fail() || !(ss >> ws).eof()) {
throw std::bad_cast("could not stream to target");
}
return t;
}
};
template<>
struct stream_caster<std::string,std::string> {
static const std::string& stream_cast(const std::string& s)
{
return s;
}
};
}
template< typename Target, typename Source >
inline Target stream_cast(const Source& s)
{
return detail::stream_caster<Target,Source>::stream_cast(s);
}