LCOV - code coverage report
Current view: top level - xpcom/ds - StickyTimeDuration.h (source / functions) Hit Total Coverage
Test: output.info Lines: 26 34 76.5 %
Date: 2017-07-14 16:53:18 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef mozilla_StickyTimeDuration_h
       8             : #define mozilla_StickyTimeDuration_h
       9             : 
      10             : #include "mozilla/TimeStamp.h"
      11             : #include "mozilla/FloatingPoint.h"
      12             : 
      13             : namespace mozilla {
      14             : 
      15             : /**
      16             :  * A ValueCalculator class that performs additional checks before performing
      17             :  * arithmetic operations such that if either operand is Forever (or the
      18             :  * negative equivalent) the result remains Forever (or the negative equivalent
      19             :  * as appropriate).
      20             :  *
      21             :  * Currently this only checks if either argument to each operation is
      22             :  * Forever/-Forever. However, it is possible that, for example,
      23             :  * aA + aB > INT64_MAX (or < INT64_MIN).
      24             :  *
      25             :  * We currently don't check for that case since we don't expect that to
      26             :  * happen often except under test conditions in which case the wrapping
      27             :  * behavior is probably acceptable.
      28             :  */
      29             : class StickyTimeDurationValueCalculator
      30             : {
      31             : public:
      32             :   static int64_t
      33         790 :   Add(int64_t aA, int64_t aB)
      34             :   {
      35         790 :     MOZ_ASSERT((aA != INT64_MAX || aB != INT64_MIN) &&
      36             :                (aA != INT64_MIN || aB != INT64_MAX),
      37             :                "'Infinity + -Infinity' and '-Infinity + Infinity'"
      38             :                " are undefined");
      39             : 
      40             :     // Forever + x = Forever
      41             :     // x + Forever = Forever
      42         790 :     if (aA == INT64_MAX || aB == INT64_MAX) {
      43           0 :       return INT64_MAX;
      44             :     }
      45             :     // -Forever + x = -Forever
      46             :     // x + -Forever = -Forever
      47         790 :     if (aA == INT64_MIN || aB == INT64_MIN) {
      48           0 :       return INT64_MIN;
      49             :     }
      50             : 
      51         790 :     return aA + aB;
      52             :   }
      53             : 
      54             :   // Note that we can't just define Add and have BaseTimeDuration call Add with
      55             :   // negative arguments since INT64_MAX != -INT64_MIN so the saturating logic
      56             :   // won't work.
      57             :   static int64_t
      58          24 :   Subtract(int64_t aA, int64_t aB)
      59             :   {
      60          24 :     MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) || aA != aB,
      61             :                "'Infinity - Infinity' and '-Infinity - -Infinity'"
      62             :                " are undefined");
      63             : 
      64             :     // Forever - x  = Forever
      65             :     // x - -Forever = Forever
      66          24 :     if (aA == INT64_MAX || aB == INT64_MIN) {
      67           0 :       return INT64_MAX;
      68             :     }
      69             :     // -Forever - x = -Forever
      70             :     // x - Forever  = -Forever
      71          24 :     if (aA == INT64_MIN || aB == INT64_MAX) {
      72           0 :       return INT64_MIN;
      73             :     }
      74             : 
      75          24 :     return aA - aB;
      76             :   }
      77             : 
      78             :   template <typename T>
      79             :   static int64_t
      80             :   Multiply(int64_t aA, T aB) {
      81             :     // Specializations for double, float, and int64_t are provided following.
      82             :     return Multiply(aA, static_cast<int64_t>(aB));
      83             :   }
      84             : 
      85             :   static int64_t
      86             :   Divide(int64_t aA, int64_t aB) {
      87             :     MOZ_ASSERT(aB != 0, "Division by zero");
      88             :     MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
      89             :                (aB != INT64_MAX && aB != INT64_MIN),
      90             :                "Dividing +/-Infinity by +/-Infinity is undefined");
      91             : 
      92             :     // Forever / +x = Forever
      93             :     // Forever / -x = -Forever
      94             :     // -Forever / +x = -Forever
      95             :     // -Forever / -x = Forever
      96             :     if (aA == INT64_MAX || aA == INT64_MIN) {
      97             :       return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
      98             :     }
      99             :     // x /  Forever = 0
     100             :     // x / -Forever = 0
     101             :     if (aB == INT64_MAX || aB == INT64_MIN) {
     102             :       return 0;
     103             :     }
     104             : 
     105             :     return aA / aB;
     106             :   }
     107             : 
     108             :   static double
     109         156 :   DivideDouble(int64_t aA, int64_t aB)
     110             :   {
     111         156 :     MOZ_ASSERT(aB != 0, "Division by zero");
     112         156 :     MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
     113             :                (aB != INT64_MAX && aB != INT64_MIN),
     114             :                "Dividing +/-Infinity by +/-Infinity is undefined");
     115             : 
     116             :     // Forever / +x = Forever
     117             :     // Forever / -x = -Forever
     118             :     // -Forever / +x = -Forever
     119             :     // -Forever / -x = Forever
     120         156 :     if (aA == INT64_MAX || aA == INT64_MIN) {
     121             :       return (aA >= 0) ^ (aB >= 0)
     122           0 :              ? NegativeInfinity<double>()
     123           0 :              : PositiveInfinity<double>();
     124             :     }
     125             :     // x /  Forever = 0
     126             :     // x / -Forever = 0
     127         156 :     if (aB == INT64_MAX || aB == INT64_MIN) {
     128           0 :       return 0.0;
     129             :     }
     130             : 
     131         156 :     return static_cast<double>(aA) / aB;
     132             :   }
     133             : 
     134             :   static int64_t
     135             :   Modulo(int64_t aA, int64_t aB)
     136             :   {
     137             :     MOZ_ASSERT(aA != INT64_MAX && aA != INT64_MIN,
     138             :                "Infinity modulo x is undefined");
     139             : 
     140             :     return aA % aB;
     141             :   }
     142             : };
     143             : 
     144             : template <>
     145             : inline int64_t
     146             : StickyTimeDurationValueCalculator::Multiply<int64_t>(int64_t aA,
     147             :                                                           int64_t aB)
     148             : {
     149             :   MOZ_ASSERT((aA != 0 || (aB != INT64_MIN && aB != INT64_MAX)) &&
     150             :              ((aA != INT64_MIN && aA != INT64_MAX) || aB != 0),
     151             :              "Multiplication of infinity by zero");
     152             : 
     153             :   // Forever  * +x = Forever
     154             :   // Forever  * -x = -Forever
     155             :   // -Forever * +x = -Forever
     156             :   // -Forever * -x = Forever
     157             :   //
     158             :   // i.e. If one or more of the arguments is +/-Forever, then
     159             :   // return -Forever if the signs differ, or +Forever otherwise.
     160             :   if (aA == INT64_MAX || aA == INT64_MIN ||
     161             :       aB == INT64_MAX || aB == INT64_MIN) {
     162             :     return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
     163             :   }
     164             : 
     165             :   return aA * aB;
     166             : }
     167             : 
     168             : template <>
     169             : inline int64_t
     170         474 : StickyTimeDurationValueCalculator::Multiply<double>(int64_t aA, double aB)
     171             : {
     172         474 :   MOZ_ASSERT((aA != 0 || (!IsInfinite(aB))) &&
     173             :              ((aA != INT64_MIN && aA != INT64_MAX) || aB != 0.0),
     174             :              "Multiplication of infinity by zero");
     175             : 
     176             :   // As with Multiply<int64_t>, if one or more of the arguments is
     177             :   // +/-Forever or +/-Infinity, then return -Forever if the signs differ,
     178             :   // or +Forever otherwise.
     179         474 :   if (aA == INT64_MAX || aA == INT64_MIN || IsInfinite(aB)) {
     180           0 :     return (aA >= 0) ^ (aB >= 0.0) ? INT64_MIN : INT64_MAX;
     181             :   }
     182             : 
     183         474 :   return aA * aB;
     184             : }
     185             : 
     186             : template <>
     187             : inline int64_t
     188             : StickyTimeDurationValueCalculator::Multiply<float>(int64_t aA, float aB)
     189             : {
     190             :   MOZ_ASSERT(IsInfinite(aB) == IsInfinite(static_cast<double>(aB)),
     191             :              "Casting to float loses infinite-ness");
     192             : 
     193             :   return Multiply(aA, static_cast<double>(aB));
     194             : }
     195             : 
     196             : /**
     197             :  * Specialization of BaseTimeDuration that uses
     198             :  * StickyTimeDurationValueCalculator for arithmetic on the mValue member.
     199             :  *
     200             :  * Use this class when you need a time duration that is expected to hold values
     201             :  * of Forever (or the negative equivalent) *and* when you expect that
     202             :  * time duration to be used in arithmetic operations (and not just value
     203             :  * comparisons).
     204             :  */
     205             : typedef BaseTimeDuration<StickyTimeDurationValueCalculator>
     206             :   StickyTimeDuration;
     207             : 
     208             : // Template specializations to allow arithmetic between StickyTimeDuration
     209             : // and TimeDuration objects by falling back to the safe behavior.
     210             : inline StickyTimeDuration
     211         454 : operator+(const TimeDuration& aA, const StickyTimeDuration& aB)
     212             : {
     213         454 :   return StickyTimeDuration(aA) + aB;
     214             : }
     215             : inline StickyTimeDuration
     216         336 : operator+(const StickyTimeDuration& aA, const TimeDuration& aB)
     217             : {
     218         336 :   return aA + StickyTimeDuration(aB);
     219             : }
     220             : 
     221             : inline StickyTimeDuration
     222             : operator-(const TimeDuration& aA, const StickyTimeDuration& aB)
     223             : {
     224             :   return StickyTimeDuration(aA) - aB;
     225             : }
     226             : inline StickyTimeDuration
     227          24 : operator-(const StickyTimeDuration& aA, const TimeDuration& aB)
     228             : {
     229          24 :   return aA - StickyTimeDuration(aB);
     230             : }
     231             : 
     232             : inline StickyTimeDuration&
     233             : operator+=(StickyTimeDuration &aA, const TimeDuration& aB)
     234             : {
     235             :   return aA += StickyTimeDuration(aB);
     236             : }
     237             : inline StickyTimeDuration&
     238             : operator-=(StickyTimeDuration &aA, const TimeDuration& aB)
     239             : {
     240             :   return aA -= StickyTimeDuration(aB);
     241             : }
     242             : 
     243             : inline double
     244             : operator/(const TimeDuration& aA, const StickyTimeDuration& aB)
     245             : {
     246             :   return StickyTimeDuration(aA) / aB;
     247             : }
     248             : inline double
     249             : operator/(const StickyTimeDuration& aA, const TimeDuration& aB)
     250             : {
     251             :   return aA / StickyTimeDuration(aB);
     252             : }
     253             : 
     254             : inline StickyTimeDuration
     255             : operator%(const TimeDuration& aA, const StickyTimeDuration& aB)
     256             : {
     257             :   return StickyTimeDuration(aA) % aB;
     258             : }
     259             : inline StickyTimeDuration
     260             : operator%(const StickyTimeDuration& aA, const TimeDuration& aB)
     261             : {
     262             :   return aA % StickyTimeDuration(aB);
     263             : }
     264             : 
     265             : } // namespace mozilla
     266             : 
     267             : #endif /* mozilla_StickyTimeDuration_h */

Generated by: LCOV version 1.13