Saving and loading a class state from and to steam c++ - c++

I'm trying to figure out how to save and load an objects state to a binary stream. For context, we currently have this working but only a 'save-to-file' implementation. However, we want the serialization done in-memory to better interact with some parallelization libraries. I'm hoping this will be quite simple but my current implementation doesn't do much - can anybody spot what I'm doing wrong?
class ForSerializationAsBinary {
public:
ForSerializationAsBinary() = default;
explicit ForSerializationAsBinary(int number)
: number_(number) {}
std::ostringstream toBinaryStream() {
std::ostringstream out(std::ios::binary);
out.write((char *) &number_, sizeof(int));
return out;
}
static void fromBinaryStream(ForSerializationAsBinary &obj, std::ostringstream &os) {
int n;
std::istringstream is(std::ios::binary);
is.basic_ios<char>::rdbuf(os.rdbuf());
is.read((char *) &n, sizeof(int));
std::cout << "n: " << n << std::endl;
obj.number_ = n;
}
int number_;
};
TEST(Serialisation, SimpleSerialization) {
ForSerializationAsBinary serializationAsBinary(4);
auto o = serializationAsBinary.toBinaryStream();
ForSerializationAsBinary loaded;
ForSerializationAsBinary::fromBinaryStream(loaded, o);
std::cout << "loaded.number_: " << loaded.number_ << std::endl;
}
And the current output of the test
n: 0
loaded.number_: 0

Looks like I found the answer : just use a std::stringstream instead of the o or i versions:
class ForSerializationAsBinary {
public:
ForSerializationAsBinary() = default;
explicit ForSerializationAsBinary(int number)
: number_(number) {}
std::stringstream toBinaryStream() {
std::stringstream out(std::ios::binary);
out.write((const char *) &number_, sizeof(int));
return out;
}
static void fromBinaryStream(ForSerializationAsBinary &obj, std::stringstream &os) {
int n;
os.read((char *) &n, sizeof(int));
std::cout << "n: " << n << std::endl;
obj.number_ = n;
}
int number_;
};

Related

Convert numeric struct to textual line of numbers on C++

Need some idea how to convert struct (might be also nested) to line of strings where each string is the number of the struct according to the order.
I hope i clear enough.
For example:
struct MyStruct
{
int a;
float b;
};
struct External
{
double c;
MyStruct d;
};
void main()
{
External x;
x.c = 2.345;
x.d.a = 12;
x.d.b = 3.8f;
std:string res = convert_to_string (&x);
cout << res;
// Expected print result:
// "2.345, 12, 3.8"
}
The struct can be very long, so the solution of sorts of itoa(dtoa) or sprintf for each field is possible, but very long and needs code update for every struct change.
Probably some kind of struct run-time or precompile parsing and serialization is needed here.
Ideas ?
What about this? C++ to the rescue :)
#include <iostream>
struct MyStruct {
int a;
float b;
friend std::ostream& operator<<(std::ostream& os, const MyStruct& ms) {
std::cout << std::to_string(ms.a) << " " << std::to_string(ms.b);
return os;
}
};
struct External {
double c;
MyStruct d;
friend std::ostream& operator<<(std::ostream& os, const External& e) {
std::cout << std::to_string(e.c) << " " << e.d;
return os;
}
};
int main() {
External x;
x.c = 2.345;
x.d.a = 12;
x.d.b = 3.8f;
std::cout << x << std::endl;
// Expected print result:
// "2.345, 12, 3.8"
}
Or if you really want a string:
#include <iostream>
struct MyStruct {
int a;
float b;
std::string to_string() const {
std::string str = std::to_string(this->a);
str += " ";
str += std::to_string(this->b);
return str;
}
};
struct External {
double c;
MyStruct d;
std::string to_string() const {
std::string str = std::to_string(this->c);
str += " ";
str += this->d.to_string();
return str;
}
};
int main() {
External x;
x.c = 2.345;
x.d.a = 12;
x.d.b = 3.8f;
std::cout << x.to_string() << std::endl;
// Expected print result:
// "2.345, 12, 3.8"
}

How to convert from std::vector<float> to std::istream?

