Boost C++ Libraries: Ticket #9843: binary serializer wrong behaviour treating enums
https://svn.boost.org/trac10/ticket/9843
<p>
from iserializer.hpp
template<class Archive>
struct load_enum_type {
</p>
<blockquote>
<p>
template<class T>
static void invoke(Archive &ar, T &t){
</p>
<blockquote>
<p>
<em> convert integers to correct enum to load
int i;
ar >> boost::serialization::make_nvp(NULL, i);
t = static_cast< T >(i);
</em></p>
</blockquote>
<p>
}
</p>
</blockquote>
<p>
};
</p>
<p>
it tries to load all enums int-sized.
even in this case:
enum class <a class="missing wiki">WrongBehaviour</a> : unsigned char
{ };
</p>
<p>
it reads 4-byte in my case, while 1 byte's expected.
</p>
en-usBoost C++ Libraries/htdocs/site/boost.png
https://svn.boost.org/trac10/ticket/9843
Trac 1.4.3Robert RameyMon, 07 Apr 2014 15:57:17 GMTstatus changed; resolution set
https://svn.boost.org/trac10/ticket/9843#comment:1
https://svn.boost.org/trac10/ticket/9843#comment:1
<ul>
<li><strong>status</strong>
<span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span>
</li>
<li><strong>resolution</strong>
→ <span class="trac-field-new">invalid</span>
</li>
</ul>
<p>
Hmmm - this would be quite surprising after many years.
</p>
<p>
Are you're using exactly the same platform for de-serialization as for serialization? Remember that the binary archive is explicitly defined not to be portable in the interests of performance. I would need a better test case to justify spending more time on this.
</p>
<p>
Robert Ramey
</p>
Ticketjpjps@…Thu, 10 Apr 2014 07:09:22 GMTstatus changed; resolution deleted
https://svn.boost.org/trac10/ticket/9843#comment:2
https://svn.boost.org/trac10/ticket/9843#comment:2
<ul>
<li><strong>status</strong>
<span class="trac-field-old">closed</span> → <span class="trac-field-new">reopened</span>
</li>
<li><strong>resolution</strong>
<span class="trac-field-deleted">invalid</span>
</li>
</ul>
<p>
simple snippet:
</p>
<pre class="wiki"> enum class SyncCode : unsigned char
{
ProcessId,
ModuleFileName,
};
std::ostringstream stream;
binary_oarchive archive(stream, boost::archive::no_header);
archive << SyncCode::ProcessId;
auto firstSize = stream.str().size();
stream = std::ostringstream();
archive << (unsigned char)SyncCode::ProcessId;
auto secondarySize = stream.str().size();
</pre><p>
firstSize results 4, secondarySize 1.
on vs2013 / windows8.1 x64, targeted x86.
</p>
<p>
simple trick works on this case:
</p>
<pre class="wiki">//oserializer.hpp
template<class Archive>
struct save_enum_type
{
template<unsigned char TypeSize>
struct same_sized_integral_type; // undefined
template<>
struct same_sized_integral_type<1>
{
typedef unsigned char type;
};
template<>
struct same_sized_integral_type<2>
{
typedef unsigned short type;
};
template<>
struct same_sized_integral_type<4>
{
typedef unsigned int type;
};
template<>
struct same_sized_integral_type<8>
{
typedef unsigned long long type;
};
template<class T>
static void invoke(Archive &ar, const T &t){
// convert enum to integers on save
const same_sized_integral_type<sizeof(T)>::type i =
static_cast<same_sized_integral_type<sizeof(T)>::type>(t);
ar << boost::serialization::make_nvp(NULL, i);
}
};
</pre>
TicketanonymousThu, 10 Apr 2014 08:06:33 GMT
<link>https://svn.boost.org/trac10/ticket/9843#comment:3 </link>
<guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9843#comment:3</guid>
<description>
<p>
ahh, I finally figured out... there were some extensions of mine. to enable ability to serialize of literals:
</p>
<pre class="wiki"> //interface_oarchive.hpp
template<class T>
Archive & operator<<(const T && t){
return *this->This() << t;
}
</pre><p>
it could be considered not a problem of 'original' boost.
</p>
</description>
<category>Ticket</category>
</item>
<item>
<dc:creator>anonymous</dc:creator>
<pubDate>Thu, 10 Apr 2014 08:37:16 GMT</pubDate>
<title/>
<link>https://svn.boost.org/trac10/ticket/9843#comment:4 </link>
<guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9843#comment:4</guid>
<description>
<p>
brought more straightfoward case:
</p>
<pre class="wiki"> enum class PacketCode : unsigned char
{
Something,
};
PacketCode packetcode;
//no exception
std::istringstream stream(std::string(4, 0));
binary_iarchive archive(stream, boost::archive::no_header);
archive >> packetcode;
//exception. it tries to read 4 bytes
stream = std::istringstream(std::string(1, 0));
archive >> packetcode;
</pre>
</description>
<category>Ticket</category>
</item>
<item>
<dc:creator>Robert Ramey</dc:creator>
<pubDate>Fri, 11 Apr 2014 01:44:49 GMT</pubDate>
<title>status changed; resolution set
https://svn.boost.org/trac10/ticket/9843#comment:5
https://svn.boost.org/trac10/ticket/9843#comment:5
<ul>
<li><strong>status</strong>
<span class="trac-field-old">reopened</span> → <span class="trac-field-new">closed</span>
</li>
<li><strong>resolution</strong>
→ <span class="trac-field-new">invalid</span>
</li>
</ul>
<p>
Hmmm, I would really, really, really have to think about using move here. Basically this would permit serialization of temporary objects which opens a whole can of worms regarding tracking. I think would also have to consider that using move might change the object being serialized - which would make another problem.
</p>
<p>
Actually the usage of move semantics in the serialization library is likely an interesting question and could lead to better performance in some cases - e.g. collections.
</p>
<p>
But for now, I think we're done with this.
</p>
<p>
Robert Ramey
</p>
TicketanonymousMon, 14 Apr 2014 05:39:45 GMT
<link>https://svn.boost.org/trac10/ticket/9843#comment:6 </link>
<guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9843#comment:6</guid>
<description>
<p>
I would really sorry for the confusion caused by my comments 2,3. I coudn't find any way to delete comments.
</p>
<p>
But we should bring the original issue. The original one is that "boost binary archive does not consider of sized-enums. It treats all the enums as int-sized" as described in comment 4.
</p>
<p>
So it causes some problems:
</p>
<pre class="wiki">// from iserializer.hpp, load_enum_type<>::invoke<>(...):
int i;
ar >> boost::serialization::make_nvp(NULL, i); // loads as "int"
t = static_cast< T >(i); // convert it to "enum type"
</pre><p>
When T is such
</p>
<pre class="wiki">enum class PacketCode : unsigned char
{
Something,
};
</pre><p>
Again, I sorry for bothering you.
</p>
</description>
<category>Ticket</category>
</item>
<item>
<dc:creator>anonymous</dc:creator>
<pubDate>Mon, 14 Apr 2014 05:39:59 GMT</pubDate>
<title>status changed; resolution deleted
https://svn.boost.org/trac10/ticket/9843#comment:7
https://svn.boost.org/trac10/ticket/9843#comment:7
<ul>
<li><strong>status</strong>
<span class="trac-field-old">closed</span> → <span class="trac-field-new">reopened</span>
</li>
<li><strong>resolution</strong>
<span class="trac-field-deleted">invalid</span>
</li>
</ul>
TicketRobert RameyMon, 14 Apr 2014 05:59:39 GMT
<link>https://svn.boost.org/trac10/ticket/9843#comment:8 </link>
<guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9843#comment:8</guid>
<description>
<p>
OK - I see the problem now.
</p>
<pre class="wiki">// works
enum class PacketCode {
Something,
};
// doesn't work
enum class PacketCode : unsigned char
{
Something,
};
</pre><p>
But I can't see where the problem is since the load and save functions both confer to/from integers the serialization should be in sync. Your original complaint says that it's saving one byte and reading back 4. The file oserializer.hpp contains:
</p>
<pre class="wiki">template<class Archive>
struct save_enum_type
{
template<class T>
static void invoke(Archive &ar, const T &t){
// convert enum to integers on save
const int i = static_cast<int>(t);
ar << boost::serialization::make_nvp(NULL, i);
}
};
</pre><p>
I'm guessing I did this because the streams didn't accept an enum. If you would like, you can make a test case similar to the ones in the test suite and submit a patch. I'd be willing to consider it.
</p>
<p>
Robert Ramey
</p>
</description>
<category>Ticket</category>
</item>
</channel>
</rss>