text: // 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.
  
  #include "src/bigint/bigint-internal.h"
  
  namespace v8 {
  namespace bigint {
  
  // Used for checking consistency between library and public header.
  #if DEBUG
  #if V8_ADVANCED_BIGINT_ALGORITHMS
  bool kAdvancedAlgorithmsEnabledInLibrary = true;
  #else
  bool kAdvancedAlgorithmsEnabledInLibrary = false;
  #endif  // V8_ADVANCED_BIGINT_ALGORITHMS
  #endif  // DEBUG
  
  ProcessorImpl::ProcessorImpl(Platform* platform) : platform_(platform) {}
  
  ProcessorImpl::~ProcessorImpl() { delete platform_; }
  
  Status ProcessorImpl::get_and_clear_status() {
    Status result = status_;
    status_ = Status::kOk;
    return result;
  }
  
  Processor* Processor::New(Platform* platform) {
    ProcessorImpl* impl = new ProcessorImpl(platform);
    return static_cast<Processor*>(impl);
  }
  
  void Processor::Destroy() { delete static_cast<ProcessorImpl*>(this); }
  
  void ProcessorImpl::Multiply(RWDigits Z, Digits X, Digits Y) {
    X.Normalize();
    Y.Normalize();
    if (X.len() == 0 || Y.len() == 0) return Z.Clear();
    if (X.len() < Y.len()) std::swap(X, Y);
    if (Y.len() == 1) return MultiplySingle(Z, X, Y[0]);
    if (Y.len() < kKaratsubaThreshold) return MultiplySchoolbook(Z, X, Y);
  #if !V8_ADVANCED_BIGINT_ALGORITHMS
    return MultiplyKaratsuba(Z, X, Y);
  #else
    if (Y.len() < kToomThreshold) return MultiplyKaratsuba(Z, X, Y);
    if (Y.len() < kFftThreshold) return MultiplyToomCook(Z, X, Y);
    return MultiplyFFT(Z, X, Y);
  #endif
  }
  
  void ProcessorImpl::Divide(RWDigits Q, Digits A, Digits B) {
    A.Normalize();
    B.Normalize();
    DCHECK(B.len() > 0);  // NOLINT(readability/check)
    int cmp = Compare(A, B);
    if (cmp < 0) return Q.Clear();
    if (cmp == 0) {
      Q[0] = 1;
      for (int i = 1; i < Q.len(); i++) Q[i] = 0;
      return;
    }
    if (B.len() == 1) {
      digit_t remainder;
      return DivideSingle(Q, &remainder, A, B[0]);
    }
    if (B.len() < kBurnikelThreshold) {
      return DivideSchoolbook(Q, RWDigits(nullptr, 0), A, B);
    }
  #if !V8_ADVANCED_BIGINT_ALGORITHMS
    return DivideBurnikelZiegler(Q, RWDigits(nullptr, 0), A, B);
  #else
    if (B.len() < kBarrettThreshold || A.len() == B.len()) {
      DivideBurnikelZiegler(Q, RWDigits(nullptr, 0), A, B);
    } else {
      ScratchDigits R(B.len());
      DivideBarrett(Q, R, A, B);
    }
  #endif
  }
  
  void ProcessorImpl::Modulo(RWDigits R, Digits A, Digits B) {
    A.Normalize();
    B.Normalize();
    DCHECK(B.len() > 0);  // NOLINT(readability/check)
    int cmp = Compare(A, B);
    if (cmp < 0) {
      for (int i = 0; i < B.len(); i++) R[i] = B[i];
      for (int i = B.len(); i < R.len(); i++) R[i] = 0;
      return;
    }
    if (cmp == 0) return R.Clear();
    if (B.len() == 1) {
      digit_t remainder;
      DivideSingle(RWDigits(nullptr, 0), &remainder, A, B[0]);
      R[0] = remainder;
      for (int i = 1; i < R.len(); i++) R[i] = 0;
      return;
    }
    if (B.len() < kBurnikelThreshold) {
      return DivideSchoolbook(RWDigits(nullptr, 0), R, A, B);
    }
    int q_len = DivideResultLength(A, B);
    ScratchDigits Q(q_len);
  #if !V8_ADVANCED_BIGINT_ALGORITHMS
    return DivideBurnikelZiegler(Q, R, A, B);
  #else
    if (B.len() < kBarrettThreshold || A.len() == B.len()) {
      DivideBurnikelZiegler(Q, R, A, B);
    } else {
      DivideBarrett(Q, R, A, B);
    }
  #endif
  }
  
  Status Processor::Multiply(RWDigits Z, Digits X, Digits Y) {
    ProcessorImpl* impl = static_cast<ProcessorImpl*>(this);
    impl->Multiply(Z, X, Y);
    return impl->get_and_clear_status();
  }
  
  Status Processor::Divide(RWDigits Q, Digits A, Digits B) {
    ProcessorImpl* impl = static_cast<ProcessorImpl*>(this);
    impl->Divide(Q, A, B);
    return impl->get_and_clear_status();
  }
  
  Status Processor::Modulo(RWDigits R, Digits A, Digits B) {
    ProcessorImpl* impl = static_cast<ProcessorImpl*>(this);
    impl->Modulo(R, A, B);
    return impl->get_and_clear_status();
  }
  
  }  // namespace bigint
  }  // namespace v8
  