I have an std::vector and the function expects an std::istream:
callMe(std::istream& is)
What is the best way to do the conversion? Is there something more clever than?
std::stringstream sstr;
for(int i = 0; i < myVector.size(); ++i) {
sstr << myVector[i] << " ";
}
std::istringstream istr{sstr.str()};
callMe(istr);
EDIT: Thanks for the suggestions so far! Updated code:
std::stringstream sstr;
for(const float& val : myVector) {
sstr << val << " ";
}
callMe(sstr);
The issue is that std::istream is inherently character-based. If you want to keep using callMe(std::istream& is) as an interface, you are bound to convert every element of myVector to characters and back at some point. If you want to stick with this option, I personally find ostream_iterator an elegant solution:
copy(begin(data), end(data), std::ostream_iterator<float>(sstr));
Full example:
void callMeStream(std::istream &is)
{
float f1;
is >> f1;
std::cout << "Stream: " << f1 << std::endl;
}
// ...
std::vector<float> data = {3.5, 1.5, 2.5 /* ... */};
std::stringstream sstr;
copy(begin(data), end(data), std::ostream_iterator<float>(sstr));
callMeStream(sstr); // Output: "Stream: 3.51"
If you are willing to change the signature of callMe, this conversion can be avoided:
template <class T>
void callMeTemplate(T &is)
{
float f1;
is >> f1;
std::cout << "Template: " << f1 << std::endl;
}
#define NO_ELEMENT -1.0;
class data_wrapper
{
std::vector<float>::const_iterator current;
const std::vector<float>::const_iterator last;
public:
data_wrapper(const std::vector<float> &data) : current(begin(data)), last(end(data)) {}
data_wrapper &operator>>(float &value)
{
if (last == current)
{
value = NO_ELEMENT;
}
else
{
value = *current++;
}
return *this;
}
};
// ...
data_wrapper wrapper(data);
callMeTemplate(wrapper); // Output: "Template: 3.5"
In the second example, the float value never gets converted to a character sequence, and could accept both data_wrapper and std::istream types. Of course, if you are willing to change the signature of callMe entirely, you might as well change it to accept a begin/end iterator range or a vector directly.

MessagePack C++ - How to iterate through an unknown data structure?

