xref: /aosp_15_r20/external/webrtc/net/dcsctp/common/sequence_numbers.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker #ifndef NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_
11*d9f75844SAndroid Build Coastguard Worker #define NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <cstdint>
14*d9f75844SAndroid Build Coastguard Worker #include <limits>
15*d9f75844SAndroid Build Coastguard Worker #include <utility>
16*d9f75844SAndroid Build Coastguard Worker 
17*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/common/internal_types.h"
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker namespace dcsctp {
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker // UnwrappedSequenceNumber handles wrapping sequence numbers and unwraps them to
22*d9f75844SAndroid Build Coastguard Worker // an int64_t value space, to allow wrapped sequence numbers to be easily
23*d9f75844SAndroid Build Coastguard Worker // compared for ordering.
24*d9f75844SAndroid Build Coastguard Worker //
25*d9f75844SAndroid Build Coastguard Worker // Sequence numbers are expected to be monotonically increasing, but they do not
26*d9f75844SAndroid Build Coastguard Worker // need to be unwrapped in order, as long as the difference to the previous one
27*d9f75844SAndroid Build Coastguard Worker // is not larger than half the range of the wrapped sequence number.
28*d9f75844SAndroid Build Coastguard Worker //
29*d9f75844SAndroid Build Coastguard Worker // The WrappedType must be a webrtc::StrongAlias type.
30*d9f75844SAndroid Build Coastguard Worker template <typename WrappedType>
31*d9f75844SAndroid Build Coastguard Worker class UnwrappedSequenceNumber {
32*d9f75844SAndroid Build Coastguard Worker  public:
33*d9f75844SAndroid Build Coastguard Worker   static_assert(
34*d9f75844SAndroid Build Coastguard Worker       !std::numeric_limits<typename WrappedType::UnderlyingType>::is_signed,
35*d9f75844SAndroid Build Coastguard Worker       "The wrapped type must be unsigned");
36*d9f75844SAndroid Build Coastguard Worker   static_assert(
37*d9f75844SAndroid Build Coastguard Worker       std::numeric_limits<typename WrappedType::UnderlyingType>::max() <
38*d9f75844SAndroid Build Coastguard Worker           std::numeric_limits<int64_t>::max(),
39*d9f75844SAndroid Build Coastguard Worker       "The wrapped type must be less than the int64_t value space");
40*d9f75844SAndroid Build Coastguard Worker 
41*d9f75844SAndroid Build Coastguard Worker   // The unwrapper is a sort of factory and converts wrapped sequence numbers to
42*d9f75844SAndroid Build Coastguard Worker   // unwrapped ones.
43*d9f75844SAndroid Build Coastguard Worker   class Unwrapper {
44*d9f75844SAndroid Build Coastguard Worker    public:
Unwrapper()45*d9f75844SAndroid Build Coastguard Worker     Unwrapper() : largest_(kValueLimit) {}
46*d9f75844SAndroid Build Coastguard Worker     Unwrapper(const Unwrapper&) = default;
47*d9f75844SAndroid Build Coastguard Worker     Unwrapper& operator=(const Unwrapper&) = default;
48*d9f75844SAndroid Build Coastguard Worker 
49*d9f75844SAndroid Build Coastguard Worker     // Given a wrapped `value`, and with knowledge of its current last seen
50*d9f75844SAndroid Build Coastguard Worker     // largest number, will return a value that can be compared using normal
51*d9f75844SAndroid Build Coastguard Worker     // operators, such as less-than, greater-than etc.
52*d9f75844SAndroid Build Coastguard Worker     //
53*d9f75844SAndroid Build Coastguard Worker     // This will also update the Unwrapper's state, to track the last seen
54*d9f75844SAndroid Build Coastguard Worker     // largest value.
Unwrap(WrappedType value)55*d9f75844SAndroid Build Coastguard Worker     UnwrappedSequenceNumber<WrappedType> Unwrap(WrappedType value) {
56*d9f75844SAndroid Build Coastguard Worker       WrappedType wrapped_largest =
57*d9f75844SAndroid Build Coastguard Worker           static_cast<WrappedType>(largest_ % kValueLimit);
58*d9f75844SAndroid Build Coastguard Worker       int64_t result = largest_ + Delta(value, wrapped_largest);
59*d9f75844SAndroid Build Coastguard Worker       if (largest_ < result) {
60*d9f75844SAndroid Build Coastguard Worker         largest_ = result;
61*d9f75844SAndroid Build Coastguard Worker       }
62*d9f75844SAndroid Build Coastguard Worker       return UnwrappedSequenceNumber<WrappedType>(result);
63*d9f75844SAndroid Build Coastguard Worker     }
64*d9f75844SAndroid Build Coastguard Worker 
65*d9f75844SAndroid Build Coastguard Worker     // Similar to `Unwrap`, but will not update the Unwrappers's internal state.
PeekUnwrap(WrappedType value)66*d9f75844SAndroid Build Coastguard Worker     UnwrappedSequenceNumber<WrappedType> PeekUnwrap(WrappedType value) const {
67*d9f75844SAndroid Build Coastguard Worker       WrappedType uint32_largest =
68*d9f75844SAndroid Build Coastguard Worker           static_cast<WrappedType>(largest_ % kValueLimit);
69*d9f75844SAndroid Build Coastguard Worker       int64_t result = largest_ + Delta(value, uint32_largest);
70*d9f75844SAndroid Build Coastguard Worker       return UnwrappedSequenceNumber<WrappedType>(result);
71*d9f75844SAndroid Build Coastguard Worker     }
72*d9f75844SAndroid Build Coastguard Worker 
73*d9f75844SAndroid Build Coastguard Worker     // Resets the Unwrapper to its pristine state. Used when a sequence number
74*d9f75844SAndroid Build Coastguard Worker     // is to be reset to zero.
Reset()75*d9f75844SAndroid Build Coastguard Worker     void Reset() { largest_ = kValueLimit; }
76*d9f75844SAndroid Build Coastguard Worker 
77*d9f75844SAndroid Build Coastguard Worker    private:
Delta(WrappedType value,WrappedType prev_value)78*d9f75844SAndroid Build Coastguard Worker     static int64_t Delta(WrappedType value, WrappedType prev_value) {
79*d9f75844SAndroid Build Coastguard Worker       static constexpr typename WrappedType::UnderlyingType kBreakpoint =
80*d9f75844SAndroid Build Coastguard Worker           kValueLimit / 2;
81*d9f75844SAndroid Build Coastguard Worker       typename WrappedType::UnderlyingType diff = *value - *prev_value;
82*d9f75844SAndroid Build Coastguard Worker       diff %= kValueLimit;
83*d9f75844SAndroid Build Coastguard Worker       if (diff < kBreakpoint) {
84*d9f75844SAndroid Build Coastguard Worker         return static_cast<int64_t>(diff);
85*d9f75844SAndroid Build Coastguard Worker       }
86*d9f75844SAndroid Build Coastguard Worker       return static_cast<int64_t>(diff) - kValueLimit;
87*d9f75844SAndroid Build Coastguard Worker     }
88*d9f75844SAndroid Build Coastguard Worker 
89*d9f75844SAndroid Build Coastguard Worker     int64_t largest_;
90*d9f75844SAndroid Build Coastguard Worker   };
91*d9f75844SAndroid Build Coastguard Worker 
92*d9f75844SAndroid Build Coastguard Worker   // Returns the wrapped value this type represents.
Wrap()93*d9f75844SAndroid Build Coastguard Worker   WrappedType Wrap() const {
94*d9f75844SAndroid Build Coastguard Worker     return static_cast<WrappedType>(value_ % kValueLimit);
95*d9f75844SAndroid Build Coastguard Worker   }
96*d9f75844SAndroid Build Coastguard Worker 
97*d9f75844SAndroid Build Coastguard Worker   template <typename H>
AbslHashValue(H state,const UnwrappedSequenceNumber<WrappedType> & hash)98*d9f75844SAndroid Build Coastguard Worker   friend H AbslHashValue(H state,
99*d9f75844SAndroid Build Coastguard Worker                          const UnwrappedSequenceNumber<WrappedType>& hash) {
100*d9f75844SAndroid Build Coastguard Worker     return H::combine(std::move(state), hash.value_);
101*d9f75844SAndroid Build Coastguard Worker   }
102*d9f75844SAndroid Build Coastguard Worker 
103*d9f75844SAndroid Build Coastguard Worker   bool operator==(const UnwrappedSequenceNumber<WrappedType>& other) const {
104*d9f75844SAndroid Build Coastguard Worker     return value_ == other.value_;
105*d9f75844SAndroid Build Coastguard Worker   }
106*d9f75844SAndroid Build Coastguard Worker   bool operator!=(const UnwrappedSequenceNumber<WrappedType>& other) const {
107*d9f75844SAndroid Build Coastguard Worker     return value_ != other.value_;
108*d9f75844SAndroid Build Coastguard Worker   }
109*d9f75844SAndroid Build Coastguard Worker   bool operator<(const UnwrappedSequenceNumber<WrappedType>& other) const {
110*d9f75844SAndroid Build Coastguard Worker     return value_ < other.value_;
111*d9f75844SAndroid Build Coastguard Worker   }
112*d9f75844SAndroid Build Coastguard Worker   bool operator>(const UnwrappedSequenceNumber<WrappedType>& other) const {
113*d9f75844SAndroid Build Coastguard Worker     return value_ > other.value_;
114*d9f75844SAndroid Build Coastguard Worker   }
115*d9f75844SAndroid Build Coastguard Worker   bool operator>=(const UnwrappedSequenceNumber<WrappedType>& other) const {
116*d9f75844SAndroid Build Coastguard Worker     return value_ >= other.value_;
117*d9f75844SAndroid Build Coastguard Worker   }
118*d9f75844SAndroid Build Coastguard Worker   bool operator<=(const UnwrappedSequenceNumber<WrappedType>& other) const {
119*d9f75844SAndroid Build Coastguard Worker     return value_ <= other.value_;
120*d9f75844SAndroid Build Coastguard Worker   }
121*d9f75844SAndroid Build Coastguard Worker 
122*d9f75844SAndroid Build Coastguard Worker   // Increments the value.
Increment()123*d9f75844SAndroid Build Coastguard Worker   void Increment() { ++value_; }
124*d9f75844SAndroid Build Coastguard Worker 
125*d9f75844SAndroid Build Coastguard Worker   // Returns the next value relative to this sequence number.
next_value()126*d9f75844SAndroid Build Coastguard Worker   UnwrappedSequenceNumber<WrappedType> next_value() const {
127*d9f75844SAndroid Build Coastguard Worker     return UnwrappedSequenceNumber<WrappedType>(value_ + 1);
128*d9f75844SAndroid Build Coastguard Worker   }
129*d9f75844SAndroid Build Coastguard Worker 
130*d9f75844SAndroid Build Coastguard Worker   // Returns a new sequence number based on `value`, and adding `delta` (which
131*d9f75844SAndroid Build Coastguard Worker   // may be negative).
AddTo(UnwrappedSequenceNumber<WrappedType> value,int delta)132*d9f75844SAndroid Build Coastguard Worker   static UnwrappedSequenceNumber<WrappedType> AddTo(
133*d9f75844SAndroid Build Coastguard Worker       UnwrappedSequenceNumber<WrappedType> value,
134*d9f75844SAndroid Build Coastguard Worker       int delta) {
135*d9f75844SAndroid Build Coastguard Worker     return UnwrappedSequenceNumber<WrappedType>(value.value_ + delta);
136*d9f75844SAndroid Build Coastguard Worker   }
137*d9f75844SAndroid Build Coastguard Worker 
138*d9f75844SAndroid Build Coastguard Worker   // Returns the absolute difference between `lhs` and `rhs`.
Difference(UnwrappedSequenceNumber<WrappedType> lhs,UnwrappedSequenceNumber<WrappedType> rhs)139*d9f75844SAndroid Build Coastguard Worker   static typename WrappedType::UnderlyingType Difference(
140*d9f75844SAndroid Build Coastguard Worker       UnwrappedSequenceNumber<WrappedType> lhs,
141*d9f75844SAndroid Build Coastguard Worker       UnwrappedSequenceNumber<WrappedType> rhs) {
142*d9f75844SAndroid Build Coastguard Worker     return (lhs.value_ > rhs.value_) ? (lhs.value_ - rhs.value_)
143*d9f75844SAndroid Build Coastguard Worker                                      : (rhs.value_ - lhs.value_);
144*d9f75844SAndroid Build Coastguard Worker   }
145*d9f75844SAndroid Build Coastguard Worker 
146*d9f75844SAndroid Build Coastguard Worker  private:
UnwrappedSequenceNumber(int64_t value)147*d9f75844SAndroid Build Coastguard Worker   explicit UnwrappedSequenceNumber(int64_t value) : value_(value) {}
148*d9f75844SAndroid Build Coastguard Worker   static constexpr int64_t kValueLimit =
149*d9f75844SAndroid Build Coastguard Worker       static_cast<int64_t>(1)
150*d9f75844SAndroid Build Coastguard Worker       << std::numeric_limits<typename WrappedType::UnderlyingType>::digits;
151*d9f75844SAndroid Build Coastguard Worker 
152*d9f75844SAndroid Build Coastguard Worker   int64_t value_;
153*d9f75844SAndroid Build Coastguard Worker };
154*d9f75844SAndroid Build Coastguard Worker 
155*d9f75844SAndroid Build Coastguard Worker // Unwrapped Transmission Sequence Numbers (TSN)
156*d9f75844SAndroid Build Coastguard Worker using UnwrappedTSN = UnwrappedSequenceNumber<TSN>;
157*d9f75844SAndroid Build Coastguard Worker 
158*d9f75844SAndroid Build Coastguard Worker // Unwrapped Stream Sequence Numbers (SSN)
159*d9f75844SAndroid Build Coastguard Worker using UnwrappedSSN = UnwrappedSequenceNumber<SSN>;
160*d9f75844SAndroid Build Coastguard Worker 
161*d9f75844SAndroid Build Coastguard Worker // Unwrapped Message Identifier (MID)
162*d9f75844SAndroid Build Coastguard Worker using UnwrappedMID = UnwrappedSequenceNumber<MID>;
163*d9f75844SAndroid Build Coastguard Worker 
164*d9f75844SAndroid Build Coastguard Worker }  // namespace dcsctp
165*d9f75844SAndroid Build Coastguard Worker 
166*d9f75844SAndroid Build Coastguard Worker #endif  // NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_
167