Coverage for /home/runner/work/zserio/zserio/compiler/extensions/python/runtime/src/zserio/hashcode.py: 100%

90 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2024-12-05 10:43 +0000

1""" 

2The module provides utility methods for hash code calculation. 

3""" 

4 

5import typing 

6 

7from zserio.float import float_to_uint32, float_to_uint64 

8 

9HASH_SEED = 23 

10HASH_PRIME_NUMBER = 37 

11 

12 

13def calc_hashcode_bool(seed_value: int, value: bool) -> int: 

14 """ 

15 Calculates hash code for a boolean value. 

16 

17 :param seed_value: Seed value (current hash code). 

18 :param value: Value to use. 

19 :returns: Calculated hash code. 

20 """ 

21 

22 return calc_hashcode_int32(seed_value, 1 if value else 0) 

23 

24 

25def calc_hashcode_int32(seed_value: int, value: int) -> int: 

26 """ 

27 Calculates hash code for a 32-bit integral value. 

28 

29 :param seed_value: Seed value (current hash code). 

30 :param value: Value to use. 

31 :returns: Calculated hash code. 

32 """ 

33 

34 if value is None: 

35 return calc_hashcode_int32(seed_value, 0) 

36 

37 return (HASH_PRIME_NUMBER * seed_value + value) & 0xFFFFFFFF 

38 

39 

40def calc_hashcode_int64(seed_value: int, value: int) -> int: 

41 """ 

42 Calculates hash code for a 64-bit integral value. 

43 

44 :param seed_value: Seed value (current hash code). 

45 :param value: Value to use. 

46 :returns: Calculated hash code. 

47 """ 

48 

49 if value is None: 

50 return calc_hashcode_int32(seed_value, 0) 

51 

52 int_value_for_hash = (value & 0xFFFFFFFF) ^ ((value & 0xFFFFFFFFFFFFFFFF) >> 32) 

53 return (HASH_PRIME_NUMBER * seed_value + int_value_for_hash) & 0xFFFFFFFF 

54 

55 

56def calc_hashcode_float32(seed_value: int, value: float) -> int: 

57 """ 

58 Calculates hash code for a 32-bit float value. 

59 

60 :param seed_value: Seed value (current hash code). 

61 :param value: Value to use. 

62 :returns: Calculated hash code. 

63 """ 

64 

65 if value is None: 

66 return calc_hashcode_int32(seed_value, 0) 

67 

68 int_value = float_to_uint32(value) 

69 return calc_hashcode_int32(seed_value, int_value) 

70 

71 

72def calc_hashcode_float64(seed_value: int, value: float) -> int: 

73 """ 

74 Calculates hash code for a 64-bit float value. 

75 

76 :param seed_value: Seed value (current hash code). 

77 :param value: Value to use. 

78 :returns: Calculated hash code. 

79 """ 

80 

81 if value is None: 

82 return calc_hashcode_int32(seed_value, 0) 

83 

84 int_value = float_to_uint64(value) 

85 return calc_hashcode_int64(seed_value, int_value) 

86 

87 

88def calc_hashcode_bytes(seed_value: int, value: bytearray) -> int: 

89 """ 

90 Calculates hash code for a bytes value. 

91 

92 :param seed_value: Seed value (current hash code). 

93 :param value: Value to use. 

94 :returns: Calculated hash code. 

95 """ 

96 

97 if value is None: 

98 return calc_hashcode_int32(seed_value, 0) 

99 

100 result = seed_value 

101 for element in value: 

102 result = calc_hashcode_int32(result, element) 

103 

104 return result 

105 

106 

107def calc_hashcode_string(seed_value: int, value: str) -> int: 

108 """ 

109 Calculates hash code for a string value. 

110 

111 :param seed_value: Seed value (current hash code). 

112 :param value: Value to use. 

113 :returns: Calculated hash code. 

114 """ 

115 

116 if value is None: 

117 return calc_hashcode_int32(seed_value, 0) 

118 

119 result = seed_value 

120 for element in value: 

121 result = calc_hashcode_int32(result, ord(element)) 

122 

123 return result 

124 

125 

126def calc_hashcode_object(seed_value: int, value: typing.Any) -> int: 

