IdentityHasher::hashBoolean()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 2
eloc 2
nc 2
nop 1
crap 2
1
<?php
2
3
/**
4
 * This file is part of the phpcommon/comparison package.
5
 *
6
 * (c) Marcos Passos <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE file
9
 * that was distributed with this source code.
10
 */
11
12
namespace PhpCommon\Comparison\Hasher;
13
14
use PhpCommon\Comparison\Equatable;
15
use PhpCommon\Comparison\Hasher;
16
use PhpCommon\IntMath\IntMath as Math;
17
18
/**
19
 * Provides an external means for producing hash codes and comparing values for
20
 * identity.
21
 *
22
 * This equivalence relation uses the strict equal operator (`===`) to compare
23
 * values, while hashing strategy varies according to the type of value.
24
 *
25
 * @author Marcos Passos <[email protected]>
26
 */
27
class IdentityHasher extends GenericHasher
28
{
29
    /**
30
     * Constant used to compute hash codes for `null`
31
     */
32
    const HASH_NULL = 0;
33
    
34
    /**
35
     * Constant used to compute hash codes for arrays
36
     */
37
    const HASH_ARRAY = 991;
38
39
    /**
40
     * The hash code for the boolean value `false`
41
     */
42
    const HASH_FALSE = 1237;
43
44
    /**
45
     * The hash code for the boolean value `true`
46
     */
47
    const HASH_TRUE = 1231;
48
49
    /**
50
     * Constant used to compute hash codes for objects
51
     */
52
    const HASH_OBJECT = 1093;
53
54
    /**
55
     * Constant used to compute hash codes for resources
56
     */
57
    const HASH_RESOURCE = 1471;
58
59
    /**
60
     * Constant used to compute hash codes for strings
61
     */
62
    const HASH_STRING = 1321;
63
64
    /**
65
     * Checks whether the current relation is considered equal to another.
66
     *
67
     * Since this class is stateless, its instances will always be considered
68
     * equal if they are of the same type.
69
     */
70 20
    public function equals(Equatable $other)
71
    {
72 20
        return static::class === get_class($other);
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     *
78
     * The specified values are considered equivalent if and only if the
79
     * right-hand value is also an array and they both contain the same
80
     * number of entries, in the same order and each pair of corresponding
81
     * entries is equivalent according to this relation. Empty arrays are
82
     * equivalent to one another.
83
     */
84 46
    protected function equivalentArray(array $left, $right)
85
    {
86 46
        return $left === $right;
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     *
92
     * The specified values are considered equivalent if and only if the
93
     * right-hand value is also a boolean and both are `true` or both are
94
     * `false`.
95
     */
96 66
    protected function equivalentBoolean($left, $right)
97
    {
98 66
        return $left === $right;
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     *
104
     * The specified values are considered equivalent if and only if the
105
     * right-hand value is also a float and they are numerically equal
106
     * (have the same number value). Positive and negative zeros are equal
107
     * to one another. {@link NAN} is not equal to anything, including
108
     * {@link NAN}.
109
     */
110 34
    protected function equivalentFloat($left, $right)
111
    {
112 34
        return $left === $right;
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     *
118
     * The specified values are considered equivalent if and only if the
119
     * right-hand value is also an integer and they are numerically equal
120
     * (have the same number value). Positive and negative zeros are equal
121
     * to one another.
122
     */
123 70
    protected function equivalentInteger($left, $right)
124
    {
125 70
        return $left === $right;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     *
131
     * The specified value is considered equivalent to `null` if and only if it
132
     * is strictly equal to `null`.
133
     */
134 34
    protected function equivalentNull($right)
135
    {
136 34
        return null === $right;
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     *
142
     * The specified values are considered equivalent if and only if the
143
     * right-hand value is also an object and both are references to the
144
     * same instance.
145
     */
146 44
    protected function equivalentObject($left, $right)
147
    {
148 44
        return $left === $right;
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     *
154
     * The specified values are considered equivalent if and only if the
155
     * right-hand value is also a resource and both have the same unique
156
     * resource number.
157
     */
158 26
    protected function equivalentResource($left, $right)
159
    {
160 26
        return $left === $right;
161
    }
162
163
    /**
164
     * {@inheritdoc}
165
     *
166
     * The specified values are considered equivalent if and only if the
167
     * right-hand value is also a string and both have the same sequence of
168
     * characters.
169
     */
170 82
    protected function equivalentString($left, $right)
171
    {
172 82
        return $left === $right;
173
    }
174
175
    /**
176
     * {@inheritdoc}
177
     *
178
     * The hash code is based on the _deep contents_ of the specified array.
179
     * More precisely, it is computed as follows:
180
     *
181
     * ```php
182
     * $hashCode = IdentityEquivalence::HASH_ARRAY;
183
     * foreach ($array => $key => $element)
184
     *     $hashCode = 31 * $hashCode + (hash($key) ^ hash($element));
185
     * ```
186
     *
187
     * Where `hash()` is a function that returns a hash code for a given value.
188
     * Note that the hash code of an empty array is the constant
189
     * {@link IdentityEquivalence::HASH_ARRAY} itself.
190
     */
191 12
    protected function hashArray(array $value)
192
    {
193 12
        $hash = self::HASH_ARRAY;
194
195 12
        foreach ($value as $key => $current) {
196 8
            $keyHash = $this->hashString($key);
197 8
            $valueHash = $this->hash($current);
198
199 8
            $hash = $hash * 31 + ($keyHash ^ $valueHash);
200 12
        }
201
202 12
        return $hash;
203
    }
204
205
    /**
206
     * {@inheritdoc}
207
     *
208
     * It is defined by mapping the values `true` and `false` to
209
     * integer numbers defined by {@link IdentityEquivalence::HASH_TRUE} and
210
     * {@link IdentityEquivalence::HASH_FALSE} respectively.
211
     */
212 8
    protected function hashBoolean($value)
213
    {
214 8
        return $value ? self::HASH_TRUE : self::HASH_FALSE;
215
    }
216
217
    /**
218
     * {@inheritdoc}
219
     *
220
     * It is computed by converting the float value to the integer bit
221
     * representation, according to the IEEE 754 floating-point single format
222
     * bit layout.
223
     *
224
     * @link https://pt.wikipedia.org/wiki/IEEE_754 IEEE Standard for
225
     *       Floating-Point Arithmetic.
226
     *
227
     */
228 6
    protected function hashFloat($value)
229
    {
230 6
        return unpack('i', pack('f', $value))[1];
231
    }
232
233
    /**
234
     * {@inheritdoc}
235
     *
236
     * This method uses the integer number as the hash code itself.
237
     */
238 12
    protected function hashInteger($value)
239
    {
240 12
        return $value;
241
    }
242
243
    /**
244
     * {@inheritdoc}
245
     *
246
     * The hash code for `null` is a constant defined by
247
     * {@link IdentityEquivalence::HASH_NULL}.
248
     */
249 6
    protected function hashNull()
250
    {
251 6
        return self::HASH_NULL;
252
    }
253
254
    /**
255
     * {@inheritdoc}
256
     *
257
     * The hash code is computed as follows:
258
     *
259
     * ```php
260
     * $k = IdentityEquivalence::HASH_OBJECT;
261
     * $hashCode = $k * hashString(spl_object_hash($object));
262
     * ```
263
     *
264
     * Where {@link IdentityEquivalence::HASH_OBJECT} is a constant and
265
     * `hashString()` is a function that returns a hash code for a given
266
     * string.
267
     */
268 6
    protected function hashObject($value)
269
    {
270 6
        return self::HASH_OBJECT * $this->hashString(spl_object_hash($value));
271
    }
272
273
    /**
274
     * {@inheritdoc}
275
     *
276
     * The hash code is computed as follows:
277
     *
278
     * ```php
279
     * $hashCode = IdentityEquivalence::HASH_STRING;
280
     * for ($i = 0; $i < length($string); $i++)
281
     *     $hashCode = $hashCode * 31 + charCode($string[$i]);
282
     * ```
283
     *
284
     * Where {@link IdentityEquivalence::HASH_STRING} is a constant, `$i` is
285
     * the position of the current character in the string, `$string[$i]` is
286
     * the ith character of the string, `length()` is a function that returns
287
     * the length of the string, `charCode()` is a function that returns the
288
     * ASCII code (as an integer) of a given character, and `^` indicates
289
     * exponentiation. Note that the hash code of a zero length string is the
290
     * constant {@link IdentityEquivalence::HASH_STRING} itself.
291
     */
292 16
    protected function hashString($value)
293
    {
294 16
        $hash = self::HASH_STRING;
295 16
        $value = strval($value);
296 16
        $length = strlen($value);
297
298 16
        if ($length === 0) {
299 2
            return $hash;
300
        }
301
302 14
        for ($i = 0; $i < $length; $i++) {
303 14
            $hash = Math::add(Math::multiply($hash, 31), ord($value[$i]));
304 14
        }
305
306 14
        return $hash;
307
    }
308
309
    /**
310
     * {@inheritdoc}
311
     *
312
     * The hash code is computed as follows:
313
     *
314
     * ```php
315
     * $k = IdentityEquivalence::HASH_RESOURCE;
316
     * $hashCode =  $k * (1 + resourceId($value));
317
     * ```
318
     *
319
     * Where `$k` is a constant defined by
320
     * {@link IdentityEquivalence::HASH_RESOURCE} and `resourceId()` is a
321
     * function that returns the unique resource number assigned to the
322
     * resource by PHP at runtime.
323
     */
324 4
    protected function hashResource($value)
325
    {
326 4
        return self::HASH_RESOURCE * (1 + (int) $value);
327
    }
328
}
329