When writing a custom serializer for msgpack_c one also needs to implement object_with_zone.
The documentation how to implement this is very sparse ( https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor ).
In what circumstances is this method called?
You can create a msgpack::object from C++ types.
See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_object#conversion
When you call msgpack::object constructor with zone like msgpack::object(mc, z);, object_with_zone<T>::operator() is called internally.
If you don't want to create msgpack::object from C++ types, you don't need to define object_with_zone specialization. Packing, unpacking, and converting to C++ types from msgpack::object don't require it.
Here is an example:
#include <iostream>
#include <msgpack.hpp>
class my_class {
public:
my_class(std::string const& name, int age):name_(name), age_(age) {}
std::string const& get_name() const { return name_; }
int get_age() const { return age_; }
private:
std::string name_;
int age_;
};
// User defined class template specialization
namespace msgpack {
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
namespace adaptor {
template <>
struct object_with_zone<my_class> {
void operator()(msgpack::object::with_zone& o, my_class const& v) const {
std::cout << "object_with_zone<my_class> is called" << std::endl;
o.type = type::ARRAY;
o.via.array.size = 2;
o.via.array.ptr = static_cast<msgpack::object*>(
o.zone.allocate_align(sizeof(msgpack::object) * o.via.array.size, MSGPACK_ZONE_ALIGNOF(msgpack::object)));
o.via.array.ptr[0] = msgpack::object(v.get_name(), o.zone);
o.via.array.ptr[1] = msgpack::object(v.get_age(), o.zone);
}
};
} // namespace adaptor
} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
} // namespace msgpack
int main() {
my_class mc("John", 42);
msgpack::zone z;
auto obj = msgpack::object(mc, z);
std::cout << obj << std::endl;
}
Output:
object_with_zone<my_class> is called
["John", 42]
Running demo: https://wandbox.org/permlink/dNmZX1FpUL3w8D5m
updated
Additional question. Why would i want to use the zone ?
Answer:
A zone is used internally when you unpack MessagePack formatted byte stream. You get msgpack::object_handle. msgpack::object_handle has a zone and a msgpack::object. See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_object#what-is-msgpackobject.
The reason of using msgpack::zone is for performance. If msgpack::object is STR, BIN, or EXT, the msgpack::object need to allocate a memory dynamically. The msgpack::object can have a handle of the memory by itself but it is inefficient. The destructor of msgpack::object need to deallocate memory, if the msgpack::object allocate memory. msgpack::object is a composite data structure. That means the destructor cannot be inlined.
One of the goal of msgpack-c is efficient unpacking. So msgpack-c uses msgpack::zone.
It is unpacking story. msgpack::zone is also used when msgpack::object is created from C++ types. I'm not sure when users want to do, is is up to users.
Related
I want to write a class that can monitor a bunch of different values for easy debugging. Imagine setting "watches" in a visual debugger. I'm picturing something like this:
struct Foo {
int x = 0;
std::string s = "bar";
};
int main() {
Foo f;
ValueMonitor::watch("number", &f.x);
ValueMonitor::watch("string", &f.s);
for (int i = 0; i < 10; ++i) {
++f.x;
if (i > 5) {
f.s = "new string";
}
// print the current value of the variable with the given key
// these should change as the loop goes on
ValueMonitor::print("number");
ValueMonitor::print("string");
// or
ValueMonitor::printAll();
// obviously this would be unnecessary in this example since I
// have easy access to f, but imagine monitoring different
// values from all over a much larger code base
}
}
Then these could be easily monitored somewhere in the application's GUI or whatever.
However, I don't know how to handle the different types that would be stored in this class. Ideally, I should be able to store anything that has a string representation. I have a few ideas but none of them really seem right:
Store pointers to a superclass that defines a toString function or operator<<, like Java's Object. But this would require me to make wrappers for any primitives I want to monitor.
Something like boost::any or boost::spirit::hold_any. I think any needs to be type casted before I can print it... I guess I could try/catch casting to a bunch of different types, but that would be slow. hold_any requires defined stream operators, which would be perfect... but I can't get it to work with pointers.
Anyone have any ideas?
I found a solution somewhere else. I was pretty blown away, so might as well post it here for future reference. It looks something like this:
class Stringable
{
public:
virtual ~Stringable() {};
virtual std::string str() const = 0;
using Ptr = std::shared_ptr<Stringable>;
};
template <typename T>
class StringableRef : public Stringable
{
private:
T* _ptr;
public:
StringableRef(T& ref)
: _ptr(&ref) {}
virtual ~StringableRef() {}
virtual std::string str() const
{
std::ostringstream ss;
ss << *_ptr;
return ss.str();
}
};
class ValueMonitor
{
private:
static std::map<std::string, Stringable::Ptr> _values;
public:
ValueMonitor() {}
~ValueMonitor() {}
template <typename T>
static void watch(const std::string& label, T& ref)
{
_values[label] = std::make_shared<StringableRef<T>>(ref);
}
static void printAll()
{
for (const auto& valueItr : _values)
{
const String& name = valueItr.first;
const std::shared_ptr<Stringable>& value = valueItr.second;
std::cout << name << ": " << value->str() << std::endl;
}
}
static void clear()
{
_values.clear();
}
};
std::map<std::string, Stringable::Ptr> ValueMonitor::_values;
.
int main()
{
int i = 5;
std::string s = "test"
ValueMonitor::watch("number", i);
ValueMonitor::watch("string", s);
ValueMonitor::printAll();
i = 10;
s = "new string";
ValueMonitor::printAll();
return 0;
}
I have a ResourceManager which takes in classes of type Resource. Resource is a parent class of other classes such as ShaderProgram, Texture, Mesh and even Camera who are completely unrelated to one another.
Suffice it to say, the ResourceManager works. But there is one thing that is very tedious and annoying, and that's when I retrieve the objects from the ResourceManager. Here is the problem:
In order to get an object from ResourceManager you call either of these functions:
static Resource* get(int id);
static Resource* get(const std::string &name);
The first function checks one std::unordered_map by an integer id; whereas the second function checks another std::unordered_map by the name that is manually given by the client. I have two versions of these functions for flexibility sakes because there are times where we don't care what the object contained within ResourceManager is (like Mesh) and there are times where we do care about what it is (like Camera or ShaderProgram) because we may want to retrieve the said objects by name rather than id.
Either way, both functions return a pointer to a Resource. When you call the function, it's as easy as something like:
rm::get("skyboxShader");
Where rm is just a typedef of ResourceManager since the class is static (all members/functions are static). The problem though is that the rm::get(..) function returns a Resource*, and not the child class that was added to the ResourceManager to begin with. So, in order to solve this problem I have to do a manual type conversion so that I can get ShaderProgram* instead of Resource*. I do it like this:
auto s = static_cast<ShaderProgram*>(rm::get(name));
So, everytime I want to access a Resource I have to insert the type I want to actually get into the static_cast. This is problematic insofar that everytime someone needs to access a Resource they have to type convert it. So, naturally I created a function, and being that ShaderProgram is the subject here, thus:
ShaderProgram* Renderer::program(const std::string &name)
{
auto s = static_cast<ShaderProgram*>(rm::get(name));
return s;
}
This function is static, and ResourceManager is a static class so the two go well hand-in-hand. This is a nice helper function and it works effectively and my program renders the result just fine. The problem is what I have to do when I'm dealing with other Resources; that means for every Resource that exists, there has to be a type-conversion function to accommodate it. Now THAT is annoying. Isn't there a way I can write a generic type-conversion function something like this?
auto Renderer::getResource(classTypeYouWant T, const std::string &name)
{
auto s = static_cast<T*>(rm::get(name));
return s;
}
Here, the auto keyword causes the function to derive which type it's supposed to be dealing with and return the result accordingly. My first guess is that I might have to use templates; but the problem with templates is that I can't limit which types get inserted into the function, and I really REALLY don't want floating-point id numbers, char ids, let alone custom-defined ids. It's either string (might change to const char* tbh) or ints or else.
How can I create a generic conversion function like the one described above?
Have you looked at using dynamic_cast? If the conversion fails with dynamic_cast the the pointer will be set to nullptr. So you could either write overloads for each type or you could write a template function where you pass the the type you want to convert to as well as the string or id and if the conversion succeeds or fails return true or false.
template<typename T>
bool Renderer::getResource(T*& type, const std::string &name)
{
type = dynamic_cast<decltype(std::remove_reference<decltype(T)>::type)>(rm::get(name));
if (type == nullptr)
return false;
return true;
}
OK, I did not like the idea of a typeless storage, but maybe you find that basic program as a start point. There are a lot of things which must be beautified, but some work must remain :-)
Again: It is a design failure to solve something in that way!
In addition to your example code this solution provides a minimum of safety while checking for the stored type while recall the element. But this solution needs rtti an this is not available on all platforms.
#include <map>
#include <iostream>
#include <typeinfo>
class ResourcePointerStorage
{
private:
std::map< const std::string, std::pair<void*, const std::type_info*>> storage;
public:
bool Get(const std::string& id, std::pair<void*, const std::type_info*>& ptr )
{
auto it= storage.find( id );
if ( it==storage.end() ) return false;
ptr= it->second;
return true;
}
bool Put( const std::string& id, void* ptr, const std::type_info* ti)
{
storage[id]=make_pair(ptr, ti);
}
};
template < typename T>
bool Get(ResourcePointerStorage& rm, const std::string& id, T** ptr)
{
std::pair<void*, const std::type_info*> p;
if ( rm.Get( id,p ))
{
if ( *p.second != typeid(T)) { return false; }
*ptr= static_cast<T*>(p.first);
return true;
}
else
{
return 0;
}
}
template < typename T>
void Put( ResourcePointerStorage& rm, const std::string& id, T *ptr)
{
rm.Put( id, ptr, &typeid(T) );
}
class Car
{
private:
int i;
public:
Car(int _i):i(_i){}
void Print() { std::cout << "A car " << i << std::endl; }
};
class Animal
{
private:
double d;
public:
Animal( double _d):d(_d) {}
void Show() { std::cout << "An animal " << d << std::endl; }
};
int main()
{
ResourcePointerStorage store;
Put( store, "A1", new Animal(1.1) );
Put( store, "A2", new Animal(2.2) );
Put( store, "C1", new Car(3) );
Animal *an;
Car *car;
if ( Get(store, "A1", &an)) { an->Show(); } else { std::cout << "Error" << std::endl; }
if ( Get(store, "A2", &an)) { an->Show(); } else { std::cout << "Error" << std::endl; }
if ( Get(store, "C1", &car)) { car->Print(); } else { std::cout << "Error" << std::endl; }
// not stored object
if ( Get(store, "XX", &an)) { } else { std::cout << "Expected false condition" << std::endl; }
// false type
if ( Get(store, "A1", &car)) { } else { std::cout << "Expected false condition" << std::endl; }
};
I've found the solution to my question. I created a macro:
#define convert(type, func) dynamic_cast<type>(func)
Extremely generic and code-neutral which allows types to be dynamic_casted from the return type of the function. It also allows for doing checks:
if (!convert(ShaderProgram*, rm::get("skyboxShader")))
cerr << "Conversion unsuccessful!" << endl;
else cout << "Conversion successful!" << endl;
I hope my solution will help people who search for questions similar of this kind. Thanks all!
I have a code, which writes a number to std::string using std::ostringstream:
template<class T>
class Converter
{
private:
static std::string s_buffer;
public:
static const char* Out(const T& val)
{
std::ostringstream os;
os << val;
s_buffer = os.str();
return(s_buffer.data());
}
};
The Converter::Out is called a lot. So much that it even shows up in the profiler. And essentially, what happens here is:
An instance of ostringstream is created
It creates a buffer to write to and writes to it
I copy that buffer to the static string and return it
I think, that if I could get the stream to write directly to the static string, thus avoiding the copy, I may get some performance improvement. But how can I do it - std::ostringstream can accept only const std::string in constructor, which would be a preliminary fill, not the buffer to write to.
Maybe Boost has some alternative, though I didn't find one... :(
You can access the buffer of an ostringstream using the rdbuf() method; unfortunately, access to the underlying character buffer is protected. However, you can easily work around that via inheritance:
template<class T>
class Converter
{
private:
static struct Buf : public std::ostringstream, public std::basic_stringbuf<char>
{
Buf() { static_cast<std::basic_ios<char>&>(*this).rdbuf(this); }
void clear() { setp(pbase(), pbase()); }
char const* c_str() { *pptr() = '\0'; return pbase(); }
} s_buf;
public:
static const char* Out(const T& val)
{
s_buf.clear();
s_buf << val;
return s_buf.c_str();
}
};
If Boost is an option, you can use boost::iostreams::filtering_ostream backed by a string or vector<char>: http://lists.boost.org/boost-users/2012/09/75887.php
I'm using Boost.bimap for implementing a LRU cache with some complex key containing a string.
The problem is that the key is copied every-time I'm invoking find(). I would like to avoid this un-necessary copy (and in general: make as few as possible copies of the string, maybe via templates?)
A minimal test-case (with a gist version):
#include <string>
#include <iostream>
#include <boost/bimap.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/set_of.hpp>
class Test
{
public:
struct ComplexKey
{
std::string text;
int dummy;
ComplexKey(const std::string &text, int dummy) : text(text), dummy(dummy) {}
~ComplexKey()
{
std::cout << "~ComplexKey " << (void*)this << " " << text << std::endl;
}
bool operator<(const ComplexKey &rhs) const
{
return tie(text, dummy) < tie(rhs.text, rhs.dummy);
}
};
typedef boost::bimaps::bimap<
boost::bimaps::set_of<ComplexKey>,
boost::bimaps::list_of<std::string>
> container_type;
container_type cache;
void run()
{
getValue("foo", 123); // 3 COPIES OF text
getValue("bar", 456); // 3 COPIES OF text
getValue("foo", 123); // 2 COPIES OF text
}
std::string getValue(const std::string &text, int dummy)
{
const ComplexKey key(text, dummy); // COPY #1 OF text
auto it = cache.left.find(key); // COPY #2 OF text (BECAUSE key IS COPIED)
if (it != cache.left.end())
{
return it->second;
}
else
{
auto value = std::to_string(text.size()) + "." + std::to_string(dummy); // WHATEVER...
cache.insert(typename container_type::value_type(key, value)); // COPY #3 OF text
return value;
}
}
};
Bimap is not using the std:map directly (I'm saying this because you are using set_of) but rather creates views via different container adaptors and in the process the keys are copied. It's not possible to significantly improve performance the way you've defined bimap in the question.
To obtain better performance from bimap with respect to the ComplexKey you will rather have to store a pointer to the ComplexKey (preferably raw; no ownership of the keys implied by the bimap) and provide your own sorters. Pointers are cheap to copy, the downside is that you'll have to manage the keys lifetime in parallel to the map.
Do something along the lines of,
std::vector<unique_ptr<ComplexKey>> ComplexKeyOwningContainer;
typedef boost::bimaps::bimap<
boost::bimaps::set_of<ComplexKey*, ComplexKeyPtrSorter>,
boost::bimaps::list_of<std::string>
> container_type;
Note that if you are after performance you also need to be careful about std::string which is the other side of your bimap. They can be quite expensive, temporaries are frequent, and they will suffer from same issues as the ComplexKey key.
I have read that one must not store std::auto_ptr in std::vector and that boost::ptr_vector could be used instead. I have been able to do so, I don't know however how to use ptr_vector, when I don't want to store pointers, but a struct, which has a pointer member.
In this example, I want to open some files and store the associated ofstream object with some additional data, for later use. I would like to replace the file field of struct data with a smart pointer. Since the vector<data> v should be the owner, I think that a shared_ptr would work, but wouldn't be appropriate.
What should I replace the naked pointer file with?
#include <iostream>
#include <fstream>
#include <vector>
struct data {
std::string filename;
std::ofstream* file;
data(const std::string filename, std::ofstream* file)
: filename(filename), file(file)
{
}
};
std::vector<data> open_files()
{
std::vector<data> v;
v.push_back(data("foo", new std::ofstream("foo")));
return v;
}
int main()
{
std::vector<data> v = open_files();
/* use the files */
*(v[0].file) << "foo";
delete v[0].file; // either rely on dtor to close(), or call it manually
}
Update:
I feel I have done a sub optimal job in describing my problem, let me try with another example. Also I am looking for a C++03 solution:
#include <memory>
#include <vector>
#include <boost/ptr_container/ptr_vector.hpp>
struct T {
std::auto_ptr<int> a;
};
int main()
{
// instead of
// std::vector<std::auto_ptr<int> > v;
// use
boost::ptr_vector<int> v;
// what to use instead of
// std::vector<T> w;
}
Concerning your data class, I would suggest using an std::unique_ptr<std::ofstream>. This is not to save you from an accidental memory leak, since you are deleting the pointer in the constructor, but rather to make the ownership explicit. A user of your code would have to know what data is doing with the pointer it takes in the constructor:
std::ofstream ofs;
{
data d1("crash", &ofs);
} // error! d1 will attempt to delete stack allocated object
std::ofstream* pOfs = new std::ofstream(....);
data d2("crash again", pOfs);
delete pOFs; // user thinks data makes a deep copy
However, with unique_ptr the intend is clear, hence it is harder to make mistakes:
data d3("OK", std::unique_ptr<std::ofstream>(new std::ofstream(....)));
std::unique_ptr<std::ofstream> pOfs2(new std::ofstream(....));
data d4("OK", pOfs2); // safe, pOfs's contents have been safely moved
// we can check pOfs2 after the move
if (pOfs2) { /* */ }
You can delete pointer in destructor:
struct data
{
std::string filename;
std::ofstream* file;
data(const std::string filename, std::ofstream* file)
: filename(filename), file(file)
{
}
~data()
{
delete file;
}
};
Or use std::unique_ptr to wrap that pointer but its unnecessary in your case.
You don't need to have an ofstream* as a member.
#include <iostream>
#include <fstream>
#include <vector>
struct data {
std::string filename;
data(const std::string filename) : filename(filename)
{}
};
std::vector<data> open_files()
{
std::vector<data> v;
v.push_back(data("foo"));
return v;
}
If you want to append to the file, specify the app file mode.
void print_files(const std::vector<data>& v)
{
for(std::vector<data>::const_iterator it = v.begin(); it != v.end(); ++it)
{
std::ofstream os(it->filename, std::ostream::app);
os << "bar";
}
}
int main()
{
std::vector<data> v = open_files();
print_files(v);
}