// Copyright (c) 2020-2021, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto.  Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once

#include <map>
#include <stdint.h>

namespace carb
{
namespace flatcache
{

// Each frame in the history buffer is timestamped with a frame time, stored as
// a rational number to minimize rounding issues. See threadgate::TimeRatio.
struct RationalTime
{
    int64_t numerator;
    uint64_t denominator;

        // Minimize denominator small by dividing by gcd(numerator,denominator)
    RationalTime reduce() const
    {
        RationalTime result{0, 0};

        int64_t gcdNumDen = gcd(numerator, denominator);

        if (gcdNumDen != 0)
        {
            result.numerator = numerator / gcdNumDen;
            result.denominator = denominator / gcdNumDen;
        }

        return result;
    }

    bool operator==(RationalTime rhs) const
    {
        RationalTime thisReduced = reduce();
        RationalTime rhsReduced = rhs.reduce();

        return (thisReduced.numerator == rhsReduced.numerator) && (thisReduced.denominator == rhsReduced.denominator);
    }

    bool operator!=(RationalTime rhs) const
    {
        return !(*this == rhs);
    }

    static int64_t gcd(int64_t a, int64_t b)
    {
        while (b != 0)
        {
            int64_t t = b;
            b = a % b;
            a = t;
        }
        return std::max(a, -a);
    }

    RationalTime operator-(RationalTime b) const
    {
        RationalTime result;
        result.numerator = numerator * int64_t(b.denominator) - b.numerator * int64_t(denominator);
        result.denominator = denominator * b.denominator;

        return result.reduce();
    }

    RationalTime operator*(int64_t b) const
    {
        RationalTime result;
        result.numerator = numerator * b;
        result.denominator = denominator;

        return result.reduce();
    }
};
static const RationalTime kInvalidTime = { 0, 0 };


} // namespace flatcache
} // namespace carb
