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 f6d3887  Doc: First sketch of Scalar documentation.
f6d3887 is described below

commit f6d388731ff4d3a93b534a2f49341ee42a593733
Author: Alan M. Carroll <[email protected]>
AuthorDate: Tue Mar 14 11:08:37 2017 -0500

    Doc: First sketch of Scalar documentation.
---
 doc/developer-guide/api/types/SystemTypes.en.rst   |   8 +
 .../internal-libraries/index.en.rst                |   3 +-
 .../internal-libraries/scalar.en.rst               | 254 ++++++++++++++++++
 lib/ts/Scalar.h                                    | 288 ++++++++++-----------
 lib/ts/test_Scalar.cc                              |  41 +--
 5 files changed, 422 insertions(+), 172 deletions(-)

diff --git a/doc/developer-guide/api/types/SystemTypes.en.rst 
b/doc/developer-guide/api/types/SystemTypes.en.rst
index d8ba024..76b8d65 100644
--- a/doc/developer-guide/api/types/SystemTypes.en.rst
+++ b/doc/developer-guide/api/types/SystemTypes.en.rst
@@ -56,3 +56,11 @@ These types are provided by the compiler ("built-in") or 
from a required operati
 .. cpp:type:: size_t
 
    `Reference <https://linux.die.net/include/stdint.h>`__.
+
+.. cpp:type:: intmax_t
+
+   The largest native signed integer type.
+
+.. cpp:type:: unspecified_type
+
+   This represents a type whose name is not known to, nor needed by, the API 
user. Usually this is a complex template which is consumed by other elements of 
the API and not intended for explicit use.
diff --git a/doc/developer-guide/internal-libraries/index.en.rst 
b/doc/developer-guide/internal-libraries/index.en.rst
index de56316..1b6cd1e 100644
--- a/doc/developer-guide/internal-libraries/index.en.rst
+++ b/doc/developer-guide/internal-libraries/index.en.rst
@@ -28,4 +28,5 @@ development team.
 .. toctree::
    :maxdepth: 2
 
