bin_log.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 __BIN_LOG_HH
00018 # define __BIN_LOG_HH
00019 
00020 # include "bin_pow.hh"
00021 # include "static_bin_log.hh"
00022 # include <type_traits>
00023 
00024 namespace fast {
00025 
00026   template <typename integral_type, int N>
00027   struct bin_log_helper {
00028     enum: integral_type {
00029       shift = 1 << (N-1),
00030       pattern = ((integral_type)bin_pow_pow<integral_type, N>::value-1)
00031       << shift
00032     };
00033     static void step(integral_type& v, integral_type& r) {
00034       if (v & pattern) {
00035         v >>= shift;
00036         r |= shift;
00037       }
00038       bin_log_helper<integral_type, N-1>::step(v, r);
00039     }
00040   };
00041 
00042   template <typename integral_type>
00043   struct bin_log_helper<integral_type, 0> {
00044     static void step(integral_type&, integral_type&) {
00045     }
00046   };
00047 
00048   template <typename integral_type>
00049   integral_type bin_log(integral_type v) {
00050     static_assert(std::is_integral<integral_type>::value,
00051                   "Cannot use non integral types.");
00052     static_assert(sizeof(integral_type) ==
00053                   1<< static_bin_log<integral_type,
00054                                      sizeof(integral_type)>::value,
00055                   "Type size is not a power of two.");
00056 
00057     integral_type r = 0;
00058     bin_log_helper<integral_type,
00059                    static_bin_log<integral_type,
00060                    sizeof(integral_type)<<3>::value>::step(v, r);
00061     return r;
00062   }
00063 
00064 }
00065 
00066 #endif