Can boost help me organize/parse lots of binary data?

I am receiving a "live" stream of binary data that represents the states of various objects. Sort of like this: Car Speed (m/s): float32 Temperature (deg): uint16 ... My real packets have hundreds of items in them. I will be decoding many of these "packets" and doing various things with them like printing their values to console, etc. My plan is just to make classes: class Car { public: void Decode(istream&); private: float speed; unsigned temperature ... }; But it will not be very extendable. Unfocused open-ended question: Does boost offer something that will help me with this? Thank you, Chris

[Please do not mail me a copy of your followup] boost-users@lists.boost.org spake the secret code <CAPi0psstZu3oe_Nwmf9i8qK4G2yYbjLad45t9naqwLYM1mRDdg@mail.gmail.com> thusly:
Unfocused open-ended question: Does boost offer something that will help me with this?
Boost.Spirit is a recursive descent parser framework that can produce very fast parsers. It uses expression templates to generate parsers from a BNF-like grammar written in C++. You can also use the same techniques to generate output from a datastructure. So conceivably, you could do what you describe by using: Boost.Spirit.Qi to parse the stream into data structures Boost.Spirit.Karma to emit the necessary output from the data structures -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Computer Graphics Museum <http://computergraphicsmuseum.org> The Terminals Wiki <http://terminals.classiccmp.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

On Wed, Feb 20, 2013 at 3:27 PM, Richard <legalize+jeeves@mail.xmission.com> wrote:
Boost.Spirit.Qi to parse the stream into data structures Boost.Spirit.Karma to emit the necessary output from the data structures
Richard, Thank you. I am unfamiliar with Spirit and Karma. Your comment not only introduced me to them but highlighted just how vague my question was. I was thinking less about the actual decoding (who would have known based on what I wrote) and more on how I would "generically" and "extensibly" handle the many fields I am about to receive. For example, consider the following horrible code. Is there a "boost" way to do this kind of thing... (perhaps Spirit/Karma is the answer and I am just more out of touch than I imagine): Good things about the classes below: It is easy to add a new parameter. Just push one onto the back of EmployeePacket::Items The class EmployeePacket doesn't have hundreds of data members such as "string name_, int age_" Bad things about the classes below: Extracting data from the EmployeePacket requires hideous dynamic_casts and hard-coded vector indices Thank you again for your comments/criticisms/suggestions, Chris === class EmployeePacket { std::vector<Item*> Items; EmployeePacket() { Items.push_back(new String("name", "John Doe")); Items.push_back(new Double("salary", "USD", 1, 1)); } void Decode(istream& Stream) { for (auto pItem : Items) pItem->Decode(Stream) } double GetSalary() { return dynamic_cast<Double*>(Items[1])->value; } } class Item { virtual void Decode(istream& Stream) = 0; } class Double : public Item { 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) { Stream.read(&value, 8); value = value * decode_conversion_scale + decode_conversion_translate; } class String : public Item { string name; string value; void Decode(istream& Stream); }

[Please do not mail me a copy of your followup] boost-users@lists.boost.org spake the secret code <CAPi0pssMXAbNnpPVKof2RAuXZY=WD-81XoJR0dFSc7PqcBBocQ@mail.gmail.com> thusly:
For example, consider the following horrible code. Is there a "boost" way to do this kind of thing... (perhaps Spirit/Karma is the answer and I am just more out of touch than I imagine):
OK, this is starting to look more like a serialization problem. You have serialized objects into a binary representation on your input stream and you need to deserialize them from the stream into your data structure. Boost has a serialization library for this sort of thing, but I haven't used it myself. Does this look more like what you need? <http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/index.html> -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Computer Graphics Museum <http://computergraphicsmuseum.org> The Terminals Wiki <http://terminals.classiccmp.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

On 21 February 2013 02:20 Richard [mailto:legalize+jeeves@mail.xmission.com] wrote :-
OK, this is starting to look more like a serialization problem. You have serialized objects into a binary representation on your input stream and you need to deserialize them from the stream into your data structure.
Boost has a serialization library for this sort of thing, but I haven't used it myself.
Does this look more like what you need? <http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/index.html> --
Whilst the serialization library is a very useful tool and may well do what you want it might be worth having a look at Google's protocol buffers library [1] See [2] For some pros/cons of the 2 approaches Alex [1]https://developers.google.com/protocol-buffers/docs/overview [2]http://stackoverflow.com/questions/1061169/boost-serialization-vs-google-pro...

