SDSL: Succinct Data Structure Library
A C++ template library for succinct data structures
 All Classes Namespaces Files Functions Variables Typedefs Friends
sdsl/include/sdsl/uint256_t.hpp
Go to the documentation of this file.
00001 /* sdsl - succinct data structures library
00002     Copyright (C) 2012 Simon Gog
00003 
00004     This program is free software: you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation, either version 3 of the License, or
00007     (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program.  If not, see http://www.gnu.org/licenses/ .
00016 */
00021 #ifndef INCLUDED_SDSL_UINT256
00022 #define INCLUDED_SDSL_UINT256
00023 
00024 #include <iostream>
00025 #include "bitmagic.hpp"
00026 #include "uint128_t.hpp"
00027 
00028 namespace sdsl
00029 {
00030 
00031 class uint256_t
00032 {
00033     public:
00034         friend std::ostream& operator << (std::ostream&, const uint256_t&);
00035     private:
00036         uint64_t m_lo;
00037         uint64_t m_mid;
00038         uint128_t m_high;
00039 
00040     public:
00041         uint256_t(uint64_t lo=0, uint64_t mid=0,
00042                   uint128_t high=0):m_lo(lo),
00043             m_mid(mid),
00044             m_high(high) {}
00045 
00046         uint256_t(const uint256_t& x):m_lo(x.m_lo), m_mid(x.m_mid), m_high(x.m_high) {}
00047 
00048         uint16_t popcount() {
00049             return ((uint16_t)bit_magic::b1Cnt(m_lo)) + bit_magic::b1Cnt(m_mid)
00050                    + bit_magic::b1Cnt(m_high>>64) + bit_magic::b1Cnt(m_high);
00051         }
00052 
00053         uint16_t l1BP() {
00054             if (m_high == 0) {
00055                 if (m_mid) {
00056                     return bit_magic::l1BP(m_mid) + 64;
00057                 } else {
00058                     return bit_magic::l1BP(m_lo);
00059                 }
00060             } else {
00061                 uint64_t hh = (m_high >> 64);
00062                 if (hh) {
00063                     return bit_magic::l1BP(hh) + 192;
00064                 } else {
00065                     return bit_magic::l1BP(m_high) + 128;
00066                 }
00067             }
00068         }
00069 
00070         uint16_t select(uint32_t i) {
00071             uint16_t x = 0;
00072             if ((x=bit_magic::b1Cnt(m_lo)) >= i) {
00073                 return bit_magic::i1BP(m_lo, i);
00074             }
00075             i -= x;
00076             if ((x=bit_magic::b1Cnt(m_mid)) >= i) {
00077                 return bit_magic::i1BP(m_mid, i) + 64;
00078             }
00079             i -= x;
00080             uint64_t hh = m_high >> 64;
00081             uint64_t lh = m_high;
00082             if ((x=bit_magic::b1Cnt(lh)) >= i) {
00083                 return bit_magic::i1BP(lh, i) + 128;
00084             }
00085             i -= x;
00086             return bit_magic::i1BP(hh, i) + 192;
00087         }
00088 
00089         uint256_t& operator+=(const uint256_t& x) {
00090             uint128_t lo = (uint128_t)m_lo + x.m_lo;
00091             uint128_t mid = (uint128_t)m_mid + x.m_mid + (lo >> 64);
00092             m_lo = lo; m_mid = mid;
00093             m_high += x.m_high + (mid >> 64);
00094             return *this;
00095 //                      return uint256_t(lo, mid, m_high + x.m_high + (mid >> 64));
00096         }
00097 
00098         uint256_t operator+(uint256_t x) {
00099             uint128_t lo = (uint128_t)m_lo + x.m_lo;
00100             uint128_t mid = (uint128_t)m_mid + x.m_mid + (lo >> 64);
00101             return uint256_t(lo, mid, m_high + x.m_high + (mid >> 64));
00102         }
00103 
00104         uint256_t operator-(uint256_t x) {
00105 //                      add two's complement of x
00106             uint128_t lo = (uint128_t)m_lo + (~x.m_lo) + 1;
00107             uint128_t mid = (uint128_t)m_mid + (~x.m_mid) + (lo >> 64);
00108             return uint256_t(lo, mid, m_high + (~x.m_high) + (mid >> 64));
00109         }
00110 
00111         uint256_t& operator-=(const uint256_t& x) {
00112 //                      add two's complement of x
00113             uint128_t lo = (uint128_t)m_lo + (~x.m_lo) + 1;
00114             uint128_t mid = (uint128_t)m_mid + (~x.m_mid) + (lo >> 64);
00115             m_lo = lo;
00116             m_mid = mid;
00117             m_high += (~x.m_high) + (mid >> 64);
00118             return *this;
00119         }
00120 
00121 
00122         uint256_t operator|(const uint256_t& x) {
00123             return uint256_t(m_lo|x.m_lo, m_mid|x.m_mid, m_high|x.m_high);
00124         }
00125 
00126         uint256_t& operator|=(const uint256_t& x) {
00127             m_lo |= x.m_lo; m_mid |= x.m_mid; m_high |= x.m_high;
00128             return *this;
00129         }
00130 
00131         uint256_t operator&(const uint256_t& x) {
00132             return uint256_t(m_lo&x.m_lo, m_mid&x.m_mid, m_high&x.m_high);
00133         }
00134         /* // is not needed since we can convert uint256_t to uint64_t
00135                         uint64_t operator&(uint64_t x){
00136                                 return m_lo & x;
00137                         }
00138         */
00139 
00140         uint256_t operator<<(int x) {
00141             if (x < 128) {
00142                 uint128_t high = m_high << x;
00143                 uint128_t low  = (((uint128_t)m_mid<<64) | m_lo);
00144                 high |= (low >> (128-x));
00145                 low = low << x;
00146                 return uint256_t(low, low>>64, high);
00147             } else { // x >= 128
00148                 uint128_t high = (((uint128_t)m_mid<<64) | m_lo) << (x-128); // TODO: check x==128
00149                 return uint256_t(0, 0, high);
00150             }
00151         }
00152 
00153         uint256_t operator>>(int x) {
00154             if (x < 128) {
00155                 uint128_t low  = (((uint128_t)m_mid<<64) | m_lo) >> x;
00156                 low |= ((m_high << (127-x))<<1);
00157                 return uint256_t(low, low>>64, m_high>>x);
00158             } else { // x >= 128
00159                 uint128_t low = (m_high >> (x-128)); // TODO: check x=128
00160                 return uint256_t(low, low>>64, 0);
00161             }
00162         }
00163 
00164         uint256_t& operator=(const uint64_t& x) {
00165             m_high = 0;
00166             m_mid = 0;
00167             m_lo = x;
00168             return *this;
00169         }
00170 
00171         bool operator==(const uint256_t& x) const {
00172             return (m_lo == x.m_lo) and (m_mid == x.m_mid) and (m_high == x.m_high);
00173         }
00174 
00175         bool operator!=(const uint256_t& x) const {
00176             return !(*this == x);
00177         }
00178 
00179         bool operator>=(const uint256_t& x) const {
00180             if (m_high != x.m_high) {
00181                 return m_high > x.m_high;
00182             }
00183             if (m_mid != x.m_mid) {
00184                 return m_mid > x.m_mid;
00185             } else {
00186                 return m_lo >= x.m_lo;
00187             }
00188         }
00189 
00190         bool operator<=(const uint256_t& x) const {
00191             if (m_high != x.m_high) {
00192                 return m_high < x.m_high;
00193             }
00194             if (m_mid != x.m_mid) {
00195                 return m_mid < x.m_mid;
00196             } else {
00197                 return m_lo <= x.m_lo;
00198             }
00199         }
00200 
00201         bool operator>(const uint256_t& x) const {
00202             if (m_high != x.m_high) {
00203                 return m_high > x.m_high;
00204             }
00205             if (m_mid != x.m_mid) {
00206                 return m_mid > x.m_mid;
00207             } else {
00208                 return m_lo > x.m_lo;
00209             }
00210         }
00211 
00212         bool operator>(const uint64_t& x) const {
00213             if (m_high > 0 or m_mid > 0) {
00214                 return true;
00215             }
00216             return m_lo > x;
00217         }
00218 
00219         bool operator<(const uint256_t& x) const {
00220             if (m_high != x.m_high) {
00221                 return m_high < x.m_high;
00222             }
00223             if (m_mid != x.m_mid) {
00224                 return m_mid < x.m_mid;
00225             } else {
00226                 return m_lo < x.m_lo;
00227             }
00228         }
00229 
00230         operator uint64_t() {
00231             return m_lo;
00232         }
00233 };
00234 
00235 std::ostream& operator<<(std::ostream& os, const uint256_t& x)
00236 {
00237     uint64_t X[4] = {(uint64_t)(x.m_high >> 64), (uint64_t)x.m_high, x.m_mid, x.m_lo};
00238     for (int j=0; j < 4; ++j) {
00239         for (int i=0; i < 16; ++i) {
00240             os << std::hex << ((X[j]>>60)&0xFULL) << std::dec;
00241             X[j] <<= 4;
00242         }
00243     }
00244     return os;
00245 }
00246 
00247 } // end namespace
00248 
00249 #endif