HashVisitor.swift 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Sources/SwiftProtobuf/HashVisitor.swift - Hashing support
  2. //
  3. // Copyright (c) 2014 - 2016 Apple Inc. and the project authors
  4. // Licensed under Apache License v2.0 with Runtime Library Exception
  5. //
  6. // See LICENSE.txt for license information:
  7. // https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
  8. //
  9. // -----------------------------------------------------------------------------
  10. ///
  11. /// Hashing is basically a serialization problem, so we can leverage the
  12. /// generated traversal methods for that.
  13. ///
  14. // -----------------------------------------------------------------------------
  15. import Foundation
  16. private let i_2166136261 = Int(bitPattern: 2_166_136_261)
  17. private let i_16777619 = Int(16_777_619)
  18. /// Computes the hash of a message by visiting its fields recursively.
  19. ///
  20. /// Note that because this visits every field, it has the potential to be slow
  21. /// for large or deeply nested messages. Users who need to use such messages as
  22. /// dictionary keys or set members can use a wrapper struct around the message
  23. /// and use a custom Hashable implementation that looks at the subset of the
  24. /// message fields they want to include.
  25. internal struct HashVisitor: Visitor {
  26. internal private(set) var hasher: Hasher
  27. init(_ hasher: Hasher) {
  28. self.hasher = hasher
  29. }
  30. mutating func visitUnknown(bytes: Data) throws {
  31. hasher.combine(bytes)
  32. }
  33. mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
  34. hasher.combine(fieldNumber)
  35. hasher.combine(value)
  36. }
  37. mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
  38. hasher.combine(fieldNumber)
  39. hasher.combine(value)
  40. }
  41. mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
  42. hasher.combine(fieldNumber)
  43. hasher.combine(value)
  44. }
  45. mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
  46. hasher.combine(fieldNumber)
  47. hasher.combine(value)
  48. }
  49. mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
  50. hasher.combine(fieldNumber)
  51. hasher.combine(value)
  52. }
  53. mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
  54. hasher.combine(fieldNumber)
  55. hasher.combine(value)
  56. }
  57. mutating func visitSingularEnumField<E: Enum>(
  58. value: E,
  59. fieldNumber: Int
  60. ) {
  61. hasher.combine(fieldNumber)
  62. hasher.combine(value)
  63. }
  64. mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) {
  65. hasher.combine(fieldNumber)
  66. value.hash(into: &hasher)
  67. }
  68. mutating func visitRepeatedFloatField(value: [Float], fieldNumber: Int) throws {
  69. assert(!value.isEmpty)
  70. hasher.combine(fieldNumber)
  71. hasher.combine(value)
  72. }
  73. mutating func visitRepeatedDoubleField(value: [Double], fieldNumber: Int) throws {
  74. assert(!value.isEmpty)
  75. hasher.combine(fieldNumber)
  76. hasher.combine(value)
  77. }
  78. mutating func visitRepeatedInt32Field(value: [Int32], fieldNumber: Int) throws {
  79. assert(!value.isEmpty)
  80. hasher.combine(fieldNumber)
  81. hasher.combine(value)
  82. }
  83. mutating func visitRepeatedInt64Field(value: [Int64], fieldNumber: Int) throws {
  84. assert(!value.isEmpty)
  85. hasher.combine(fieldNumber)
  86. hasher.combine(value)
  87. }
  88. mutating func visitRepeatedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
  89. assert(!value.isEmpty)
  90. hasher.combine(fieldNumber)
  91. hasher.combine(value)
  92. }
  93. mutating func visitRepeatedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
  94. assert(!value.isEmpty)
  95. hasher.combine(fieldNumber)
  96. hasher.combine(value)
  97. }
  98. mutating func visitRepeatedSInt32Field(value: [Int32], fieldNumber: Int) throws {
  99. assert(!value.isEmpty)
  100. hasher.combine(fieldNumber)
  101. hasher.combine(value)
  102. }
  103. mutating func visitRepeatedSInt64Field(value: [Int64], fieldNumber: Int) throws {
  104. assert(!value.isEmpty)
  105. hasher.combine(fieldNumber)
  106. hasher.combine(value)
  107. }
  108. mutating func visitRepeatedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
  109. assert(!value.isEmpty)
  110. hasher.combine(fieldNumber)
  111. hasher.combine(value)
  112. }
  113. mutating func visitRepeatedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
  114. assert(!value.isEmpty)
  115. hasher.combine(fieldNumber)
  116. hasher.combine(value)
  117. }
  118. mutating func visitRepeatedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
  119. assert(!value.isEmpty)
  120. hasher.combine(fieldNumber)
  121. hasher.combine(value)
  122. }
  123. mutating func visitRepeatedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
  124. assert(!value.isEmpty)
  125. hasher.combine(fieldNumber)
  126. hasher.combine(value)
  127. }
  128. mutating func visitRepeatedBoolField(value: [Bool], fieldNumber: Int) throws {
  129. assert(!value.isEmpty)
  130. hasher.combine(fieldNumber)
  131. hasher.combine(value)
  132. }
  133. mutating func visitRepeatedStringField(value: [String], fieldNumber: Int) throws {
  134. assert(!value.isEmpty)
  135. hasher.combine(fieldNumber)
  136. hasher.combine(value)
  137. }
  138. mutating func visitRepeatedBytesField(value: [Data], fieldNumber: Int) throws {
  139. assert(!value.isEmpty)
  140. hasher.combine(fieldNumber)
  141. hasher.combine(value)
  142. }
  143. mutating func visitRepeatedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
  144. assert(!value.isEmpty)
  145. hasher.combine(fieldNumber)
  146. hasher.combine(value)
  147. }
  148. mutating func visitRepeatedMessageField<M: Message>(value: [M], fieldNumber: Int) throws {
  149. assert(!value.isEmpty)
  150. hasher.combine(fieldNumber)
  151. for v in value {
  152. v.hash(into: &hasher)
  153. }
  154. }
  155. mutating func visitRepeatedGroupField<G: Message>(value: [G], fieldNumber: Int) throws {
  156. assert(!value.isEmpty)
  157. hasher.combine(fieldNumber)
  158. for v in value {
  159. v.hash(into: &hasher)
  160. }
  161. }
  162. mutating func visitMapField<KeyType, ValueType: MapValueType>(
  163. fieldType: _ProtobufMap<KeyType, ValueType>.Type,
  164. value: _ProtobufMap<KeyType, ValueType>.BaseType,
  165. fieldNumber: Int
  166. ) throws {
  167. hasher.combine(fieldNumber)
  168. hasher.combine(value)
  169. }
  170. mutating func visitMapField<KeyType, ValueType>(
  171. fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
  172. value: _ProtobufEnumMap<KeyType, ValueType>.BaseType,
  173. fieldNumber: Int
  174. ) throws where ValueType.RawValue == Int {
  175. hasher.combine(fieldNumber)
  176. hasher.combine(value)
  177. }
  178. mutating func visitMapField<KeyType, ValueType>(
  179. fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
  180. value: _ProtobufMessageMap<KeyType, ValueType>.BaseType,
  181. fieldNumber: Int
  182. ) throws {
  183. hasher.combine(fieldNumber)
  184. hasher.combine(value)
  185. }
  186. }