|
Boost Users : |
Subject: Re: [Boost-users] Can boost help me organize/parse lots of binary data?
From: Antony Polukhin (antoshkka_at_[hidden])
Date: 2013-02-22 01:16:40
2013/2/21 Larry Evans <cppljevans_at_[hidden]>:
> I haven't a clear idea how this would work because I assumed that
> the binary input stream would have to have something that
> 1st would be decoded into the tag for the variant.
> Then, if your variant visitor solution is used, some
> code (not shown) would create some default constructed value for
> the bounded type corresponding to that tag and then call the visitor.
>
> All the above is just off the top of my head, but, as I said,
> I'm not real sure the variant visitor solution would work.
>
> Could you provide more pseudo code to clarify.
Here is some more pseudo code, may be it will help you.
#include <boost/variant.hpp>
struct name_visitor: public boost::static_visitor<std::string> {
template <class T>
const std::string& opertor()(const T& val) const {
return val.name;
}
// Specific visitor for Person
std::string opertor()(const Person& val) const {
return val.first_name + " " + val.second_name;
}
// Specific visitor for Something
std::string opertor()(const Something& val) const {
throw std::logic_error("Class Something has no name!");
}
};
class EmployeePacket
{
typedef boost::variant<String, Double, Person, Something> variant_t;
std::vector<variant_t> Items;
EmployeePacket()
{
// copying variants is not as fast as copying pointers,
// so it is better to reserve some space first
Items.reserve(200);
}
void Decode(istream& Stream)
{
while (Stream) {
switch (Stream.getc()) {
case 'S': Items.push_back(String(Stream)); break;
case 'D': Items.push_back(Double(Stream)); break;
case 'P': Items.push_back(Person(Stream)); break;
}
}
}
double GetSalary(std::size_t index) const
{
// Will throw if at 'index' is not a Double type
return boost::get<Double>(Items[index]).value;
}
std::string GetName(std::size_t index) const {
return boost::apply_visitor(name_visitor(), Items[index]);
}
}
// All the folloving classes must have a constructor that accepts an istream&
class Double
{
string name;
string units;
// double decode_conversion_scale;
// double decode_conversion_translate;
// unsigned number_of_bits_used_to_encode
// double scale_factor
double value;
void Decode(istream& Stream) // Will be called from constructor
{
Stream.read(&value, 8);
value = value * decode_conversion_scale + decode_conversion_translate;
}
class String
{
string name;
string value;
void Decode(istream& Stream); // Will be called from constructor
}
class Person
{
string first_name;
string second_name;
void Decode(istream& Stream); // Will be called from constructor
}
class Something
{
/*string name; Has NO name! */
void Decode(istream& Stream);
}
Forgot to mention about disadvantages:
* slower copy construction and copy assignment of variant types
(compared to pointers)
* all the types used in variant must be full (not just forward declared)
If second disadvantage is 'too disadvantageous' for you, I can provide
exactly the same example with boost::any instead of boost::variant
-- Best regards, Antony Polukhin
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net