I want to share structured data between C++ and Python languages using MessagePack like this one:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ],
"x" : [ x0,..,xN],
"P" : [ [P00, ..., P0N], ..., [PM0,...,PMN] ]
}
The number of variables is optional so in some cases I will have for example only:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ]
}
Decoding this in Python is pretty simple, my problem is to figure out
how to decode this in C++ if I don't know in advance the structure of
the data ? or the exact number of variables that I would have; is it
possible to iterate the structure in these cases?
I managed to handle a "fixed" data structure ( always with the same
number of variables ) defining a struct for example:
struct variables
{
std::vector< std::vector<double> > t;
std::vector< double > x;
std::vector< std::vector<double> > P;
MSPACK_DEFINE_MAP( t, x, P );
};
std::stringstream inBuffer;
.... (read data )
std::string str( inBuffer.str() );
msgpack::object_handle oh = msgpack::unpack( str.data(), str.size() );
msgpack::object deserialized = oh.get();
variables var;
deserialized.convert( var );
Is there a better way to accomplish this ?, how could manage optional
variables that could not appear in the structure ?; I repeat the
previous question: could I iterate an unknown data structure in C++?,
how ?
Thanks in advance!
Regards, Ernesto
There are two ways to treat unknown data structure.
The first way is using parse/visitor mechanism.
Here is an example:
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
// This is a simple print example visitor.
// You can do any processing in your visitor.
struct my_visitor : msgpack::null_visitor {
bool start_map_key() {
processing_map_key = true;
return true;
}
bool end_map_key() {
processing_map_key = false;
return true;
}
bool start_array(uint32_t size) {
std::cout << "array (size:" << size << ")[" << std::endl;
return true;
}
bool end_array() {
std::cout << "]" << std::endl;
return true;
}
bool visit_str(const char* v, uint32_t size) {
if (processing_map_key) {
std::cout << "map key:" << std::string(v, size) << std::endl;
}
return true;
}
bool visit_positive_integer(uint64_t v) {
std::cout << "found value:" << v << std::endl;
return true;
}
bool processing_map_key = false;
std::string indent;
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
// print data (for debug)
{
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
}
// apply visitor
{
my_visitor mv;
msgpack::parse(ss.str().data(), ss.str().size(), mv);
}
}
Running demo: https://wandbox.org/permlink/3NrR4IMDIuLTk9e9
See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_visitor.
The other way is using msgpack::type::variant or `msgpack::type::variant_ref.
The former copies data, you can update it. The latter doesn't copy data. You cannot update it.
This approach requires boost. So you need to define MSGPACK_USE_BOOST. I recommend defining as a compiler option.
// Boost is required
#define MSGPACK_USE_BOOST
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
struct my_visitor:boost::static_visitor<void> {
void operator()(uint64_t v) const {
std::cout << "positive insteger:" << v << std::endl;
}
// const is required for map key because std::multimap's key (first) is const.
void operator()(std::string const& v) const {
std::cout << "string:" << v << std::endl;
}
void operator()(std::vector<msgpack::type::variant>& v) const {
std::cout << "array found" << std::endl;
for (auto& e : v) {
boost::apply_visitor(*this, e);
}
}
void operator()(std::multimap<msgpack::type::variant, msgpack::type::variant>& v) const {
std::cout << "map found" << std::endl;
for (auto& e : v) {
std::cout << "key:" << std::endl;
boost::apply_visitor(*this, e.first);
std::cout << "value:" << std::endl;
boost::apply_visitor(*this, e.second);
}
}
template <typename T>
void operator()(T const&) const {
std::cout << " match others" << std::endl;
}
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
msgpack::type::variant v = oh.get().as<msgpack::type::variant>();
boost::apply_visitor(my_visitor(), v);
}
Running demo: https://wandbox.org/permlink/HQwJjfwW8rLEMi0d
See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_variant
Here are exampless:
https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_capitalize.cpp
https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_mapbased.cpp
Both ways can treat unpredictable data structure. You need to do some visitor processing. If the data structure is predictable some extent, your original approach is also good way.
Actually there is a simpler way, if you are dealing with maps (like stated in the question), not arrays.
msgpack::object_handle oh = msgpack::unpack(/* some data */);
std::map<std::string,msgpack::type::variant> map = obj.convert();
This way you will get a map with all the data, no need for a visitor or boost.

Is there a simple way to get the number of characters printed in C++?

printf(...) returns the number of characters output to the console, which I find very helpful in designing certain programs. So, I was wondering if there is a similar feature in C++, since the cout<< is an operator without a return type (at least from what I understand of it).
You can associate your own streambuf to cout to count the characters.
This is the class that wraps it all:
class CCountChars {
public:
CCountChars(ostream &s1) : m_s1(s1), m_buf(s1.rdbuf()), m_s1OrigBuf(s1.rdbuf(&m_buf)) {}
~CCountChars() { m_s1.rdbuf(m_s1OrigBuf); m_s1 << endl << "output " << m_buf.GetCount() << " chars" << endl; }
private:
CCountChars &operator =(CCountChars &rhs) = delete;
class CCountCharsBuf : public streambuf {
public:
CCountCharsBuf(streambuf* sb1) : m_sb1(sb1) {}
size_t GetCount() const { return m_count; }
protected:
virtual int_type overflow(int_type c) {
if (streambuf::traits_type::eq_int_type(c, streambuf::traits_type::eof()))
return c;
else {
++m_count;
return m_sb1->sputc((streambuf::char_type)c);
}
}
virtual int sync() {
return m_sb1->pubsync();
}
streambuf *m_sb1;
size_t m_count = 0;
};
ostream &m_s1;
CCountCharsBuf m_buf;
streambuf * const m_s1OrigBuf;
};
And you use it like this:
{
CCountChars c(cout);
cout << "bla" << 3 << endl;
}
While the object instance exists it counts all characters output by cout.
Keep in mind that this will only count characters output via cout, not characters printed with printf.
You could create a filtering stream buffer which reports the number of characters written. For example:
class countbuf
: std::streambuf {
std::streambuf* sbuf;
std::streamsize size;
public:
countbuf(std::streambuf* sbuf): sbuf(sbuf), size() {}
int overflow(int c) {
if (traits_type::eof() != c) {
++this->size;
}
return this->sbuf.sputc(c);
}
int sync() { return this->sbuf->pubsync(); }
std::streamsize count() { this->size; }
};
You'd just use this stream buffer as a filter:
int main() {
countbuf sbuf;
std::streambuf* orig = std::cout.rdbuf(&sbuf);
std::cout << "hello: ";
std::cout << sbuf.count() << "\n";
std::cout.rdbuf(orig);
}

"cast with the appropriate bitmask" while using alternative cout

So I decided to make a console class as an alternative to std::cout << stream << std::endl routine.
Here's my code:
class Console {
public:
Console() {
this->console = GetStdHandle(STD_OUTPUT_HANDLE);
this->current_color = 7;
}
void color(int k) {
this->current_color = k;
SetConsoleTextAttribute(this->console, this->current_color);
}
void remove() {
FreeConsole();
}
void print(std::string s) {
std::cout << s;
}
void log(std::string s) {
this->color(7);
std::cout << s << std::endl;
this->color(this->current_color);
}
void error(std::string s) {
this->color(12);
std::cout << s << std::endl;
this->color(this->current_color);
}
private:
HANDLE console;
int current_color;
};
Initializing console as Console console;, I use console.log("String " + n), where n is an unsigned short, for example. The code compiles fine, however this thing shows up:
What is it and how do I fix it?
Your program contains undefined behavior.
console.log("String " + n) (where n is an integral type) is interpreted as follows:
const char* tmp_ptr1 = "String ";
const char* tmp_ptr2 = tmp_ptr1 + n;
console.log(std::string(tmp_ptr2));
If n > 7 or n < 0 the code above performs out-of-bounds access. In your case this access happens to pick up some other (sub)string from the string literals linked into your program's data section and you see it on your screen. In theory anything else could happen.