Boost logo

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