I see how karma can be used to generate into a container that manages memory, like std::string. But what about the case where a buffer (char[N]) has been pre-allocated?
{
using namespace boost::spirit::karma;
{
std::string buffer;
generate(std::inserter(buffer, buffer.begin()), double_, 3.13);
std::cout << ':' << buffer << ':' << std::endl;
}
{
//////////////////////////////////////////////////////////////////////
// How to make the following work? Is there a builtin output
// iterator that just works?
#if defined(MAJIC)
char buffer[1024];
generate(buffer, double_, 3.13);
std::cout << ':' << buffer << ':' << std::endl;
#endif
}
}
I would like to find a way to parse the double into an address of an existing buffer. It is ok to assume the buffer is large enough for this case. Maybe the underlying question is really - is there already an output iterator adapter or something in karma for native arrays that could be used?
The Karma iterator-based API (here) takes... output iterators.
You can just create one for you array.
Problem with that is that you need to be very sure about the buffer capacity never being insufficient:
char buffer[1024];
char* it = buffer;
karma::generate(it, karma::double_ << karma::eol, 3.13);
std::cout.write(buffer, std::distance(buffer, it));
Note how you cannot assume the buffer to be NUL-terminated. Use the generated size.
array_sink
:There's a more convenient, more general approach in Boost Iostreams that is safe in the face of fixed-size buffers too:
char buffer[310];
io::stream<io::array_sink> as(buffer);
boost::spirit::ostream_iterator it(as);
Here's a live demo that demonstrates the characteristics:
#include <boost/spirit/include/karma.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
namespace karma = boost::spirit::karma;
namespace io = boost::iostreams;
void test(std::vector<int> const& v)
{
char buffer[310];
io::stream<io::array_sink> as(buffer);
boost::spirit::ostream_iterator it(as);
using namespace karma;
if (generate(it, int_ % ", " << eol, v))
{
std::cout << "Success: ";
std::cout.write(buffer, as.tellp());
} else
std::cout << "Generation failed (insufficient capacity?)\n";
}
int main() {
std::cout << "Should be ok: \n";
std::vector<int> v(100, 1);
test(v);
std::cout << "This will exceed buffer capacity: \n";
std::iota(v.begin(), v.end(), 42);
test(v);
}
Which prints
Should be ok:
Success: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
This will exceed buffer capacity:
Generation failed (insufficient capacity?)