On 02/20/13 20:19, Richard wrote:
[Please do not mail me a copy of your followup]
boost-users@lists.boost.org spake the secret code <CAPi0pssMXAbNnpPVKof2RAuXZY=WD-81XoJR0dFSc7PqcBBocQ@mail.gmail.com> thusly:
For example, consider the following horrible code. Is there a "boost" way to do this kind of thing... (perhaps Spirit/Karma is the answer and I am just more out of touch than I imagine):
OK, this is starting to look more like a serialization problem. You have serialized objects into a binary representation on your input stream and you need to deserialize them from the stream into your data structure.
Boost has a serialization library for this sort of thing, but I haven't used it myself.
Does this look more like what you need? <http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/index.html> Hi Richard,
I've not used serialization either; however, I would assume it uses some sort of archive "coding" to represent a class which is probably not the same "coding" used by Chris' "live" binary data stream. Chris, what's the format of your binary data stream? -regards, Larry

This looks like a perfect place for Boost.Variant. Here is some pseudo code: #include <boost/variant.hpp> struct DecoderVisitor: boost ::static_vizitor<> { istream& Stream; explicit DecoderVisitor(istream& Stream): Stream(Stream){} void operator()(String& s) const { s.Decode(Stream); } void operator()(Double& d) const { d.Decode(Stream); } // or you may just write // template <class T> // void operator()(T& val) const { // val.Decode(Stream); //} }; class EmployeePacket { typedef boost::variant<String, Double> variant_t; std::vector<variant_t> Items; EmployeePacket() { Items.push_back(String("name", "John Doe")); Items.push_back(Double("salary", "USD", 1, 1)); } void Decode(istream& Stream) { for (auto pItem : Items) boost::apply_visitor(DecoderVisitor(Stream), pItem) } double GetSalary() { return boost::get<Double>(Items[1]).value; } } 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) { Stream.read(&value, 8); value = value * decode_conversion_scale + decode_conversion_translate; } class String { string name; string value; void Decode(istream& Stream); } Advantages are: * less calls to new => faster code * no raw pointers => much safer * no virtual functions and dynamic casts => much faster and safer * you exactly specify which types will be stored in variant => more compile time checks And Boost.Variants documentation is not big and it is a simple enough library. -- Best regards, Antony Polukhin

On 02/21/13 08:15, Antony Polukhin wrote:
This looks like a perfect place for Boost.Variant. Here is some pseudo code:
#include <boost/variant.hpp>
struct DecoderVisitor: boost ::static_vizitor<> { istream& Stream;
explicit DecoderVisitor(istream& Stream): Stream(Stream){}
void operator()(String& s) const { s.Decode(Stream); }
void operator()(Double& d) const { d.Decode(Stream); }
// or you may just write // template <class T> // void operator()(T& val) const { // val.Decode(Stream); //} };
class EmployeePacket { typedef boost::variant<String, Double> variant_t; std::vector<variant_t> Items;
EmployeePacket() { Items.push_back(String("name", "John Doe")); Items.push_back(Double("salary", "USD", 1, 1)); }
void Decode(istream& Stream) { for (auto pItem : Items) boost::apply_visitor(DecoderVisitor(Stream), pItem) }
double GetSalary() { return boost::get<Double>(Items[1]).value; } }
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) { Stream.read(&value, 8); value = value * decode_conversion_scale + decode_conversion_translate; }
class String { string name; string value; void Decode(istream& Stream); }
Hi Anthony, 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. Also, Chris, could you provide more details about this binary input stream? -regards, Larry

