Coverage Report

Created: 2025-07-18 06:29

/src/sentencepiece/third_party/protobuf-lite/int128.cc
Line
Count
Source (jump to first uncovered line)
1
// Protocol Buffers - Google's data interchange format
2
// Copyright 2008 Google Inc.  All rights reserved.
3
// https://developers.google.com/protocol-buffers/
4
//
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are
7
// met:
8
//
9
//     * Redistributions of source code must retain the above copyright
10
// notice, this list of conditions and the following disclaimer.
11
//     * Redistributions in binary form must reproduce the above
12
// copyright notice, this list of conditions and the following disclaimer
13
// in the documentation and/or other materials provided with the
14
// distribution.
15
//     * Neither the name of Google Inc. nor the names of its
16
// contributors may be used to endorse or promote products derived from
17
// this software without specific prior written permission.
18
//
19
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31
#include <google/protobuf/stubs/int128.h>
32
33
#include <iomanip>
34
#include <ostream>  // NOLINT(readability/streams)
35
#include <sstream>
36
37
#include <google/protobuf/stubs/logging.h>
38
39
#include <google/protobuf/port_def.inc>
40
41
namespace google {
42
namespace protobuf {
43
44
const uint128_pod kuint128max = {
45
    static_cast<uint64>(PROTOBUF_LONGLONG(0xFFFFFFFFFFFFFFFF)),
46
    static_cast<uint64>(PROTOBUF_LONGLONG(0xFFFFFFFFFFFFFFFF))
47
};
48
49
// Returns the 0-based position of the last set bit (i.e., most significant bit)
50
// in the given uint64. The argument may not be 0.
51
//
52
// For example:
53
//   Given: 5 (decimal) == 101 (binary)
54
//   Returns: 2
55
#define STEP(T, n, pos, sh)                   \
56
0
  do {                                        \
57
0
    if ((n) >= (static_cast<T>(1) << (sh))) { \
58
0
      (n) = (n) >> (sh);                      \
59
0
      (pos) |= (sh);                          \
60
0
    }                                         \
61
0
  } while (0)
62
0
static inline int Fls64(uint64 n) {
63
0
  GOOGLE_DCHECK_NE(0, n);
64
0
  int pos = 0;
65
0
  STEP(uint64, n, pos, 0x20);
66
0
  uint32 n32 = n;
67
0
  STEP(uint32, n32, pos, 0x10);
68
0
  STEP(uint32, n32, pos, 0x08);
69
0
  STEP(uint32, n32, pos, 0x04);
70
0
  return pos + ((PROTOBUF_ULONGLONG(0x3333333322221100) >> (n32 << 2)) & 0x3);
71
0
}
72
#undef STEP
73
74
// Like Fls64() above, but returns the 0-based position of the last set bit
75
// (i.e., most significant bit) in the given uint128. The argument may not be 0.
76
0
static inline int Fls128(uint128 n) {
77
0
  if (uint64 hi = Uint128High64(n)) {
78
0
    return Fls64(hi) + 64;
79
0
  }
80
0
  return Fls64(Uint128Low64(n));
81
0
}
82
83
void uint128::DivModImpl(uint128 dividend, uint128 divisor,
84
0
                         uint128* quotient_ret, uint128* remainder_ret) {
85
0
  if (divisor == 0) {
86
0
    GOOGLE_LOG(FATAL) << "Division or mod by zero: dividend.hi=" << dividend.hi_
87
0
                      << ", lo=" << dividend.lo_;
88
0
  } else if (dividend < divisor) {
89
0
    *quotient_ret = 0;
90
0
    *remainder_ret = dividend;
91
0
    return;
92
0
  } else {
93
0
    int dividend_bit_length = Fls128(dividend);
94
0
    int divisor_bit_length = Fls128(divisor);
95
0
    int difference = dividend_bit_length - divisor_bit_length;
96
0
    uint128 quotient = 0;
97
0
    while (difference >= 0) {
98
0
      quotient <<= 1;
99
0
      uint128 shifted_divisor = divisor << difference;
100
0
      if (shifted_divisor <= dividend) {
101
0
        dividend -= shifted_divisor;
102
0
        quotient += 1;
103
0
      }
104
0
      difference -= 1;
105
0
    }
106
    //record the final quotient and remainder
107
0
    *quotient_ret = quotient;
108
0
    *remainder_ret = dividend;
109
0
  }
110
0
}
111
112
113
0
uint128& uint128::operator/=(const uint128& divisor) {
114
0
  uint128 quotient = 0;
115
0
  uint128 remainder = 0;
116
0
  DivModImpl(*this, divisor, &quotient, &remainder);
117
0
  *this = quotient;
118
0
  return *this;
119
0
}
120
0
uint128& uint128::operator%=(const uint128& divisor) {
121
0
  uint128 quotient = 0;
122
0
  uint128 remainder = 0;
123
0
  DivModImpl(*this, divisor, &quotient, &remainder);
124
0
  *this = remainder;
125
0
  return *this;
126
0
}
127
128
0
std::ostream& operator<<(std::ostream& o, const uint128& b) {
129
0
  std::ios_base::fmtflags flags = o.flags();
130
131
  // Select a divisor which is the largest power of the base < 2^64.
132
0
  uint128 div;
133
0
  std::streamsize div_base_log;
134
0
  switch (flags & std::ios::basefield) {
135
0
    case std::ios::hex:
136
0
      div =
137
0
          static_cast<uint64>(PROTOBUF_ULONGLONG(0x1000000000000000));  // 16^15
138
0
      div_base_log = 15;
139
0
      break;
140
0
    case std::ios::oct:
141
0
      div = static_cast<uint64>(
142
0
          PROTOBUF_ULONGLONG(01000000000000000000000));  // 8^21
143
0
      div_base_log = 21;
144
0
      break;
145
0
    default:  // std::ios::dec
146
0
      div = static_cast<uint64>(
147
0
          PROTOBUF_ULONGLONG(10000000000000000000));  // 10^19
148
0
      div_base_log = 19;
149
0
      break;
150
0
  }
151
152
  // Now piece together the uint128 representation from three chunks of
153
  // the original value, each less than "div" and therefore representable
154
  // as a uint64.
155
0
  std::ostringstream os;
156
0
  std::ios_base::fmtflags copy_mask =
157
0
      std::ios::basefield | std::ios::showbase | std::ios::uppercase;
158
0
  os.setf(flags & copy_mask, copy_mask);
159
0
  uint128 high = b;
160
0
  uint128 low;
161
0
  uint128::DivModImpl(high, div, &high, &low);
162
0
  uint128 mid;
163
0
  uint128::DivModImpl(high, div, &high, &mid);
164
0
  if (high.lo_ != 0) {
165
0
    os << high.lo_;
166
0
    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
167
0
    os << mid.lo_;
168
0
    os << std::setw(div_base_log);
169
0
  } else if (mid.lo_ != 0) {
170
0
    os << mid.lo_;
171
0
    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
172
0
  }
173
0
  os << low.lo_;
174
0
  std::string rep = os.str();
175
176
  // Add the requisite padding.
177
0
  std::streamsize width = o.width(0);
178
0
  if (width > rep.size()) {
179
0
    if ((flags & std::ios::adjustfield) == std::ios::left) {
180
0
      rep.append(width - rep.size(), o.fill());
181
0
    } else {
182
0
      rep.insert(static_cast<std::string::size_type>(0),
183
0
                 width - rep.size(), o.fill());
184
0
    }
185
0
  }
186
187
  // Stream the final representation in a single "<<" call.
188
0
  return o << rep;
189
0
}
190
191
}  // namespace protobuf
192
}  // namespace google