-   memview.en.rst
+   memview.en
+   scalar.en
diff --git a/doc/developer-guide/internal-libraries/scalar.en.rst 
b/doc/developer-guide/internal-libraries/scalar.en.rst
new file mode 100644
index 0000000..73dd69b
--- /dev/null
+++ b/doc/developer-guide/internal-libraries/scalar.en.rst
@@ -0,0 +1,254 @@
+.. Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements. See the NOTICE file distributed 
with this work for
+   additional information regarding copyright ownership. The ASF licenses this 
file to you under the
+   Apache License, Version 2.0 (the "License"); you may not use this file 
except in compliance with
+   the License. You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software 
distributed under the License
+   is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+   or implied. See the License for the specific language governing permissions 
and limitations under
+   the License.
+
+.. include:: ../../common.defs
+
+.. _lib_scalar:
+
+.. highlight:: cpp
+
+.. default-domain:: cpp
+
+TS.Scalar
+*********
+
+TS.Scalar is a header only library that provides scaled and typed numerical 
values. Using TS.Scalar
+starts with defining types which have a *scale factor* and optionally a *tag*. 
Values in an instance
+of TS.Scalar are always multiples of the scale factor.
+
+The tag is used to create categories of related types, the same underlying 
"metric" at different scales. To enforce this TS.Scalar does not allow 
assignment between instances with different tags. If this is not important the 
tag can be omitted and a default generic one will be used, thereby allowing 
arbitrary assignments.
+
+TS.Scalar is designed to be fast and efficient. When converting bewteen 
similar types with different
+scales it will do the minimum amout of work while minimizing the risk of 
integer overflow. Instances
+have the same memory footprint as the underlying integer storage type. It is 
intended to replace
+lengthy and error prone hand optimizations used to handle related values of 
different scales.
+
+Definition
+**********
+
+TS.Scalar consists primarily of the template class :code:`Scalar`. Instances 
of :class:`Scalar` hold
+a *count* and represent a *value* which is the *count* multiplied by 
:arg:`SCALE`. Note this
+quantizes the values that can be represented by an instance.
+
+.. class:: template < intmax_t SCALE, typename COUNTER, typename TAG > Scalar
+
+   .. var:: intmax_t SCALE
+
+      The scaling factor for the type. This must be an positive integer. 
Values for an instance will
+      always be an integral multiple of :arg:`SCALE`.
+
+   .. type:: COUNTER
+
+      This is the type used to hold the internal count. This must be an 
integral type. It can be omitted and will default to :code:`int`. The size of 
an instance is the same size as :arg:`COUNTER`.
+
+   .. type:: TAG
+
+      A distinguishing tag which must be a type. It can be omitted and will 
default to :code:`tag::generic`. This means that :class:`Scalar` types without 
a tag will all interoperate. The tag type is usually a :code:`struct` defined 
in name only. ::
+
+         struct YoureIt; // no other information about YoureIt is required.
+         typedef Scalar<100, int, YoureIt> HectoTouch; // how many hundreds of 
touches.
+
+      :arg:`TAG` s a mechanism for preventing accidental cross assignments. 
Assignment of any sort from
+      a :class:`Scalar` to another with a different :arg:`TAG` is a compile 
time error. If this isn't
+      useful the :arg:`TAG` can be omitted and will default to the same for 
all derived types.
+
+   .. function:: COUNTER count() const
+
+      Return the internal count.
+
+   .. function: intmax_t value() const
+
+      Return the value.
+
+   .. function:: Scalar& assign(COUNTER c)
+
+      Set the count to :arg:`c`.
+
+Usage
+******
+
+In normal use a scalar evaluates to its value rather than its count. The goal 
is to provide an
+instance that appears to store unscaled values in a quantized way. The count 
is accessible if
+needed.
+
+Assigment
+=========
+
+Assigning values to, from, and between :class:`Scalar` instances is usually 
straightforward with a few simple rules.
+
+*  The :func:`Scalar::assign` is used to directly assign a count.
+*  The increment and decrement operators, and the :code:`inc` and :code:`dec` 
methods, operate on the count.
+*  All other contexts use the value.
+*  The assignment operator will scale if this can be done without loss, 
otherwise it is a compile error.
+*  Untyped integer values are treated as having a :arg:`SCALE` of 1.
+
+If the assignment of one scalar to another is not lossless (e.g. the left hand 
side of the assignment has a large scale than the right hand side) one of the 
two following free functions must be used to indicate how to handle the loss.
+
+.. function:: unspecified_type round_up(Scalar v)
+
+   Return a wrapper that indicates :arg:`v` should be rounded up as needed.
+
+.. function:: unspecified_type round_down(Scalar vs)
+
+   Return a wrapper that indicates :arg:`v` should be rounded down as needed.
+
+To illustrate, suppose there were the definitions
+
+.. code-block:: cpp
+
+   typedef Scalar<10> deka;
+   typedef Scalar<100> hecto;
+
+An assignment of a :code:`hecto` to a :code:`deka` is implicit as the scaling 
is lossless.
+
+.. code-block:: cpp
+
+   hecto a(17);
+   deka b;
+   b = a; // compiles.
+
+The opposite is not implicit because the value of a :code:`deka` can be one 
not representable by a :code:`hecto`. In such a case it would have to be 
rounded, either up or down.
+
+.. code-block:: cpp
+
+   b.assign(143); // b gets the value 1430
+   a = b; // compile error
+   a = round_up(b); // a has count 15 and value 1500
+
+:code:`round_up` and :code:`round_down` can also be used with basic integers.
+
+.. function:: unspecified_type round_down(intmax_t)
+
+.. function:: unspecified_type round_up(intmax_t)
+
+Note this is very different from using :func:`Scalar::assign`. The latter sets 
the *count* of
+the scalar instance. :code:`round_up` and :code:`round_down` set the *value* 
of the scalar, dividing
+the provided value by the scale to set the count to make the value match the 
assignment as closesly
+as possible.
+
+.. code-block:: cpp
+
+   a = round_down(2480); // a has count 24, value 2400.
+
+Arithmetic
+==========
+
+Arithmetic with scalars is based on the idea that a scalar represents its 
value. This value retains the
+scalar type for conversion checking but otherwise acts as the value. This 
makes using scalar
+instances as integral arguments to other functions simple. For instance 
consider following the
+definition.
+
+.. code-block:: cpp
+
+   struct SerializedData { ...};
+   using Sector = Scalar<512>;
+
+To allocate a buffer large enough for a :code:`SerializedData` that is also a 
multiple of a sector would be
+
+.. code-block:: cpp
+
+   Sector n = round_up(sizeof(serialized_data));
+   void* buffer = malloc(n);
+
+Or more directly
+
+.. code-block:: cpp
+
+   void* buffer = malloc(Sector(round_up(sizeof(serialized_data))));
+
+TS.Scalar is designed to be easy to use but when using multiple scales 
simultaneously, especially in the same expression, the computed type can be 
surprising. The best approach is to be explicit - a TS.Scalar instance is very 
inexpensive to create (at most 1 integer copy) therefore subexpressions can 
easily be forced to a specific scale by constructing the appropriate scalar 
with :code:`round_up` or :code:`round_down` of the subexpression. Or, define a 
unit scale type and convert to that [...]
+
+Advanced Features
+=================
+
+TS.Scalar has a few advanced features which are not usually needed and for 
which usable defaults are
+provided. This is not always the case and therefore access to the machinery is 
provided.
+
+I/O
+---
+
+When a scalar is printed it prints out as its value, not count. For a family 
of scalars it can be
+desireable to have the type printed along with the value. This can be done by 
adding a member named
+:literal:`label` to the *tag* type of the scalar. If the :literal:`label` 
member can be provided to
+an I/O stream then it will be after the value of the scalar. Otherwise it is 
ignored. An example can
+be found in the <Bytes>_ section of the example usage.
+
+Examples
+========
+
+The expected common use of TS.Scalar is to create a family of scalars 
representing the same
+underlying unit of measure, differing only in scale. The standard example of 
this is computer memory
+sizezs which have this property and are quite frequently used in |TS|.
+
+Bytes
+-----
+
+The initial use of :class:`Scalar` will be in the cache component. This has 
already been tested in some experimental work which will in time be blended 
back in to the main codebase. The use will be to represent different amounts of 
data, in memory and on disk.
+
+.. code-block:: cpp
+
+   namespace tag { struct bytes { static const char * label = " bytes"; }; }
+   typedef Scalar<1, off_t, tag::bytes> Bytes;
+   typedef Scalar<512, off_t, tag::bytes> CacheDiskBlocks;
+   typedef Scalar<1024, off_t, tag::byteds> KB;
+   typedef Scalar<8 * KB::SCALE, off_t, tag::bytes> CacheStoreBlocks;
+   typedef Scalar<1024 * KB::SCALE, off_t, tag::bytes> MB;
+   typedef Scalar<128 * MB::SCALE, off_t, tag::bytes> CacheStripeBlocks;
+   typedef Scalar<1024 * MB::SCALE, off_t, tag::bytes> GB;
+   typedef Scalar<1024 * GB::SCALE, off_t, tag::bytes> TB
+
+This collection of types represents the data size units of interest to the 
cache and therefore enables to code to be much clearer about the units and to 
avoid errors in converting from one to another.
+
+A common task is to add sizes together and round up to a multiple of some 
fixed size. One example is the stripe header data, which is stored as a 
multiple of 8192 bytes, that is a number of :code:`CacheStripeBlocks`. That can 
be done with
+
+.. code-block:: cpp
+
+   header->len = round_up(sizeof(CacheStripMeta) + segment_count * 
sizeof(SegmentFreeListHead));
+
+vs. the original code with magic constants and the hope that the value is 
scaled as you think it is.
+
+.. code-block:: cpp
+
+   header->len = (((sizeof(CacheStripeMeta) + header->segments * 
sizeof(SegmentFreeListHead)) >> STORE_BLOCK_SHIFT) << STORE_BLOCK_SHIFT)
+
+Esoteric Uses
+--------------
+
+Scalar type can be useful even with only temporaries. For instance, to round 
to the nearest 100.
+
+.. code-block:: cpp
+
+   int round_100(int y) { return Scalar<100>(round_up(y)); }
+
+This could also be done in line just as well avoiding the boiler plate logic.
+
+Design Notes
+============
+
+The semantics of arithmetic were the most vexing issue in building this 
library. The ultimate
+problem is that addition to the count and to the value are both reasonable and 
common operations and
+different users may well have different expectations of which is more 
"natural" when operating with
+a scalar and a raw numeric value. In practice my conclusion was that even 
before feeling "natural"
+the library should avoid surprise. Therefore the ambiguity of arithmetic with 
non-scalars was
+avoided by not permitting those operations, even though it can mean a bit more 
work on the part of
+the library user. The increment / decrement and compound assignment operators 
were judged sufficient
+similar to pointer arithmetic to be unsurprising in this context. This was 
further influenced by the
+fact that, in general, these operators are useless in the value context. E.g. 
if a scalar has a
+scale greater than 1 (the common case) then increment and decrement of the 
value is always a null
+operation. Once those operators are used on the count is is least surprising 
that the compound
+operators act in the same way. The next step, to arithmetic operators, is not 
so clear and so those
+require explicit scale indicators, such as :code:`round_down` or explicit 
constructors. It was a
+design goal to avoid, as much as possible, the requirement that the library 
user keep track of the
+scale of specific variables. This has proved very useful in practice, but at 
the same time when
+doing arithmentic is is almost always the case that either the values are both 
scalars (making the
+arithmetic unambiguous) or the scale of the literal is known (e.g., "add 6 
kilobytes").
diff --git a/lib/ts/Scalar.h b/lib/ts/Scalar.h
index c2f7caa..92b2665 100644
--- a/lib/ts/Scalar.h
+++ b/lib/ts/Scalar.h
@@ -157,6 +157,7 @@ round_up(C n)
 {
   return {n};
 }
+
 /// Mark a @c Scalar value to be scaled, rounding up.
 template <intmax_t N, typename C, typename T>
 constexpr detail::scalar_round_up_t<N, C, T>
@@ -164,6 +165,7 @@ round_up(Scalar<N, C, T> v)
 {
   return {v.count()};
 }
+
 /// Mark a unit value to be scaled, rounding down.
 template <typename C>
 constexpr detail::scalar_unit_round_down_t<C>
@@ -171,6 +173,7 @@ round_down(C n)
 {
   return {n};
 }
+
 /// Mark a @c Scalar value, to be rounded down.
 template <intmax_t N, typename C, typename T>
 constexpr detail::scalar_round_down_t<N, C, T>
@@ -211,15 +214,15 @@ template <intmax_t N, typename C = int, typename T = 
tag::generic> class Scalar
 public:
   /// Scaling factor - make it external accessible.
   constexpr static intmax_t SCALE = N;
-  typedef C Count; ///< Type used to hold the count.
-  typedef T Tag;   ///< Make tag accessible.
+  typedef C Counter; ///< Type used to hold the count.
+  typedef T Tag;     ///< Make tag accessible.
 
   static_assert(N > 0, "The scaling factor (1st template argument) must be a 
positive integer");
   static_assert(std::is_integral<C>::value, "The counter type (2nd template 
argument) must be an integral type");
 
   constexpr Scalar(); ///< Default contructor.
   ///< Construct to have @a n scaled units.
-  explicit constexpr Scalar(Count n);
+  explicit constexpr Scalar(Counter n);
   /// Copy constructor.
   constexpr Scalar(self const &that); /// Copy constructor.
   /// Copy constructor for same scale.
@@ -251,7 +254,7 @@ public:
 
   /// Direct assignment.
   /// The count is set to @a n.
-  self &assign(Count n);
+  self &assign(Counter n);
   /// The value @a that is scaled appropriately.
   /// @note Requires the scale of @a that be an integer multiple of the scale 
of @a this. If this isn't the case then
   /// the @c round_up or @c round_down must be used to indicate the rounding 
direction.
@@ -263,21 +266,18 @@ public:
   self &assign(detail::scalar_round_down_t<N, C, T> v);
 
   /// The number of scale units.
-  constexpr Count count() const;
+  constexpr Counter count() const;
   /// The scaled value.
-  constexpr Count units() const;
+  constexpr intmax_t value() const;
   /// User conversion to scaled value.
-  constexpr operator Count() const;
+  constexpr operator intmax_t() const;
 
   /// Addition operator.
   /// The value is scaled from @a that to @a this.
   /// @note Requires the scale of @a that be an integer multiple of the scale 
of @a this. If this isn't the case then
   /// the @c scale_up or @c scale_down casts must be used to indicate the 
rounding direction.
-  template <intmax_t S, typename I> self &operator+=(Scalar<S, I, T> const 
&that);
-  /// Addition - add @a n as a number of scaled units.
-  self &operator+=(C n);
-  /// Addition - add @a n as a number of scaled units.
   self &operator+=(self const &that);
+  template <intmax_t S, typename I> self &operator+=(Scalar<S, I, T> const 
&that);
   template <typename I> self &operator+=(detail::scalar_unit_round_up_t<I> n);
   template <typename I> self &operator+=(detail::scalar_unit_round_down_t<I> 
n);
   self &operator+=(detail::scalar_round_up_t<N, C, T> v);
@@ -291,17 +291,17 @@ public:
   self &operator--();
   /// Decrement - decrease count by 1.
   self operator--(int);
+  /// Increment by @a n.
+  self &inc(Counter n);
+  /// Decrement by @a n.
+  self &dec(Counter n);
 
   /// Subtraction operator.
   /// The value is scaled from @a that to @a this.
   /// @note Requires the scale of @a that be an integer multiple of the scale 
of @a this. If this isn't the case then
   /// the @c scale_up or @c scale_down casts must be used to indicate the 
rounding direction.
-  template <intmax_t S, typename I> self &operator-=(Scalar<S, I, T> const 
&that);
-  /// Subtraction - subtract @a n as a number of scaled units.
-  self &operator-=(C n);
-  /// Subtraction - subtract @a n as a number of scaled units.
   self &operator-=(self const &that);
-
+  template <intmax_t S, typename I> self &operator-=(Scalar<S, I, T> const 
&that);
   template <typename I> self &operator-=(detail::scalar_unit_round_up_t<I> n);
   template <typename I> self &operator-=(detail::scalar_unit_round_down_t<I> 
n);
   self &operator-=(detail::scalar_round_up_t<N, C, T> v);
@@ -313,17 +313,26 @@ public:
   /// Division - divide (rounding down) the count by @a n.
   self &operator/=(C n);
 
+  /// Utility overload of the function operator to create instances at the 
same scale.
+  self operator()(Counter n) const;
+
+  /// Return a value at the same scale with a count increased by @a n.
+  self plus(Counter n) const;
+
+  /// Return a value at the same scale with a count decreased by @a n.
+  self minus(Counter n) const;
+
   /// Run time access to the scale (template arg @a N).
   static constexpr intmax_t scale();
 
 protected:
-  Count _n; ///< Number of scale units.
+  Counter _n; ///< Number of scale units.
 };
 
 template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, 
T>::Scalar() : _n()
 {
 }
-template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, 
T>::Scalar(Count n) : _n(n)
+template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, 
T>::Scalar(Counter n) : _n(n)
 {
 }
 template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, 
T>::Scalar(self const &that) : _n(that._n)
@@ -362,28 +371,31 @@ constexpr Scalar<N, C, 
T>::Scalar(detail::scalar_unit_round_down_t<I> v) : _n(v.
 
 template <intmax_t N, typename C, typename T>
 constexpr auto
-Scalar<N, C, T>::count() const -> Count
+Scalar<N, C, T>::count() const -> Counter
 {
   return _n;
 }
+
 template <intmax_t N, typename C, typename T>
-constexpr auto
-Scalar<N, C, T>::units() const -> Count
+constexpr intmax_t
+Scalar<N, C, T>::value() const
 {
   return _n * SCALE;
 }
-template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, 
T>::operator C() const
+
+template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, 
T>::operator intmax_t() const
 {
   return _n * SCALE;
 }
 
 template <intmax_t N, typename C, typename T>
 inline auto
-Scalar<N, C, T>::assign(Count n) -> self &
+Scalar<N, C, T>::assign(Counter n) -> self &
 {
   _n = n;
   return *this;
 }
+
 template <intmax_t N, typename C, typename T>
 inline auto
 Scalar<N, C, T>::operator=(self const &that) -> self &
@@ -391,6 +403,7 @@ Scalar<N, C, T>::operator=(self const &that) -> self &
   _n = that._n;
   return *this;
 }
+
 template <intmax_t N, typename C, typename T>
 inline auto
 Scalar<N, C, T>::operator=(detail::scalar_round_up_t<N, C, T> v) -> self &
@@ -494,7 +507,7 @@ operator<(Scalar<N, C1, T> const &lhs, Scalar<S, I, T> 
const &rhs)
   else if (R::num == 1)
     return lhs.count() < rhs.count() * R::den;
   else
-    return lhs.units() < rhs.units();
+    return lhs.value() < rhs.value();
 }
 
 template <intmax_t N, typename C1, intmax_t S, typename I, typename T>