On 02/21/13 10:47, Larry Evans wrote:
On 02/21/13 08:15, Antony Polukhin wrote:
This looks like a perfect place for Boost.Variant. Here is some pseudo code:
#include <boost/variant.hpp>
struct DecoderVisitor: boost ::static_vizitor<> { istream& Stream;
explicit DecoderVisitor(istream& Stream): Stream(Stream){}
void operator()(String& s) const { s.Decode(Stream); }
void operator()(Double& d) const { d.Decode(Stream); }
// or you may just write // template <class T> // void operator()(T& val) const { // val.Decode(Stream); //} };
class EmployeePacket { typedef boost::variant<String, Double> variant_t; std::vector<variant_t> Items;
EmployeePacket() { Items.push_back(String("name", "John Doe")); Items.push_back(Double("salary", "USD", 1, 1)); }
void Decode(istream& Stream) { for (auto pItem : Items) boost::apply_visitor(DecoderVisitor(Stream), pItem) }
double GetSalary() { return boost::get<Double>(Items[1]).value; } }
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) { Stream.read(&value, 8); value = value * decode_conversion_scale + decode_conversion_translate; }
class String { string name; string value; void Decode(istream& Stream); }
Hi Anthony,
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. Or, something like the serialization library's "external key":
http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/extended_type_in... AFAICT, such an external key serves a purpose similar to variant's tag in that it's used to tag which value is stored in some "storage medium'. In the case of variant, the "storage medium" is a character buffer inside variant. In the case of the serialization library, it's the serialization's archive file. Of course maybe I'm oversimplifying. [snip]

2013/2/21 Larry Evans <cppljevans@suddenlink.net>:
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

On 02/22/13 00:16, Antony Polukhin wrote:
2013/2/21 Larry Evans <cppljevans@suddenlink.net>:
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.
That "something" looks like the 'S' or 'D' or 'P' character returned by the Stream.getc() call in the EmployeePacket::Decode method you provided below.
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.
Yes, Anthony, it helps a lot. I was confused by your earlier code, the one that appeared to use a variant visitor to do the decoding of Chris' binary input stream: http://article.gmane.org/gmane.comp.lib.boost.user/77401 In the example code from your last post, which is quoted below, the variant visitor is not used to decode this input stream, it's only used to perform some operaton on the variant. Quoting from Chris' OP: I will be decoding many of these "packets" and doing various things with them like printing their values to console, etc. That quote mentions two purposes: 1) Decoding packets 2) Operating on the decoded packets The code quoted below does 2); however, the 1) is done by the Decode methods shown below, the most complicated of which is the EmployeePacket::Decode. This EmployeePacket::Decode is somewhat like a very simple Spirit alternative parser: http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/referenc... So, I think *both* variant and spirit could solve both of Chris' problems; however, I don't think using variant with its visitor is sufficient to solve both problems.
#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); }
[snip] -Best Regards, Larry

On 02/22/13 08:38, Larry Evans wrote:
On 02/22/13 00:16, Antony Polukhin wrote: [snip] In the example code from your last post, which is quoted below, the variant visitor is not used to decode this input stream, it's only used to perform some operaton on the variant. Quoting from Chris' OP:
I will be decoding many of these "packets" and doing various things with them like printing their values to console, etc.
That quote mentions two purposes:
1) Decoding packets 2) Operating on the decoded packets
The code quoted below does 2); however, the 1) is done by the Decode
This should read: The variant visitor code quoted below does 2)
methods shown below, the most complicated of which is the EmployeePacket::Decode. This EmployeePacket::Decode is somewhat like a very simple Spirit alternative parser:
http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/referenc...
Actually, I think a Spirit would be an instance of the "inversion of control": http://martinfowler.com/bliki/InversionOfControl.html of EmployeePacket::Decode. IOW, the Decode method of processing the binary input stream uses "Normal Control" whereas using spirit to process the input stream would use "Inversion of the Normal Control" to process the binary input stream. That's because, like the #ruby example in the InversionOfControl.html, the Decode method uses "Normal Control" because it decides when to read the input stream (corresponding to the #ruby example's "when to ask questions, when to read responses"), and using a switch statement, when to call another Decode function to process the read data (corresponding to the #ruby example's "when to process those results".). OTOH, spirit, AFAICT, uses "Inverson of the Normal Control" in that it, instead of the user, decides when to read the input and when to call the processing functions (a.k.a the semantic actions, or the "process_name" and "process_quest" functions in the Tk exmaple in InversionOfControl.html). Hence, if you decide to use spirit, I think the Decode functions would have to be rewritten to be semantic actions to be called by the spirit's parsers :( [snip] HTH. -Larry

