| // Copyright 2021 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_BIGINT_DIV_HELPERS_H_ |
| #define V8_BIGINT_DIV_HELPERS_H_ |
| |
| #include <memory> |
| |
| #include "src/bigint/bigint.h" |
| #include "src/bigint/util.h" |
| |
| namespace v8 { |
| namespace bigint { |
| |
| void LeftShift(RWDigits Z, Digits X, int shift); |
| void RightShift(RWDigits Z, Digits X, int shift); |
| |
| inline void PutAt(RWDigits Z, Digits A, int count) { |
| int len = std::min(A.len(), count); |
| int i = 0; |
| for (; i < len; i++) Z[i] = A[i]; |
| for (; i < count; i++) Z[i] = 0; |
| } |
| |
| // Division algorithms typically need to left-shift their inputs into |
| // "bit-normalized" form (i.e. top bit is set). The inputs are considered |
| // read-only, and V8 relies on that by allowing concurrent reads from them, |
| // so by default, {ShiftedDigits} allocate temporary storage for their |
| // contents. In-place modification is opt-in for cases where callers can |
| // guarantee that it is safe. |
| // When callers allow in-place shifting and wish to undo it, they have to do |
| // so manually using {Reset()}. |
| // If {shift} is not given, it is auto-detected from {original}'s |
| // leading zeros. |
| class ShiftedDigits : public Digits { |
| public: |
| explicit ShiftedDigits(Digits& original, int shift = -1, |
| bool allow_inplace = false) |
| : Digits(original.digits_, original.len_) { |
| int leading_zeros = CountLeadingZeros(original.msd()); |
| if (shift < 0) { |
| shift = leading_zeros; |
| } else if (shift > leading_zeros) { |
| allow_inplace = false; |
| len_++; |
| } |
| shift_ = shift; |
| if (shift == 0) { |
| inplace_ = true; |
| return; |
| } |
| inplace_ = allow_inplace; |
| if (!inplace_) { |
| digit_t* digits = new digit_t[len_]; |
| storage_.reset(digits); |
| digits_ = digits; |
| } |
| RWDigits rw_view(digits_, len_); |
| LeftShift(rw_view, original, shift_); |
| } |
| ~ShiftedDigits() = default; |
| |
| void Reset() { |
| if (inplace_) { |
| RWDigits rw_view(digits_, len_); |
| RightShift(rw_view, rw_view, shift_); |
| } |
| } |
| |
| int shift() { return shift_; } |
| |
| private: |
| int shift_; |
| bool inplace_; |
| std::unique_ptr<digit_t[]> storage_; |
| }; |
| |
| } // namespace bigint |
| } // namespace v8 |
| |
| #endif // V8_BIGINT_DIV_HELPERS_H_ |