LCOV - code coverage report
Current view: top level - src/base - uint128.cc (source / functions) Hit Total Coverage
Test: vlink Lines: 27 67 40.3 %
Date: 2026-06-27 19:56:04 Functions: 3 8 37.5 %
Branches: 8 14 57.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2026 by Thun Lu. All rights reserved.
       3                 :            :  * Author: Thun Lu <thun.lu@zohomail.cn>
       4                 :            :  * Repo:   https://github.com/thun-res/vlink
       5                 :            :  *  _    __   __      _           __
       6                 :            :  * | |  / /  / /     (_) ____    / /__
       7                 :            :  * | | / /  / /     / / / __ \  / //_/
       8                 :            :  * | |/ /  / /___  / / / / / / / ,<
       9                 :            :  * |___/  /_____/ /_/ /_/ /_/ /_/|_|
      10                 :            :  *
      11                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
      12                 :            :  * you may not use this file except in compliance with the License.
      13                 :            :  * You may obtain a copy of the License at
      14                 :            :  *
      15                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
      16                 :            :  *
      17                 :            :  * Unless required by applicable law or agreed to in writing, software
      18                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      19                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      20                 :            :  * See the License for the specific language governing permissions and
      21                 :            :  * limitations under the License.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include "./base/uint128.h"
      25                 :            : 
      26                 :            : #include <iomanip>
      27                 :            : #include <iostream>
      28                 :            : #include <stdexcept>
      29                 :            : #include <utility>
      30                 :            : 
      31                 :            : #if defined(_MSC_VER)
      32                 :            : #include <intrin.h>
      33                 :            : #endif
      34                 :            : 
      35                 :            : namespace vlink {
      36                 :            : 
      37                 :          4 : std::ostream& operator<<(std::ostream& os, const Uint128& value) noexcept {
      38                 :          4 :   std::ios_base::fmtflags f(os.flags());
      39                 :            : 
      40                 :          4 :   os << "0x" << std::uppercase << std::hex << std::setfill('0');
      41                 :            : 
      42         [ +  + ]:          4 :   if (value.high_ != 0) {
      43                 :          1 :     os << value.high_ << std::setw(16) << value.low_;
      44                 :            :   } else {
      45                 :          3 :     os << value.low_;
      46                 :            :   }
      47                 :            : 
      48                 :          4 :   os.flags(f);
      49                 :            : 
      50                 :          4 :   return os;
      51                 :            : }
      52                 :            : 
      53                 :            : // Uint128
      54                 :          0 : int Uint128::clz64(uint64_t x) noexcept {
      55                 :            : #if defined(__GNUG__) || defined(__clang__)
      56         [ #  # ]:          0 :   return x ? __builtin_clzll(x) : 64;
      57                 :            : #elif defined(_MSC_VER)
      58                 :            :   unsigned long idx;  // NOLINT(runtime/int, google-runtime-int)
      59                 :            : 
      60                 :            :   if (_BitScanReverse64(&idx, x)) {
      61                 :            :     return 63 - static_cast<int>(idx);
      62                 :            :   }
      63                 :            : 
      64                 :            :   return 64;
      65                 :            : #else
      66                 :            : 
      67                 :            :   if (x == 0) {
      68                 :            :     return 64;
      69                 :            :   }
      70                 :            : 
      71                 :            :   int n = 0;
      72                 :            : 
      73                 :            :   while ((x & (1ull << 63)) == 0) {
      74                 :            :     x <<= 1;
      75                 :            :     ++n;
      76                 :            :   }
      77                 :            : 
      78                 :            :   return n;
      79                 :            : #endif
      80                 :            : }
      81                 :            : 
      82                 :          0 : void Uint128::mul_64_128(uint64_t a, uint64_t b, uint64_t& hi, uint64_t& lo) noexcept {
      83                 :            : #if defined(__SIZEOF_INT128__)
      84                 :          0 :   __uint128_t p = static_cast<__uint128_t>(a) * static_cast<__uint128_t>(b);
      85                 :            : 
      86                 :          0 :   hi = static_cast<uint64_t>(p >> 64);
      87                 :          0 :   lo = static_cast<uint64_t>(p);
      88                 :            : #else
      89                 :            :   const uint64_t a0 = static_cast<uint32_t>(a);
      90                 :            :   const uint64_t a1 = a >> 32;
      91                 :            :   const uint64_t b0 = static_cast<uint32_t>(b);
      92                 :            :   const uint64_t b1 = b >> 32;
      93                 :            : 
      94                 :            :   const uint64_t p00 = a0 * b0;
      95                 :            :   const uint64_t p01 = a0 * b1;
      96                 :            :   const uint64_t p10 = a1 * b0;
      97                 :            :   const uint64_t p11 = a1 * b1;
      98                 :            : 
      99                 :            :   uint64_t carry = 0;
     100                 :            :   uint64_t mid = (p00 >> 32) + (p01 & 0xFFFFFFFFULL) + (p10 & 0xFFFFFFFFULL);
     101                 :            :   lo = (p00 & 0xFFFFFFFFULL) | (mid << 32);
     102                 :            :   carry = (mid >> 32);
     103                 :            : 
     104                 :            :   hi = p11 + (p01 >> 32) + (p10 >> 32) + carry;
     105                 :            : #endif
     106                 :          0 : }
     107                 :            : 
     108                 :          0 : uint64_t Uint128::add64_carry(uint64_t a, uint64_t b, uint64_t& carry_out) noexcept {
     109                 :          0 :   uint64_t s = a + b;
     110                 :            : 
     111         [ #  # ]:          0 :   carry_out = (s < a) ? 1 : 0;
     112                 :            : 
     113                 :          0 :   return s;
     114                 :            : }
     115                 :            : 
     116                 :          0 : void Uint128::add_128_with64(uint64_t& high, uint64_t& low, uint64_t add_low, uint64_t add_high) noexcept {
     117                 :          0 :   uint64_t c = 0;
     118                 :            : 
     119                 :          0 :   low = add64_carry(low, add_low, c);
     120                 :            : 
     121                 :          0 :   high = high + add_high + c;
     122                 :          0 : }
     123                 :            : 
     124                 :          0 : Uint128 Uint128::mul_u128_fallback(const Uint128& x, const Uint128& y) noexcept {
     125                 :          0 :   uint64_t xh = x.get_high();
     126                 :          0 :   uint64_t xl = x.get_low();
     127                 :          0 :   uint64_t yh = y.get_high();
     128                 :          0 :   uint64_t yl = y.get_low();
     129                 :            : 
     130                 :          0 :   uint64_t p0_hi = 0;
     131                 :          0 :   uint64_t p0_lo = 0;
     132                 :          0 :   mul_64_128(xl, yl, p0_hi, p0_lo);
     133                 :            : 
     134                 :          0 :   uint64_t p1_hi = 0;
     135                 :          0 :   uint64_t p1_lo = 0;
     136                 :          0 :   mul_64_128(xl, yh, p1_hi, p1_lo);
     137                 :            : 
     138                 :          0 :   uint64_t p2_hi = 0;
     139                 :          0 :   uint64_t p2_lo = 0;
     140                 :          0 :   mul_64_128(xh, yl, p2_hi, p2_lo);
     141                 :            : 
     142                 :          0 :   uint64_t p3_hi = 0;
     143                 :          0 :   uint64_t p3_lo = 0;
     144                 :          0 :   mul_64_128(xh, yh, p3_hi, p3_lo);
     145                 :            : 
     146                 :          0 :   uint64_t low = p0_lo;
     147                 :          0 :   uint64_t high = p0_hi;
     148                 :            : 
     149                 :          0 :   uint64_t c1 = 0;
     150                 :          0 :   high = add64_carry(high, p1_lo, c1);
     151                 :          0 :   uint64_t c2 = 0;
     152                 :          0 :   high = add64_carry(high, p2_lo, c2);
     153                 :            : 
     154                 :            :   (void)p1_hi;
     155                 :            :   (void)p2_hi;
     156                 :            :   (void)p3_hi;
     157                 :            :   (void)c1;
     158                 :            :   (void)c2;
     159                 :            : 
     160                 :          0 :   return Uint128(high, low);
     161                 :            : }
     162                 :            : 
     163                 :         11 : std::pair<Uint128, Uint128> Uint128::u128_divmod(const Uint128& dividend, const Uint128& divisor) {
     164   [ +  -  +  +  :         11 :   if VUNLIKELY (divisor.get_high() == 0 && divisor.get_low() == 0) {
                   +  + ]
     165         [ +  - ]:          4 :     throw std::domain_error("Uint128 division by zero");
     166                 :            :   }
     167                 :            : 
     168                 :            : #if defined(__SIZEOF_INT128__)
     169                 :          7 :   __uint128_t a = (static_cast<__uint128_t>(dividend.get_high()) << 64) | dividend.get_low();
     170                 :          7 :   __uint128_t b = (static_cast<__uint128_t>(divisor.get_high()) << 64) | divisor.get_low();
     171                 :            : 
     172                 :          7 :   __uint128_t q = a / b;
     173                 :          7 :   __uint128_t r = a % b;
     174                 :            : 
     175                 :          7 :   return {Uint128(static_cast<uint64_t>(q >> 64), static_cast<uint64_t>(q)),
     176                 :          7 :           Uint128(static_cast<uint64_t>(r >> 64), static_cast<uint64_t>(r))};
     177                 :            : #else
     178                 :            :   Uint128 zero{0};
     179                 :            : 
     180                 :            :   if (dividend < divisor) {
     181                 :            :     return {zero, dividend};
     182                 :            :   }
     183                 :            : 
     184                 :            :   if (dividend == divisor) {
     185                 :            :     return {Uint128{1}, zero};
     186                 :            :   }
     187                 :            : 
     188                 :            :   Uint128 quotient{0};
     189                 :            :   Uint128 remainder{0};
     190                 :            : 
     191                 :            :   for (int i = 127; i >= 0; --i) {
     192                 :            :     remainder <<= 1;
     193                 :            :     Uint128 bit_mask = (i >= 64) ? Uint128{1ULL << (i - 64), 0} : Uint128{0, 1ULL << i};
     194                 :            : 
     195                 :            :     if ((dividend & bit_mask) != zero) {
     196                 :            :       remainder |= Uint128{1};
     197                 :            :     }
     198                 :            : 
     199                 :            :     if (remainder >= divisor) {
     200                 :            :       remainder -= divisor;
     201                 :            :       quotient |= bit_mask;
     202                 :            :     }
     203                 :            :   }
     204                 :            : 
     205                 :            :   return {quotient, remainder};
     206                 :            : #endif
     207                 :            : }
     208                 :            : 
     209                 :            : }  // namespace vlink
     210                 :            : 
     211                 :            : namespace std {
     212                 :          6 : size_t hash<vlink::Uint128>::operator()(const vlink::Uint128& value) const noexcept {
     213                 :          6 :   uint64_t h = value.get_high();
     214                 :          6 :   uint64_t l = value.get_low();
     215                 :            : 
     216                 :          6 :   h ^= l;
     217                 :          6 :   h ^= h >> 33;
     218                 :          6 :   h *= 0xff51afd7ed558ccdULL;
     219                 :          6 :   h ^= h >> 33;
     220                 :          6 :   h *= 0xc4ceb9fe1a85ec53ULL;
     221                 :          6 :   h ^= h >> 33;
     222                 :            : 
     223                 :          6 :   return static_cast<size_t>(h);
     224                 :            : }
     225                 :            : }  // namespace std

Generated by: LCOV version 1.14