github.com/randomizedcoder/goTrackRTP@v0.0.2/trackRTP_math.go (about)

     1  package goTrackRTP
     2  
     3  // https://github.com/randomizedcoder/goTracker/
     4  
     5  // Math related functions ( sequence wrap handling )
     6  
     7  // Quote:
     8  // This function works by comparing the two numbers and their difference.
     9  // If their difference is less than 1/2 the maximum sequence number value,
    10  // then they must be close together - so we just check if one is greater
    11  // than the other, as usual.
    12  // However, if they are far apart, their difference will be greater than 1/2
    13  // the max sequence, then we paradoxically consider the sequence number more
    14  // recent if it is less than the current sequence number.
    15  // https://gafferongames.com/post/reliability_ordering_and_congestion_avoidance_over_udp/
    16  
    17  // See also: https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go
    18  
    19  // Using Less because the btree library uses less
    20  // https://github.com/google/btree/blob/v1.1.2/btree_generic.go#L135
    21  
    22  // isLess(seq, m uint16) is !isGreater
    23  // NOTE seq is first argument!!  We swap them here
    24  func isLess[T uint16](s1, s2 uint16) bool {
    25  	//log.Printf("isLess, s1:%d, s2:%d", s1, s2)
    26  	b := isLessBranchless(s1, s2)
    27  	//log.Printf("isLess, isLessBranchless(seq, m):%t", b)
    28  	return b
    29  }
    30  
    31  // isLessBranchless is a non-banching (if-ess) version to find less that handles sequence wrapping
    32  func isLessBranchless(s1, s2 uint16) bool {
    33  
    34  	diff := int(s1) - int(s2)
    35  
    36  	diff += int(maxUint16/2) + 1
    37  	diff &= int(maxUint16)
    38  
    39  	return diff > 0 && diff <= int(maxUint16/2)
    40  }
    41  
    42  // isLessBranch is a banching (if) version to find less that handles sequence wrapping
    43  func isLessBranch(s1, s2 uint16) bool {
    44  
    45  	if s1 < s2 {
    46  		return s2-s1 <= maxUint16/2
    47  	} else {
    48  		return s1-s2 > maxUint16/2
    49  	}
    50  }
    51  
    52  // uint16Diff returns difference in uint16 sequence handling wrapping
    53  func uint16Diff(s1, s2 uint16) uint16 {
    54  
    55  	//log.Printf("uint16Diff, m:%d, seq:%d", m, seq)
    56  
    57  	if s1 == s2 {
    58  		return 0
    59  	}
    60  
    61  	var abs uint16
    62  	if s1 < s2 {
    63  		abs = s2 - s1
    64  	} else {
    65  		abs = s1 - s2
    66  	}
    67  
    68  	if abs > maxUint16/2 {
    69  		return maxUint16 - abs + 1
    70  	}
    71  
    72  	//log.Printf("uint16Diff, s1:%d, s2:%d, abs:%d", s1, s2, abs)
    73  
    74  	return abs
    75  }
    76  
    77  // // isGreater determines if seq is ahead of m
    78  // func isGreater[T uint16](m, seq uint16) bool {
    79  // 	return isGreaterBranchless(m, seq)
    80  // }
    81  // // isGreaterBranchless determines if seq is ahead of m
    82  // // branchless version
    83  // func isGreaterBranchless[T uint16](m, seq uint16) bool {
    84  
    85  // 	diff := int(m) - int(seq)
    86  // 	diff += int(maxUint16/2) + 1
    87  // 	diff &= int(maxUint16)
    88  
    89  // 	return diff > 0 && diff <= int(maxUint16/2)
    90  // }
    91  
    92  // // isGreater determines if seq is ahead of m
    93  // func isGreaterBranch[T uint16](m, seq uint16) bool {
    94  // 	if m < seq {
    95  // 		return seq-m <= maxUint16/2
    96  // 	} else {
    97  // 		return m-seq > maxUint16/2
    98  // 	}
    99  // }