I created a grammar using boost spirit x3. While testing my resulting parser, i recognized that there is a case where the parser throws the following exeption:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
I didnt know this could happen using boost spirit x3, I thought the parse method eighter returns false or throws a boost::spirit::x3::expectation_failure, what am I doing wrong in my grammar, because this should not happen here.
I uploaded my mcve HERE, if you execute the binary the std::logic error will bw thrown.
example.cpp
#include "example_def.hpp"
#include "config.hpp"
namespace client { namespace parser {
BOOST_SPIRIT_INSTANTIATE(var_dec_type, iterator_type, context_type)
}}
main.cpp
#include <iostream>
//#define SINGLE_TU
#if defined(SINGLE_TU)
#pragma message "yesdef(SINGLE_TU)"
#else
#pragma message "notdef(SINGLE_TU)"
#endif
#ifdef SINGLE_TU
#include "types_def.hpp"
#include "example_def.hpp"
#else
#include "example.hpp"
#endif
template<typename Parser, typename Attribute>
bool test(const std::string& str, Parser&& p, Attribute&& attr)
{
using iterator_type = std::string::const_iterator;
iterator_type in = str.begin();
iterator_type end = str.end();
bool ret = boost::spirit::x3::phrase_parse(in, end, p, boost::spirit::x3::ascii::space, attr);
ret &= (in == end);
return ret;
}
int main()
{
client::ast::VariableDec attr;
std::cout << test("var foo : foo<bar, baz<bahama>>", client::var_dec() , attr);
return 0;
}
types.cpp
#include "config.hpp"
#include "types_def.hpp"
#include <iostream>
namespace client {namespace parser {
BOOST_SPIRIT_INSTANTIATE(type_type, iterator_type, context_type);
BOOST_SPIRIT_INSTANTIATE(class_type_type, iterator_type, context_type);
#define PARSE_RULE_BODY
#if defined(PARSE_RULE_BODY)
#pragma message "yesdef(PARSE_RULE_BODY)"
//This causes the parse_rule generated by
//BOOST_SPIRIT_DEFINE for type
//to *not* be used.
#include <boost/fusion/iterator/deref.hpp>
#else
#pragma message "notdef(PARSE_RULE_BODY)"
//This causes the parse_rule generated by
//BOOST_SPIRIT_DEFINE for type
//to be used.
#endif
#define SEHE_TYPES_DEF_HPP_PASTE
#define EXPLICT_SPECIALIZATION_FROM_LINKER_ERROR_MSG
#if defined(SEHE_TYPES_DEF_HPP_PASTE)
#pragma message "yesdef(SEHE_TYPES_DEF_HPP_PASTE)"
//Source:
// The following code was copy&pasted&reformatted from lines 38-53 of:
// https://github.com/sehe/linker_error_example/blob/explicit_instantiation/types_def.hpp
// on about 2016-11-15.
// with minor modifications:
// * reformatting
// * Added body with:
// * printing first..last.
//=======================
namespace {
template <typename Seq, size_t N>
using field_at =
boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, Seq
, N
>;
template <typename Seq, size_t N, size_t M>
using fields =
boost::fusion::iterator_range<field_at<Seq, N>, field_at<Seq, M> >;
using Attributes =
fields<client::ast::VariableDec, 1, 2>;
using Context =
x3::context
< x3::skipper_tag
, x3::char_class<boost::spirit::char_encoding::ascii, x3::space_tag> const
, x3::unused_type
>;
}
template
#ifdef PARSE_RULE_BODY
<>
#endif
bool parse_rule
< std::string::const_iterator
, Context
, Attributes
>(
decltype(type) rule,
std::string::const_iterator &first,
std::string::const_iterator const &last,
Context const &context,
Attributes &attr)
#ifndef PARSE_RULE_BODY
;
#else
{
std::cout<<"***in function="<<__func__<<"\n";
std::string::const_iterator beg=first;
std::cout<<":input=\n{";
for(; beg!=last; ++beg) std::cout<<*beg;
std::cout<<"}\n";
using required_t=type_type::attribute_type;
required_t required_v=boost::fusion::deref(attr.first);
//attr type required by parse_rule generated by:
// BOOST_SPIRIT_INSTANTIATE(type_type, iterator_type, context_type)
;
bool result=parse_rule(rule,first,last,context,required_v)
//This should call the parse_rule generated by:
// BOOST_SPIRIT_INSTANTIATE(type_type, iterator_type, context_type)
;
std::cout<<":result="<<result<<"\n";
return result;
}
#endif
#elif defined(EXPLICT_SPECIALIZATION_FROM_LINKER_ERROR_MSG)
#pragma message "yesdef(EXPLICT_SPECIALIZATION_FROM_LINKER_ERROR_MSG)"
template
#ifdef PARSE_RULE_BODY
<>
#endif
//The following simply copied&pasted from an earlier linker error
//message, and then reformatted to clarify what
//was being specialized.
bool
parse_rule
< __gnu_cxx::__normal_iterator
< char const*
, std::__cxx11::basic_string
< char
, std::char_traits<char>
, std::allocator<char>
>
>
, boost::spirit::x3::context
< boost::spirit::x3::skipper_tag
, boost::spirit::x3::char_class
< boost::spirit::char_encoding::ascii
, boost::spirit::x3::space_tag
> const
, boost::spirit::x3::unused_type
>
, boost::fusion::iterator_range
< boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, client::ast::VariableDec
, 1
>
, boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, client::ast::VariableDec
, 2
>
>
>
( boost::spirit::x3::rule//==decltype(type) where types from types_def.hpp:16
< client::parser::type_class//types.hpp:15
, boost::spirit::x3::variant
< client::ast::nil
, boost::spirit::x3::forward_ast
< client::ast::LambdaType
>
, boost::spirit::x3::forward_ast
< client::ast::ClassType
>
>
, false
>
, __gnu_cxx::__normal_iterator//==std::string::const_iterator
< char const*
, std::__cxx11::basic_string
< char
, std::char_traits<char>
, std::allocator<char>
>
>& first
, __gnu_cxx::__normal_iterator//==std::string::const_iterator
< char const*
, std::__cxx11::basic_string
< char
, std::char_traits<char>
, std::allocator<char>
>
> const& last
, boost::spirit::x3::context//=?Context from #if defined(SEHE_TYPES_DEF_HPP_PASTE)
< boost::spirit::x3::skipper_tag
, boost::spirit::x3::char_class
< boost::spirit::char_encoding::ascii
, boost::spirit::x3::space_tag
> const
, boost::spirit::x3::unused_type
> const& context
, boost::fusion::iterator_range//=?Attributes from #if defined(SEHE_TYPES_DEF_HPP_PASTE)
< boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, client::ast::VariableDec
, 1
>
, boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, client::ast::VariableDec
, 2
>
>& attr
)
#ifndef PARSE_RULE_BODY
;
#else
{
std::cout<<"***in function="<<__func__<<"\n";
std::string::const_iterator beg=first;
std::cout<<":input=\n{";
for(; beg!=last; ++beg) std::cout<<*beg;
std::cout<<"}\n";
return false;
}
#endif//PARSE_RULE_BODY
#endif//(SEHE_TYPES_DEF_HPP_PASTE)
}}
ast.hpp
//
// Created by lukas on 11.11.16.
//
#ifndef LINKER_ERROR_EXAMPLE_AST_HPP_HPP
#define LINKER_ERROR_EXAMPLE_AST_HPP_HPP
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <vector>
#include <string>
namespace client { namespace ast {
namespace x3 = boost::spirit::x3;
struct LambdaType;
struct ClassType;
struct nil{};
typedef x3::variant <
nil,
x3::forward_ast<LambdaType>,
x3::forward_ast<ClassType>
> Type;
struct LambdaType {
std::vector<Type> parameters_;
Type return_type_;
};
struct ClassType {
std::vector<std::string> name_;
std::vector<Type> template_args_;
};
struct VariableDec {
std::string _name;
Type _type;
};
}}
BOOST_FUSION_ADAPT_STRUCT(client::ast::LambdaType, parameters_, return_type_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::ClassType, name_, template_args_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::VariableDec, _name, _type)
#endif //LINKER_ERROR_EXAMPLE_AST_HPP_HPP
config.hpp
#ifndef LINKER_ERROR_EXAMPLE_CONFIG_HPP
#define LINKER_ERROR_EXAMPLE_CONFIG_HPP
#include <boost/spirit/home/x3.hpp>
namespace client{
namespace parser{
namespace x3 = boost::spirit::x3;
typedef std::string::const_iterator iterator_type;
typedef x3::phrase_parse_context<x3::ascii::space_type>::type context_type;
}
}
#endif //LINKER_ERROR_EXAMPLE_CONFIG_HPP
example_def.hpp
#ifndef LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
#define LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
#include "ast.hpp"
#include "example.hpp"
#include "types.hpp"
namespace client { namespace parser {
#ifndef SINGLE_TU
namespace { const auto& type = client::type(); }
#endif
const var_dec_type var_dec = "var_dec";
#define EXAMPLE_DEF_LINK_ERR
#if defined(EXAMPLE_DEF_LINK_ERR)
#pragma message "yesdef(EXAMPLE_DEF_LINK_ERR)"
#else
#pragma message "notdef(EXAMPLE_DEF_LINK_ERR)"
#endif
auto const var_dec_def = x3::lexeme["var "]
> +x3::alnum
> ":"
#ifdef EXAMPLE_DEF_LINK_ERR
>> type //<- this gets linker error.
#else
> type //<- This links.
#endif
> ";";
BOOST_SPIRIT_DEFINE(
var_dec
)
}}
namespace client {
const parser::var_dec_type& var_dec()
{
return parser::var_dec;
}
}
#endif //LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
example.hpp
#ifndef LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
#define LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
#include <boost/spirit/home/x3.hpp>
#include "ast.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
class var_dec_class {};
typedef x3::rule<var_dec_class, ast::VariableDec> var_dec_type;
BOOST_SPIRIT_DECLARE(var_dec_type)
}}
namespace client {
const parser::var_dec_type& var_dec();
}
#endif //LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
types_def.hpp
#ifndef KYLE_TYPES_DEF_HPP
#define KYLE_TYPES_DEF_HPP
#include "types.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
typedef x3::rule<struct lambda_type_class, ast::LambdaType> lambda_type_type;
const class_type_type class_type = "class_type";
const lambda_type_type lambda_type = "lambda_type";
const type_type type = "type";
auto const identifier = +x3::alnum;
auto const type_def =
(lambda_type | class_type);
auto const lambda_type_def =
("(" > -(type % ",") > ")" > "=>" > type)
| (x3::repeat(1)[class_type] >> "=>" > type);
auto const class_type_def =
(identifier % "::") >> -("<" > type % "," > ">");
BOOST_SPIRIT_DEFINE(
lambda_type,
class_type,
type
)
}}
namespace client {
const parser::class_type_type& class_type()
{
return parser::class_type;
}
const parser::type_type& type()
{
return parser::type;
}
}
#endif //KYLE_TYPES_DEF_HPP
types.hpp
#ifndef KYLE_PARSER_TYPES_HPP
#define KYLE_PARSER_TYPES_HPP
#include <boost/spirit/home/x3.hpp>
#include "ast.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
struct class_type_class;
struct type_class;
typedef x3::rule<class_type_class, ast::ClassType> class_type_type;
typedef x3::rule<type_class, ast::Type> type_type;
BOOST_SPIRIT_DECLARE(class_type_type,
type_type)
}}
namespace client {
const parser::class_type_type& class_type();
const parser::type_type& type();
}
#endif
It throws an expectation_failed exception.
Quite obviously it's because you have a missing ;.
After cleaning out the horrendous kludges that were related to the old linker-error workarounds, I simply changed the example_def expression to:
auto const var_dec_def = x3::lexeme["var "] > +x3::alnum >> (":" > type) > ";";
Now, add proper error handling:
int main()
{
client::ast::VariableDec attr;
std::string const input("var foo : foo<bar, baz<bahama>>;");
try {
std::cout << test(input, client::var_dec() , attr);
} catch(boost::spirit::x3::expectation_failure<std::string::const_iterator> const& e) {
std::cout << "Expected: " << e.which() << " at '" << std::string(e.where(), input.end()) << "'\n";
return 255;
}
}
Prints:
1
Leaving out the trailing ; prints:
Expected: ';' at ''
Full demo: error-handling branch
CMakeLists.txt | 6 +-
example.cpp | 9 +++
example_def.hpp | 33 +--------
main.cpp | 20 ++----
types.cpp | 203 ++++----------------------------------------------------
types_def.hpp | 20 ++----
6 files changed, 38 insertions(+), 253 deletions(-)
example.cpp
#include "example_def.hpp"
#include "config.hpp"
namespace client { namespace parser {
BOOST_SPIRIT_INSTANTIATE(var_dec_type, iterator_type, context_type)
}}
namespace client {
const parser::var_dec_type& var_dec()
{
return parser::var_dec;
}
}
main.cpp
#include <iostream>
#include "example.hpp"
template<typename Parser, typename Attribute>
bool test(const std::string& str, Parser&& p, Attribute&& attr)
{
using iterator_type = std::string::const_iterator;
iterator_type in = str.begin();
iterator_type end = str.end();
bool ret = boost::spirit::x3::phrase_parse(in, end, p, boost::spirit::x3::ascii::space, attr);
ret &= (in == end);
return ret;
}
int main()
{
client::ast::VariableDec attr;
std::string const input("var foo : foo<bar, baz<bahama>>");
try {
std::cout << test(input, client::var_dec() , attr);
} catch(boost::spirit::x3::expectation_failure<std::string::const_iterator> const& e) {
std::cout << "Expected: " << e.which() << " at '" << std::string(e.where(), input.end()) << "'\n";
return 255;
}
}
types.cpp
#include "config.hpp"
#include "types_def.hpp"
namespace client {namespace parser {
BOOST_SPIRIT_INSTANTIATE(type_type, iterator_type, context_type);
BOOST_SPIRIT_INSTANTIATE(class_type_type, iterator_type, context_type);
}}
namespace client {
const parser::class_type_type& class_type()
{
return parser::class_type;
}
const parser::type_type& type()
{
return parser::type;
}
}
ast.hpp
//
// Created by lukas on 11.11.16.
//
#ifndef LINKER_ERROR_EXAMPLE_AST_HPP_HPP
#define LINKER_ERROR_EXAMPLE_AST_HPP_HPP
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <vector>
#include <string>
namespace client { namespace ast {
namespace x3 = boost::spirit::x3;
struct LambdaType;
struct ClassType;
struct nil{};
typedef x3::variant <
nil,
x3::forward_ast<LambdaType>,
x3::forward_ast<ClassType>
> Type;
struct LambdaType {
std::vector<Type> parameters_;
Type return_type_;
};
struct ClassType {
std::vector<std::string> name_;
std::vector<Type> template_args_;
};
struct VariableDec {
std::string _name;
Type _type;
};
}}
BOOST_FUSION_ADAPT_STRUCT(client::ast::LambdaType, parameters_, return_type_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::ClassType, name_, template_args_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::VariableDec, _name, _type)
#endif //LINKER_ERROR_EXAMPLE_AST_HPP_HPP
config.hpp
#ifndef LINKER_ERROR_EXAMPLE_CONFIG_HPP
#define LINKER_ERROR_EXAMPLE_CONFIG_HPP
#include <boost/spirit/home/x3.hpp>
namespace client{
namespace parser{
namespace x3 = boost::spirit::x3;
typedef std::string::const_iterator iterator_type;
typedef x3::phrase_parse_context<x3::ascii::space_type>::type context_type;
}
}
#endif //LINKER_ERROR_EXAMPLE_CONFIG_HPP
example_def.hpp
#ifndef LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
#define LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
#include "ast.hpp"
#include "example.hpp"
#include "types.hpp"
namespace client { namespace parser {
namespace { const auto& type = client::type(); }
const var_dec_type var_dec = "var_dec";
auto const var_dec_def = x3::lexeme["var "] > +x3::alnum >> (":" > type) > ";";
BOOST_SPIRIT_DEFINE(var_dec)
}}
#endif //LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
example.hpp
#ifndef LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
#define LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
#include <boost/spirit/home/x3.hpp>
#include "ast.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
class var_dec_class {};
typedef x3::rule<var_dec_class, ast::VariableDec> var_dec_type;
BOOST_SPIRIT_DECLARE(var_dec_type)
}}
namespace client {
const parser::var_dec_type& var_dec();
}
#endif //LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
types_def.hpp
#ifndef KYLE_TYPES_DEF_HPP
#define KYLE_TYPES_DEF_HPP
#include "types.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
typedef x3::rule<struct lambda_type_class, ast::LambdaType> lambda_type_type;
const class_type_type class_type = "class_type";
const lambda_type_type lambda_type = "lambda_type";
const type_type type = "type";
auto const identifier = +x3::alnum;
auto const type_def =
(lambda_type | class_type);
auto const lambda_type_def =
("(" > -(type % ",") > ")" > "=>" > type)
| x3::repeat(1)[class_type] >> "=>" > type;
auto const class_type_def =
(identifier % "::") >> -("<" > type % "," > ">");
BOOST_SPIRIT_DEFINE(
lambda_type,
class_type,
type
)
}}
#endif //KYLE_TYPES_DEF_HPP
types.hpp
#ifndef KYLE_PARSER_TYPES_HPP
#define KYLE_PARSER_TYPES_HPP
#include <boost/spirit/home/x3.hpp>
#include "ast.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
struct class_type_class;
struct type_class;
typedef x3::rule<class_type_class, ast::ClassType> class_type_type;
typedef x3::rule<type_class, ast::Type> type_type;
BOOST_SPIRIT_DECLARE(class_type_type,
type_type)
}}
namespace client {
const parser::class_type_type& class_type();
const parser::type_type& type();
}
#endif
Related
I have this writer, I run this like so: ./writer 12 14
it creates two shared memory segments with a spsc queue in each one.
The writer just send text with a counter to the spsc queue of his memory segment.
#include <boost/container/scoped_allocator.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/process.hpp>
#include <iostream>
using namespace std::chrono_literals;
namespace bip = boost::interprocess;
namespace chro = std::chrono;
namespace blf = boost::lockfree;
using char_alloc = bip::allocator<char, bip::managed_shared_memory::segment_manager>;
using shared_string = bip::basic_string<char, std::char_traits<char>, char_alloc>;
using ring_buffer = blf::spsc_queue<shared_string, blf::capacity<200>>;
int main(int argc, char* argv[]) {
if (argc > 1) {
std::string n1 = argv[1];
std::string n2 = argv[2];
const std::string shm_name1 = "segmentrb" + n1;
const std::string shm_name2 = "segmentrb" + n2;
const std::string qname = "queue";
boost::interprocess::shared_memory_object::remove(shm_name1.c_str());
boost::interprocess::shared_memory_object::remove(shm_name2.c_str());
bip::managed_shared_memory seg1(bip::open_or_create, shm_name1.c_str(), 10'000);
char_alloc char_alloc1(seg1.get_segment_manager());
ring_buffer* qu1 = seg1.find_or_construct<ring_buffer>(qname.c_str())();
bip::managed_shared_memory seg2(bip::open_or_create, shm_name2.c_str(), 10'000);
char_alloc char_alloc2(seg2.get_segment_manager());
ring_buffer* qu2 = seg2.find_or_construct<ring_buffer>(qname.c_str())();
int counter = 0;
while (true) {
std::string text1 = "Text from 1, count ";
text1.append(std::to_string(counter));
qu1->push(shared_string(text1.c_str(), char_alloc1));
std::string text2 = "Text from 2, count ";
text2.append(std::to_string(counter));
qu2->push(shared_string(text2.c_str(), char_alloc2));
std::this_thread::sleep_for(std::chrono::milliseconds(1));
counter++;
}
}
}
Then I have this reader, that reads an pop the spsc of the two segments:
I run this with: ./reader 12 14
#include <boost/container/scoped_allocator.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/process.hpp>
#include <boost/unordered_map.hpp>
#include <iostream>
using namespace std::chrono_literals;
namespace bip = boost::interprocess;
namespace chro = std::chrono;
namespace blf = boost::lockfree;
using char_alloc = bip::allocator<char, bip::managed_shared_memory::segment_manager>;
using shared_string = bip::basic_string<char, std::char_traits<char>, char_alloc>;
using ring_buffer = blf::spsc_queue<shared_string, blf::capacity<200>>;
int main(int argc, char* argv[]) {
if (argc > 1) {
std::string n1 = argv[1];
std::string n2 = argv[2];
const std::string shm_name1 = "segmentrb" + n1;
const std::string shm_name2 = "segmentrb" + n2;
const std::string qname = "queue";
bip::managed_shared_memory seg1(bip::open_only, shm_name1.c_str());
char_alloc char_alloc1(seg1.get_segment_manager());
ring_buffer* qu1 = seg1.find<ring_buffer>(qname.c_str()).first;
bip::managed_shared_memory seg2(bip::open_only, shm_name2.c_str());
char_alloc char_alloc2(seg2.get_segment_manager());
ring_buffer* qu2 = seg2.find<ring_buffer>(qname.c_str()).first;
while (true) {
shared_string v1(char_alloc1);
shared_string v2(char_alloc2);
qu1->pop(v1);
qu2->pop(v2);
long lv1 = v1.length();
long lv2 = v2.length();
long lvs = lv1 + lv2;
if (lvs > 0) {
if (lv1 > 0) {
std::cout << "Rec1: " << v1 << "\n";
}
if (lv2 > 0) {
std::cout << "Rec2: " << v2 << "\n";
}
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
}
}
when I do kill -9 on the reader I get this on the writer:
terminate called after throwing an instance of 'boost::interprocess::bad_alloc'
what(): boost::interprocess::bad_alloc
Aborted (core dumped)
How can I avoid the writer being killed?
Reviewed your producer code, removing duplicate code:
Live On Coliru
#include <boost/container/scoped_allocator.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/process.hpp>
#include <iostream>
using namespace std::chrono_literals;
namespace bip = boost::interprocess;
namespace blf = boost::lockfree;
using namespace std::literals;
namespace Shared {
using Segment = bip::managed_shared_memory;
using Mgr = Segment::segment_manager;
template <typename T> using Alloc = bip::allocator<T, Mgr>;
using shared_string = bip::basic_string<char, std::char_traits<char>, Alloc<char>>;
using ring_buffer = blf::spsc_queue<shared_string, blf::capacity<200>>;
struct Queue {
Queue(std::string const& name, std::string const& qname = "queue")
: _name(name)
, _buffer(_segment.find_or_construct<ring_buffer>(qname.c_str())()) {}
std::string const& name() const { return _name; }
bool push(std::string const& item) {
return _buffer->push(
shared_string(item.begin(), item.end(), _segment.get_segment_manager()));
}
private:
std::string const _name;
struct pre_remover_t {
pre_remover_t(std::string const& name) {
bip::shared_memory_object::remove(name.c_str());
}
} _pre_remover{_name};
bip::managed_shared_memory _segment{bip::open_or_create, _name.c_str(), 10'000};
ring_buffer* _buffer = nullptr;
};
} // namespace Shared
int main(int argc, char* argv[]) {
std::deque<Shared::Queue> queues;
for (auto& arg : std::vector<std::string>(argv + 1, argv + argc))
queues.emplace_back("segmentrb" + arg);
for (int counter = 0; true; ++counter) {
for (auto& q : queues)
q.push("Text from " + q.name() + ", count " + std::to_string(counter));
std::this_thread::sleep_for(1ms);
}
}
Reading that makes the problem readily evident: You are pushing elements every 1ms.
Killing the producer gives you 200*1ms = 0.2s before the queue is full. Obviously, then push will fail with the exception indicating that the queue is out of capacity.
UPDATE
From the comments, a version that combines producer and consumer:
Live On Coliru
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <deque>
#include <iomanip>
#include <iostream>
#include <ranges>
#include <thread>
namespace bip = boost::interprocess;
namespace blf = boost::lockfree;
using namespace std::literals;
using std::this_thread::sleep_for;
using std::ranges::views::transform;
namespace Shared {
static constexpr std::string_view queue_name = "queue";
using Segment = bip::managed_shared_memory;
struct pre_remover_t {
pre_remover_t(std::string const& name) { bip::shared_memory_object::remove(name.c_str()); }
};
using Mgr = Segment::segment_manager;
template <typename T> using Alloc = bip::allocator<T, Mgr>;
using String = bip::basic_string<char, std::char_traits<char>, Alloc<char>>;
using ring_buffer = blf::spsc_queue<String, blf::capacity<200>>;
struct Producer {
Producer(std::string const& name)
: _name(name)
, _buffer(_segment.find_or_construct<ring_buffer>(queue_name.data())()) {}
std::string const& name() const { return _name; }
bool push(std::string const& item) {
std::cerr << "push: " << quoted(item) << std::endl;
return _buffer->push(
String(item.begin(), item.end(), _segment.get_segment_manager()));
}
private:
std::string const _name;
pre_remover_t _pre_remover{_name};
Segment _segment{bip::open_or_create, _name.c_str(), 10'000};
ring_buffer* _buffer = nullptr;
};
struct Consumer {
Consumer(std::string const& name)
: _name(name)
, _buffer(_segment.find_or_construct<ring_buffer>(queue_name.data())()) {}
String pop() {
String r(_segment.get_segment_manager());
_buffer->pop(r);
return r;
}
private:
std::string const _name;
Segment _segment{bip::open_only, _name.c_str()};
ring_buffer* _buffer = nullptr;
};
} // namespace Shared
int main(int argc, char* argv[]) {
std::deque<std::string> args(argv + 1, argv + argc);
bool const is_producer = args.front() == "producer";
args.pop_front();
if (is_producer) {
std::deque<Shared::Producer> queues;
for (auto& arg : args)
queues.emplace_back("segmentrb" + arg);
for (int counter = 0; true; ++counter) {
for (auto& q : queues)
q.push("Text from " + q.name() + ", count " + std::to_string(counter));
sleep_for(1s);
}
} else { // consumer
std::deque<Shared::Consumer> queues;
for (auto& arg : args)
queues.emplace_back("segmentrb" + arg);
for (;;) {
auto no_data = true;
for (int index = 0; auto&& v : queues | transform(&Shared::Consumer::pop)) {
if (!v.empty()) {
no_data = false;
std::cout << "Rec" << ++index << ": " << v << "\n";
}
}
if (no_data) {
std::cerr << "Consumer no-data cycle" << std::endl;
sleep_for(2s);
}
}
}
}
With a local demonstration as well:
I try to parse
list<char> fldName
I used the nested structures. But I have a trouble with parsing when one structure nested in other. Look at the sollowing minimal sample code:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <string_view>
using namespace std::string_view_literals;
using namespace boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
namespace client::ast
{
struct ValidType
{
std::string Name;
std::string SubName1;
std::string SubName2;
};
struct StructField
{
ValidType Type;
std::string Name;
};
} // namespace client::ast
BOOST_FUSION_ADAPT_STRUCT(client::ast::ValidType,
Name, SubName1, SubName2
)
BOOST_FUSION_ADAPT_STRUCT(client::ast::StructField,
Type, Name
)
namespace client::parser
{
using ascii::char_;
template <typename T> static auto as = [](auto p) { return rule<struct tag, T> {"as"} = p; };
#define STRING(x) as<std::string>(x)
rule<class ValidType, ast::ValidType> const ValidType = "ValidType";
rule<class StructField, ast::StructField> const StructField = "StructField";
auto const ValidName = lexeme[(alpha | char_('_')) > *(alnum | char_('_'))];
auto const ValidType_SecondPart = char('<') > STRING(ValidName) > ('>' | ',' > STRING(ValidName) > '>');
auto const ValidType_def = STRING(ValidName) > -(ValidType_SecondPart);
auto const StructField_def = ValidType_def > STRING(ValidName);
BOOST_SPIRIT_DEFINE(ValidType);
BOOST_SPIRIT_DEFINE(StructField);
} // namespace client::parser
int main()
{
using boost::spirit::x3::ascii::space;
auto theData = R"(
list<char> fldName
)"sv;
using client::parser::StructField;
client::ast::StructField fld;
bool result = phrase_parse(theData.begin(), theData.end(), StructField, space, fld);
return result;
}
I receive following error:
Error C2338 Size of the passed attribute is less than expected
But I have no idea what is wrong. Its looks like boost::spirit::x3 have a bug with parsing nested structures.
Is there exists any way how to parse nested stuctures?
Answer - ValidType_def -> ValidType :
auto const StructField_def = ValidType_def > STRING(ValidName);
->
auto const StructField_def = ValidType > STRING(ValidName);
I tried to run some simple parser that will parse [ 1, 11, 3, 6-4]. Basically, integer list with range notation.
I want to put everything into AST without semantic action. So I use x3::variant. My code 'seems' very similar to the expression example. However, it can't compile under g++ 6.2. It indeed compile ok with clang++ 6.0 but yield wrong result.
The boost version is 1.63.
It seems that I have some 'move' or initialization issue.
#include <iostream>
#include <list>
#include <vector>
#include <utility>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/include/io.hpp>
namespace ns
{
namespace ast
{
namespace x3 = boost::spirit::x3;
// forward definition
class uintObj;
struct varVec;
// define type
using uintPair_t = std::pair<unsigned int, unsigned int>;
using uintVec_t = std::vector<uintObj>;
// general token value:
class uintObj : public x3::variant <
unsigned int,
uintPair_t
>
{
public:
using base_type::base_type;
using base_type::operator=;
};
struct varVec
{
uintVec_t valVector;
};
}
}
BOOST_FUSION_ADAPT_STRUCT(
ns::ast::varVec,
valVector
)
namespace ns
{
namespace parser
{
// namespace x3 = boost::spirit::x3;
// using namespace x3;
using namespace boost::spirit::x3;
// definition of the range pair:
rule<class uintPair, ast::uintPair_t> const uintPair = "uintPair";
auto const uintPair_def =
uint_
>> '-'
>> uint_
;
rule<class uintObj, ast::uintObj> const uintObj = "uintObj";
auto const uintObj_def =
uint_
| uintPair
;
// define rule definition : rule<ID, attrib>
// more terse definition :
// struct varVec_class;
// using varVec_rule_t = x3::rule<varVec_class, ast::varVec>;
// varVec_rule_t const varVec = "varVec";
// varVec is the rule, "varVec" is the string name of the rule.
rule<class varVec, ast::varVec> const varVec = "varVec";
auto const varVec_def =
'['
>> uintObj % ','
>> ']'
;
BOOST_SPIRIT_DEFINE(
varVec,
uintObj,
uintPair
);
}
}
int main()
{
std::string input ("[1, 11, 3, 6-4]\n");
std::string::const_iterator begin = input.begin();
std::string::const_iterator end = input.end();
ns::ast::varVec result; // ast tree
using ns::parser::varVec; // grammar
using boost::spirit::x3::ascii::space;
bool success = phrase_parse(begin, end, varVec, space, result);
if (success && begin == end)
std::cout << "good" << std::endl;
else
std::cout << "bad" << std::endl;
return 0;
}
Swap the alternative order for the uintObj_def
auto const uintObj_def =
uintPair
| uint_
;
The formulation you have now will always match on a uint_ because the uintPair begins with a valid uint_.
mjcaisse's answer calls out the main problem I think you had. There were a few missing pieces, so I decided to make a simplified version that shows parsing results:
Live On Wandbox
#include <iostream>
#include <iomanip>
//#include <boost/fusion/adapted.hpp>
//#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
namespace x3 = boost::spirit::x3;
namespace ns { namespace ast {
// forward definition
struct uintObj;
//struct varVec;
// define type
using uintPair_t = std::pair<unsigned int, unsigned int>;
using uintVec_t = std::vector<uintObj>;
// general token value:
struct uintObj : x3::variant<unsigned int, uintPair_t> {
using base_type::base_type;
using base_type::operator=;
friend std::ostream& operator<<(std::ostream& os, uintObj const& This) {
struct {
std::ostream& os;
void operator()(unsigned int v) const { os << v; }
void operator()(uintPair_t v) const { os << v.first << "-" << v.second; }
} vis { os };
boost::apply_visitor(vis, This);
return os;
}
};
using varVec = uintVec_t;
} }
namespace ns { namespace parser {
using namespace boost::spirit::x3;
template <typename T> auto as = [](auto p) { return rule<struct _, T> {} = p; };
auto const uintPair = as<ast::uintPair_t> ( uint_ >> '-' >> uint_ );
auto const uintObj = as<ast::uintObj> ( uintPair | uint_ );
auto const varVec = as<ast::varVec> ( '[' >> uintObj % ',' >> ']' );
} }
int main() {
using namespace ns;
std::string const input("[1, 11, 3, 6-4]\n");
auto begin = input.begin(), end = input.end();
ast::varVec result; // ast tree
bool success = phrase_parse(begin, end, parser::varVec, x3::ascii::space, result);
if (success) {
std::cout << "good\n";
for (auto& r : result)
std::cout << r << "\n";
}
else
std::cout << "bad\n";
if (begin != end)
std::cout << "Remaining unparsed: " << std::quoted(std::string(begin, end)) << std::endl;
}
Prints
good
1
11
3
6-4
The following program has been reduced from the original. I get a segmentation fault when it runs. If I remove line 24 with ArithmeticUnaryExpression then the program no longer crashes. How do I get rid of the segmentation fault?
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/spirit/include/qi_expect.hpp>
#include <boost/spirit/home/x3/directive/expect.hpp>
#include <iostream>
#include <string>
namespace wctl_parser {
namespace x3 = boost::spirit::x3;
namespace ascii = x3::ascii;
namespace qi = boost::spirit::qi;
using x3::ulong_;
using x3::lexeme;
//--- Ast structures
struct ArithmeticUnaryExpression;
using AtomicProp = std::string;
using ArithmeticExpression = x3::variant<
x3::forward_ast<ArithmeticUnaryExpression>,
unsigned long
>;
struct ArithmeticUnaryExpression {
std::string op;
ArithmeticExpression operand;
};
using Expression = x3::variant<
ArithmeticExpression
>;
template <typename T> auto rule = [](const char* name = typeid(T).name()) {
struct _{};
return x3::rule<_, T> {name};
};
template <typename T> auto as = [](auto p) { return rule<T>() = p; };
//--- Rules
x3::rule<struct aTrivRule, ArithmeticExpression> aTriv("aTriv");
x3::rule<struct exprRule, Expression> expr("expression");
auto const aTriv_def = rule<ArithmeticExpression>("aTriv")
= ulong_
// | '(' > expr > ')'
;
auto const primitive = rule<Expression>("primitive")
= aTriv
;
auto const expr_def
= primitive
;
BOOST_SPIRIT_DEFINE(aTriv)
BOOST_SPIRIT_DEFINE(expr)
auto const entry = x3::skip(ascii::space) [expr];
} //End namespace
int main() {
std::string str("prop");
namespace x3 = boost::spirit::x3;
wctl_parser::Expression root;
auto iter = str.begin();
auto end = str.end();
bool r = false;
r = parse(iter, end, wctl_parser::entry, root);
if (r) {
std::cout << "Parses OK:" << std::endl << str << std::endl;
if (iter != end) std::cout << "Partial match" << std::endl;
std::cout << std::endl << "----------------------------\n";
}
else {
std::cout << "!! Parsing failed:" << std::endl << str << std::endl << std::endl << "----------------------------\n";
}
return 0;
}
Your variant
using ArithmeticExpression = x3::variant<
x3::forward_ast<ArithmeticUnaryExpression>,
unsigned long
>;
will default-construct to the first element type. The first element type contains ArithmeticExpression which is also default constructed. Can you see the problem already?
Just make sure the default constructed state doesn't lead to infinite recursion:
using ArithmeticExpression = x3::variant<
unsigned long,
x3::forward_ast<ArithmeticUnaryExpression>
>;
when i try and compile the following code i get a compile fail (error C2903: 'apply' : symbol is neither a class template nor a function template ...) when token_list > 10 tokens.
The code compiles and parses correctly when tokens <= 10. Is there a limit to the number of tokens ?
#define BOOST_VARIANT_MINIMIZE_SIZE
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <iostream>
#include <string>
namespace qi = boost::spirit::qi;
namespace lex = boost::spirit::lex;
template <typename Lexer>
struct token_list : lex::lexer<Lexer>
{
token_list()
{
cs1 = "tok1";
cs2 = "tok2";
cs3 = "tok3";
cs4 = "tok4";
cs5 = "tok5";
cs6 = "tok6";
cs7 = "tok7";
cs8 = "tok8";
cs9 = "tok9";
cs10 = "tok10";
cs11 = "tok11";
this->self.add
(cs1) (cs2) (cs3) (cs4) (cs5) (cs6) (cs7) (cs8) (cs9) (cs10) (cs11);
}
lex::token_def<std::string> cs1, cs2, cs3, cs4, cs5, cs6, cs7, cs8,
cs9, cs10, cs11;
};
template <typename Iterator>
struct Grammar : qi::grammar<Iterator>
{
template <typename TokenDef>
Grammar(TokenDef const& tok) : Grammar::base_type(call_setup)
{
call_setup = tok.cs1>>tok.cs2>>tok.cs3>>tok.cs4>>tok.cs5>>
tok.cs6>>tok.cs7>>tok.cs8>>-tok.cs9>>tok.cs10>>
tok.cs11;
}
qi::rule<Iterator> call_setup;
};
int main()
{
typedef std::string::const_iterator It;
typedef lex::lexertl::token<It, boost::mpl::vector<std::string>> token_type;
typedef lex::lexertl::lexer<token_type> lexer_type;
typedef token_list<lexer_type>::iterator_type iterator_type;
token_list<lexer_type> Call_Setup;
Grammar<iterator_type> g(Call_Setup);
std::cout<<"Enter string to parse\n";
std::cout<<"Type [q or Q] to quit\n\n";
std::string str;
while (getline(std::cin, str)){
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
It first = str.begin();
It last = str.end();
bool r = lex::tokenize_and_parse(first, last, Call_Setup, g);
if (r) {
std::cout << "Parsing passed"<< "\n";
}
else {
std::string rest(first, last);
std::cerr << "Parsing failed\n" << "stopped at: \"" << rest << "\"\n";
}
}
system("PAUSE");
}
The rule call_setup stores a sequence in your case and this is a boost fusion vector. By default the max length of that thing is 10.
You increase it by putting #define FUSION_MAX_VECTOR_SIZE 20 at the beginning of your code. Then it compiles without problems.