I'm working on a boost-based solution that addresses most of my concerns. I'll post here for review. Thanks again, Chris

On 02/20/13 19:21, Chris Stankevitz wrote:
On Wed, Feb 20, 2013 at 3:27 PM, Richard <legalize+jeeves@mail.xmission.com> wrote:
Boost.Spirit.Qi to parse the stream into data structures Boost.Spirit.Karma to emit the necessary output from the data structures
Richard,
Thank you. I am unfamiliar with Spirit and Karma. Your comment not only introduced me to them but highlighted just how vague my question was. I was thinking less about the actual decoding (who would have known based on what I wrote) and more on how I would "generically" and "extensibly" handle the many fields I am about to receive.
For example, consider the following horrible code. Is there a "boost" way to do this kind of thing... (perhaps Spirit/Karma is the answer and I am just more out of touch than I imagine):
Good things about the classes below: It is easy to add a new parameter. Just push one onto the back of EmployeePacket::Items The class EmployeePacket doesn't have hundreds of data members such as "string name_, int age_"
Bad things about the classes below: Extracting data from the EmployeePacket requires hideous dynamic_casts and hard-coded vector indices
Thank you again for your comments/criticisms/suggestions,
Chris
===
class EmployeePacket { std::vector<Item*> Items;
EmployeePacket() { Items.push_back(new String("name", "John Doe")); Items.push_back(new Double("salary", "USD", 1, 1)); }
void Decode(istream& Stream) { for (auto pItem : Items) pItem->Decode(Stream) }
double GetSalary() { return dynamic_cast<Double*>(Items[1])->value; } }
class Item { virtual void Decode(istream& Stream) = 0; }
class Double : public Item { 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) { Stream.read(&value, 8); value = value * decode_conversion_scale + decode_conversion_translate; }
class String : public Item { string name; string value; void Decode(istream& Stream); } Hi Chris,
How do you decide whether the Stream argument to Decode contains a String or a Double? Is that already known? IOW, if you open the istream, do you *know* what types it contains already and only need to fill in the values? -regards, Larry

On Thu, Feb 21, 2013 at 9:04 AM, Larry Evans <cppljevans@suddenlink.net> wrote:
How do you decide whether the Stream argument to Decode contains a String or a Double? Is that already known? IOW, if you open the istream, do you *know* what types it contains already and only need to fill in the values?
Thank you all for your interest and help. I LOVE boost and have been using it for almost a year now. I cannot live without signals2, thread, and shared_ptr. They have changed the way I. I am eager to learn about the other components. I created a simple program that basically does what I want to do. Of course in my real application the objects are more complicated and this is just one small piece of everything I need to do. What I hope to highlight with this sample cpp is: 1. I am decoding data. The format is about as simple and "fixed" as you can imagine. 2. The data is not "POD-encoded" values. Sometimes I have to perform conversions on the values. For example "temperature" in the example. 3. I would like to keep track of some static known-at-compile-time meta-data for each of the values such as the units they are in. This I use for display purposes. 4. Some values have meta data that other values do not, such as floating point values which have a "number of significant digits after the decimal point" which I illustrate with the "temperature" example. 5. I will have many values. ~60. In my example I attempt to highlight what a mess the class will turn into if I make no attempt to use boost::variant, boost::any, polymorphism, etc. 6. An external class "TCTimer" in my example will want access to Get/Set values in the class. 7. I appear to be confusing/merging several concepts: 1) decoding 2) tracking meta data for members 3) replace-lots-of-members-and-with-a-vector-of-something-like-boost::variant Again, thank you, Chris

