{"id":377,"date":"2016-01-06T01:55:44","date_gmt":"2016-01-06T09:55:44","guid":{"rendered":"http:\/\/www.teamfizzgames.com\/Matt\/?p=377"},"modified":"2016-01-06T02:01:56","modified_gmt":"2016-01-06T10:01:56","slug":"oh-hey-there-the-return-also-i-do-things-with-templates-and-bitfields-that-may-or-may-not-be-dumb","status":"publish","type":"post","link":"https:\/\/www.teamfizzgames.com\/Matt\/oh-hey-there-the-return-also-i-do-things-with-templates-and-bitfields-that-may-or-may-not-be-dumb\/","title":{"rendered":"Oh, Hey There: The Return (Also, I Do Things With Templates And Bitfields That May Or May Not Be Dumb)"},"content":{"rendered":"<p>Going long periods between blog posts has always been fairly par for the course for me, but this last break\u00a0was pretty excessive even by my standards. \u00a0Two years is really just too long! \u00a0Of course, shortly after that last post I ended up getting a job at 343 Industries (which is, incidentally, amazing!) and I can&#8217;t really blog about what I do at work, which lead to said\u00a0hiatus. \u00a0What are you going to do? \u00a0Go two years between blog posts, apparently.<\/p>\n<p>Anyway, the last two years have predominantly been writing HLSL, and that&#8217;s been great and I love my job, but recently I&#8217;ve been starting to worry that my C++ is getting rusty. \u00a0Can&#8217;t let that happen, how would I feel superior to other programmers if I&#8217;m not pro at C++? \u00a0Right? \u00a0Right! \u00a0So, with Halo 5 shipped I&#8217;ve had a little more free time and a thought occurred to me that got me jump started back into writing some &#8220;real&#8221; code. \u00a0It&#8217;s a little bit of utility around a bitfield class, and I think that it&#8217;s useful, but I also couldn&#8217;t find any real reference to anyone else having done it. \u00a0That either means that I&#8217;m an absolute genius or there are very legitimate reasons why no one does what I&#8217;m about to show\u00a0and I&#8217;m just not seeing them. \u00a0Which feels pretty likely, but you tell me!<\/p>\n<p>So, I started with a bitfield class that just used an unsigned int as storage and had pretty basic bit\u00a0and bulk getters and setters. \u00a0Nothing super fancy, but effective for what I was doing with it. \u00a0The next logical step was to template the storage type, and that was easy, which gave me the following code.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\ntemplate &lt;typename t_field&gt;\r\nclass Bitflag\r\n{\r\npublic:\r\n  \/\/Default Constructor\r\n  Bitflag() : m_flags(0) {}\r\n\r\n  \/\/Initial Value Constructor\r\n  Bitflag(t_field pFlags) : m_flags(pFlags) {}\r\n\r\n  \/\/Bit Get\r\n  bool Get(t_field pIndex) const {\r\n    return ((m_flags &amp; pIndex) == 0) ? false : true;\r\n  }\r\n\r\n  \/\/Bulk Get\r\n  t_field Get() const {\r\n    return m_flags;\r\n  }\r\n\r\n  \/\/Bit Set\r\n  void Set(t_field pIndex, bool pState) {\r\n    \/\/ Optimized based on information found at \r\n    \/\/ https:\/\/graphics.stanford.edu\/~seander\/bithacks.html#ConditionalSetOrClearBitsWithoutBranching\r\n    \/\/ Safe to squelch this warning\r\n\r\n    #pragma warning(push)\r\n    #pragma warning(disable : 4804)\r\n\r\n    m_flags = (m_flags &amp; ~pIndex) | (-pState &amp; pIndex);\r\n\r\n    #pragma warning(pop)\r\n  }\r\n\r\n  \/\/Bulk Set\r\n  void Set(t_field pFlags) {\r\n    m_flags = pFlags;\r\n  }\r\nprivate:\r\n  t_field   m_flags;\r\n};\r\n<\/pre>\n<p>And for the purpose of what I&#8217;m actually blogging about, the Bitflag class never actually gets any fancier or more complicated. \u00a0Instead, I looked at what I had, and I realized that rather than really using the flexibility of the templated type to optimize storage size for the class, I just got lazy and slapped every usage with unsigned int. \u00a0Which just took me back to where I was before I even templated the class. \u00a0The hell, right? \u00a0This lead me to the question, &#8220;Could I write code that, given the size of the flag set I want to be able to store in a Bitflag, would always set the templated type to the smallest appropriate type?&#8221; \u00a0And if the answer was yes, then it could serve a few purposes; actually optimize my storage size, automatically change if necessary as the size of the represented flag set changed, automatically change if necessary as I compiled on other platforms where storage sizes might be different. \u00a0That sounded great, so I dove into it, and it turns out that the answer is indeed yes.<\/p>\n<p>I&#8217;ll start with the code that I ended up writing, and then I&#8217;ll explain what it&#8217;s doing, why I had it do that, and where it might go next.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#define BITFLAG_SIZE(val) BitflagHelpers::bitflag_type_selector&lt;val&gt;::value_type\r\n\r\nnamespace BitflagHelpers\r\n{\r\n  static const int g_bits_per_byte        = 8;\r\n\r\n  static const int g_undefined_ushort     = -1;\r\n  static const int g_undefined_uint       = -2;\r\n  static const int g_undefined_ulong      = -3;\r\n  static const int g_undefined_ulonglong  = -4;\r\n\r\n  template &lt;int t&gt;\r\n  struct bitflag_type\r\n  {\r\n    typedef int type;\r\n  };\r\n\r\n  \/\/ Be careful with this case when it comes to serialization\r\n  template &lt;&gt;\r\n  struct bitflag_type&lt;sizeof(unsigned char) * g_bits_per_byte&gt;\r\n  {\r\n    typedef unsigned char type;\r\n  };\r\n\r\n  \/\/ We protect from doubled specialization in the case that a type is \r\n  \/\/ the same size as the previous type by setting that instantiation \r\n  \/\/ to a negative global value.  Remove the warning for specing a \r\n  \/\/ signed value into an unsigned type.  Do something better later?\r\n  #pragma warning(push)\r\n  #pragma warning(disable : 4309)\r\n\r\n  template &lt;&gt;\r\n  struct bitflag_type&lt;(sizeof(unsigned short) != sizeof(unsigned char)) \r\n    ? (sizeof(unsigned short) * g_bits_per_byte) : (g_undefined_ushort)&gt;\r\n  {\r\n    typedef unsigned short type;\r\n  };\r\n\r\n  template &lt;&gt;\r\n  struct bitflag_type&lt;(sizeof(unsigned int) != sizeof(unsigned short))\r\n    ? (sizeof(unsigned int) * g_bits_per_byte) : (g_undefined_uint)&gt;\r\n  {\r\n    typedef unsigned int type;\r\n  };\r\n\r\n  template &lt;&gt;\r\n  struct bitflag_type&lt;(sizeof(unsigned long) != sizeof(unsigned int))\r\n    ? (sizeof(unsigned long) * g_bits_per_byte) : (g_undefined_ulong)&gt;\r\n  {\r\n    typedef unsigned long type;\r\n  };\r\n\r\n  template &lt;&gt;\r\n  struct bitflag_type&lt;(sizeof(unsigned long long) != sizeof(unsigned long))\r\n    ? (sizeof(unsigned long long) * g_bits_per_byte) : (g_undefined_ulonglong)&gt;\r\n  {\r\n    typedef unsigned long long type;\r\n  };\r\n\r\n  #pragma warning(pop)\r\n\r\n  template &lt;int t&gt;\r\n  struct bitflag_type_selector\r\n  {\r\n    typedef \r\n      typename std::conditional&lt;(t &lt;= sizeof(unsigned char) * g_bits_per_byte), \r\n        bitflag_type&lt;sizeof(unsigned char) * g_bits_per_byte&gt;::type,\r\n      typename std::conditional&lt;(t &lt;= sizeof(unsigned short) * g_bits_per_byte), \r\n        bitflag_type&lt;sizeof(unsigned short) * g_bits_per_byte&gt;::type,\r\n      typename std::conditional&lt;(t &lt;= sizeof(unsigned int) * g_bits_per_byte), \r\n        bitflag_type&lt;sizeof(unsigned int) * g_bits_per_byte&gt;::type,\r\n      typename std::conditional&lt;(t &lt;= sizeof(unsigned long) * g_bits_per_byte), \r\n        bitflag_type&lt;sizeof(unsigned long) * g_bits_per_byte&gt;::type,\r\n      bitflag_type&lt;sizeof(unsigned long long) * g_bits_per_byte&gt;::type&gt;::type&gt;::type&gt;::type&gt;::type value_type;\r\n  };\r\n}\r\n<\/pre>\n<p>So, the idea is that when you have a Bitflag variable, rather than specifying a type, you give it the BITFLAG_SIZE macro with the size of the flag set you want to be able to store. \u00a0So, instead of something like Bitflag&lt;unsigned int&gt; flags, you&#8217;d write\u00a0something like Bitflag&lt;BITFLAG_SIZE(28)&gt; flags. \u00a0Under the hood, the macro uses a set of templates that take advantage of the C\/C++ language standard that doesn&#8217;t define specific sizes for unsigned integral types, just relations; it says that unsigned char &lt;= unsigned short &lt;= unsigned int &lt;= unsigned long &lt;= unsigned long long. \u00a0Everything else works because of those relationships.<\/p>\n<p>The bitflag_type specializations all check to make sure that any two adjacent types don&#8217;t have the same size, and set the specialization to a special value in that case to prevent double specialization, which would cause a compile failure. \u00a0In the case of Win64, unsigned int and unsigned long are both 32 bits, so the unsigned long spec ends up being -3 instead of 32. \u00a0And then it never gets used as a result, which is perfectly fine.<\/p>\n<p>The final piece was the bitflag_type_selector, which makes use of std::conditional to allow the template specializations to be assigned to ranges. \u00a0Without that, it&#8217;d be pretty tedious to write all the code that&#8217;d allow anything but exact size matches to the types to be paired to the proper specialization of bitflag_type. \u00a0So, yay for std::conditional!<\/p>\n<p>One thing to watch out for here is data serialization for a Bitflag that&#8217;s using an unsigned char for its storage. \u00a0Take the case of a flag mask of 33. \u00a0That will get serialized as 33 by any basic serialization scheme for an unsigned short, unsigned int, unsigned long, or unsigned long long, which is great. \u00a0But, for an unsigned char, it will see 3 and 3, which probably isn&#8217;t what you wanted. \u00a0It&#8217;s solvable for sure, but I feel it&#8217;s worth mentioning. \u00a0I did look\u00a0into using\u00a0uint8_t, but it turns out that this is very implementation specific, and a lot of implementations are just typedef&#8217;s of unsigned char anyway.<\/p>\n<p>While not a requirement of this setup by any means, I like to store my flag sets in enumerations. \u00a0So, for me, the next step was to be able to feed the enumeration into the BITFLAG_SIZE macro and always get the right size. \u00a0I ended up doing that (with more templates), and that will be the subject of the next blog post. \u00a0One that hopefully comes sooner than this one did! \u00a0I guess we&#8217;ll see, I tend to have a problem keeping up with my desired posting schedule.<\/p>\n<p>But that is the end of this post. \u00a0Hopefully you found this useful, and hopefully I&#8217;m not insane and\/or stupid. \u00a0I welcome any feedback, and you are certainly welcome to use the code provided in whatever project you want. \u00a0If you do, I&#8217;d love to know about it! \u00a0Here&#8217;s the file if you just want to download it instead of copy\/pasting the various blocks I posted above: <a href=\"http:\/\/www.teamfizzgames.com\/Matt\/download\/codesamples\/BitFlag.hpp\" target=\"_blank\">Bitflag.hpp<\/a>.<\/p>\n<p>I&#8217;d also like to thank Brennan Conroy and Robert Francis for dealing with a full day of my inane ramblings and providing useful insight while I worked on this. \u00a0I probably wouldn&#8217;t be making this post if it wasn&#8217;t for their help.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Going long periods between blog posts has always been fairly par for the course for me, but this last break\u00a0was pretty excessive even by my standards. \u00a0Two years is really just too long! \u00a0Of course, shortly after that last post I ended up getting a job at 343 Industries (which \u2026 <a class=\"continue-reading-link\" href=\"https:\/\/www.teamfizzgames.com\/Matt\/oh-hey-there-the-return-also-i-do-things-with-templates-and-bitfields-that-may-or-may-not-be-dumb\/\"> Continue reading <span class=\"meta-nav\">&rarr; <\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[6],"tags":[27,28],"class_list":["post-377","post","type-post","status-publish","format-standard","hentry","category-nongraphicsdevelopment","tag-bitfield","tag-templates"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p39ImV-65","_links":{"self":[{"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/posts\/377","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/comments?post=377"}],"version-history":[{"count":13,"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/posts\/377\/revisions"}],"predecessor-version":[{"id":390,"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/posts\/377\/revisions\/390"}],"wp:attachment":[{"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/media?parent=377"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/categories?post=377"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.teamfizzgames.com\/Matt\/wp-json\/wp\/v2\/tags?post=377"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}