@@ -509,7 +522,7 @@ operator==(Scalar<N, C1, T> const &lhs, Scalar<S, I, T> 
const &rhs)
   else if (R::num == 1)
     return lhs.count() == rhs.count() * R::den;
   else
-    return lhs.units() == rhs.units();
+    return lhs.value() == rhs.value();
 }
 
 template <intmax_t N, typename C1, intmax_t S, typename I, typename T>
@@ -524,7 +537,7 @@ operator<=(Scalar<N, C1, T> const &lhs, Scalar<S, I, T> 
const &rhs)
   else if (R::num == 1)
     return lhs.count() <= rhs.count() * R::den;
   else
-    return lhs.units() <= rhs.units();
+    return lhs.value() <= rhs.value();
 }
 
 // Derived compares.
@@ -552,212 +565,207 @@ template <intmax_t N, typename C, typename T>
 bool
 operator<(Scalar<N, C, T> const &lhs, C n)
 {
-  return lhs.units() < n;
+  return lhs.value() < n;
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator<(C n, Scalar<N, C, T> const &rhs)
 {
-  return n < rhs.units();
+  return n < rhs.value();
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator<(Scalar<N, C, T> const &lhs, int n)
 {
-  return lhs.units() < static_cast<C>(n);
+  return lhs.value() < static_cast<C>(n);
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator<(int n, Scalar<N, C, T> const &rhs)
 {
-  return static_cast<C>(n) < rhs.units();
+  return static_cast<C>(n) < rhs.value();
 }
 template <intmax_t N>
 bool
 operator<(Scalar<N, int> const &lhs, int n)
 {
-  return lhs.units() < n;
+  return lhs.value() < n;
 }
 template <intmax_t N>
 bool
 operator<(int n, Scalar<N, int> const &rhs)
 {
-  return n < rhs.units();
+  return n < rhs.value();
 }
 
 template <intmax_t N, typename C, typename T>
 bool
 operator==(Scalar<N, C, T> const &lhs, C n)
 {
-  return lhs.units() == n;
+  return lhs.value() == n;
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator==(C n, Scalar<N, C, T> const &rhs)
 {
-  return n == rhs.units();
+  return n == rhs.value();
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator==(Scalar<N, C, T> const &lhs, int n)
 {
-  return lhs.units() == static_cast<C>(n);
+  return lhs.value() == static_cast<C>(n);
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator==(int n, Scalar<N, C, T> const &rhs)
 {
-  return static_cast<C>(n) == rhs.units();
+  return static_cast<C>(n) == rhs.value();
 }
 template <intmax_t N>
 bool
 operator==(Scalar<N, int> const &lhs, int n)
 {
-  return lhs.units() == n;
+  return lhs.value() == n;
 }
 template <intmax_t N>
 bool
 operator==(int n, Scalar<N, int> const &rhs)
 {
-  return n == rhs.units();
+  return n == rhs.value();
 }
 
 template <intmax_t N, typename C, typename T>
 bool
 operator>(Scalar<N, C, T> const &lhs, C n)
 {
-  return lhs.units() > n;
+  return lhs.value() > n;
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator>(C n, Scalar<N, C, T> const &rhs)
 {
-  return n > rhs.units();
+  return n > rhs.value();
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator>(Scalar<N, C, T> const &lhs, int n)
 {
-  return lhs.units() > static_cast<C>(n);
+  return lhs.value() > static_cast<C>(n);
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator>(int n, Scalar<N, C, T> const &rhs)
 {
-  return static_cast<C>(n) > rhs.units();
+  return static_cast<C>(n) > rhs.value();
 }
 template <intmax_t N>
 bool
 operator>(Scalar<N, int> const &lhs, int n)
 {
-  return lhs.units() > n;
+  return lhs.value() > n;
 }
 template <intmax_t N>
 bool
 operator>(int n, Scalar<N, int> const &rhs)
 {
-  return n > rhs.units();
+  return n > rhs.value();
 }
 
 template <intmax_t N, typename C, typename T>
 bool
 operator<=(Scalar<N, C, T> const &lhs, C n)
 {
-  return lhs.units() <= n;
+  return lhs.value() <= n;
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator<=(C n, Scalar<N, C, T> const &rhs)
 {
-  return n <= rhs.units();
+  return n <= rhs.value();
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator<=(Scalar<N, C, T> const &lhs, int n)
 {
-  return lhs.units() <= static_cast<C>(n);
+  return lhs.value() <= static_cast<C>(n);
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator<=(int n, Scalar<N, C, T> const &rhs)
 {
-  return static_cast<C>(n) <= rhs.units();
+  return static_cast<C>(n) <= rhs.value();
 }
 template <intmax_t N>
 bool
 operator<=(Scalar<N, int> const &lhs, int n)
 {
-  return lhs.units() <= n;
+  return lhs.value() <= n;
 }
 template <intmax_t N>
 bool
 operator<=(int n, Scalar<N, int> const &rhs)
 {
-  return n <= rhs.units();
+  return n <= rhs.value();
 }
 
 template <intmax_t N, typename C, typename T>
 bool
 operator>=(Scalar<N, C, T> const &lhs, C n)
 {
-  return lhs.units() >= n;
+  return lhs.value() >= n;
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator>=(C n, Scalar<N, C, T> const &rhs)
 {
-  return n >= rhs.units();
+  return n >= rhs.value();
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator>=(Scalar<N, C, T> const &lhs, int n)
 {
-  return lhs.units() >= static_cast<C>(n);
+  return lhs.value() >= static_cast<C>(n);
 }
 template <intmax_t N, typename C, typename T>
 bool
 operator>=(int n, Scalar<N, C, T> const &rhs)
 {
-  return static_cast<C>(n) >= rhs.units();
+  return static_cast<C>(n) >= rhs.value();
 }
 template <intmax_t N>
 bool
 operator>=(Scalar<N, int> const &lhs, int n)
 {
-  return lhs.units() >= n;
+  return lhs.value() >= n;
 }
 template <intmax_t N>
 bool
 operator>=(int n, Scalar<N, int> const &rhs)
 {
-  return n >= rhs.units();
+  return n >= rhs.value();
 }
 
 // Arithmetic operators
 template <intmax_t N, typename C, typename T>
-template <intmax_t S, typename I>
-auto
-Scalar<N, C, T>::operator+=(Scalar<S, I, T> const &that) -> self &
-{
-  typedef std::ratio<S, N> R;
-  static_assert(R::den == 1, "Addition not permitted - target scale is not an 
integral multiple of source scale.");
-  _n += that.count() * R::num;
-  return *this;
-}
-template <intmax_t N, typename C, typename T>
 auto
 Scalar<N, C, T>::operator+=(self const &that) -> self &
 {
   _n += that._n;
   return *this;
 }
+
 template <intmax_t N, typename C, typename T>
+template <intmax_t S, typename I>
 auto
-Scalar<N, C, T>::operator+=(C n) -> self &
+Scalar<N, C, T>::operator+=(Scalar<S, I, T> const &that) -> self &
 {
-  _n += n;
+  typedef std::ratio<S, N> R;
+  static_assert(R::den == 1, "Addition not permitted - target scale is not an 
integral multiple of source scale.");
+  _n += that.count() * R::num;
   return *this;
 }
+
 template <intmax_t N, typename C, typename T>
 template <typename I>
 auto
@@ -766,6 +774,7 @@ Scalar<N, C, 
T>::operator+=(detail::scalar_unit_round_up_t<I> v) -> self &
   _n += v.template scale<N, C>();
   return *this;
 }
+
 template <intmax_t N, typename C, typename T>
 template <typename I>
 auto
@@ -802,54 +811,21 @@ operator+(Scalar<N, C, T> const &lhs, Scalar<N, C, T> 
const &rhs)
 {
   return Scalar<N, C, T>(lhs) += rhs;
 }
-template <intmax_t N, typename C, typename T>
-Scalar<N, C, T>
-operator+(Scalar<N, C, T> const &lhs, C n)
-{
-  return Scalar<N, C, T>(lhs) += n;
-}
-template <intmax_t N, typename C, typename T>
-Scalar<N, C, T>
-operator+(C n, Scalar<N, C, T> const &rhs)
-{
-  return Scalar<N, C, T>(rhs) += n;
-}
-template <intmax_t N, typename C, typename T>
-Scalar<N, C, T>
-operator+(Scalar<N, C, T> const &lhs, int n)
-{
-  return Scalar<N, C, T>(lhs) += n;
-}
-template <intmax_t N, typename C, typename T>
-Scalar<N, C, T>
-operator+(int n, Scalar<N, C, T> const &rhs)
-{
-  return Scalar<N, C, T>(rhs) += n;
-}
-template <intmax_t N, typename T>
-Scalar<N, int>
-operator+(Scalar<N, int, T> const &lhs, int n)
-{
-  return Scalar<N, int, T>(lhs) += n;
-}
-template <intmax_t N>
-Scalar<N, int>
-operator+(int n, Scalar<N, int> const &rhs)
-{
-  return Scalar<N, int>(rhs) += n;
-}
+
 template <intmax_t N, typename C, typename T, typename I>
 Scalar<N, C, T>
 operator+(detail::scalar_unit_round_up_t<I> lhs, Scalar<N, C, T> const &rhs)
 {
   return Scalar<N, C, T>(rhs) += lhs.template scale<N, C>();
 }
+
 template <intmax_t N, typename C, typename T, typename I>
 Scalar<N, C, T>
 operator+(Scalar<N, C, T> const &lhs, detail::scalar_unit_round_up_t<I> rhs)
 {
   return Scalar<N, C, T>(lhs) += rhs.template scale<N, C>();
 }
+
 template <intmax_t N, typename C, typename T, typename I>
 Scalar<N, C, T>
 operator+(detail::scalar_unit_round_down_t<I> lhs, Scalar<N, C, T> const &rhs)
@@ -888,29 +864,24 @@ operator+(Scalar<N, C, T> const &lhs, 
detail::scalar_round_down_t<N, C, T> rhs)
 }
 
 template <intmax_t N, typename C, typename T>
-template <intmax_t S, typename I>
-auto
-Scalar<N, C, T>::operator-=(Scalar<S, I, T> const &that) -> self &
-{
-  typedef std::ratio<S, N> R;
-  static_assert(R::den == 1, "Subtraction not permitted - target scale is not 
an integral multiple of source scale.");
-  _n -= that.count() * R::num;
-  return *this;
-}
-template <intmax_t N, typename C, typename T>
 auto
 Scalar<N, C, T>::operator-=(self const &that) -> self &
 {
   _n -= that._n;
   return *this;
 }
+
 template <intmax_t N, typename C, typename T>
+template <intmax_t S, typename I>
 auto
-Scalar<N, C, T>::operator-=(C n) -> self &
+Scalar<N, C, T>::operator-=(Scalar<S, I, T> const &that) -> self &
 {
-  _n -= n;
+  typedef std::ratio<S, N> R;
+  static_assert(R::den == 1, "Subtraction not permitted - target scale is not 
an integral multiple of source scale.");
+  _n -= that.count() * R::num;
   return *this;
 }
+
 template <intmax_t N, typename C, typename T>
 template <typename I>
 auto
@@ -955,84 +926,56 @@ operator-(Scalar<N, C, T> const &lhs, Scalar<N, C, T> 
const &rhs)
 {
   return Scalar<N, C, T>(lhs) -= rhs;
 }
-template <intmax_t N, typename C, typename T>
-Scalar<N, C, T>
-operator-(Scalar<N, C, T> const &lhs, C n)
-{
-  return Scalar<N, C, T>(lhs) -= n;
-}
-template <intmax_t N, typename C, typename T>
-Scalar<N, C, T>
-operator-(C n, Scalar<N, C, T> const &rhs)
-{
-  return Scalar<N, C, T>(n) -= rhs;
-}
-template <intmax_t N, typename C, typename T>
-Scalar<N, C, T>
-operator-(Scalar<N, C, T> const &lhs, int n)
-{
-  return Scalar<N, C, T>(lhs) -= n;
-}
-template <intmax_t N, typename C, typename T>
-Scalar<N, C, T>
-operator-(int n, Scalar<N, C, T> const &rhs)
-{
-  return Scalar<N, C, T>(n) -= rhs;
-}
-template <intmax_t N>
-Scalar<N, int>
-operator-(Scalar<N, int> const &lhs, int n)
-{
-  return Scalar<N, int>(lhs) -= n;
-}
-template <intmax_t N>
-Scalar<N, int>
-operator-(int n, Scalar<N, int> const &rhs)
-{
-  return Scalar<N, int>(n) -= rhs;
-}
+
 template <intmax_t N, typename C, typename T, typename I>
 Scalar<N, C, T>
 operator-(detail::scalar_unit_round_up_t<I> lhs, Scalar<N, C, T> const &rhs)
 {
   return Scalar<N, C, T>(lhs.template scale<N, C>()) -= rhs;
 }
+
 template <intmax_t N, typename C, typename T, typename I>
 Scalar<N, C, T>
 operator-(Scalar<N, C, T> const &lhs, detail::scalar_unit_round_up_t<I> rhs)
 {
   return Scalar<N, C, T>(lhs) -= rhs.template scale<N, C>();
 }
+
 template <intmax_t N, typename C, typename T, typename I>
 Scalar<N, C, T>
 operator-(detail::scalar_unit_round_down_t<I> lhs, Scalar<N, C, T> const &rhs)
 {
   return Scalar<N, C, T>(lhs.template scale<N, C>()) -= rhs;
 }
+
 template <intmax_t N, typename C, typename T, typename I>
 Scalar<N, C, T>
 operator-(Scalar<N, C, T> const &lhs, detail::scalar_unit_round_down_t<I> rhs)
 {
   return Scalar<N, C, T>(lhs) -= rhs.template scale<N, C>();
 }
+
 template <intmax_t N, typename C, typename T>
 Scalar<N, C, T>
 operator-(detail::scalar_round_up_t<N, C, T> lhs, Scalar<N, C, T> const &rhs)
 {
   return Scalar<N, C, T>(lhs._n) -= rhs;
 }
+
 template <intmax_t N, typename C, typename T>
 Scalar<N, C, T>
 operator-(Scalar<N, C, T> const &lhs, detail::scalar_round_up_t<N, C, T> rhs)
 {
   return Scalar<N, C, T>(lhs) -= rhs._n;
 }
+
 template <intmax_t N, typename C, typename T>
 Scalar<N, C, T>
 operator-(detail::scalar_round_down_t<N, C, T> lhs, Scalar<N, C, T> const &rhs)
 {
   return Scalar<N, C, T>(lhs._n) -= rhs;
 }
+
 template <intmax_t N, typename C, typename T>
 Scalar<N, C, T>
 operator-(Scalar<N, C, T> const &lhs, detail::scalar_round_down_t<N, C, T> rhs)
@@ -1068,6 +1011,22 @@ template <intmax_t N, typename C, typename T> auto 
Scalar<N, C, T>::operator--(i
 
 template <intmax_t N, typename C, typename T>
 auto
+Scalar<N, C, T>::inc(Counter n) -> self &
+{
+  _n += n;
+  return *this;
+}
+
+template <intmax_t N, typename C, typename T>
+auto
+Scalar<N, C, T>::dec(Counter n) -> self &
+{
+  _n -= n;
+  return *this;
+}
+
+template <intmax_t N, typename C, typename T>
+auto
 Scalar<N, C, T>::operator*=(C n) -> self &
 {
   _n *= n;
@@ -1113,12 +1072,14 @@ operator/(Scalar<N, C, T> const &lhs, C n)
 {
   return Scalar<N, C, T>(lhs) /= n;
 }
+
 template <intmax_t N, typename C, typename T>
 Scalar<N, C, T>
 operator/(Scalar<N, C, T> const &lhs, int n)
 {
   return Scalar<N, C, T>(lhs) /= n;
 }
+
 template <intmax_t N>
 Scalar<N, int>
 operator/(Scalar<N, int> const &lhs, int n)
@@ -1126,6 +1087,27 @@ operator/(Scalar<N, int> const &lhs, int n)
   return Scalar<N, int>(lhs) /= n;
 }
 
+template <intmax_t N, typename C, typename T>
+auto
+Scalar<N, C, T>::operator()(Counter n) const -> self
+{
+  return self{n};
+}
+
+template <intmax_t N, typename C, typename T>
+auto
+Scalar<N, C, T>::plus(Counter n) const -> self
+{
+  return {_n + n};
+}
+
+template <intmax_t N, typename C, typename T>
+auto
+Scalar<N, C, T>::minus(Counter n) const -> self
+{
+  return {_n - n};
+}
+
 namespace detail
 {
   // These classes exist only to create distinguishable overloads.
@@ -1162,7 +1144,7 @@ ostream &
 operator<<(ostream &s, ApacheTrafficServer::Scalar<N, C, T> const &x)
 {
   static ApacheTrafficServer::detail::tag_label_B b; // Can't be const or the 
compiler gets upset.
-  s << x.units();
+  s << x.value();
   return ApacheTrafficServer::detail::tag_label<T>(s, b);
 }
 
diff --git a/lib/ts/test_Scalar.cc b/lib/ts/test_Scalar.cc
index dece272..3696103 100644
--- a/lib/ts/test_Scalar.cc
+++ b/lib/ts/test_Scalar.cc
@@ -64,7 +64,7 @@ struct TestBox {
 
   template <typename A, typename B, typename... Rest>
   bool
-  equal(A const &expected, B const &got, Rest const &... rest)
+  equal(A const &got, B const &expected, Rest const &... rest)
   {
     return result(expected == got, "Expected ", expected, " got ", got, 
rest...);
   }
@@ -118,7 +118,7 @@ Test_1()
   PageSize pg1(1);
 
   test.equal(pg1.count(), 1, "Count wrong", FAIL_LINE);
-  test.equal(pg1.units(), SCALE, "Units wrong", FAIL_LINE);
+  test.equal(pg1.value(), SCALE, "Units wrong", FAIL_LINE);
 }
 
 // Test multiples.
@@ -229,19 +229,19 @@ Test_5()
   KBytes kbytes(2);
   MBytes mbytes(5);
 
-  Bytes z1 = bytes + 128;
+  Bytes z1 = ts::round_up(bytes + 128);
   test.equal(z1.count(), 224, FAIL_LINE);
-  KBytes z2 = kbytes + 3;
+  KBytes z2 = kbytes + kbytes(3);
   test.equal(z2.count(), 5, FAIL_LINE);
   Bytes z3(bytes);
   z3 += kbytes;
-  test.equal(z3.units(), 2048 + 96, FAIL_LINE);
+  test.equal(z3.value(), 2048 + 96, FAIL_LINE);
   MBytes z4 = mbytes;
-  z4 += 5;
+  z4.inc(5);
   z2 += z4;
-  test.equal(z2.units(), (10 << 20) + (5 << 10), FAIL_LINE);
+  test.equal(z2.value(), (10 << 20) + (5 << 10), FAIL_LINE);
 
-  z1 += 128;
+  z1.inc(128);
   test.equal(z1.count(), 352, FAIL_LINE);
 
   z2.assign(2);
@@ -269,7 +269,7 @@ Test_5()
   z2 += ts::round_up(97384);
   test.equal(z2.count(), 353, FAIL_LINE);
 
-  decltype(z2) a = z2 + ts::round_down(167229);
+  decltype(z2) a = ts::round_down(z2 + 167229);
   test.equal(a.count(), 516, FAIL_LINE);
 
   KiBytes k(3148);
@@ -289,7 +289,7 @@ Test_5()
   k += ts::round_up(97384);
   test.equal(k.count(), 353, FAIL_LINE);
 
-  decltype(k) ka = k + ts::round_down(167229);
+  decltype(k) ka = ts::round_down(k + 167229);
   test.equal(ka.count(), 516, FAIL_LINE);
 }
 
@@ -376,14 +376,19 @@ test_Compile()
     std::cout << "Operator > works" << std::endl;
   }
 
-  (void)(x += 10);
-  (void)(x += static_cast<int>(10));
-  (void)(x += static_cast<long int>(10));
-  (void)(x += delta);
-  (void)(y += 10);
-  (void)(y += static_cast<int>(10));
-  (void)(y += static_cast<long int>(10));
-  (void)(y += delta);
+  (void)(x.inc(10));
+  (void)(x.inc(static_cast<int>(10)));
+  (void)(x.inc(static_cast<long int>(10)));
+  (void)(x.inc(delta));
+  (void)(y.inc(10));
+  (void)(y.inc(static_cast<int>(10)));
+  (void)(y.inc(static_cast<long int>(10)));
+  (void)(y.inc(delta));
+
+  (void)(x.dec(10));
+  (void)(x.dec(static_cast<int>(10)));
+  (void)(x.dec(static_cast<long int>(10)));
+  (void)(x.dec(delta));
 }
 
 int

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to