File: HashingAvalanche.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (58 lines) | stat: -rw-r--r-- 1,871 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// RUN: %target-build-swift -Xfrontend -disable-access-control -module-name a %s -o %t.out -O
// RUN: %target-codesign %t.out
// RUN: %target-run %t.out
// REQUIRES: executable_test

import SwiftPrivate
import StdlibUnittest


var HashingTestSuite = TestSuite("Hashing")

func avalancheTest<Input: FixedWidthInteger & UnsignedInteger>(
  for type: Input.Type,
  _ hashUnderTest: @escaping (Input) -> Int,
  _ pValue: Double
) {
  typealias Output = Int
  let testsInBatch = 100000
  let testData = (0 ..< testsInBatch).map { _ in Input.random(in: .min ... .max) }
  let testDataHashed = testData.map { hashUnderTest($0) }

  for inputBit in 0..<Input.bitWidth {
    // Using an array here makes the test too slow.
    let bitFlips = UnsafeMutablePointer<Int>.allocate(capacity: Output.bitWidth)
    bitFlips.initialize(to: 0, count: Output.bitWidth)
    for i in testData.indices {
      let inputA = testData[i]
      let outputA = testDataHashed[i]
      let inputB = inputA ^ (1 << UInt64(inputBit))
      let outputB = hashUnderTest(inputB)
      var delta = outputA ^ outputB
      for outputBit in 0..<Output.bitWidth {
        if delta & 1 == 1 {
          bitFlips[outputBit] += 1
        }
        delta = delta >> 1
      }
    }
    for outputBit in 0..<Output.bitWidth {
      expectTrue(
        chiSquaredUniform2(testsInBatch, bitFlips[outputBit], pValue),
        "inputBit: \(inputBit), outputBit: \(outputBit)")
    }
    bitFlips.deallocate()
  }
}

// White-box testing: assume that the other N-bit to N-bit mixing functions
// just dispatch to these.  (Avalanche test is relatively expensive.)
HashingTestSuite.test("Hasher.combine(UInt64)/avalanche") {
  avalancheTest(for: UInt64.self, _hashValue(for:), 0.02)
}

HashingTestSuite.test("Hasher.combine(UInt32)/avalanche") {
  avalancheTest(for: UInt32.self, _hashValue(for:), 0.02)
}

runAllTests()