A Discrete-Event Network Simulator
API
lollipop-counter.h
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2020 Universita' di Firenze, Italy
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
19  */
20 
21 
22 #ifndef LOLLIPOP_COUNTER_H
23 #define LOLLIPOP_COUNTER_H
24 
25 #include <limits>
26 #include "ns3/abort.h"
27 
28 namespace ns3 {
29 
62 template <class T>
64 {
65 public:
73  {
74  NS_ABORT_MSG_UNLESS (std::is_unsigned<T>::value, "Lollipop counters must be defined on unsigned integer types");
75 
76  uint16_t numberofDigits = std::numeric_limits<T>::digits;
77  m_sequenceWindow = 1 << (numberofDigits / 2);
78 
80  }
81 
91  {
92  uint16_t numberofDigits = std::numeric_limits<T>::digits;
93  m_sequenceWindow = 1 << (numberofDigits / 2);
94 
95  m_value = val;
96  }
97 
105  {
106  m_value = o.m_value;
107  return *this;
108  }
109 
113  void Reset ()
114  {
116  }
117 
127  void SetSequenceWindowSize (uint16_t numberOfBits)
128  {
129  uint16_t numberofDigits = std::numeric_limits<T>::digits;
130 
131  NS_ABORT_MSG_IF (numberOfBits >= numberofDigits, "The size of the Sequence Window should be less than the counter size (which is " << +m_maxValue << ")");
132 
133  m_sequenceWindow = 1 << numberOfBits;
134 
136  }
137 
151  bool IsComparable (const LollipopCounter &val) const
152  {
153  NS_ABORT_MSG_IF (m_sequenceWindow != val.m_sequenceWindow, "Can not compare two Lollipop Counters with different sequence windows");
154 
157  {
158  // They are desynchronized - comparison is impossible.
159  T absDiff = AbsoluteMagnitudeOfDifference (val);
160  if (absDiff > m_sequenceWindow)
161  {
162  return false;
163  }
164  }
165  return true;
166  }
167 
173  bool IsInit () const
174  {
175  if ( m_value > m_circularRegion )
176  {
177  return true;
178  }
179  return false;
180  }
181 
188  friend bool operator == (const LollipopCounter & lhs, const LollipopCounter & rhs)
189  {
190 
191  NS_ABORT_MSG_IF (lhs.m_sequenceWindow != rhs.m_sequenceWindow, "Can not compare two Lollipop Counters with different sequence windows");
192 
193  if (lhs.m_value == rhs.m_value)
194  {
195  return true;
196  }
197  return false;
198  }
199 
206  friend bool operator > (const LollipopCounter & lhs, const LollipopCounter & rhs)
207  {
208  NS_ABORT_MSG_IF (lhs.m_sequenceWindow != rhs.m_sequenceWindow, "Can not compare two Lollipop Counters with different sequence windows");
209 
210  if (lhs.m_value == rhs.m_value)
211  {
212  return false;
213  }
214 
215  if ((lhs.m_value <= m_circularRegion && rhs.m_value <= m_circularRegion)
216  || (lhs.m_value > m_circularRegion && rhs.m_value > m_circularRegion) )
217  {
218  // both counters are in the same region
219 
220  T absDiff = lhs.AbsoluteMagnitudeOfDifference (rhs);
221  if (absDiff > lhs.m_sequenceWindow)
222  {
223  // They are desynchronized - comparison is impossible.
224  // return false because we can not return anything else.
225  return false;
226  }
227 
228  // They are synchronized - comparison according to RFC1982.
229  T serialRegion = ((m_circularRegion >> 1) + 1);
230  return (((lhs.m_value < rhs.m_value) && ((rhs.m_value - lhs.m_value) > serialRegion))
231  || ((lhs.m_value > rhs.m_value) && ((lhs.m_value - rhs.m_value) < serialRegion)) );
232  }
233 
234  // One counter is in the "high" region and the other is in the in the "lower" region
235  bool lhsIsHigher;
236  T difference;
237 
238  if (lhs.m_value > m_circularRegion && rhs.m_value <= m_circularRegion)
239  {
240  lhsIsHigher = true;
241  // this is guaranteed to be positive and between [1...m_lollipopMaxValue].
242  difference = lhs.m_value - rhs.m_value;
243  }
244  else
245  {
246  lhsIsHigher = false;
247  // this is guaranteed to be positive and between [1...m_lollipopMaxValue].
248  difference = rhs.m_value - lhs.m_value;
249  }
250 
251  T distance = (m_maxValue - difference) + 1; // this is guaranteed to be positive and between [1...m_lollipopMaxValue].
252  if (distance > lhs.m_sequenceWindow)
253  {
254  if (lhsIsHigher)
255  {
256  return true;
257  }
258  else
259  {
260  return false;
261  }
262  }
263  else
264  {
265  if (lhsIsHigher)
266  {
267  return false;
268  }
269  else
270  {
271  return true;
272  }
273  }
274 
275  // this should never be reached.
276  return false;
277  }
278 
285  friend bool operator < (const LollipopCounter & lhs, const LollipopCounter & rhs)
286  {
287  if (!lhs.IsComparable (rhs))
288  {
289  return false;
290  }
291 
292  if (lhs > rhs)
293  {
294  return false;
295  }
296  else if (lhs == rhs)
297  {
298  return false;
299  }
300 
301  return true;
302  }
303 
309  friend LollipopCounter operator++ (LollipopCounter& val) // prefix ++
310  {
311  val.m_value++;
312 
313  if ( val.m_value == val.m_circularRegion + 1 )
314  {
315  val.m_value = 0;
316  }
317 
318  return val;
319  }
320 
327  friend LollipopCounter operator++ (LollipopCounter& val, int noop) // postfix ++
328  {
329  LollipopCounter ans = val;
330  ++(val); // or just call operator++()
331  return ans;
332  }
333 
339  T GetValue () const
340  {
341  return m_value;
342  }
343 
351  friend std::ostream &
352  operator<< (std::ostream & os, LollipopCounter const & counter)
353  {
354  os << +counter.m_value;
355  return os;
356  }
357 
358 private:
359 
372  {
373  // useless because it is computed always on counters on their respective regions.
374  // Left (commented) for debugging purposes in case there is a code change.
375  // NS_ASSERT_MSG ((m_value <= m_circularRegion && val.m_value <= m_circularRegion) ||
376  // (m_value > m_circularRegion && val.m_value > m_circularRegion),
377  // "Absolute Magnitude Of Difference can be computed only on two values in the circular region " << +m_value << " - " << +val.m_value);
378 
379  T absDiffDirect = std::max (m_value, val.m_value) - std::min (m_value, val.m_value);
380  T absDiffWrapped = (std::min (m_value, val.m_value) + m_circularRegion + 1) - std::max (m_value, val.m_value);
381  T absDiff = std::min (absDiffDirect, absDiffWrapped);
382  return absDiff;
383  }
384 
387  static constexpr T m_maxValue = std::numeric_limits<T>::max ();
388  static constexpr T m_circularRegion = m_maxValue >> 1;
389 };
390 
401 
402 } /* namespace ns3 */
403 
404 #endif /* LOLLIPOP_COUNTER_H */
friend std::ostream & operator<<(std::ostream &os, LollipopCounter const &counter)
Output streamer for LollipopCounter.
friend bool operator==(const LollipopCounter &lhs, const LollipopCounter &rhs)
Arithmetic operator equal-to.
static constexpr T m_circularRegion
Circular region of the counter.
#define min(a, b)
Definition: 80211b.c:42
friend bool operator>(const LollipopCounter &lhs, const LollipopCounter &rhs)
Arithmetic operator greater-than.
friend bool operator<(const LollipopCounter &lhs, const LollipopCounter &rhs)
Arithmetic operator less-than.
bool IsComparable(const LollipopCounter &val) const
Checks if two counters are comparable (i.e., not desynchronized).
T GetValue() const
Get the counter value.
bool IsInit() const
Checks if a counter is in its starting region.
#define max(a, b)
Definition: 80211b.c:43
LollipopCounter< uint16_t > LollipopCounter16
16 bit Lollipop Counter.
void Reset()
Resets the counter to its initial value.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
T AbsoluteMagnitudeOfDifference(LollipopCounter const &val) const
Compute the Absolute Magnitude Of Difference between two counters.
LollipopCounter & operator=(const LollipopCounter &o)
Assignment.
static constexpr T m_maxValue
Maximum value of the counter.
T m_sequenceWindow
Sequence window used for comparing two counters.
LollipopCounter()
Builds a Lollipop counter with a default initial value.
LollipopCounter< uint8_t > LollipopCounter8
8 bit Lollipop Counter.
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
friend LollipopCounter operator++(LollipopCounter &val)
Prefix increment operator.
LollipopCounter(T val)
Builds a Lollipop counter with a specific initial value.
T m_value
Value of the Lollipop Counter.
void SetSequenceWindowSize(uint16_t numberOfBits)
Set the Sequence Window Size and resets the counter.
Template class implementing a Lollipop counter as defined in RFC 8505, RFC 6550, and [Perlman83]...