Boost C++ Libraries: Ticket #12736: crc table init at compile time https://svn.boost.org/trac10/ticket/12736 <p> struct crc_table_t should try to use constexpr constructor for table_ initialization. this will allow to move table_ to readonly data segment and remove table initialization code. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12736 Trac 1.4.3 anonymous Mon, 09 Jan 2017 14:20:03 GMT <link>https://svn.boost.org/trac10/ticket/12736#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12736#comment:1</guid> <description> <p> ... remove <strong>runtime</strong> table initialization code </p> </description> <category>Ticket</category> </item> <item> <dc:creator>zh</dc:creator> <pubDate>Wed, 08 Nov 2017 02:48:35 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12736#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12736#comment:2</guid> <description> <p> <a class="ext-link" href="https://github.com/hhggit/crc/commit/69910bbdb2cc43841bf33df3eebd22ca0b088e39"><span class="icon">​</span>https://github.com/hhggit/crc/commit/69910bbdb2cc43841bf33df3eebd22ca0b088e39</a> </p> <pre class="wiki">diff --git a/include/boost/crc.hpp b/include/boost/crc.hpp old mode 100644 new mode 100755 index 6be5aa1..43bb819 --- a/include/boost/crc.hpp +++ b/include/boost/crc.hpp @@ -17,6 +17,9 @@ #include &lt;boost/limits.hpp&gt; // for std::numeric_limits +#if __cplusplus &gt;= 201402L +#include &lt;utility&gt; +#endif // The type of CRC parameters that can go in a template should be related // on the CRC's bit count. This macro expresses that type in a compact @@ -299,13 +302,13 @@ namespace detail { typedef typename boost::uint_t&lt;Bits&gt;::fast value_type; - static value_type reflect( value_type x ); + BOOST_CXX14_CONSTEXPR static value_type reflect( value_type x ); }; // boost::detail::reflector // Function that reflects its argument template &lt; std::size_t Bits &gt; - typename reflector&lt;Bits&gt;::value_type + BOOST_CXX14_CONSTEXPR typename reflector&lt;Bits&gt;::value_type reflector&lt;Bits&gt;::reflect ( typename reflector&lt;Bits&gt;::value_type x @@ -347,7 +350,7 @@ namespace detail #if defined(__EDG_VERSION__) &amp;&amp; __EDG_VERSION__ &lt;= 243 static const least sig_bits = (~( ~( 0ul ) &lt;&lt; Bits )) ; #else - BOOST_STATIC_CONSTANT( least, sig_bits = (~( ~(least( 0u )) &lt;&lt; Bits )) ); + BOOST_STATIC_CONSTANT( least, sig_bits = least(~( least(~(least( 0u ))) &lt;&lt; Bits )) ); #endif #if defined(__GNUC__) &amp;&amp; __GNUC__ == 4 &amp;&amp; __GNUC_MINOR__ == 0 &amp;&amp; __GNUC_PATCHLEVEL__ == 2 // Work around a weird bug that ICEs the compiler in build_c_cast @@ -451,6 +454,56 @@ namespace detail }; // boost::detail::mask_uint_t #endif +#if __cplusplus &gt;= 201402L + template &lt;std::size_t Bits, BOOST_CRC_PARM_TYPE TruncPoly, bool Reflect, typename value_type, typename masking_type&gt; + constexpr static value_type calc_table(unsigned char dividend) { + // factor-out constants to avoid recalculation + value_type const fast_hi_bit = masking_type::high_bit_fast; + unsigned char const byte_hi_bit = 1u &lt;&lt; (CHAR_BIT - 1u); + value_type remainder = 0; + + // go through all the dividend's bits + for ( unsigned char mask = byte_hi_bit; mask; mask &gt;&gt;= 1 ) + { + // check if divisor fits + if ( crc_helper&lt;CHAR_BIT, Reflect&gt;::reflect(dividend) &amp; mask ) + { + remainder ^= fast_hi_bit; + } + + // do polynominal division + if ( remainder &amp; fast_hi_bit ) + { + remainder &lt;&lt;= 1; + remainder ^= TruncPoly; + } + else + { + remainder &lt;&lt;= 1; + } + } + + return crc_helper&lt;Bits, Reflect&gt;::reflect( remainder ); + } + + template &lt;std::size_t Bits, BOOST_CRC_PARM_TYPE TruncPoly, bool Reflect, typename Table &gt; + struct crc_table_generator { + typedef mask_uint_t&lt;Bits&gt; masking_type; + typedef typename masking_type::fast value_type; + + Table table_; + + constexpr value_type operator[](int i) const {return table_[i];} + + template&lt;typename T, T...Is&gt; + constexpr crc_table_generator(std::integer_sequence&lt;T, Is...&gt;) + : table_{(calc_table&lt;Bits, TruncPoly, Reflect, value_type, masking_type&gt;(Is))...} + {} + constexpr crc_table_generator() + : crc_table_generator(std::make_index_sequence&lt;sizeof(Table)/sizeof(value_type)&gt;()) + {} + }; +#endif // CRC table generator template &lt; std::size_t Bits, BOOST_CRC_PARM_TYPE TruncPoly, bool Reflect &gt; @@ -472,12 +525,22 @@ namespace detail typedef value_type table_type[ byte_combos ]; #endif - static void init_table(); +#if __cplusplus &gt;= 201402L + typedef crc_table_generator&lt;Bits, TruncPoly, Reflect, table_type&gt; generator_type; + constexpr static generator_type table_{}; +#else + static void init_table(); - static table_type table_; + static table_type table_; +#endif }; // boost::detail::crc_table_t +#if __cplusplus &gt;= 201402L + template &lt; std::size_t Bits, BOOST_CRC_PARM_TYPE TruncPoly, bool Reflect &gt; + constexpr typename crc_table_t&lt;Bits, TruncPoly, Reflect&gt;::generator_type + crc_table_t&lt;Bits, TruncPoly, Reflect&gt;::table_; +#else // CRC table generator static data member definition // (Some compilers [Borland C++] require the initializer to be present.) template &lt; std::size_t Bits, BOOST_CRC_PARM_TYPE TruncPoly, bool Reflect &gt; @@ -534,6 +597,7 @@ namespace detail did_init = true; } +#endif #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // Align the msb of the remainder to a byte @@ -570,7 +634,7 @@ namespace detail #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // Possibly reflect a remainder - static value_type reflect( value_type x ) + BOOST_CONSTEXPR static value_type reflect( value_type x ) { return detail::reflector&lt;Bits&gt;::reflect( x ); } // Compare a byte to the remainder's highest byte @@ -607,7 +671,7 @@ namespace detail typedef typename uint_t&lt;Bits&gt;::fast value_type; // Possibly reflect a remainder - static value_type reflect( value_type x ) + BOOST_CONSTEXPR static value_type reflect( value_type x ) { return x; } // Compare a byte to the remainder's highest byte @@ -839,7 +903,9 @@ BOOST_CRC_OPTIMAL_NAME::crc_optimal ) : rem_( helper_type::reflect(init_rem) ) { +#if __cplusplus &lt; 201402L crc_table_type::init_table(); +#endif } template &lt; std::size_t Bits, BOOST_CRC_PARM_TYPE TruncPoly, @@ -1059,8 +1125,9 @@ augmented_crc typename masking_type::fast rem = initial_remainder; byte_type const * const b = static_cast&lt;byte_type const *&gt;( buffer ); byte_type const * const e = b + byte_count; - +#if __cplusplus &lt; 201402L crc_table_type::init_table(); +#endif for ( byte_type const * p = b ; p &lt; e ; ++p ) { // Use the current top byte as the table index to the next </pre> </description> <category>Ticket</category> </item> </channel> </rss>