127 """ 

128 Calculates hash code for an object value. 

129 

130 This is used for all objects (in zserio runtime or generated) which override the default __hash__ method. 

131 

132 :param seed_value: Seed value (current hash code). 

133 :param value: Value to use. 

134 :returns: Calculated hash code. 

135 """ 

136 

137 # using __hash__ to prevent 32-bit Python hash() truncation 

138 # pylint: disable=unnecessary-dunder-call 

139 return calc_hashcode_int32(seed_value, value.__hash__() if value else 0) 

140 

141 

142def calc_hashcode_bool_array(seed_value: int, value: typing.List[bool]) -> int: 

143 """ 

144 Calculates hash code for a boolean array value. 

145 

146 :param seed_value: Seed value (current hash code). 

147 :param value: Value to use. 

148 :returns: Calculated hash code. 

149 """ 

150 

151 if value is None: 

152 return calc_hashcode_int32(seed_value, 0) 

153 

154 result = seed_value 

155 for element in value: 

156 result = calc_hashcode_bool(result, element) 

157 return result 

158 

159 

160def calc_hashcode_int_array(seed_value: int, value: typing.List[int]) -> int: 

161 """ 

162 Calculates hash code for an integral array value. 

163 

164 :param seed_value: Seed value (current hash code). 

165 :param value: Value to use. 

166 :returns: Calculated hash code. 

167 """ 

168 

169 if value is None: 

170 return calc_hashcode_int32(seed_value, 0) 

171 

172 result = seed_value 

173 for element in value: 

174 result = calc_hashcode_int32(result, element) 

175 return result 

176 

177 

178def calc_hashcode_float32_array(seed_value: int, value: typing.List[int]) -> int: 

179 """ 

180 Calculates hash code for a 32-bit float array value. 

181 

182 :param seed_value: Seed value (current hash code). 

183 :param value: Value to use. 

184 :returns: Calculated hash code. 

185 """ 

186 

187 if value is None: 

188 return calc_hashcode_int32(seed_value, 0) 

189 

190 result = seed_value 

191 for element in value: 

192 result = calc_hashcode_float32(result, element) 

193 return result 

194 

195 

196def calc_hashcode_float64_array(seed_value: int, value: typing.List[int]) -> int: 

197 """ 

198 Calculates hash code for a 64-bit float array value. 

199 

200 :param seed_value: Seed value (current hash code). 

201 :param value: Value to use. 

202 :returns: Calculated hash code. 

203 """ 

204 

205 if value is None: 

206 return calc_hashcode_int32(seed_value, 0) 

207 

208 result = seed_value 

209 for element in value: 

210 result = calc_hashcode_float64(result, element) 

211 return result 

212 

213 

214def calc_hashcode_bytes_array(seed_value: int, value: typing.List[bytearray]) -> int: 

215 """ 

216 Calculates hash code for a bytes array value. 

217 

218 :param seed_value: Seed value (current hash code). 

219 :param value: Value to use. 

220 :returns: Calculated hash code. 

221 """ 

222 

223 if value is None: 

224 return calc_hashcode_int32(seed_value, 0) 

225 

226 result = seed_value 

227 for element in value: 

228 result = calc_hashcode_bytes(result, element) 

229 return result 

230 

231 

232def calc_hashcode_string_array(seed_value: int, value: typing.List[str]) -> int: 

233 """ 

234 Calculates hash code for a string array value. 

235 

236 :param seed_value: Seed value (current hash code). 

237 :param value: Value to use. 

238 :returns: Calculated hash code. 

239 """ 

240 

241 if value is None: 

242 return calc_hashcode_int32(seed_value, 0) 

243 

244 result = seed_value 

245 for element in value: 

246 result = calc_hashcode_string(result, element) 

247 return result 

248 

249 

250def calc_hashcode_object_array(seed_value: int, value: typing.List[typing.Any]) -> int: 

251 """ 

252 Calculates hash code for an object array value. 

253 

254 This is used for arrays of all objects (in zserio runtime or generated) which override the default 

255 __hash__ method. 

256 

257 :param seed_value: Seed value (current hash code). 

258 :param value: Value to use. 

259 :returns: Calculated hash code. 

260 """ 

261 

262 if value is None: 

263 return calc_hashcode_int32(seed_value, 0) 

264 

265 result = seed_value 

266 for element in value: 

267 result = calc_hashcode_object(result, element) 

268 return result