// Copyright 2013 The Flutter 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 "flutter/impeller/geometry/rational.h"

#include <cmath>
#include <cstdlib>
#include <numeric>

namespace impeller {
namespace {
uint32_t AbsToUnsigned(int32_t x) {
  return static_cast<uint32_t>(std::abs(x));
}
}  // namespace

bool Rational::operator==(const Rational& that) const {
  if (den_ == that.den_) {
    return num_ == that.num_;
  } else if ((num_ >= 0) != (that.num_ >= 0)) {
    return false;
  } else {
    return AbsToUnsigned(num_) * that.den_ == AbsToUnsigned(that.num_) * den_;
  }
}

bool Rational::operator<(const Rational& that) const {
  if (den_ == that.den_) {
    return num_ < that.num_;
  } else if ((num_ >= 0) != (that.num_ >= 0)) {
    return num_ < that.num_;
  } else {
    return AbsToUnsigned(num_) * that.den_ < AbsToUnsigned(that.num_) * den_;
  }
}

uint64_t Rational::GetHash() const {
  if (num_ == 0) {
    return 0;
  }
  uint64_t gcd = std::gcd(num_, den_);
  return ((num_ / gcd) << 32) | (den_ / gcd);
}

Rational Rational::Invert() const {
  if (num_ >= 0) {
    return Rational(den_, num_);
  } else {
    return Rational(-1 * static_cast<int32_t>(den_), std::abs(num_));
  }
}

}  // namespace impeller
