A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
sequence-number.h
Go to the documentation of this file.
1//
2// Copyright (c) 2008-2010 INESC Porto
3//
4// SPDX-License-Identifier: GPL-2.0-only
5//
6// Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt> <gjcarneiro@gmail.com>
7//
8
9#ifndef NS3_SEQ_NUM_H
10#define NS3_SEQ_NUM_H
11
12#include "ns3/assert.h"
13#include "ns3/type-name.h"
14
15#include <compare>
16#include <concepts>
17#include <iostream>
18#include <limits>
19#include <stdint.h>
20
21namespace ns3
22{
23
24/**
25 * @ingroup network
26 * @defgroup seq-counters Sequence Counter
27 * @brief "sequence number" classes
28 */
29
30/**
31 * @ingroup seq-counters
32 * @brief Generic "sequence number" class
33 *
34 * This class can be used to handle sequence numbers. In networking
35 * protocols, sequence numbers are fixed precision integer numbers
36 * that are used to order events relative to each other. A sequence
37 * number is expected to increase over time but, since it has a
38 * limited number of bits, the number will "wrap around" from the
39 * maximum value that can represented with the given number of bits
40 * back to zero. For this reason, comparison of two sequence numbers,
41 * and subtraction, is non-trivial. The SequenceNumber class behaves
42 * like a number, with the usual arithmetic operators implemented, but
43 * knows how to correctly compare and subtract sequence numbers.
44 *
45 * Sequence number operations are defined in \RFC{1982}. However, the
46 * RFC leaves as implementation-dependent the case of two sequence numbers
47 * whose difference is equal to half of the possible range (e.g., 0 and
48 * 128 for a 8-bit sequence number).
49 * \RFC{3626} (OLSR) fixes this ambiguity by defining the relationship.
50 * This implementation follows the \RFC{3626} definition. Hence, in this
51 * example, 128 is less than 0.
52 *
53 * The relationship table for a 4-bit sequence number is the following:
54 * - 4-bit sequence number value 0 = 0
55 * - 4-bit sequence number value 1 > 0
56 * - 4-bit sequence number value 2 > 0
57 * - 4-bit sequence number value 3 > 0
58 * - 4-bit sequence number value 4 > 0
59 * - 4-bit sequence number value 5 > 0
60 * - 4-bit sequence number value 6 > 0
61 * - 4-bit sequence number value 7 > 0
62 * - 4-bit sequence number value 8 < 0
63 * - 4-bit sequence number value 9 < 0
64 * - 4-bit sequence number value 10 < 0
65 * - 4-bit sequence number value 11 < 0
66 * - 4-bit sequence number value 12 < 0
67 * - 4-bit sequence number value 13 < 0
68 * - 4-bit sequence number value 14 < 0
69 * - 4-bit sequence number value 15 < 0
70 *
71 * This is a templated class. To use it you need to supply one
72 * fundamental type as a template parameter: NUMERIC_TYPE.
73 * The second parameter NUM_BITS is optional, and represents
74 * the number of bits used in the SequenceNumber.
75 * It must be equal or less than the number of available bits in the
76 * NUMERIC_TYPE.
77 *
78 * For instance, SequenceNumber<uint32_t> gives
79 * you a 32-bit sequence number, while SequenceNumber<uint16_t, 10>
80 * is a 10-bit one.
81 *
82 * For your convenience, SequenceNumber32, SequenceNumber16, and
83 * SequenceNumber8 are defined as typedefs.
84 *
85 * You can safely assign a value to a sequence number, provided that it
86 * is in the allowed range. E.g, the following code will raise an assert:
87 * @code{.cpp}
88 * // 42 is representable in uint8_t, but needs more than 4 bits
89 * SequenceNumber<uint8_t, 4> seqNum{42};
90 * @endcode
91 *
92 * Sequence numbers can be printed, but they can not be automatically
93 * converted to an integer type. Furthermore, the conversion from an
94 * integer type must be explicit, e.g., it is not possible to compare
95 * a sequence number and an integer:
96 * @code{.cpp}
97 * SequenceNumber<uint8_t, 4> seqNum1{0}; // OK
98 * SequenceNumber<uint8_t, 4> seqNum2{1}; // OK
99 * seqNum2 = 2; // OK
100 * std::cout << "seqNum1 < seqNum2? " << std::boolalpha << (seqNum1 < seqNum2) << "\n"; // OK
101 * // std::cout << "seqNum1 < 1? " << std::boolalpha << (seqNum1 < 1) << "\n"; // ERROR
102 * @endcode
103 * The above limitation is to avoid mistakes, since integers and sequence numbers have very
104 * different comparison rules.
105 *
106 * @note Due to the internal representation and the semantics of `operator -` between two
107 * sequence numbers, `SequenceNumber<uint64_t>` are disallowed.
108 */
109template <typename NUMERIC_TYPE, uint8_t NUM_BITS = std::numeric_limits<NUMERIC_TYPE>::digits>
110 requires std::unsigned_integral<std::remove_cv_t<NUMERIC_TYPE>> && (NUM_BITS < 64) &&
111 (NUM_BITS <= std::numeric_limits<NUMERIC_TYPE>::digits)
112
114{
115 public:
116 /**
117 * SIGNED_TYPE is used in some operators, and is the signed counterpart
118 * of NUMERIC_TYPE
119 */
120 using SIGNED_TYPE = std::make_signed_t<NUMERIC_TYPE>;
121
122 /// Total number of sequence numbers.
123 static constexpr size_t N_SEQUENCE_NUMBERS = 1 << NUM_BITS;
124
125 /// Number of bits used by the sequence number
126 static constexpr NUMERIC_TYPE N_BITS{NUM_BITS};
127
128 SequenceNumber() = default;
129
130 /**
131 * @brief Constructs a SequenceNumber with the given value
132 * @param value the sequence number value
133 */
134 explicit SequenceNumber(NUMERIC_TYPE value)
135 {
136 NS_ASSERT_MSG(value <= MAX_VALUE,
137 "SequenceNumber: " << static_cast<uint64_t>(value)
138 << " is outside the allowed range [0, "
139 << static_cast<uint64_t>(MAX_VALUE) << "]");
140 m_value = value;
141 }
142
143 /**
144 * @brief Constructs a SequenceNumber from an assignment of given value
145 * @param value sequence number to copy
146 * @returns reference to the assignee
147 */
149 {
150 NS_ASSERT_MSG(value <= MAX_VALUE,
151 "SequenceNumber: " << static_cast<uint64_t>(value)
152 << " is outside the allowed range [0, "
153 << static_cast<uint64_t>(MAX_VALUE) << "]");
154 m_value = value;
155 return *this;
156 }
157
158 /**
159 * @brief Extracts the numeric value of the sequence number
160 * @returns the sequence number value
161 */
162 constexpr NUMERIC_TYPE GetValue() const
163 {
164 return m_value;
165 }
166
167 /**
168 * @brief Prefix increment operator
169 * @returns incremented sequence number
170 */
172 {
173 // The following is equivalent to a modulus
174 m_value = (m_value + 1) & MAX_VALUE;
175 return *this;
176 }
177
178 /**
179 * @brief Postfix increment operator
180 * @returns incremented sequence number
181 */
188
189 /**
190 * @brief Prefix decrement operator
191 * @returns decremented sequence number
192 */
194 {
195 m_value = (m_value - 1) & MAX_VALUE;
196 return *this;
197 }
198
199 /**
200 * @brief Postfix decrement operator
201 * @returns decremented sequence number
202 */
209
210 /**
211 * @brief Plus equals operator
212 * @param value value to add to sequence number
213 * @returns incremented sequence number
214 */
216 {
217 m_value += value;
219
220 return *this;
221 }
222
223 /**
224 * @brief Minus equals operator
225 * @param value value to subtract from sequence number
226 * @returns decremented sequence number
227 */
229 {
230 m_value -= value;
232 return *this;
233 }
234
235 /**
236 * @brief Operator defining addition of two sequence numbers.
237 *
238 * @note: this operator ignores the logical relationship between
239 * the operands (i.e., lesser, greater) and simply adds the respective
240 * values. If possible, avoid to use it.
241 *
242 * @param other sequence number added to this
243 * @returns sequence number representing sum
244 */
247 {
248 NUMERIC_TYPE val = m_value + other.m_value;
249 val &= MAX_VALUE;
251 }
252
253 /**
254 * @brief Addition operator for adding numeric value to sequence number.
255 *
256 * This function is syntactic sugar for:
257 * @code{.cpp}
258 * SequenceNumber<uint8_t> seqNum(0u);
259 * for (auto index=0; index<value, index++)
260 * {
261 * seqNum++;
262 * }
263 * @endcode
264 *
265 * @param delta value to add to sequence number
266 * @returns sequence number representing sum
267 */
269 {
270 NUMERIC_TYPE val = m_value + delta;
271 val &= MAX_VALUE;
273 }
274
275 /**
276 * @brief Subtraction operator for subtracting numeric value from sequence number.
277 *
278 * This function is syntactic sugar for:
279 * @code{.cpp}
280 * SequenceNumber<uint8_t> seqNum(0u);
281 * for (auto index=0; index<value, index++)
282 * {
283 * seqNum--;
284 * }
285 * @endcode
286 *
287 * @param delta value to subtract from sequence number
288 * @returns sequence number representing difference
289 */
291 {
292 NUMERIC_TYPE val = m_value - delta;
293 val &= MAX_VALUE;
295 }
296
297 /**
298 * @brief Subtraction operator for subtracting a sequence number from another sequence number.
299 *
300 * This function returns a signed distance between two sequence numbers. The dynamic range
301 * of the difference might be larger than the underlying unit type. I.e., the following
302 * code is a bug:
303 * @code{.cpp}
304 * SequenceNumber<uint8_t> seqNum1(0u);
305 * SequenceNumber<uint8_t> seqNum2(128u);
306 * int8_t difference = seqNum1 - seqNum2;
307 * @endcode
308 * because the result will be negative, even if the first operand is greater than the second.
309 *
310 * @param other sequence number to subtract from this sequence number
311 * @returns numeric value representing the signed difference
312 */
314 {
315 int64_t diff = static_cast<int64_t>(m_value) - static_cast<int64_t>(other.m_value);
316 static constexpr auto MAX_VALUE_D = static_cast<int64_t>(MAX_VALUE);
317 static constexpr auto HALF_MAX_VALUE_D = static_cast<int64_t>(HALF_MAX_VALUE);
318
319 if (diff > HALF_MAX_VALUE_D)
320 {
321 return (diff - 1 - MAX_VALUE_D);
322 }
323 else if (diff < -HALF_MAX_VALUE_D)
324 {
325 return (diff + 1 + MAX_VALUE_D);
326 }
327 return diff;
328 }
329
330 /**
331 * @brief Equality operator for comparing sequence number
332 * @param other sequence number to compare to this sequence number
333 * @returns true if the sequence numbers are equal
334 */
335 constexpr bool operator==(const SequenceNumber<NUMERIC_TYPE, NUM_BITS>& other) const
336 {
337 return m_value == other.m_value;
338 }
339
340 /**
341 * Spaceship comparison operator. All the other comparison operators
342 * are automatically generated from this one.
343 *
344 * Here is the critical part, how the comparison is made taking into
345 * account wrap-around. From RFC 3626:
346 *
347 * The sequence number S1 is said to be "greater than" the sequence
348 * number S2 if:
349 * S1 > S2 AND S1 - S2 <= MAXVALUE/2 OR
350 * S2 > S1 AND S2 - S1 > MAXVALUE/2
351 *
352 * @param other sequence number to compare to this one
353 * @returns The result of the comparison.
354 */
355 constexpr std::strong_ordering operator<=>(
357 {
358 if (m_value == other.m_value)
359 {
360 return std::strong_ordering::equivalent;
361 }
362 if (((m_value > other.m_value) && (m_value - other.m_value) <= HALF_MAX_VALUE) ||
363 ((other.m_value > m_value) && (other.m_value - m_value) > HALF_MAX_VALUE))
364 {
365 return std::strong_ordering::greater;
366 }
367 return std::strong_ordering::less;
368 }
369
370 /**
371 * @brief For printing sequence number
372 * @param os output stream
373 * @param val sequence number to display
374 * @returns output stream os
375 */
376 template <typename NUMERIC_TYPE2, uint8_t NUM_BITS2>
377 friend std::ostream& operator<<(std::ostream& os,
379
380 /**
381 * @brief For loading sequence number from input streams
382 * @param is input stream
383 * @param val sequence number to load
384 * @returns input stream is
385 */
386 template <typename NUMERIC_TYPE2, uint8_t NUM_BITS2>
387 friend std::istream& operator>>(std::istream& is,
389
390 public:
391 // Unimplemented operators
397 const SequenceNumber<NUMERIC_TYPE, NUM_BITS>&) const = delete;
399 const SequenceNumber<NUMERIC_TYPE, NUM_BITS>&) const = delete;
401 const SequenceNumber<NUMERIC_TYPE, NUM_BITS>&) const = delete;
402 bool operator!() const = delete;
407 const SequenceNumber<NUMERIC_TYPE, NUM_BITS>&) const = delete;
409 const SequenceNumber<NUMERIC_TYPE, NUM_BITS>&) const = delete;
411 const SequenceNumber<NUMERIC_TYPE, NUM_BITS>&) const = delete;
413 const SequenceNumber<NUMERIC_TYPE, NUM_BITS>&) const = delete;
415 const SequenceNumber<NUMERIC_TYPE, NUM_BITS>&) const = delete;
416 int operator*() = delete;
417
418 private:
419 NUMERIC_TYPE m_value{0}; //!< Sequence number value
420
421 /// Maximum representable value
422 static constexpr NUMERIC_TYPE MAX_VALUE = NUM_BITS < std::numeric_limits<NUMERIC_TYPE>::digits
423 ? (NUMERIC_TYPE{1} << NUM_BITS) - 1
424 : std::numeric_limits<NUMERIC_TYPE>::max();
425
426 /// Half the maximum representable value, used internally.
427 static constexpr NUMERIC_TYPE HALF_MAX_VALUE = MAX_VALUE / 2;
428};
429
430/**
431 * @brief Stream insertion operator.
432 *
433 * @param os the stream
434 * @param val the value
435 * @returns a reference to the stream
436 */
437template <typename NUMERIC_TYPE, uint8_t NUM_BITS>
438std::ostream&
439operator<<(std::ostream& os, const SequenceNumber<NUMERIC_TYPE, NUM_BITS>& val)
440{
441 os << static_cast<uint64_t>(val.m_value);
442 return os;
443}
444
445/**
446 * @brief Stream extraction operator.
447 *
448 * @param is the stream
449 * @param val the value
450 * @returns a reference to the stream
451 */
452template <typename NUMERIC_TYPE, uint8_t NUM_BITS>
453std::istream&
455{
456 NUMERIC_TYPE value;
457 is >> value;
458
459 NS_ASSERT_MSG(value <= val.MAX_VALUE,
460 "SequenceNumber: " << static_cast<uint64_t>(value)
461 << " is outside the allowed range [0, "
462 << static_cast<uint64_t>(val.MAX_VALUE) << "]");
463
464 val.m_value = value;
465 return is;
466}
467
468/**
469 * @ingroup seq-counters
470 * 32 bit Sequence number.
471 */
473/**
474 * @ingroup seq-counters
475 * 16 bit Sequence number.
476 */
478/**
479 * @ingroup seq-counters
480 * 8 bit Sequence number.
481 */
483
484namespace TracedValueCallback
485{
486
487/**
488 * @ingroup seq-counters
489 * TracedValue callback signature for SequenceNumber32
490 *
491 * @param [in] oldValue original value of the traced variable
492 * @param [in] newValue new value of the traced variable
493 */
494using SequenceNumber32 = void (*)(SequenceNumber32 oldValue, SequenceNumber32 newValue);
495
496/**
497 * @ingroup seq-counters
498 * TracedValue callback signature for SequenceNumber16
499 *
500 * @param [in] oldValue original value of the traced variable
501 * @param [in] newValue new value of the traced variable
502 */
503using SequenceNumber16 = void (*)(SequenceNumber16 oldValue, SequenceNumber16 newValue);
504
505/**
506 * @ingroup seq-counters
507 * TracedValue callback signature for SequenceNumber8
508 *
509 * @param [in] oldValue original value of the traced variable
510 * @param [in] newValue new value of the traced variable
511 */
512using SequenceNumber8 = void (*)(SequenceNumber8 oldValue, SequenceNumber8 newValue);
513
514} // namespace TracedValueCallback
515
516/**
517 * @ingroup seq-counters
518 *
519 * ns3::TypeNameGet<SequenceNumber32>() specialization.
520 * @returns The type name as a string.
521 */
523
524/**
525 * @ingroup seq-counters
526 *
527 * ns3::TypeNameGet<SequenceNumber16>() specialization.
528 * @returns The type name as a string.
529 */
531
532/**
533 * @ingroup seq-counters
534 *
535 * ns3::TypeNameGet<SequenceNumber8>() specialization.
536 * @returns The type name as a string.
537 */
539
540} // namespace ns3
541
542#endif /* NS3_SEQ_NUM_H */
Generic "sequence number" class.
constexpr NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator|(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &) const =delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator-(SIGNED_TYPE delta) const
Subtraction operator for subtracting numeric value from sequence number.
bool operator||(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &) const =delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > & operator=(NUMERIC_TYPE value)
Constructs a SequenceNumber from an assignment of given value.
static constexpr uint32_t MAX_VALUE
constexpr bool operator==(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &other) const
Equality operator for comparing sequence number.
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator+(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &other) const
Operator defining addition of two sequence numbers.
friend std::istream & operator>>(std::istream &is, const SequenceNumber< NUMERIC_TYPE2, NUM_BITS2 > &val)
For loading sequence number from input streams.
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator--(int)
Postfix decrement operator.
std::make_signed_t< NUMERIC_TYPE > SIGNED_TYPE
SIGNED_TYPE is used in some operators, and is the signed counterpart of NUMERIC_TYPE.
SequenceNumber< NUMERIC_TYPE, NUM_BITS > & operator+=(SIGNED_TYPE value)
Plus equals operator.
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator+(SIGNED_TYPE delta) const
Addition operator for adding numeric value to sequence number.
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator%(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &) const =delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator&(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &) const =delete
static constexpr size_t N_SEQUENCE_NUMBERS
SequenceNumber()=default
friend std::ostream & operator<<(std::ostream &os, const SequenceNumber< NUMERIC_TYPE2, NUM_BITS2 > &val)
For printing sequence number.
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator/(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &) const =delete
bool operator&&(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &) const =delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > & operator-=(SIGNED_TYPE value)
Minus equals operator.
int64_t operator-(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &other) const
Subtraction operator for subtracting a sequence number from another sequence number.
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator++()
Prefix increment operator.
int operator*()=delete
static constexpr uint32_t HALF_MAX_VALUE
static constexpr uint32_t N_BITS
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator>>(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &) const =delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator--()
Prefix decrement operator.
SequenceNumber(NUMERIC_TYPE value)
Constructs a SequenceNumber with the given value.
constexpr std::strong_ordering operator<=>(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &other) const
Spaceship comparison operator.
bool operator!() const =delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > & operator-=(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &)=delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator~() const =delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > & operator+=(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &)=delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator*(const SequenceNumber< NUMERIC_TYPE, NUM_BITS > &) const =delete
SequenceNumber< NUMERIC_TYPE, NUM_BITS > operator++(int)
Postfix increment operator.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define TYPENAMEGET_DEFINE(T)
Macro that defines a template specialization for TypeNameGet<T>() .
Definition type-name.h:49
SequenceNumber< uint16_t > SequenceNumber16
16 bit Sequence number.
void(*)(SequenceNumber16 oldValue, SequenceNumber16 newValue) SequenceNumber16
TracedValue callback signature for SequenceNumber16.
void(*)(SequenceNumber32 oldValue, SequenceNumber32 newValue) SequenceNumber32
TracedValue callback signature for SequenceNumber32.
void(*)(SequenceNumber8 oldValue, SequenceNumber8 newValue) SequenceNumber8
TracedValue callback signature for SequenceNumber8.
SequenceNumber< uint8_t > SequenceNumber8
8 bit Sequence number.
SequenceNumber< uint32_t > SequenceNumber32
32 bit Sequence number.
auto operator^(const TracedValue< T > &lhs, const TracedValue< U > &rhs) -> TracedValue< decltype(lhs.Get() ^ rhs.Get())>
Infix arithmetic operator for TracedValue.
TracedValue Callback function types.
Definition nstime.h:874
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
std::istream & operator>>(std::istream &is, Angles &a)
Definition angles.cc:172
STL namespace.