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 
152  bool IsComparable (const LollipopCounter &val) const
153  {
154  NS_ABORT_MSG_IF (m_sequenceWindow != val.m_sequenceWindow, "Can not compare two Lollipop Counters with different sequence windows");
155 
158  {
159  // They are desynchronized - comparison is impossible.
160  T absDiff = AbsoluteMagnitudeOfDifference (val);
161  if (absDiff > m_sequenceWindow)
162  {
163  return false;
164  }
165  }
166  return true;
167  }
168 
174  bool IsInit () const
175  {
176  if ( m_value > m_circularRegion )
177  {
178  return true;
179  }
180  return false;
181  }
182 
189  friend bool operator == (const LollipopCounter & lhs, const LollipopCounter & rhs)
190  {
191 
192  NS_ABORT_MSG_IF (lhs.m_sequenceWindow != rhs.m_sequenceWindow, "Can not compare two Lollipop Counters with different sequence windows");
193 
194  if (lhs.m_value == rhs.m_value)
195  {
196  return true;
197  }
198  return false;
199  }
200 
207  friend bool operator > (const LollipopCounter & lhs, const LollipopCounter & rhs)
208  {
209  NS_ABORT_MSG_IF (lhs.m_sequenceWindow != rhs.m_sequenceWindow, "Can not compare two Lollipop Counters with different sequence windows");
210 
211  if (lhs.m_value == rhs.m_value)
212  {
213  return false;
214  }
215 
216  if ((lhs.m_value <= m_circularRegion && rhs.m_value <= m_circularRegion)
217  || (lhs.m_value > m_circularRegion && rhs.m_value > m_circularRegion) )
218  {
219  // both counters are in the same region
220 
221  T absDiff = lhs.AbsoluteMagnitudeOfDifference (rhs);
222  if (absDiff > lhs.m_sequenceWindow)
223  {
224  // They are desynchronized - comparison is impossible.
225  // return false because we can not return anything else.
226  return false;
227  }
228 
229  // They are synchronized - comparison according to RFC1982.
230  T serialRegion = ((m_circularRegion >> 1) + 1);
231  return (((lhs.m_value < rhs.m_value) && ((rhs.m_value - lhs.m_value) > serialRegion))
232  || ((lhs.m_value > rhs.m_value) && ((lhs.m_value - rhs.m_value) < serialRegion)) );
233  }
234 
235  // One counter is in the "high" region and the other is in the in the "lower" region
236  bool lhsIsHigher;
237  T difference;
238 
239  if (lhs.m_value > m_circularRegion && rhs.m_value <= m_circularRegion)
240  {
241  lhsIsHigher = true;
242  // this is guaranteed to be positive and between [1...m_lollipopMaxValue].
243  difference = lhs.m_value - rhs.m_value;
244  }
245  else
246  {
247  lhsIsHigher = false;
248  // this is guaranteed to be positive and between [1...m_lollipopMaxValue].
249  difference = rhs.m_value - lhs.m_value;
250  }
251 
252  T distance = (m_maxValue - difference) + 1; // this is guaranteed to be positive and between [1...m_lollipopMaxValue].
253  if (distance > lhs.m_sequenceWindow)
254  {
255  if (lhsIsHigher)
256  {
257  return true;
258  }
259  else
260  {
261  return false;
262  }
263  }
264  else
265  {
266  if (lhsIsHigher)
267  {
268  return false;
269  }
270  else
271  {
272  return true;
273  }
274  }
275 
276  // this should never be reached.
277  return false;
278  }
279 
286  friend bool operator < (const LollipopCounter & lhs, const LollipopCounter & rhs)
287  {
288  if (!lhs.IsComparable (rhs))
289  {
290  return false;
291  }
292 
293  if (lhs > rhs)
294  {
295  return false;
296  }
297  else if (lhs == rhs)
298  {
299  return false;
300  }
301 
302  return true;
303  }
304 
310  friend LollipopCounter operator++ (LollipopCounter& val) // prefix ++
311  {
312  val.m_value++;
313 
314  if ( val.m_value == val.m_circularRegion + 1 )
315  {
316  val.m_value = 0;
317  }
318 
319  return val;
320  }
321 
328  friend LollipopCounter operator++ (LollipopCounter& val, int noop) // postfix ++
329  {
330  LollipopCounter ans = val;
331  ++(val); // or just call operator++()
332  return ans;
333  }
334 
340  T GetValue () const
341  {
342  return m_value;
343  }
344 
352  friend std::ostream &
353  operator<< (std::ostream & os, LollipopCounter const & counter)
354  {
355  os << +counter.m_value;
356  return os;
357  }
358 
359 private:
360 
373  {
374  // useless because it is computed always on counters on their respective regions.
375  // Left (commented) for debugging purposes in case there is a code change.
376  // NS_ASSERT_MSG ((m_value <= m_circularRegion && val.m_value <= m_circularRegion) ||
377  // (m_value > m_circularRegion && val.m_value > m_circularRegion),
378  // "Absolute Magnitude Of Difference can be computed only on two values in the circular region " << +m_value << " - " << +val.m_value);
379 
380  T absDiffDirect = std::max (m_value, val.m_value) - std::min (m_value, val.m_value);
381  T absDiffWrapped = (std::min (m_value, val.m_value) + m_circularRegion + 1) - std::max (m_value, val.m_value);
382  T absDiff = std::min (absDiffDirect, absDiffWrapped);
383  return absDiff;
384  }
385 
388  static constexpr T m_maxValue = std::numeric_limits<T>::max ();
389  static constexpr T m_circularRegion = m_maxValue >> 1;
390 };
391 
402 
403 } /* namespace ns3 */
404 
405 #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 the counter is comparable with another counter (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]...