On 02/21/13 12:53, Chris Stankevitz wrote:
On Thu, Feb 21, 2013 at 9:04 AM, Larry Evans <cppljevans@suddenlink.net> wrote:
How do you decide whether the Stream argument to Decode contains a String or a Double? Is that already known? IOW, if you open the istream, do you *know* what types it contains already and only need to fill in the values?
Thank you all for your interest and help. I LOVE boost and have been using it for almost a year now. I cannot live without signals2, thread, and shared_ptr. They have changed the way I. I am eager to learn about the other components.
I created a simple program that basically does what I want to do. Of course in my real application the objects are more complicated and this is just one small piece of everything I need to do.
What I hope to highlight with this sample cpp is:
1. I am decoding data. The format is about as simple and "fixed" as you can imagine.
2. The data is not "POD-encoded" values. Sometimes I have to perform conversions on the values. For example "temperature" in the example.
3. I would like to keep track of some static known-at-compile-time meta-data for each of the values such as the units they are in. This I use for display purposes.
4. Some values have meta data that other values do not, such as floating point values which have a "number of significant digits after the decimal point" which I illustrate with the "temperature" example.
5. I will have many values. ~60. In my example I attempt to highlight what a mess the class will turn into if I make no attempt to use boost::variant, boost::any, polymorphism, etc.
6. An external class "TCTimer" in my example will want access to Get/Set values in the class.
7. I appear to be confusing/merging several concepts: 1) decoding 2) tracking meta data for members 3) replace-lots-of-members-and-with-a-vector-of-something-like-boost::variant
This 7th feature is not represented by your example code. The example code suggests the type being read is already known. OTOH, your previous example code had a vector of pointers to an abstract class: class EmployeePacket { std::vector<Item*> Items; suggesting that *maybe* the concrete classes are only known at runtime. OTOH, that same code had a CTOR: EmployeePacket() { Items.push_back(new String("name", "John Doe")); Items.push_back(new Double("salary", "USD", 1, 1)); } suggesting the actual values were really known and there was really no need for the abstract Item class or, AFAICT, any need for something like boost::variant. Could you please clarify? Also, the code: std::istringstream Stream(Bytes.substr(0, ByteCount)); unsigned short Temperature; Stream.read(reinterpret_cast<char*>(&Temperature), 2); Stream.read(reinterpret_cast<char*>(&mAge), 4); worries me because it assumes 2 bytes are used to store a short and 4 bytes are used to store an int. I'm not sure how portable this is. In addition, the comments: // First two bytes are a temperature encoded as an uint16. // 0=>25 DegF // 2^16=>125 DegF // // Next four bytes Age is encoded as an int32 // // Byte Value // 0 Temperature LSB // 1 Temperature MSB // 2 Age LSB // 3 Age ... // 4 Age ... // 5 Age MSB // // Total bytes: 6 suggest that there's a specific encoding of the values which implies that there needs to be a specific decoding of the bit's in the bytes in the Byte argument. IOW, I don't think the reinterpret_cast and using of istream.read will give you what you want according to the comments. HTH. -regards, Larry
Again, thank you,
Chris
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

AMDG On 02/20/2013 03:05 PM, Chris Stankevitz wrote:
I am receiving a "live" stream of binary data that represents the states of various objects. Sort of like this: Car Speed (m/s): float32 Temperature (deg): uint16 ...
My real packets have hundreds of items in them. I will be decoding many of these "packets" and doing various things with them like printing their values to console, etc.
My plan is just to make classes:
class Car { public: void Decode(istream&); private: float speed; unsigned temperature ... };
But it will not be very extendable.
Unfocused open-ended question: Does boost offer something that will help me with this?
I suppose that you could try something with Boost.Fusion (warning untested): BOOST_FUSION_DEFINE_STRUCT_INLINE(struct Car, (float, speed) (unsigned, temperature) ) struct decoder { typedef void result_type; template<class T> void operator()(T& t, istream& is) { decode(t, is); } }; // recursively decode nested structs template<class T> typename boost::enable_if< boost::fusion::traits::is_sequence<T>
::type decode(T& t, istream& is) { boost::fusion::for_each(t, boost::phoenix::bind(decoder(), _1, is)); }
// load arithmetic types directly template<class T> typename boost::enable_if< boost::fusion::traits::is_arithmetic<T>
::type decode(T& t, istream& is) { ... }
Anyway, the idea is that Boost.Fusion allows you to iterate over the members of a struct. In Christ, Steven Watanabe
participants (6)
-
Alex Perry
-
Antony Polukhin
-
Chris Stankevitz
-
Larry Evans
-
legalize+jeeves@mail.xmission.com
-
Steven Watanabe