blob: db5da3e128d66aef987239da4b21ef2a67610517 [file] [log] [blame] [edit]
// 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_