LibSWOC++ 1.5.14
Solid Wall of C++
Loading...
Searching...
No Matches
Scalar.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Apache Software Foundation 2019
11#pragma once
12
13#include <cstdint>
14#include <ratio>
15#include <ostream>
16#include <type_traits>
17
18#include "swoc/swoc_version.h"
19#include "swoc/swoc_meta.h"
20
21namespace swoc { inline namespace SWOC_VERSION_NS {
22
23namespace tag {
25struct generic;
26} // namespace tag
27
28template <intmax_t N, typename C, typename T> class Scalar;
29
30namespace detail {
32
33// @internal - although these conversion methods look bulky, in practice they compile down to
34// very small amounts of code due to the conditions being compile time constant - the non-taken
35// clauses are dead code and eliminated by the compiler.
36
37// The general case where neither N nor S are a multiple of the other seems a bit long but this
38// minimizes the risk of integer overflow. I need to validate that under -O2 the compiler will
39// only do 1 division to get both the quotient and remainder for (n/N) and (n%N). In cases where
40// N,S are powers of 2 I have verified recent GNU compilers will optimize to bit operations.
41
42// Convert a count @a c that is scale @a S to scale @c N
43template <intmax_t N, intmax_t S, typename C>
44C
45scale_conversion_round_up(C c) {
46 using R = std::ratio<N, S>;
47 if constexpr (N == S) {
48 return c;
49 } else if constexpr (R::den == 1) {
50 return c / R::num + (0 != c % R::num); // N is a multiple of S.
51 } else if constexpr (R::num == 1) {
52 return c * R::den; // S is a multiple of N.
53 }
54 return (c / R::num) * R::den + ((c % R::num) * R::den) / R::num + (0 != (c % R::num));
55}
56
57// Convert a count @a c that is scale @a S to scale @c N
58template <intmax_t N, intmax_t S, typename C>
59C
60scale_conversion_round_down(C c) {
61 using R = std::ratio<N, S>;
62 if constexpr (N == S) {
63 return c;
64 } else if constexpr (R::den == 1) {
65 return c / R::num; // N = k S
66 } else if constexpr (R::num == 1) {
67 return c * R::den; // S = k N
68 }
69 return (c / R::num) * R::den + ((c % R::num) * R::den) / R::num;
70}
71
72/* Helper classes for @c Scalar
73
74 These wrap values to capture extra information for @c Scalar methods. This includes whether to
75 round up or down when converting and, when the wrapped data is also a @c Scalar, the scale.
76
77 These are not intended for direct use but by the @c round_up and @c round_down free functions
78 which capture the information about the argument and construct an instance of one of these
79 classes to pass it on to a @c Scalar method.
80
81 Scale conversions between @c Scalar instances are handled in these classes via the templated
82 methods @c scale_conversion_round_up and @c scale_conversion_round_down.
83
84 Conversions between scales and types for the scalar helpers is done inside the helper classes
85 and a user type conversion operator exists so the helper can be converted by the compiler to
86 the correct type. For the units base conversion this is done in @c Scalar because the
87 generality of the needed conversion is too broad to be easily used. It can be done but there is
88 some ugliness due to the fact that in some cases two user conversions are needed, which is
89 difficult to deal with. I have tried it both ways and overall this seems a cleaner
90 implementation.
91
92 Much of this is driven by the fact that the assignment operator, in some cases, can not be
93 templated and therefore to have a nice interface for assignment this split is needed.
94
95 Note - the key point is the actual conversion is not done when the wrapper instance is created
96 but when the wrapper instance is assigned. That is what enables the conversion to be done in
97 the context of the destination, which is not otherwise possible.
98 */
99
100// Unit value, to be rounded up.
101template <typename C> struct scalar_unit_round_up_t {
102 C _n;
103
104 template <intmax_t N, typename I>
105 constexpr I
106 scale() const {
107 return static_cast<I>(_n / N + (0 != (_n % N)));
108 }
109};
110
111// Unit value, to be rounded down.
112template <typename C> struct scalar_unit_round_down_t {
113 C _n;
114
115 template <intmax_t N, typename I>
116 constexpr I
117 scale() const {
118 return static_cast<I>(_n / N);
119 }
120};
121
122// Scalar value, to be rounded up.
123template <intmax_t N, typename C, typename T> struct scalar_round_up_t {
124 C _n;
125
126 template <intmax_t S, typename I>
127 constexpr
128 operator Scalar<S, I, T>() const {
129 return Scalar<S, I, T>(scale_conversion_round_up<S, N>(_n));
130 }
131};
132
133// Scalar value, to be rounded down.
134template <intmax_t N, typename C, typename T> struct scalar_round_down_t {
135 C _n;
136
137 template <intmax_t S, typename I>
138 constexpr
139 operator Scalar<S, I, T>() const {
140 return Scalar<S, I, T>(scale_conversion_round_down<S, N>(_n));
141 }
142};
143
145} // namespace detail
146
172template <intmax_t N, typename C = int, typename T = tag::generic> class Scalar {
173 using self_type = Scalar;
174
175public:
177 constexpr static intmax_t SCALE = N;
178 using Counter = C;
179 using Tag = T;
180
181 static_assert(N > 0, "The scaling factor (1st template argument) must be a positive integer");
182 static_assert(std::is_integral<C>::value, "The counter type (2nd template argument) must be an integral type");
183
184 constexpr Scalar();
185
187 explicit constexpr Scalar(Counter n);
188
190 constexpr Scalar(self_type const &that);
191
193 template <typename I> constexpr Scalar(Scalar<N, I, T> const &that);
194
197 template <intmax_t S, typename I> constexpr Scalar(Scalar<S, I, T> const &that);
198
200 // Assignment from internal rounding structures.
201 // Conversion constructor.
202 constexpr Scalar(detail::scalar_round_up_t<N, C, T> const &v);
203
204 // Conversion constructor.
205 constexpr Scalar(detail::scalar_round_down_t<N, C, T> const &that);
206
207 // Conversion constructor.
208 template <typename I> constexpr Scalar(detail::scalar_unit_round_up_t<I> v);
209
210 // Conversion constructor.
211 template <typename I> constexpr Scalar(detail::scalar_unit_round_down_t<I> v);
213
225 template <intmax_t S, typename I> self_type &operator=(Scalar<S, I, T> const &that);
226
228 self_type &operator=(self_type const &that);
229
231
237 template <typename I> self_type &operator=(detail::scalar_unit_round_up_t<I> n);
238
245 template <typename I> self_type &operator=(detail::scalar_unit_round_down_t<I> n);
246
255 self_type &operator=(detail::scalar_round_up_t<N, C, T> v);
256
265 self_type &operator=(detail::scalar_round_down_t<N, C, T> v);
267
277 self_type &assign(Counter n);
278
283 template <intmax_t S, typename I> self_type &assign(Scalar<S, I, T> const &that);
284
286 template <typename I> self_type &assign(detail::scalar_unit_round_up_t<I> n);
287
288 template <typename I> self_type &assign(detail::scalar_unit_round_down_t<I> n);
289
290 self_type &assign(detail::scalar_round_up_t<N, C, T> v);
291
292 self_type &assign(detail::scalar_round_down_t<N, C, T> v);
294
296 constexpr Counter count() const;
297
299 constexpr Counter value() const;
300
302 constexpr operator Counter() const;
303
308 self_type &operator+=(self_type const &that);
309
319 template <intmax_t S, typename I> self_type &operator+=(Scalar<S, I, T> const &that);
320
322 template <typename I> self_type &operator+=(detail::scalar_unit_round_up_t<I> n);
323
324 template <typename I> self_type &operator+=(detail::scalar_unit_round_down_t<I> n);
325
326 self_type &operator+=(detail::scalar_round_up_t<N, C, T> v);
327
328 self_type &operator+=(detail::scalar_round_down_t<N, C, T> v);
330
332 self_type &operator++();
333
335 self_type operator++(int);
336
338 self_type &operator--();
339
341 self_type operator--(int);
342
344 self_type &inc(Counter n);
345
347 self_type &dec(Counter n);
348
353 self_type &operator-=(self_type const &that);
354
364 template <intmax_t S, typename I> self_type &operator-=(Scalar<S, I, T> const &that);
365
367 template <typename I> self_type &operator-=(detail::scalar_unit_round_up_t<I> n);
368
369 template <typename I> self_type &operator-=(detail::scalar_unit_round_down_t<I> n);
370
371 self_type &operator-=(detail::scalar_round_up_t<N, C, T> v);
372
373 self_type &operator-=(detail::scalar_round_down_t<N, C, T> v);
375
377 self_type &operator*=(C n);
378
380 self_type &operator/=(C n);
381
383 self_type operator()(Counter n) const;
384
386 self_type plus(Counter n) const;
387
389 self_type minus(Counter n) const;
390
392 static constexpr intmax_t scale();
393
394protected:
396};
397
399// Avoid issues with doxygen matching externally defined methods.
400template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, T>::Scalar() : _n() {}
401
402template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, T>::Scalar(Counter n) : _n(n) {}
403
404template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, T>::Scalar(self_type const &that) : _n(that._n) {}
405
406template <intmax_t N, typename C, typename T>
407template <typename I>
408constexpr Scalar<N, C, T>::Scalar(Scalar<N, I, T> const &that) : _n(static_cast<C>(that.count())) {}
409
410template <intmax_t N, typename C, typename T>
411template <intmax_t S, typename I>
412constexpr Scalar<N, C, T>::Scalar(Scalar<S, I, T> const &that) : _n(std::ratio<S, N>::num * that.count()) {
413 static_assert(std::ratio<S, N>::den == 1,
414 "Construction not permitted - target scale is not an integral multiple of source scale.");
415}
416
417template <intmax_t N, typename C, typename T>
418constexpr Scalar<N, C, T>::Scalar(detail::scalar_round_up_t<N, C, T> const &v) : _n(v._n) {}
419
420template <intmax_t N, typename C, typename T>
421constexpr Scalar<N, C, T>::Scalar(detail::scalar_round_down_t<N, C, T> const &v) : _n(v._n) {}
422
423template <intmax_t N, typename C, typename T>
424template <typename I>
425constexpr Scalar<N, C, T>::Scalar(detail::scalar_unit_round_up_t<I> v) : _n(v.template scale<N, C>()) {}
426
427template <intmax_t N, typename C, typename T>
428template <typename I>
429constexpr Scalar<N, C, T>::Scalar(detail::scalar_unit_round_down_t<I> v) : _n(v.template scale<N, C>()) {}
430
431template <intmax_t N, typename C, typename T>
432constexpr auto
433Scalar<N, C, T>::count() const -> Counter {
434 return _n;
435}
436
437template <intmax_t N, typename C, typename T>
438constexpr C
440 return _n * SCALE;
441}
442
443template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, T>::operator Counter() const {
444 return _n * SCALE;
445}
446
447template <intmax_t N, typename C, typename T>
448inline auto
449Scalar<N, C, T>::assign(Counter n) -> self_type & {
450 _n = n;
451 return *this;
452}
453
454template <intmax_t N, typename C, typename T>
455inline auto
456Scalar<N, C, T>::operator=(self_type const &that) -> self_type & {
457 _n = that._n;
458 return *this;
459}
460
461template <intmax_t N, typename C, typename T>
462inline auto
463Scalar<N, C, T>::operator=(detail::scalar_round_up_t<N, C, T> v) -> self_type & {
464 _n = v._n;
465 return *this;
466}
467
468template <intmax_t N, typename C, typename T>
469inline auto
470Scalar<N, C, T>::assign(detail::scalar_round_up_t<N, C, T> v) -> self_type & {
471 _n = v._n;
472 return *this;
473}
474
475template <intmax_t N, typename C, typename T>
476inline auto
477Scalar<N, C, T>::operator=(detail::scalar_round_down_t<N, C, T> v) -> self_type & {
478 _n = v._n;
479 return *this;
480}
481
482template <intmax_t N, typename C, typename T>
483inline auto
484Scalar<N, C, T>::assign(detail::scalar_round_down_t<N, C, T> v) -> self_type & {
485 _n = v._n;
486 return *this;
487}
488
489template <intmax_t N, typename C, typename T>
490template <typename I>
491inline auto
492Scalar<N, C, T>::operator=(detail::scalar_unit_round_up_t<I> v) -> self_type & {
493 _n = v.template scale<N, C>();
494 return *this;
495}
496
497template <intmax_t N, typename C, typename T>
498template <typename I>
499inline auto
500Scalar<N, C, T>::assign(detail::scalar_unit_round_up_t<I> v) -> self_type & {
501 _n = v.template scale<N, C>();
502 return *this;
503}
504
505template <intmax_t N, typename C, typename T>
506template <typename I>
507inline auto
508Scalar<N, C, T>::operator=(detail::scalar_unit_round_down_t<I> v) -> self_type & {
509 _n = v.template scale<N, C>();
510 return *this;
511}
512
513template <intmax_t N, typename C, typename T>
514template <typename I>
515inline auto
516Scalar<N, C, T>::assign(detail::scalar_unit_round_down_t<I> v) -> self_type & {
517 _n = v.template scale<N, C>();
518 return *this;
519}
520
521template <intmax_t N, typename C, typename T>
522template <intmax_t S, typename I>
523auto
524Scalar<N, C, T>::operator=(Scalar<S, I, T> const &that) -> self_type & {
525 using R = std::ratio<S, N>;
526 static_assert(R::den == 1, "Assignment not permitted - target scale is not an integral multiple of source scale.");
527 _n = that.count() * R::num;
528 return *this;
529}
530
531template <intmax_t N, typename C, typename T>
532template <intmax_t S, typename I>
533auto
534Scalar<N, C, T>::assign(Scalar<S, I, T> const &that) -> self_type & {
535 using R = std::ratio<S, N>;
536 static_assert(R::den == 1, "Assignment not permitted - target scale is not an integral multiple of source scale.");
537 _n = that.count() * R::num;
538 return *this;
539}
540
541template <intmax_t N, typename C, typename T>
542constexpr inline intmax_t
544 return SCALE;
545}
546
548
549// --- Functions ---
550
557template <typename C>
558constexpr detail::scalar_unit_round_up_t<C>
560 return {n};
561}
562
571template <intmax_t N, typename C, typename T>
572constexpr detail::scalar_round_up_t<N, C, T>
574 return {v.count()};
575}
576
583template <typename C>
584constexpr detail::scalar_unit_round_down_t<C>
586 return {n};
587}
588
597template <intmax_t N, typename C, typename T>
598constexpr detail::scalar_round_down_t<N, C, T>
600 return {v.count()};
601}
602
603// --- Compare operators
604// These optimize nicely because if R::num or R::den is 1 the compiler will drop it.
605
606template <intmax_t N, typename C1, intmax_t S, typename I, typename T>
607bool
608operator<(Scalar<N, C1, T> const &lhs, Scalar<S, I, T> const &rhs) {
609 using R = std::ratio<N, S>;
610 return lhs.count() * R::num < rhs.count() * R::den;
611}
612
613template <intmax_t N, typename C1, intmax_t S, typename I, typename T>
614bool
615operator==(Scalar<N, C1, T> const &lhs, Scalar<S, I, T> const &rhs) {
616 using R = std::ratio<N, S>;
617 return lhs.count() * R::num == rhs.count() * R::den;
618}
619
620template <intmax_t N, typename C1, intmax_t S, typename I, typename T>
621bool
622operator<=(Scalar<N, C1, T> const &lhs, Scalar<S, I, T> const &rhs) {
623 using R = std::ratio<N, S>;
624 return lhs.count() * R::num <= rhs.count() * R::den;
625}
626
627// Derived compares.
628template <intmax_t N, typename C, intmax_t S, typename I, typename T>
629bool
630operator>(Scalar<N, C, T> const &lhs, Scalar<S, I, T> const &rhs) {
631 return rhs < lhs;
632}
633
634template <intmax_t N, typename C, intmax_t S, typename I, typename T>
635bool
636operator>=(Scalar<N, C, T> const &lhs, Scalar<S, I, T> const &rhs) {
637 return rhs <= lhs;
638}
639
640// Arithmetic operators
641template <intmax_t N, typename C, typename T>
642auto
643Scalar<N, C, T>::operator+=(self_type const &that) -> self_type & {
644 _n += that._n;
645 return *this;
646}
647
648template <intmax_t N, typename C, typename T>
649template <intmax_t S, typename I>
650auto
651Scalar<N, C, T>::operator+=(Scalar<S, I, T> const &that) -> self_type & {
652 using R = std::ratio<S, N>;
653 static_assert(R::den == 1, "Addition not permitted - target scale is not an integral multiple of source scale.");
654 _n += that.count() * R::num;
655 return *this;
656}
657
659template <intmax_t N, typename C, typename T>
660template <typename I>
661auto
662Scalar<N, C, T>::operator+=(detail::scalar_unit_round_up_t<I> v) -> self_type & {
663 _n += v.template scale<N, C>();
664 return *this;
665}
666
667template <intmax_t N, typename C, typename T>
668template <typename I>
669auto
670Scalar<N, C, T>::operator+=(detail::scalar_unit_round_down_t<I> v) -> self_type & {
671 _n += v.template scale<N, C>();
672 return *this;
673}
674
675template <intmax_t N, typename C, typename T>
676auto
677Scalar<N, C, T>::operator+=(detail::scalar_round_up_t<N, C, T> v) -> self_type & {
678 _n += v._n;
679 return *this;
680}
681
682template <intmax_t N, typename C, typename T>
683auto
684Scalar<N, C, T>::operator+=(detail::scalar_round_down_t<N, C, T> v) -> self_type & {
685 _n += v._n;
686 return *this;
687}
688
690
691template <intmax_t N, typename C, intmax_t S, typename I, typename T>
692auto
693operator+(Scalar<N, C, T> lhs, Scalar<S, I, T> const &rhs) -> typename std::common_type<Scalar<N, C, T>, Scalar<S, I, T>>::type {
694 return typename std::common_type<Scalar<N, C, T>, Scalar<S, I, T>>::type(lhs) += rhs;
695}
696
700template <intmax_t N, typename C, typename T>
702operator+(Scalar<N, C, T> const &lhs, Scalar<N, C, T> const &rhs) {
703 return Scalar<N, C, T>(lhs) += rhs;
704}
705
707// These handle adding a wrapper and a scalar.
708template <intmax_t N, typename C, typename T, typename I>
709Scalar<N, C, T>
710operator+(detail::scalar_unit_round_up_t<I> lhs, Scalar<N, C, T> const &rhs) {
711 return Scalar<N, C, T>(rhs) += lhs;
712}
713
714template <intmax_t N, typename C, typename T, typename I>
716operator+(Scalar<N, C, T> const &lhs, detail::scalar_unit_round_up_t<I> rhs) {
717 return Scalar<N, C, T>(lhs) += rhs;
718}
719
720template <intmax_t N, typename C, typename T, typename I>
722operator+(detail::scalar_unit_round_down_t<I> lhs, Scalar<N, C, T> const &rhs) {
723 return Scalar<N, C, T>(rhs) += lhs;
724}
725
726template <intmax_t N, typename C, typename T, typename I>
728operator+(Scalar<N, C, T> const &lhs, detail::scalar_unit_round_down_t<I> rhs) {
729 return Scalar<N, C, T>(lhs) += rhs;
730}
731
732template <intmax_t N, typename C, typename T>
734operator+(detail::scalar_round_up_t<N, C, T> lhs, Scalar<N, C, T> const &rhs) {
735 return Scalar<N, C, T>(rhs) += lhs._n;
736}
737
738template <intmax_t N, typename C, typename T>
740operator+(Scalar<N, C, T> const &lhs, detail::scalar_round_up_t<N, C, T> rhs) {
741 return Scalar<N, C, T>(lhs) += rhs._n;
742}
743
744template <intmax_t N, typename C, typename T>
746operator+(detail::scalar_round_down_t<N, C, T> lhs, Scalar<N, C, T> const &rhs) {
747 return Scalar<N, C, T>(rhs) += lhs._n;
748}
749
750template <intmax_t N, typename C, typename T>
752operator+(Scalar<N, C, T> const &lhs, detail::scalar_round_down_t<N, C, T> rhs) {
753 return Scalar<N, C, T>(lhs) += rhs._n;
754}
756
757template <intmax_t N, typename C, typename T>
758auto
759Scalar<N, C, T>::operator-=(self_type const &that) -> self_type & {
760 _n -= that._n;
761 return *this;
762}
763
764template <intmax_t N, typename C, typename T>
765template <intmax_t S, typename I>
766auto
767Scalar<N, C, T>::operator-=(Scalar<S, I, T> const &that) -> self_type & {
768 using R = std::ratio<S, N>;
769 static_assert(R::den == 1, "Subtraction not permitted - target scale is not an integral multiple of source scale.");
770 _n -= that.count() * R::num;
771 return *this;
772}
773
775
776template <intmax_t N, typename C, typename T>
777template <typename I>
778auto
779Scalar<N, C, T>::operator-=(detail::scalar_unit_round_up_t<I> v) -> self_type & {
780 _n -= v.template scale<N, C>();
781 return *this;
782}
783
784template <intmax_t N, typename C, typename T>
785template <typename I>
786auto
787Scalar<N, C, T>::operator-=(detail::scalar_unit_round_down_t<I> v) -> self_type & {
788 _n -= v.template scale<N, C>();
789 return *this;
790}
791
792template <intmax_t N, typename C, typename T>
793auto
794Scalar<N, C, T>::operator-=(detail::scalar_round_up_t<N, C, T> v) -> self_type & {
795 _n -= v._n;
796 return *this;
797}
798
799template <intmax_t N, typename C, typename T>
800auto
801Scalar<N, C, T>::operator-=(detail::scalar_round_down_t<N, C, T> v) -> self_type & {
802 _n -= v._n;
803 return *this;
804}
805
807
808template <intmax_t N, typename C, intmax_t S, typename I, typename T>
809auto
810operator-(Scalar<N, C, T> lhs, Scalar<S, I, T> const &rhs) -> typename std::common_type<Scalar<N, C, T>, Scalar<S, I, T>>::type {
811 return typename std::common_type<Scalar<N, C, T>, Scalar<S, I, T>>::type(lhs) -= rhs;
812}
813
817template <intmax_t N, typename C, typename T>
819operator-(Scalar<N, C, T> const &lhs, Scalar<N, C, T> const &rhs) {
820 return Scalar<N, C, T>(lhs) -= rhs;
821}
822
824// Handle subtraction for intermediate wrappers.
825template <intmax_t N, typename C, typename T, typename I>
826Scalar<N, C, T>
827operator-(detail::scalar_unit_round_up_t<I> lhs, Scalar<N, C, T> const &rhs) {
828 return Scalar<N, C, T>(lhs.template scale<N, C>()) -= rhs;
829}
830
831template <intmax_t N, typename C, typename T, typename I>
833operator-(Scalar<N, C, T> const &lhs, detail::scalar_unit_round_up_t<I> rhs) {
834 return Scalar<N, C, T>(lhs) -= rhs;
835}
836
837template <intmax_t N, typename C, typename T, typename I>
839operator-(detail::scalar_unit_round_down_t<I> lhs, Scalar<N, C, T> const &rhs) {
840 return Scalar<N, C, T>(lhs.template scale<N, C>()) -= rhs;
841}
842
843template <intmax_t N, typename C, typename T, typename I>
845operator-(Scalar<N, C, T> const &lhs, detail::scalar_unit_round_down_t<I> rhs) {
846 return Scalar<N, C, T>(lhs) -= rhs;
847}
848
849template <intmax_t N, typename C, typename T>
851operator-(detail::scalar_round_up_t<N, C, T> lhs, Scalar<N, C, T> const &rhs) {
852 return Scalar<N, C, T>(lhs._n) -= rhs;
853}
854
855template <intmax_t N, typename C, typename T>
857operator-(Scalar<N, C, T> const &lhs, detail::scalar_round_up_t<N, C, T> rhs) {
858 return Scalar<N, C, T>(lhs) -= rhs._n;
859}
860
861template <intmax_t N, typename C, typename T>
863operator-(detail::scalar_round_down_t<N, C, T> lhs, Scalar<N, C, T> const &rhs) {
864 return Scalar<N, C, T>(lhs._n) -= rhs;
865}
866
867template <intmax_t N, typename C, typename T>
869operator-(Scalar<N, C, T> const &lhs, detail::scalar_round_down_t<N, C, T> rhs) {
870 return Scalar<N, C, T>(lhs) -= rhs._n;
871}
873
874template <intmax_t N, typename C, typename T>
875auto
877 ++_n;
878 return *this;
879}
880
881template <intmax_t N, typename C, typename T>
882auto
884 self_type zret(*this);
885 ++_n;
886 return zret;
887}
888
889template <intmax_t N, typename C, typename T>
890auto
892 --_n;
893 return *this;
894}
895
896template <intmax_t N, typename C, typename T>
897auto
899 self_type zret(*this);
900 --_n;
901 return zret;
902}
903
904template <intmax_t N, typename C, typename T>
905auto
906Scalar<N, C, T>::inc(Counter n) -> self_type & {
907 _n += n;
908 return *this;
909}
910
911template <intmax_t N, typename C, typename T>
912auto
913Scalar<N, C, T>::dec(Counter n) -> self_type & {
914 _n -= n;
915 return *this;
916}
917
918template <intmax_t N, typename C, typename T>
919auto
920Scalar<N, C, T>::operator*=(C n) -> self_type & {
921 _n *= n;
922 return *this;
923}
924
925template <intmax_t N, typename C, typename T>
927operator*(Scalar<N, C, T> const &lhs, C n) {
928 return Scalar<N, C, T>(lhs) *= n;
929}
930
931template <intmax_t N, typename C, typename T>
932Scalar<N, C, T>
933operator*(C n, Scalar<N, C, T> const &rhs) {
934 return Scalar<N, C, T>(rhs) *= n;
935}
936
937template <intmax_t N, typename C, typename T>
939operator*(Scalar<N, C, T> const &lhs, int n) {
940 return Scalar<N, C, T>(lhs) *= n;
941}
942
943template <intmax_t N, typename C, typename T>
945operator*(int n, Scalar<N, C, T> const &rhs) {
946 return Scalar<N, C, T>(rhs) *= n;
947}
948
949template <intmax_t N>
951operator*(Scalar<N, int> const &lhs, int n) {
952 return Scalar<N, int>(lhs) *= n;
953}
954
955template <intmax_t N>
957operator*(int n, Scalar<N, int> const &rhs) {
958 return Scalar<N, int>(rhs) *= n;
959}
960
961template <intmax_t N, typename C, typename T>
962auto
963Scalar<N, C, T>::operator/=(C n) -> self_type & {
964 _n /= n;
965 return *this;
966}
967
968template <intmax_t N, typename C, intmax_t S, typename I, typename T>
969auto
970operator/(Scalar<N, C, T> lhs, Scalar<S, I, T> rhs) -> typename std::common_type<C, I>::type {
971 using R = std::ratio<N, S>;
972 return (lhs.count() * R::num) / (rhs.count() * R::den);
973}
974
975template <intmax_t N, typename C, typename T, typename I>
976Scalar<N, C, T>
977operator/(Scalar<N, C, T> lhs, I n) {
978 static_assert(std::is_integral<I>::value, "Scalar divsion only support integral types.");
979 return Scalar<N, C, T>(lhs) /= n;
980}
981
982template <intmax_t N, typename C, typename T>
983auto
985 return self_type{n};
986}
987
988template <intmax_t N, typename C, typename T>
989auto
990Scalar<N, C, T>::plus(Counter n) const -> self_type {
991 return {_n + n};
992}
993
994template <intmax_t N, typename C, typename T>
995auto
996Scalar<N, C, T>::minus(Counter n) const -> self_type {
997 return {_n - n};
998}
999
1013template <intmax_t N, typename C>
1014C
1015round_up(C value) {
1016 return N * detail::scale_conversion_round_up<N, 1>(value);
1017}
1018
1032template <intmax_t N, typename C>
1033C
1034round_down(C value) {
1035 return N * detail::scale_conversion_round_down<N, 1>(value);
1036}
1037
1038namespace detail {
1039template <typename T>
1040auto
1041tag_label(std::ostream &, const meta::CaseTag<0> &) -> void {}
1042
1043template <typename T>
1044auto
1045tag_label(std::ostream &w, const meta::CaseTag<1> &) -> decltype(T::label, meta::TypeFunc<void>()) {
1046 w << T::label;
1047}
1048
1049template <typename T>
1050inline std::ostream &
1051tag_label(std::ostream &w) {
1052 tag_label<T>(w, meta::CaseArg);
1053 return w;
1054}
1055} // namespace detail
1056}} // namespace swoc::SWOC_VERSION_NS
1057
1058namespace std {
1062template <intmax_t N, typename C, intmax_t S, typename I, typename T>
1063struct common_type<swoc::Scalar<N, C, T>, swoc::Scalar<S, I, T>> {
1064 using R = std::ratio<N, S>;
1065 using type = swoc::Scalar<N / R::num, typename common_type<C, I>::type, T>;
1066};
1067
1068template <intmax_t N, typename C, typename T>
1069ostream &
1070operator<<(ostream &s, swoc::Scalar<N, C, T> const &x) {
1071 s << x.value();
1072 return swoc::detail::tag_label<T>(s);
1073}
1074
1075} // namespace std
self_type & operator/=(C n)
Division - divide (rounding down) the count by n.
Definition Scalar.h:963
self_type plus(Counter n) const
Return a value at the same scale with a count increased by n.
Definition Scalar.h:990
constexpr Counter count() const
The number of scale units.
self_type & operator*=(C n)
Multiplication - multiple the count by n.
Definition Scalar.h:920
self_type & operator+=(Scalar< S, I, T > const &that)
self_type & assign(Counter n)
self_type operator--(int)
Decrement - decrease count by 1.
Definition Scalar.h:898
constexpr Scalar(Scalar< S, I, T > const &that)
self_type & operator=(self_type const &that)
Self type assignment.
constexpr Counter value() const
The scaled value.
constexpr Scalar(Counter n)
Construct to have value that is n scaled units.
self_type & operator--()
Decrement - decrease count by 1.
Definition Scalar.h:891
constexpr Scalar()
Default constructor.
self_type & operator-=(self_type const &that)
Definition Scalar.h:759
self_type & operator-=(Scalar< S, I, T > const &that)
self_type & dec(Counter n)
Decrement by n.
Definition Scalar.h:913
self_type & operator+=(self_type const &that)
Definition Scalar.h:643
self_type minus(Counter n) const
Return a value at the same scale with a count decreased by n.
Definition Scalar.h:996
self_type & operator=(Scalar< S, I, T > const &that)
constexpr Scalar(self_type const &that)
Copy constructor.
self_type & operator++()
Increment - increase count by 1.
Definition Scalar.h:876
self_type operator()(Counter n) const
Utility overload of the function operator to create instances at the same scale.
Definition Scalar.h:984
static constexpr intmax_t scale()
Run time access to the scale (template arg N).
constexpr Scalar(Scalar< N, I, T > const &that)
Copy constructor.
self_type operator++(int)
Increment - increase count by 1.
Definition Scalar.h:883
self_type & inc(Counter n)
Increment by n.
Definition Scalar.h:906
tag::generic Tag
Definition Scalar.h:179
static constexpr intmax_t SCALE
Definition Scalar.h:177
self_type & assign(Scalar< S, I, T > const &that)
STL namespace.
For template deduction guides.
Definition ArenaWriter.cc:9
bool operator>(IP4Addr const &lhs, IP4Addr const &rhs)
Definition IPAddr.h:863
bool operator<=(IP4Addr const &lhs, IP4Addr const &rhs)
Definition IPAddr.h:857
bool operator>=(IP4Addr const &lhs, IP4Addr const &rhs)
Definition IPAddr.h:869
Scalar_INTERNAL constexpr detail::scalar_unit_round_up_t< C > round_up(C n)
Definition Scalar.h:559
bool operator==(IPAddr const &lhs, sockaddr const *sa)
Equality.
Definition swoc_ip.cc:650
bool operator<(IP4Addr const &lhs, IP4Addr const &rhs)
Definition IPAddr.h:851
constexpr detail::scalar_unit_round_down_t< C > round_down(C n)
Definition Scalar.h:585