1 /*************************************************************************** 2 * foxxll/common/uint_types.hpp 3 * 4 * Class representing a 40-bit or 48-bit unsigned integer encoded in five or 5 * six bytes. 6 * 7 * Part of FOXXLL. See http://foxxll.org 8 * 9 * Copyright (C) 2013 Timo Bingmann <tb@panthema.net> 10 * 11 * Distributed under the Boost Software License, Version 1.0. 12 * (See accompanying file LICENSE_1_0.txt or copy at 13 * http://www.boost.org/LICENSE_1_0.txt) 14 **************************************************************************/ 15 16 #ifndef FOXXLL_COMMON_UINT_TYPES_HEADER 17 #define FOXXLL_COMMON_UINT_TYPES_HEADER 18 19 #include <cassert> 20 #include <limits> 21 #include <ostream> 22 23 #include <foxxll/common/types.hpp> 24 #include <foxxll/common/utils.hpp> 25 #include <foxxll/config.hpp> 26 27 #include <tlx/define/likely.hpp> 28 29 namespace foxxll { 30 31 /*! 32 * Construct an 40-bit or 48-bit unsigned integer stored in five or six bytes. 33 * 34 * The purpose of this class is to provide integers with smaller data storage 35 * footprints when more than 32-bit, but less than 64-bit indexes are 36 * needed. This is commonly the case for storing file offsets and indexes. Here 37 * smaller types currently suffice for files < 1 TiB or < 16 TiB. 38 * 39 * The class combines a 32-bit integer with a HighType (either 8-bit or 16-bit) 40 * to get a larger type. Only unsigned values are supported, which fits the 41 * general application of file offsets. 42 * 43 * Calculation in uint_pair are generally done by transforming everything to 44 * 64-bit data type, so that 64-bit register arithmetic can be used. The 45 * exception here is \b increment and \b decrement, which is done directly on 46 * the lower/higher part. Not all arithmetic operations are supported, patches 47 * welcome if you really need the operations. 48 */ 49 #if FOXXLL_MSVC 50 #pragma pack(push, 1) 51 #endif 52 template <typename HighType> 53 class uint_pair 54 { 55 public: 56 //! lower part type, always 32-bit 57 using low_type = uint32_t; 58 //! higher part type, currently either 8-bit or 16-bit 59 using high_type = HighType; 60 61 private: 62 //! member containing lower significant integer value 63 low_type low; 64 //! member containing higher significant integer value 65 high_type high; 66 67 //! return highest value storable in lower part, also used as a mask. low_max()68 static low_type low_max() 69 { 70 return std::numeric_limits<low_type>::max(); 71 } 72 73 //! number of bits in the lower integer part, used a bit shift value. 74 static const size_t low_bits = 8 * sizeof(low_type); 75 76 //! return highest value storable in higher part, also used as a mask. high_max()77 static high_type high_max() 78 { 79 return std::numeric_limits<high_type>::max(); 80 } 81 82 //! number of bits in the higher integer part, used a bit shift value. 83 static const size_t high_bits = 8 * sizeof(high_type); 84 85 public: 86 //! number of binary digits (bits) in uint_pair 87 static const size_t digits = low_bits + high_bits; 88 89 //! number of bytes in uint_pair 90 static const size_t bytes = sizeof(low_type) + sizeof(high_type); 91 92 //! empty constructor, does not even initialize to zero! uint_pair()93 uint_pair() 94 { 95 // compile-time assertions about size of low_type 96 static_assert( 97 8 * sizeof(low_type) == 32, 98 "8 * sizeof(low_type) == 32" 99 ); 100 // compile-time assertions about size of our data structure, this tests 101 // packing of structures by the compiler 102 static_assert( 103 sizeof(uint_pair) == bytes, 104 "sizeof(uint_pair) == bytes" 105 ); 106 static_assert( 107 sizeof(uint_pair) == digits / 8, 108 "sizeof(uint_pair) == digits / 8" 109 ); 110 static_assert(digits / 8 == bytes, "digits / 8 == bytes"); 111 } 112 113 //! construct unit pair from lower and higher parts. uint_pair(const low_type & l,const high_type & h)114 uint_pair(const low_type& l, const high_type& h) 115 : low(l), high(h) 116 { } 117 118 //! implicit conversion from a simple 32-bit unsigned integer uint_pair(const uint32_t & a)119 uint_pair(const uint32_t& a) // NOLINT 120 : low(a), high(0) 121 { } 122 123 //! implicit conversion from a simple 32-bit signed integer uint_pair(const int32_t & a)124 uint_pair(const int32_t& a) // NOLINT 125 : low(a), high(0) 126 { 127 if (a >= 0) 128 low = a; 129 else 130 low = a, high = high_max(); 131 } 132 133 //! implicit conversion from an uint64_t (unsigned long long) uint_pair(const uint64_t & a)134 uint_pair(const uint64_t& a) // NOLINT 135 : low(static_cast<low_type>(a & low_max())), 136 high(static_cast<high_type>((a >> low_bits) & high_max())) 137 { 138 // check for overflow 139 assert((a >> (low_bits + high_bits)) == 0); 140 } 141 142 //! return the number as an uint64_t (unsigned long long) ull() const143 uint64_t ull() const 144 { 145 return static_cast<uint64_t>(high) << low_bits | static_cast<uint64_t>(low); 146 } 147 148 //! implicit cast to an unsigned long long operator uint64_t() const149 operator uint64_t () const 150 { 151 return ull(); 152 } 153 154 //! return the number as a uint64_t u64() const155 uint64_t u64() const 156 { 157 return static_cast<uint64_t>(high) << low_bits | static_cast<uint64_t>(low); 158 } 159 160 //! prefix increment operator (directly manipulates the integer parts) operator ++()161 uint_pair& operator ++ () 162 { 163 if (TLX_UNLIKELY(low == low_max())) 164 ++high, low = 0; 165 else 166 ++low; 167 return *this; 168 } 169 170 //! prefix decrement operator (directly manipulates the integer parts) operator --()171 uint_pair& operator -- () 172 { 173 if (TLX_UNLIKELY(low == 0)) 174 --high, low = low_max(); 175 else 176 --low; 177 return *this; 178 } 179 180 //! addition operator (uses 64-bit arithmetic) operator +=(const uint_pair & b)181 uint_pair& operator += (const uint_pair& b) 182 { 183 uint64_t add = static_cast<uint64_t>(low) + b.low; 184 low = static_cast<low_type>(add & low_max()); 185 high = static_cast<high_type>(high + b.high + ((add >> low_bits) & high_max())); 186 return *this; 187 } 188 189 //! equality checking operator operator ==(const uint_pair & b) const190 bool operator == (const uint_pair& b) const 191 { 192 return (low == b.low) && (high == b.high); 193 } 194 195 //! inequality checking operator operator !=(const uint_pair & b) const196 bool operator != (const uint_pair& b) const 197 { 198 return (low != b.low) || (high != b.high); 199 } 200 201 //! less-than comparison operator operator <(const uint_pair & b) const202 bool operator < (const uint_pair& b) const 203 { 204 return (high < b.high) || (high == b.high && low < b.low); 205 } 206 207 //! less-or-equal comparison operator operator <=(const uint_pair & b) const208 bool operator <= (const uint_pair& b) const 209 { 210 return (high < b.high) || (high == b.high && low <= b.low); 211 } 212 213 //! greater comparison operator operator >(const uint_pair & b) const214 bool operator > (const uint_pair& b) const 215 { 216 return (high > b.high) || (high == b.high && low > b.low); 217 } 218 219 //! greater-or-equal comparison operator operator >=(const uint_pair & b) const220 bool operator >= (const uint_pair& b) const 221 { 222 return (high > b.high) || (high == b.high && low >= b.low); 223 } 224 225 //! make a uint_pair outputtable via iostreams, using unsigned long long. operator <<(std::ostream & os,const uint_pair & a)226 friend std::ostream& operator << (std::ostream& os, const uint_pair& a) 227 { 228 return os << a.ull(); 229 } 230 231 //! return an uint_pair instance containing the smallest value possible min()232 static uint_pair min() 233 { 234 return uint_pair( 235 std::numeric_limits<low_type>::min(), 236 std::numeric_limits<high_type>::min() 237 ); 238 } 239 240 //! return an uint_pair instance containing the largest value possible max()241 static uint_pair max() 242 { 243 return uint_pair( 244 std::numeric_limits<low_type>::max(), 245 std::numeric_limits<high_type>::max() 246 ); 247 } 248 } 249 #if FOXXLL_MSVC 250 ; // NOLINT 251 #pragma pack(pop) 252 #else 253 __attribute__ ((packed)); // NOLINT 254 #endif 255 256 //! \addtogroup foxxll_support 257 //! \{ 258 259 //! Construct a 40-bit unsigned integer stored in five bytes. 260 using uint40 = uint_pair<uint8_t>; 261 262 //! Construct a 48-bit unsigned integer stored in six bytes. 263 using uint48 = uint_pair<uint16_t>; 264 265 //! \} 266 267 } // namespace foxxll 268 269 namespace std { 270 271 //! template class providing some numeric_limits fields for uint_pair types. 272 template <typename HighType> 273 class numeric_limits<foxxll::uint_pair<HighType> > 274 { 275 public: 276 //! yes we have information about uint_pair 277 static const bool is_specialized = true; 278 279 //! return an uint_pair instance containing the smallest value possible min()280 static foxxll::uint_pair<HighType> min() 281 { return foxxll::uint_pair<HighType>::min(); } 282 283 //! return an uint_pair instance containing the largest value possible max()284 static foxxll::uint_pair<HighType> max() 285 { return foxxll::uint_pair<HighType>::max(); } 286 287 //! return an uint_pair instance containing the smallest value possible lowest()288 static foxxll::uint_pair<HighType> lowest() 289 { return min(); } 290 291 //! unit_pair types are unsigned 292 static const bool is_signed = false; 293 294 //! uint_pair types are integers 295 static const bool is_integer = true; 296 297 //! unit_pair types contain exact integers 298 static const bool is_exact = true; 299 300 //! unit_pair radix is binary 301 static const int radix = 2; 302 303 //! number of binary digits (bits) in uint_pair 304 static const int digits = foxxll::uint_pair<HighType>::digits; 305 306 //! epsilon is zero epsilon()307 static const foxxll::uint_pair<HighType> epsilon() 308 { return foxxll::uint_pair<HighType>(0, 0); } 309 310 //! rounding error is zero round_error()311 static const foxxll::uint_pair<HighType> round_error() 312 { return foxxll::uint_pair<HighType>(0, 0); } 313 314 //! no exponent 315 static const int min_exponent = 0; 316 317 //! no exponent 318 static const int min_exponent10 = 0; 319 320 //! no exponent 321 static const int max_exponent = 0; 322 323 //! no exponent 324 static const int max_exponent10 = 0; 325 326 //! no infinity 327 static const bool has_infinity = false; 328 }; 329 330 } // namespace std 331 332 #endif // !FOXXLL_COMMON_UINT_TYPES_HEADER 333 334 /**************************************************************************/ 335