You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2019/02/12 19:16:14 UTC

[trafficserver] branch master updated: Scalar: add generic rounding.

This is an automated email from the ASF dual-hosted git repository.

amc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 840f4b8  Scalar: add generic rounding.
840f4b8 is described below

commit 840f4b8412d3ac55d47e5f1b3a5836e37810a730
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Fri Feb 8 09:16:42 2019 -0600

    Scalar: add generic rounding.
---
 include/tscore/Scalar.h              | 38 ++++++++++++++++++++++++++----------
 src/tscore/unit_tests/test_Scalar.cc | 18 +++++++++++++++++
 2 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/include/tscore/Scalar.h b/include/tscore/Scalar.h
index e71a082..06c3398 100644
--- a/include/tscore/Scalar.h
+++ b/include/tscore/Scalar.h
@@ -44,19 +44,19 @@ template <intmax_t N, typename C, typename T> class Scalar;
 
 namespace detail
 {
-  // @internal - althought these conversion methods look bulky, in practice they compile down to
-  // very small amounts of code due to dead code elimination and that all of the conditions are
-  // compile time constants.
+  // @internal - although these conversion methods look bulky, in practice they compile down to
+  // very small amounts of code due to the conditions being compile time constant - the non-taken
+  // clauses are dead code and eliminated by the compiler.
 
   // The general case where neither N nor S are a multiple of the other seems a bit long but this
   // minimizes the risk of integer overflow.  I need to validate that under -O2 the compiler will
   // only do 1 division to get both the quotient and remainder for (n/N) and (n%N). In cases where
   // N,S are powers of 2 I have verified recent GNU compilers will optimize to bit operations.
 
-  /// Convert a count @a c that is scale @s S to scale @c N
-  template <intmax_t N, intmax_t S>
-  intmax_t
-  scale_conversion_round_up(intmax_t c)
+  /// Convert a count @a c that is scale @s S to the corresponding count for scale @c N
+  template <intmax_t N, intmax_t S, typename C>
+  C
+  scale_conversion_round_up(C c)
   {
     typedef std::ratio<N, S> R;
     if (N == S) {
@@ -71,9 +71,9 @@ namespace detail
   }
 
   /// Convert a count @a c that is scale @s S to scale @c N
-  template <intmax_t N, intmax_t S>
-  intmax_t
-  scale_conversion_round_down(intmax_t c)
+  template <intmax_t N, intmax_t S, typename C>
+  C
+  scale_conversion_round_down(C c)
   {
     typedef std::ratio<N, S> R;
     if (N == S) {
@@ -108,6 +108,10 @@ namespace detail
 
      Much of this is driven by the fact that the assignment operator, in some cases, can not be
      templated and therefore to have a nice interface for assignment this split is needed.
+
+     Note - the key point is the actual conversion is not done when the wrapper instance is created
+     but when the wrapper instance is assigned. That is what enables the conversion to be done in
+     the context of the destination, which is not otherwise possible.
    */
 
   // Unit value, to be rounded up.
@@ -893,6 +897,20 @@ Scalar<N, C, T>::minus(Counter n) const -> self
   return {_n - n};
 }
 
+template <intmax_t N, typename C>
+C
+round_up(C value)
+{
+  return N * detail::scale_conversion_round_up<N, 1>(value);
+}
+
+template <intmax_t N, typename C>
+C
+round_down(C value)
+{
+  return N * detail::scale_conversion_round_down<N, 1>(value);
+}
+
 namespace detail
 {
   // These classes exist only to create distinguishable overloads.
diff --git a/src/tscore/unit_tests/test_Scalar.cc b/src/tscore/unit_tests/test_Scalar.cc
index 3f8ac69..6e89560 100644
--- a/src/tscore/unit_tests/test_Scalar.cc
+++ b/src/tscore/unit_tests/test_Scalar.cc
@@ -76,6 +76,24 @@ TEST_CASE("Scalar", "[libts][Scalar]")
   sz_b = sz; // Should be OK because SCALE_1 is an integer multiple of SCALE_2
   //  sz = sz_b; // Should not compile.
   REQUIRE(sz_b.count() == 119 * (SCALE_1 / SCALE_2));
+
+  // Test generic rounding.
+  REQUIRE(120 == ts::round_up<10>(118));
+  REQUIRE(120 == ts::round_up<10>(120));
+  REQUIRE(130 == ts::round_up<10>(121));
+
+  REQUIRE(110 == ts::round_down<10>(118));
+  REQUIRE(120 == ts::round_down<10>(120));
+  REQUIRE(120 == ts::round_down<10>(121));
+
+  REQUIRE(1200 == ts::round_up<100>(1108));
+  REQUIRE(1200 == ts::round_up<100>(1200));
+  REQUIRE(1300 == ts::round_up<100>(1201));
+
+  REQUIRE(100 == ts::round_down<100>(118));
+  REQUIRE(1100 == ts::round_down<100>(1108));
+  REQUIRE(1200 == ts::round_down<100>(1200));
+  REQUIRE(1200 == ts::round_down<100>(1208));
 }
 
 TEST_CASE("Scalar Factors", "[libts][Scalar][factors]")