invert_bits.hh

00001 // This file is a part of Aurelia.
00002 // Copyright (C) 2010  Valentin David
00003 // Copyright (C) 2010  University of Bergen
00004 //
00005 // This program is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 #ifndef __INVERT_BITS_HH
00018 # define __INVERT_BITS_HH
00019 
00020 # include "bin_pow.hh"
00021 # include "static_bin_log.hh"
00022 # include <type_traits>
00023 
00024 namespace fast {
00025   template <typename integral_type, int size, int width, integral_type pattern>
00026   struct repeat_pattern_recurse {
00027     enum: integral_type {
00028       value = (integral_type)repeat_pattern_recurse<integral_type,
00029                                                     size,
00030                                                     2*width,
00031                                                     pattern |
00032                                                     (pattern << width)>::value
00033     };
00034   };
00035 
00036   template <typename integral_type, int size, integral_type pattern>
00037   struct repeat_pattern_recurse<integral_type, size, size, pattern> {
00038     enum: integral_type { value = pattern };
00039   };
00040 
00041   template <typename integral_type, int width, integral_type pattern>
00042   struct repeat_pattern:
00043     public repeat_pattern_recurse<integral_type, sizeof(integral_type)<<3,
00044                                   width, pattern>
00045   {};
00046 
00047   template <typename integral_type, int N>
00048   struct inversion_helper {
00049     enum: integral_type
00050       { shift = 1 << (N-1),
00051         smallpattern = ((integral_type)bin_pow_pow<integral_type, N>::value-1)
00052         << shift,
00053         pattern = repeat_pattern<integral_type, 2*shift, smallpattern>::value
00054       };
00055     static void step(integral_type& v) {
00056       integral_type l = v << shift;
00057       v >>= shift;
00058       v = (l & pattern)
00059         | (v & (pattern >> shift));
00060       inversion_helper<integral_type, N-1>::step(v);
00061     }
00062   };
00063 
00064   template <typename integral_type>
00065   struct inversion_helper<integral_type, 0> {
00066     static void step(integral_type&) {}
00067   };
00068 
00069   template <typename integral_type>
00070   inline void invert_bits(integral_type& v) {
00071     static_assert(std::is_integral<integral_type>::value,
00072                   "Cannot invert bits on non integral types.");
00073     static_assert(sizeof(integral_type) ==
00074                   1<< static_bin_log<integral_type,
00075                                      sizeof(integral_type)>::value,
00076                   "Type size is not a power of two.");
00077 
00078     inversion_helper<integral_type,
00079                      static_bin_log<integral_type,
00080                                     sizeof(integral_type)<<3>::value>::step(v);
00081   }
00082 }
00083 
00084 #endif