Completed
Push — master ( 1e032b...d01fce )
by Nate
02:22
created

HashMap::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 2
1
<?php
2
/*
3
 * Copyright (c) Nate Brunette.
4
 * Distributed under the MIT License (http://opensource.org/licenses/MIT)
5
 */
6
7
namespace Tebru\Collection;
8
9
use OutOfRangeException;
10
11
/**
12
 * Class HashMap
13
 *
14
 * [@see MapInterface] implementation
15
 *
16
 * @author Nate Brunette <[email protected]>
17
 */
18
class HashMap extends AbstractMap
19
{
20
    /**
21
     * The mapping keys
22
     *
23
     * @var array
24
     */
25
    protected $keys = [];
26
27
    /**
28
     * The mapping values
29
     *
30
     * @var array
31
     */
32
    protected $values = [];
33
34
    /**
35
     * Constructor
36
     *
37
     * @param array $map
38
     */
39 12
    public function __construct(array $map = [])
40
    {
41 12
        foreach ($map as $key => $value) {
42 1
            $hashcode = $this->hashCode($key);
43 1
            $this->keys[$hashcode] = $key;
44 1
            $this->values[$hashcode] = $value;
45
        }
46 12
    }
47
48
    /**
49
     * Removes all mappings from map
50
     *
51
     * @return void
52
     */
53 1
    public function clear()
54
    {
55 1
        $this->keys = [];
56 1
        $this->values = [];
57 1
    }
58
59
    /**
60
     * Returns true if the key exists in the lookup table
61
     *
62
     * @param mixed $key
63
     * @return bool
64
     */
65 29
    public function containsKey($key): bool
66
    {
67 29
        return array_key_exists($this->hashCode($key), $this->keys);
68
    }
69
70
    /**
71
     * Returns true if the value exists in the map
72
     *
73
     * @param mixed $value
74
     * @return bool
75
     */
76 2
    public function containsValue($value): bool
77
    {
78 2
        return in_array($value, $this->values, true);
79
    }
80
81
    /**
82
     * Return a set representation of map
83
     *
84
     * If a set is passed in, that set will be populated, otherwise
85
     * a default set will be used.
86
     *
87
     * @param SetInterface $set
88
     * @return SetInterface
89
     */
90 9
    public function entrySet(SetInterface $set = null): SetInterface
91
    {
92 9
        $set = $set ?? new HashSet();
93 9
        foreach ($this->keys as $hashCode => $key) {
94 9
            $set->add(new MapEntry($key, $this->values[$hashCode]));
95
        }
96
97 9
        return $set;
98
    }
99
100
    /**
101
     * Get the value at the specified key
102
     *
103
     * @param mixed $key
104
     * @return mixed
105
     * @throws \OutOfRangeException if the key doesn't exist
106
     */
107 7
    public function get($key)
108
    {
109 7
        $hashedKey = $this->hashCode($key);
110 7
        if (!$this->containsKey($key)) {
111 1
            throw new OutOfRangeException(sprintf('Tried to access array at key "%s"', $hashedKey));
112
        }
113
114 6
        return $this->values[$hashedKey];
115
    }
116
117
    /**
118
     * Returns true if the map is empty
119
     *
120
     * @return bool
121
     */
122 2
    public function isEmpty(): bool
123
    {
124 2
        return 0 === $this->count();
125
    }
126
127
    /**
128
     * Returns a set of they keys in the map
129
     *
130
     * If a set is passed in, that set will be populated, otherwise
131
     * a default set will be used.
132
     *
133
     * @param SetInterface $set
134
     * @return SetInterface
135
     */
136 2
    public function keySet(SetInterface $set = null): SetInterface
137
    {
138 2
        if (null === $set) {
139 1
            return new HashSet($this->keys);
140
        }
141
142 1
        $set->addAllArray($this->keys);
143
144 1
        return $set;
145
    }
146
147
    /**
148
     * Returns the previous value or null if there was no value
149
     *
150
     * @param mixed $key
151
     * @param mixed $value
152
     * @return mixed
153
     */
154 28
    public function put($key, $value)
155
    {
156 28
        $oldValue = null;
157 28
        $hashedKey = $this->hashCode($key);
158 28
        if ($this->containsKey($key)) {
159 2
            $oldValue = $this->get($key);
160 2
            $this->remove($hashedKey);
161
        }
162
163 28
        $this->keys[$hashedKey] = $key;
164 28
        $this->values[$hashedKey] = $value;
165
166 28
        return $oldValue;
167
    }
168
169
    /**
170
     * Remove the mapping for the key and returns the previous value
171
     * or null
172
     *
173
     * @param mixed $key
174
     * @return mixed
175
     */
176 4
    public function remove($key)
177
    {
178 4
        $hashedKey = $this->hashCode($key);
179 4
        if (!$this->containsKey($key)) {
180 3
            return false;
181
        }
182
183 1
        $oldValue = $this->get($key);
184 1
        unset($this->keys[$hashedKey], $this->values[$hashedKey]);
185
186 1
        return $oldValue;
187
    }
188
189
    /**
190
     * Returns the number of mappings in the map
191
     *
192
     * @return int
193
     */
194 5
    public function count(): int
195
    {
196 5
        return count($this->keys);
197
    }
198
199
    /**
200
     * Returns the keys as a collection
201
     *
202
     * @param CollectionInterface $collection
203
     * @return CollectionInterface
204
     */
205 13 View Code Duplication
    public function keys(CollectionInterface $collection = null): CollectionInterface
206
    {
207 13
        if (null === $collection) {
208 12
            return new ArrayList($this->keys);
209
        }
210
211 1
        $collection->addAllArray($this->keys);
212
213 1
        return $collection;
214
    }
215
216
    /**
217
     * Returns the values as a collection
218
     *
219
     * @param CollectionInterface $collection
220
     * @return CollectionInterface
221
     */
222 2 View Code Duplication
    public function values(CollectionInterface $collection = null): CollectionInterface
223
    {
224 2
        if (null === $collection) {
225 1
            return new ArrayList($this->values);
226
        }
227
228 1
        $collection->addAllArray($this->values);
229
230 1
        return $collection;
231
    }
232
233
    /**
234
     * Filter the collection using closure
235
     *
236
     * The closure will get passed a [@see MapEntry].  Returning true from the
237
     * closure will include that entry in the new map.
238
     *
239
     * @param callable $filter
240
     * @return MapInterface
241
     */
242 1
    public function filter(callable $filter): MapInterface
243
    {
244 1
        $map = new static();
245
246
        /** @var MapEntry $mapEntry */
247 1
        foreach ($this->entrySet() as $mapEntry) {
248 1
            if (false !== $filter($mapEntry)) {
249 1
                $map->put($mapEntry->key, $mapEntry->value);
250
            }
251
        }
252
253 1
        return $map;
254
    }
255
256
    /**
257
     * Generate a hashcode for a php value
258
     *
259
     * @param mixed $value
260
     * @return string
261
     */
262 29
    protected function hashCode($value): string
263
    {
264 29
        $type = gettype($value);
265
        switch ($type) {
266 29
            case 'object':
267 10
                return spl_object_hash($value);
268 24
            case 'array':
269 1
                return md5(serialize($value));
270
            default:
271 23
                return $type . md5($value);
272
        }
273
    }
274
}
275